rap2itf
Version:
rapper接口转换为typescirpt interface
244 lines (243 loc) • 9.61 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
exports.__esModule = true;
var json_schema_to_typescript_1 = require("json-schema-to-typescript");
var JSON5 = require("json5");
var _ = require("lodash");
function inferArraySchema(p, childProperties, common) {
var rule = (p.rule && p.rule.trim()) || '';
if (Object.keys(childProperties).length !== 0) {
// 如果有子孙那么肯定是 object
return [
p.name,
__assign(__assign({ type: 'array', items: {
type: 'object',
properties: childProperties,
// 把 child 的 required 挪到 items 下面
required: common.required,
additionalProperties: false
} }, common), { required: [] }),
];
}
else if (['+1', '1'].includes(rule) && p.value) {
// 当 rule 为 +1 时 mockjs 从属性值 array 中顺序选取 1 个元素,作为最终值。
// 当 rule 为 1 时 mockjs 从属性值 array 中随机选取 1 个元素,作为最终值。
// 这时候这个属性的类型并非 array,而是 array 子元素的类型
// 子元素的类型可以从 value 中推断出来
try {
var arr = JSON5.parse(p.value);
if (Array.isArray(arr) && arr.length) {
var type = _.chain(arr)
.map(function (e) { return typeof e; })
.uniq()
.value();
return [
p.name,
__assign({ type: type }, common),
];
}
else {
// 解析失败,返回 any
return [
p.name,
__assign({ type: ['string', 'number', 'boolean', 'object'] }, common),
];
}
}
catch (error) {
// 解析失败,返回 any
return [
p.name,
__assign({ type: ['string', 'number', 'boolean', 'object'] }, common),
];
}
}
else if (rule === '' && p.value) {
// 当有无子孙、有值、且无生成规则时,默认做 hack 满足 rap2 无法表示 array<primitive> 的问题,
// primitive 的具体类型通过 value 推断
try {
var v = JSON5.parse(p.value);
if (Array.isArray(v)) {
// 如果是空数组返回 any[]
if (!v.length) {
return [
p.name,
__assign({ type: 'array' }, common),
];
}
// 如果是数组使用数组元素类型
var type = _.chain(v)
.map(function (e) { return typeof e; })
.uniq()
.value();
return [
p.name,
__assign({ type: 'array', items: {
type: type
} }, common),
];
}
else {
// 如果不是数组直接使用 value 类型
var type = typeof v;
return [
p.name,
__assign({ type: 'array', items: {
type: type
} }, common),
];
}
}
catch (error) {
// 解析失败 返回 any[]
return [
p.name,
__assign({ type: 'array' }, common),
];
}
}
else {
// 无生成规则也无值,生成 any[]
return [
p.name,
__assign({ type: 'array' }, common),
];
}
}
var removeComment = function (str) { return str.replace(/\/\*|\*\//g, ''); };
function getRestfulPlaceHolders(itf) {
var urlSplit = itf.url.split('/');
var restfulPlaceHolders = [];
for (var i = 0; i < urlSplit.length; ++i) {
var part = urlSplit[i];
var matchKeys = part.match(/(?:\{(.*)\}|\:(.*))/);
if (!matchKeys)
continue;
var key = matchKeys[1] || matchKeys[2];
restfulPlaceHolders.push(key);
}
return restfulPlaceHolders;
}
function interfaceToJSONSchema(itf, scope) {
var properties = itf.properties.filter(function (p) { return p.scope === scope; });
properties = __spreadArray(__spreadArray([], properties, true), [
{
name: 'dummyroot',
parentId: -2,
id: -1,
scope: scope,
type: 'object'
},
], false);
if (scope === 'request') {
var placeHolders = getRestfulPlaceHolders(itf);
properties = __spreadArray(__spreadArray([], properties, true), placeHolders.map(function (name, index) { return ({
name: name,
parentId: -1,
id: index + 100,
scope: scope,
type: 'string'
}); }), true);
}
function findChildProperties(parentId) {
return _.chain(properties)
.filter(function (p) { return p.parentId === parentId; })
.map(function (p) {
var type = p.type.toLowerCase().replace(/regexp|function/, 'string');
var childProperties = findChildProperties(p.id);
var childItfs = properties.filter(function (x) { return x.parentId === p.id; });
// request 的时候按照实际标注,response 全部默认存在
var required = childItfs.filter(function (e) { return e.required; }).map(function (e) { return e.name; });
var common = {
// 这里默认所有的属性都有值
additionalProperties: false,
required: required.length ? required : undefined
};
if (p.description)
common.description = removeComment(p.description);
/**
* 处理枚举,支持以下形式:(目前为控制影响范围,只对 string、number 做处理)
* value="@pick(['p1', 'p2'])"
* issue地址:https://github.com/thx/rapper/issues/9
*/
if (['string', 'number'].includes(type) && p.value) {
var enumArr = [];
var regResult = /^@pick\(([\s\S]+)\)$/.exec(p.value);
try {
if (regResult) {
var result = regResult[1];
enumArr = eval(result);
}
}
catch (err) { }
if (Array.isArray(enumArr) && enumArr.length) {
common["enum"] = enumArr;
}
}
if (['string', 'number', 'integer', 'boolean', 'null'].includes(type)) {
return [
p.name,
__assign({ type: type }, common),
];
}
else if (type === 'object') {
return [
p.name,
__assign({ type: type, properties: childProperties }, common),
];
}
else if (type === 'array') {
return inferArraySchema(p, childProperties, common);
}
else {
// 解析失败,返回 any
return [
p.name,
__assign({ type: ['string', 'number', 'boolean', 'object'] }, common),
];
}
})
.fromPairs()
.value();
}
var propertyChildren = findChildProperties(-2);
var root = propertyChildren['dummyroot'];
// 只有一个 key 为 _root_ 或者 __root__ 的数组时,代表想表达根节点是个数组
if (Object.keys(root.properties).length === 1 &&
(root.properties._root_ || root.properties.__root__)) {
var _root_ = root.properties._root_ || root.properties.__root__;
if (_root_.type === 'array') {
return _root_;
}
}
return root;
}
function convert(itf) {
var reqJSONSchema = interfaceToJSONSchema(itf, 'request');
var resJSONSchema = interfaceToJSONSchema(itf, 'response');
var options = __assign(__assign({}, json_schema_to_typescript_1.DEFAULT_OPTIONS), { bannerComment: '' });
return Promise.all([
(0, json_schema_to_typescript_1.compile)(reqJSONSchema, 'Req', options),
(0, json_schema_to_typescript_1.compile)(resJSONSchema, 'Res', options),
]);
}
exports["default"] = convert;