Riven/srcgen/dotUtils.js

160 lines
5.1 KiB
JavaScript
Raw Normal View History

2019-10-19 21:39:53 +00:00
const changeCase = require('change-case');
2019-10-19 09:25:09 +00:00
// flatMap: https://gist.github.com/samgiles/762ee337dff48623e729
// [B](f: (A) ⇒ [B]): [B] ; Although the types in the arrays aren't strict (:
Array.prototype.flatMap = function(lambda) {
return Array.prototype.concat.apply([], this.map(lambda));
};
Array.prototype.groupBy = function(lambda) {
return Object.entries(this.reduce((agg, x) => {
const k = lambda(x);
(agg[k] = agg[k] || []).push(x);
return agg;
}, {}));
};
Array.prototype.sortBy = function(lambda) {
return this.sort((a, b) => {
const va = lambda(a);
const vb = lambda(b);
if ((typeof va) !== (typeof vb))
throw Error(`Mismatched sort types: ${typeof va}, ${typeof vb}.`);
if (typeof va === 'number')
return va - vb;
if (typeof va === 'string')
return va.localeCompare(vb);
throw Error(`Unknown sort type: ${typeof va}.`);
});
};
2019-10-19 09:25:09 +00:00
function preamble() {
2019-10-26 05:19:00 +00:00
return `\
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////`;
}
2019-10-19 09:25:09 +00:00
function capitalize(input) {
return input[0].toUpperCase() + input.slice(1);
}
function decapitalize(input) {
return input[0].toLowerCase() + input.slice(1);
}
function normalizeSchemaName(name) {
return name.replace(/DTO/ig, '');
}
function normalizeArgName(name) {
2019-10-19 21:39:53 +00:00
const tokens = name.split('_');
const argName = decapitalize(tokens.map(capitalize).join(''));
2019-10-19 09:25:09 +00:00
return 'base' === argName ? 'Base' : argName;
}
function normalizePropName(propName) {
2021-05-31 05:27:06 +00:00
let out = changeCase.snakeCase(propName);
if (/^\d/.test(out)) // No leading digits.
out = 'x' + out;
2019-10-19 21:39:53 +00:00
if ('type' === out)
return 'r#' + out;
return out;
2019-10-19 09:25:09 +00:00
}
function stringifyType(prop, { endpoint = null, optional = false, fullpath = true, owned = true }) {
2019-10-19 09:25:09 +00:00
if (prop.anyOf) {
prop = prop.anyOf[0];
}
if (optional) {
return `Option<${stringifyType(prop, { endpoint, fullpath, owned })}>`;
}
2019-10-19 09:25:09 +00:00
2019-10-26 05:19:00 +00:00
let enumType = prop['x-enum'];
if (enumType && 'locale' !== enumType)
return 'crate::consts::' + changeCase.pascalCase(enumType);
2019-10-19 09:25:09 +00:00
let refType = prop['$ref'];
if (refType) {
2019-10-22 21:28:23 +00:00
return (!endpoint ? '' : changeCase.snakeCase(endpoint) + '::') +
2019-10-19 09:25:09 +00:00
normalizeSchemaName(refType.slice(refType.indexOf('.') + 1));
}
switch (prop.type) {
2019-10-19 21:39:53 +00:00
case 'boolean': return 'bool';
case 'integer': return ('int32' === prop.format ? 'i32' : 'i64');
case 'number': return ('float' === prop.format ? 'f32' : 'f64');
case 'array':
const subprop = stringifyType(prop.items, { endpoint, optional, fullpath, owned });
2019-10-19 21:39:53 +00:00
return (owned ? (fullpath ? 'std::vec::' : '') + `Vec<${subprop}>` : `&[${subprop}]`);
case 'string': return (owned ? 'String' : '&str');
2019-10-19 09:25:09 +00:00
case 'object':
return 'std::collections::HashMap<' + stringifyType(prop['x-key'], { endpoint, optional, fullpath, owned }) + ', ' +
stringifyType(prop.additionalProperties, { endpoint, optional, fullpath, owned }) + '>';
2019-10-19 21:39:53 +00:00
default: return prop.type;
2019-10-19 09:25:09 +00:00
}
}
function formatJsonProperty(name) {
2019-10-19 21:39:53 +00:00
return `#[serde(rename = "${name}")]`;
2019-10-19 09:25:09 +00:00
}
function formatAddQueryParam(param) {
2021-05-22 02:04:04 +00:00
const k = `"${param.name}"`;
2021-06-30 21:07:37 +00:00
const name = normalizePropName(param.name);
2021-05-22 02:04:04 +00:00
const condStart = param.required ? '' : `mut request = request; if let Some(${name}) = ${name} { `;
const condEnd = param.required ? '' : ' }'
const prop = param.schema;
2019-10-29 23:51:41 +00:00
switch (prop.type) {
2021-05-22 02:04:04 +00:00
case 'array': return `let ${condStart}request = request.query(&*${name}.iter()`
+ `.map(|w| ( ${k}, w )).collect::<Vec<_>>());${condEnd}`;
case 'object':
throw 'unsupported';
default:
return `let ${condStart}request = request.query(&[ (${k}, ${name}) ]);${condEnd}`;
}
}
function formatAddHeaderParam(param) {
const k = `"${param.name}"`;
const name = changeCase.snakeCase(param.name);
const condStart = param.required ? '' : `mut request = request; if let Some(${name}) = ${name} { `;
const condEnd = param.required ? '' : ' }'
const prop = param.schema;
switch (prop.type) {
case 'string':
return `let ${condStart}request = request.header(${k}, ${name});${condEnd}`;
case 'object':
throw 'unsupported';
2019-10-29 23:51:41 +00:00
default:
2021-05-22 02:04:04 +00:00
return `let ${condStart}request = request.header(${k}, ${name}.to_string());${condEnd}`;
2019-10-29 23:51:41 +00:00
}
2019-10-19 09:25:09 +00:00
}
2019-10-19 21:39:53 +00:00
function formatRouteArgument(route, pathParams = []) {
if (!pathParams.length)
2021-05-22 00:31:52 +00:00
return `"${route}"`;
2019-10-19 21:39:53 +00:00
route = route.replace(/\{\S+?\}/g, '{}');
const args = pathParams
.map(({name}) => name)
.map(changeCase.snakeCase)
.join(', ');
2021-05-22 00:31:52 +00:00
return `&format!("${route}", ${args})`;
2019-10-19 21:39:53 +00:00
}
2019-10-19 09:25:09 +00:00
module.exports = {
2019-10-19 21:39:53 +00:00
changeCase,
preamble,
2019-10-19 09:25:09 +00:00
capitalize,
decapitalize,
normalizeSchemaName,
normalizeArgName,
normalizePropName,
stringifyType,
formatJsonProperty,
2019-10-19 21:39:53 +00:00
formatAddQueryParam,
2021-05-22 02:04:04 +00:00
formatAddHeaderParam,
2019-10-19 21:39:53 +00:00
formatRouteArgument,
2019-10-19 09:25:09 +00:00
};