UNPKG

@lcap/asl

Version:

NetEase Application Specific Language

595 lines (592 loc) 28.3 kB
"use strict"; 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