@lcap/asl
Version:
NetEase Application Specific Language
595 lines (592 loc) • 28.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const __1 = require("..");
function switchCase2If(cases) {
const cas = cases.shift();
const result = {
type: 'IfStatement',
test: cas.test,
consequent: {
type: 'BlockStatement',
body: cas.consequent || [],
},
alternate: null,
};
if (cases.length) {
result.alternate = switchCase2If(cases);
}
else {
return {
type: 'BlockStatement',
body: cas.consequent || [],
};
}
return result;
}
function default_1(source) {
const definition = typeof source === 'string' ? JSON.parse(source) : source;
function traverse(node, func, parent, index) {
func(node, parent, index);
Object.values(node).forEach((value) => {
if (Array.isArray(value)) {
value.forEach((child, index) => child && traverse(child, func, node, index));
}
else if (typeof value === 'object')
value && traverse(value, func, node, index);
});
}
const dataMap = {};
const globalDataMap = {
$route: true,
$global: true,
$refs: true,
};
/**
* 生成页面的 data
* genInitFromSchema 是为了将数据类型的处理和页面逻辑的生成分开
* 比如 param a.b 的 schema 有变化,View 代码无需再次生成
*/
const paramsData = (definition.params || [])
.map((param) => {
// pass schema to genInitData function, transform init realtime after datatypes changed
// 标记 Vue 的 data 中已经使用声明了该变量
dataMap[param.code || param.name] = true;
return safeCodeAsKey(param) + `: this.$genInitFromSchema(${JSON.stringify(param.schema)}, this.$route.query.hasOwnProperty('${param.name}') ? this.$route.query.${param.name} : ${JSON.stringify(param.defaultValue)}, true)`;
}).join(',\n').trim();
/**
* 生成变量的 data
*/
const variablesData = (definition.variables || [])
.map((variable) => {
// 标记 Vue 的 data 中已经使用声明了该变量
dataMap[variable.code || variable.name] = true;
return safeCodeAsKey(variable) + `: this.$genInitFromSchema(${JSON.stringify(variable.schema)}, ${JSON.stringify(variable.defaultValue)})`;
}).join(',\n').trim();
function safeKey(key) {
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key))
return key;
else
return `['${key}']`;
}
function safeCodeAsKey(node) {
return `['${node.code || node.name}']`;
}
function safeCodeParamKey(node) {
return node.code || node.name;
}
function nameToCodeForMemberExpression(memberExpression) {
if (!memberExpression)
return memberExpression;
memberExpression = JSON.parse(JSON.stringify(memberExpression));
if (memberExpression.type === 'MemberExpression') {
const { object, property } = memberExpression;
if (object.code)
object.name = object.code;
if (property.code)
property.name = property.code;
if (object.type === 'MemberExpression')
memberExpression.object = nameToCodeForMemberExpression(object);
}
return memberExpression;
}
const lifecycleMap = new Map();
definition.lifecycles?.forEach((item) => {
if (!item?.name)
return;
if (!lifecycleMap.has(item.name))
lifecycleMap.set(item.name, [item]);
else
lifecycleMap.get(item.name).push(item);
});
const lifecycles = Array.from(lifecycleMap).map(([name, lifecycleList]) => `
const old${name} = componentOptions['${name}'];
componentOptions['${name}'] = function () {
${lifecycleList
.map((lifecycle) => `old${name} && old${name}.call(this);this.ID_${lifecycle.logicId}();`)
.join('\n')}
}`);
const methods = (definition.logics || []).map((logic) => {
let returnObj = {
type: 'Identifier',
name: 'result',
init: { type: 'Identifier', name: 'undefined' },
};
if (logic.returns[0])
returnObj = logic.returns[0];
const newLine = () => '\n';
const colon = () => ';';
const generateNode = (node, logicItemIndex) => {
if (!node)
return '';
if (node.type === 'End') {
return `${newLine()}return ${returnObj.name}${colon()}${newLine()}`;
}
if (node.type === 'Comment') {
return `${newLine()}// ${node.value}${newLine()}`;
}
if (node.type === 'Identifier') {
if (dataMap[node.code || node.name] || globalDataMap[node.code || node.name])
return 'this.' + (node.code || node.name);
return node.name || node.code;
}
if (node.type === 'NullLiteral')
return 'null';
if (node.type === 'BooleanLiteral')
return node.value;
if (node.type === 'StringLiteral')
return `'${node.value}'`;
if (node.type === 'NumericLiteral')
return node.value;
if (node.type === 'Unparsed') {
return node.code;
}
if (node.type === 'TypeNote') {
const { type, format } = node.schema;
return `{ type: '${type}', format: '${format}' }`;
}
if (node.type === 'BinaryExpression') {
const left = node.left && node.left.type === 'BinaryExpression' ? `(${generateNode(node.left)})` : generateNode(node.left);
const right = node.right && node.right.type === 'BinaryExpression' ? `(${generateNode(node.right)})` : generateNode(node.right);
return `${left} ${node.operator} ${right}`;
}
if (node.type === 'MemberExpression') {
const object = generateNode(node.object);
const property = node.property;
if (property.type === 'Identifier')
return `${object}.${property.code || property.name}`;
else if (property.type === 'StringLiteral')
return `${object}['${property.value}']`;
else if (property.type === 'NumericLiteral')
return `${object}[${property.value}]`;
}
if (node.type === 'AssignmentExpression') {
return `${newLine()}${generateNode(node.left)} = ${generateNode(node.right)}${colon()}${newLine()}`;
}
if (node.type === 'CallExpression') {
const args = [];
for (const argumentNode of node.arguments) {
args.push(generateNode(argumentNode));
}
const name = node.callee.name;
return `${name}(${args.join(', ')})${colon()}${newLine()}`;
}
if (node.type === 'CallLogic') {
if (node.calleeCode.startsWith('callInterface_')) {
const getParams = (key) => {
// 过滤掉 null 的 param
const nodeParams = (node.params || []).filter((param) => param !== null && param !== 'null' && param !== '');
if (key === 'body') {
let inBody = '';
const bodyStr = [];
nodeParams.filter((t) => t.callInterParamValue)
.forEach((b) => {
const refTarget = __1.Vertex.getVertexByRef(b.callInterParam);
if (refTarget.in === 'body') {
inBody = generateNode(b.callInterParamValue);
}
else if (refTarget.in === '') {
bodyStr.push(`["${refTarget.name}"]: ${generateNode(b.callInterParamValue)}`);
}
});
return inBody || `{${bodyStr.join(',')}}`;
}
else {
return nodeParams
.filter((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
return refTarget && refTarget.in === key;
})
.map((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
const callInterParamValue = nameToCodeForMemberExpression(param.callInterParamValue);
const value = generateNode(callInterParamValue);
return `${safeCodeAsKey(refTarget)}: ${value}`;
});
}
};
const key = node.interfaceKey || node.callee || '';
const interfaceKeyTarget = __1.Vertex.getVertexByRef(key);
const arr = key.split('/');
const download = interfaceKeyTarget && interfaceKeyTarget.name && interfaceKeyTarget.name.includes('export');
return `await this.$services['_custom']['ID_${arr[arr.length - 1]}']({
config: {
download: ${download},
},
path: {
${getParams('path').join(',\n')}
},
query: {
${getParams('query').join(',\n')}
},
headers: {
${getParams('header').join(',\n')}
},
body: ${getParams('body') || '{}'},
})`;
}
else {
return `await this.${node.calleeCode}(${node.params.map((param) => generateNode(param.callInterParamValue) || 'undefined').join(',')})`;
}
}
if (node.type === 'CallInterface') {
const key = node.interfaceKey || '';
const arr = key.split('/');
const getParams = (key) => {
// 过滤掉 null 的 param
const nodeParams = (node.params || []).filter((param) => param !== null && param !== 'null' && param !== '');
if (key === 'body') {
const body = (nodeParams || []).find((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
return refTarget && refTarget.in === key;
});
if (body) {
return generateNode(body.callInterParamValue);
}
return '{}';
}
else {
return nodeParams
.filter((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
return refTarget && refTarget.in === key;
})
.map((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
const callInterParamValue = nameToCodeForMemberExpression(param.callInterParamValue);
const value = generateNode(callInterParamValue);
return `${safeCodeAsKey(refTarget)}: ${value}`;
});
}
};
// 如果是 interface 判断接口参数类型window.location.href
const interfaceKeyTarget = __1.Vertex.getVertexByRef(node.interfaceKey);
const download = interfaceKeyTarget && interfaceKeyTarget.name && interfaceKeyTarget.name.includes('export');
return `await this.$services['_custom']['ID_${arr[arr.length - 1]}']({
config: {
download: ${download},
},
path: {
${getParams('path').join(',\n')}
},
query: {
${getParams('query').join(',\n')}
},
headers: {
${getParams('header').join(',\n')}
},
body: ${getParams('body') || '{}'},
})`;
}
if (node.type === 'CallGraphQL') {
const getParams = (key) => {
// 过滤掉 null 的 param
const nodeParams = (node.params || []).filter((param) => param !== null && param !== 'null' && param !== '');
if (key === 'body') {
const body = (nodeParams || []).find((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
return refTarget && refTarget.in === key;
});
if (body) {
return generateNode(body.callInterParamValue);
}
else {
return '{}';
}
}
else {
return nodeParams
.filter((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
return refTarget && refTarget.in === key;
})
.map((param) => {
const refTarget = __1.Vertex.getVertexByRef(param.callInterParam);
const callInterParamValue = nameToCodeForMemberExpression(param.callInterParamValue);
const value = generateNode(callInterParamValue);
return `${safeCodeAsKey(refTarget)}: ${value}`;
});
}
};
const getOperationName = (schemaRef = '', name = '') => {
const arr = schemaRef.split('/');
const entityName = 'ID_' + arr[3];
// 处理全局查询的单复数问题
const singleName = name === 'getAll' ? `getAll${entityName}` : name;
arr.pop();
arr.push(singleName);
arr.shift();
return arr.join('_');
};
node.operationName = getOperationName(node.schemaRef, node.resolverName);
const entity = __1.Vertex.getVertexByRef(node.schemaRef);
const resolver = entity && entity.resolvers.find((resolver) => resolver.name === node.resolverName);
const key = resolver && resolver.interface.key || '';
const arr = key.split('/');
return `(await this.$services['_custom']['ID_${arr[arr.length - 1]}']({
config: {
download: ${key.includes('export')},
},
path: {
${getParams('path').join(',\n')}
},
query: {
${getParams('query').join(',\n')}
},
headers: {
${getParams('header').join(',\n')}
},
body: ${getParams('body') || '{}'},
})).Data`;
}
if (node.type === 'CallFlow') { // 待确认
const bodyParams = (node.params || [])
.filter((param) => param.in === undefined) // 放在body内部的参数
.filter((param) => generateNode(param.value) !== '')
.map((param) => `${safeKey(param.name)}: ${generateNode(param.value)}`)
.join(',\n');
const getObj = (type) => (node.params || [])
.filter((param) => param.in === type)
.reduce((obj, param) => {
const key = safeKey(param.name);
const value = generateNode(param.value);
obj[key] = value;
return obj;
}, {});
const pathObj = getObj('path');
const bodyObj = getObj('body');
let params = '';
const variables = generateNode(node.variables);
if (node.action === 'start') {
params = `{
body: {
processDefinitionKey: '${node.processDefinitionKey}',
returnVariables: true,
variables: ${variables},
${bodyParams}
}
}`;
}
else if (node.action === 'complete') {
params = `{
path: {
taskId: ${pathObj.taskId
|| generateNode(node.taskId)},
},
body: {
action: 'complete',
variables: ${variables},
${bodyParams}
}
}`;
}
else if (node.action === 'getList') {
params = `{
body: {
processDefinitionKey: '${node.processDefinitionKey}',
processInstanceId: ${generateNode(node.processInstanceId)},
includeProcessVariables: true,
sort: 'startTime',
order: 'desc',
finished: ${node.finished},
${bodyParams}
},
}`;
}
else if (node.action === 'get') {
params = `{
path: {
taskId: '${pathObj.taskId || generateNode(node.taskId)}',
},
}`;
}
else if (node.action === 'getProcessInstanceList') {
params = `{
body: {
processDefinitionKey: '${node.processDefinitionKey}',
includeProcessVariables: true,
sort: 'startTime',
order: 'desc',
finished: ${node.finished},
startedBy: ${generateNode(node.startedBy)},
${bodyParams}
}
}`;
}
else if (node.action === 'getProcessInstance') {
params = `{
path: {
processInstanceId: ${pathObj.processInstanceId || generateNode(node.processInstanceId)},
},
}`;
}
else if (node.action === 'updateVariables') {
params = `{
path: {
processInstanceId: ${pathObj.processInstanceId || generateNode(node.processInstanceId)},
},
body: ${bodyObj.variables || variables || '{}'},
}`;
}
return `this.$services.process.${node.action}(${params})`;
}
if (node.type === 'CallMessageShow') {
return `${newLine()}this.$toast.show(${generateNode(node.arguments[0])})${colon()}${newLine()}`;
}
if (node.type === 'CallConsoleLog') {
return `${newLine()}console.log(${generateNode(node.arguments[0])})${colon()}${newLine()}`;
}
if (node.type === 'Destination') {
const params = (node.params || [])
.filter((param) => param.pageParamKey && param.pageParamKeyValue)
.map((param) => {
const value = generateNode(param.pageParamKeyValue);
return safeCodeParamKey(param.pageParamKey) + '=${' + value + '}';
});
let url = node.url;
if (params.length) {
url = '`' + `${node.code}?${params.join('&')}` + '`';
}
else {
url = '`' + `${url}` + '`';
}
return `this.$destination(${url})${colon()}${newLine()}`;
}
if (node.type === 'IfStatement') {
if (Array.isArray(node.consequent)) {
node.consequent = {
type: 'BlockStatement',
body: node.consequent,
};
}
if (Array.isArray(node.alternate)) {
node.alternate = {
type: 'BlockStatement',
body: node.alternate,
};
}
let alternateScript = '';
if (node.alternate) {
alternateScript = generateNode(node.alternate);
}
let resultScript = `if(${generateNode(node.test)}) ${generateNode(node.consequent)}`;
resultScript = alternateScript ? `${resultScript} else ${alternateScript}` : resultScript;
return resultScript;
}
if (node.type === 'BlockStatement') {
if (!node.body) {
return '';
}
const body = (node.body || []).map((body) => `${generateNode(body)}${colon()}${newLine()}`);
return `{
${body.join(' ')}
}`;
}
if (node.type === 'WhileStatement') {
let bodyScript = '';
if (Array.isArray(node.body)) {
node.body.forEach((body) => {
bodyScript += `${generateNode(body)}${newLine()}`;
});
}
return `${newLine()}while(${generateNode(node.test)}) {
${bodyScript}
}${newLine()}`;
}
if (node.type === 'SwitchStatement') {
Object.assign(node, switchCase2If(node.cases));
return generateNode(node);
}
if (node.type === 'ForEachStatement') {
let bodyScript = '';
if (Array.isArray(node.body)) {
node.body.forEach((body) => {
bodyScript += `${generateNode(body)}${newLine()}`;
});
}
const indexScript = generateNode(node.index);
const startScript = generateNode(node.start);
const itemScript = generateNode(node.item);
const endScript = generateNode(node.end);
const eachScript = generateNode(node.each);
if (node.label === 'async') { // 临时测试 async 的方式
return `${newLine()}await Promise.all(${eachScript}.slice(${startScript}, ${endScript}).map(async (${itemScript}, ${indexScript}) => {
${bodyScript}
})${newLine()}`;
}
else {
return `${newLine()}for (let ${indexScript}=${startScript}; ${indexScript} < ${endScript}; ${indexScript}++){
const ${itemScript} = ${eachScript}[${indexScript}];
${bodyScript}
}${newLine()}`;
}
}
if (node.type === 'JSONSerialize') {
return `JSON.stringify(${generateNode(node.arguments[0])})${colon()}`;
}
if (node.type === 'JSONDeserialize') {
return `JSON.parse(${generateNode(node.arguments[0])})${colon()}`;
}
if (node.type === 'RaiseException') {
return `throw new Error(${generateNode(node.arguments[0])})${colon()}${newLine()}`;
}
if (node.type === 'JSBlock') {
return `${newLine()}{
const jsBlock_${logicItemIndex} = async () => {
${node.code}
}
await jsBlock_${logicItemIndex}();
}${newLine()}`;
}
if (node.type === 'BuiltInFunction') {
const params = (node.builtInFuncParams || []).map((param) => generateNode(param.builtInFuncParamValue));
return `this.$utils['${node.calleeCode}'](${params.join(',')})`;
}
if (node.type === 'UnaryExpression') {
const argument = generateNode(node.argument);
return `${node.operator}${argument}`;
}
if (node.type === 'LogicalExpression') {
const left = node.left && node.left.type === 'LogicalExpression' ? `(${generateNode(node.left)})` : generateNode(node.left);
const right = node.right && node.right.type === 'LogicalExpression' ? `(${generateNode(node.right)})` : generateNode(node.right);
return `${left} ${node.operator} ${right}`;
}
return '';
};
let script = '';
logic.body.forEach((node, index) => {
script += `${generateNode(node, index)}${newLine()}`;
});
// console.info("JSON generate:", JSON.stringify(logic.body));
// console.log(generate({ type: 'Program', body: logic.body }).code);
return `methods['${logic.name}'] = async function (${logic.params.map((param) => param.name).join(', ')}) {
${logic.params.length ? logic.params.map((param) => `${param.name} = ${param.name} !== undefined ? ${param.name} : this.$genInitFromSchema(${JSON.stringify(param.schema)}, ${JSON.stringify(param.defaultValue)});`).join('\n') + '' : ''}
${logic.variables.length ? logic.variables.map((variable) => `let ${variable.name} = this.$genInitFromSchema(${JSON.stringify(variable.schema)}, ${JSON.stringify(variable.defaultValue)});`).join('\n') + '' : ''}
let ${returnObj.name} = this.$genInitFromSchema(${JSON.stringify(returnObj.schema)}, ${JSON.stringify(returnObj.defaultValue)});
${script}
}`;
});
const output = `
const methods = componentOptions.methods = componentOptions.methods || {};
const computed = componentOptions.computed = componentOptions.computed || {};
const oldDataFunc = componentOptions.data;
const data = function () {
const oldData = oldDataFunc ? oldDataFunc.call(this) : {};
return Object.assign(oldData, {
${paramsData ? paramsData + ',' : ''}
${variablesData}
});
};
componentOptions.data = data;
const meta = componentOptions.meta = componentOptions.meta || {};
Object.assign(meta, {
title: ${JSON.stringify(definition.title)},
crumb: ${JSON.stringify(definition.crumb)},
first: ${JSON.stringify(definition.first)},
});
${lifecycles.join('\n\n')}
${methods.join('\n\n')}
`;
return output;
}
exports.default = default_1;
//# sourceMappingURL=translator.js.map