UNPKG

@lcap/nasl

Version:

NetEase Application Specific Language

438 lines 21.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseNaturalTS = exports.addType2Namespace = void 0; const babel = __importStar(require("@babel/core")); const utils_1 = require("./transforms/utils"); const transform2Entity_1 = require("./transforms/transform2Entity"); const transform2Structure_1 = require("./transforms/transform2Structure"); const transform2GlobalLogicDeclaration_1 = require("./transforms/transform2GlobalLogicDeclaration"); const transform2Enum_1 = require("./transforms/transform2Enum"); const transform2Logic_1 = require("./transforms/transform2Logic"); const transform2Variable_1 = require("./transforms/transform2Variable"); const parseNaturalTSXView_1 = require("./parseNaturalTSXView"); const transform2MetadataType_1 = require("./transforms/transform2MetadataType"); const transformThemeAndStyle_1 = require("./transforms/transformThemeAndStyle"); /** * 铺平命名空间 */ function flatNamespace(node) { const sub = node.body; if (sub.type === 'TSModuleDeclaration') { const { ids, block } = flatNamespace(sub); return { ids: [node.id, ...ids], block }; } else return { ids: [node.id], block: sub }; } /** * 将 Statements 铺平成如下的形式: * ids: extensions.mylib.enums statement: ClassDeclaration * ids: extensions.mylib.structures statement: ClassDeclaration * ids: extensions.mylib.logics statement: TSDeclareFunction * ids: extensions.mylib.logics statement: FunctionDeclaration * ids: apis.myInterface.enums statement: ClassDeclaration * ids: apis.myInterface.structures statement: ClassDeclaration * ids: apis.myInterface.interfaces statement: TSDeclareFunction * ids: apis.myInterface.interfaces statement: FunctionDeclaration */ function flatMapNamespaceStatements(nodes, isInner = false) { const result = []; nodes.forEach((node) => { let statement = node; if (node.type === 'ExportNamedDeclaration') { // if (!isInner) throwError('顶层不应该导出:' + node.declaration.type); statement = node.declaration; statement.leadingComments = node.leadingComments; } else { if (isInner && !(node.type === 'ExpressionStatement' && ['CallExpression', 'TaggedTemplateExpression'].includes(node.expression.type))) // && node.expression.callee.type === 'Identifier' && /^[@$]/.test(node.expression.callee.name))) (0, utils_1.throwError)('内层必须使用导出:' + node.type); } if (statement.type === 'TSModuleDeclaration') { const curr = flatNamespace(statement); const subResult = flatMapNamespaceStatements(curr.block.body, true); subResult.forEach((item) => { result.push({ ids: [...curr.ids, ...item.ids], statement: item.statement }); }); } else { result.push({ ids: [], statement }); } }); return result; } function handleDependency({ dependencies, moduleType, listName, options, node }) { let dependency = dependencies.find((d) => d.name === options?.moduleName); if (!dependency) { if (moduleType === 'connector') { dependency = new utils_1.naslTypes.Connector({ type: moduleType, name: options.moduleName, }); } else { dependency = new utils_1.naslTypes.Module({ type: moduleType, name: options.moduleName, }); } dependencies.push(dependency); } if (listName === 'structures' || listName === 'enums') { // 枚举、数据结构 dependency[listName].push(node); } else { let logicList = moduleType === 'extension' || moduleType === 'connector' ? dependency.logics : dependency.interfaces; if (moduleType === 'connector') { if (!TYPE_IN_NAMESPACES.includes(listName)) { let ns = dependency.namespaces.find((_ns) => _ns.name === listName); if (!ns) { ns = new utils_1.naslTypes.Namespace({ name: listName, title: listName, }); dependency.namespaces.push(ns); } logicList = ns.logics; } } const hasLogicIndex = logicList.findIndex((item) => item.name === node.name); if (options.logicType === 'declare') { // 逻辑不存在时添加 if (hasLogicIndex === -1) { logicList.push(node); } } else if (options.logicType === 'export') { if (hasLogicIndex !== -1) { // 覆盖 logicList[hasLogicIndex] = node; } else { // 添加 logicList.push(node); } } } } const HEAD_NAMESPACES = ['app', 'extensions', 'apis', 'connectors']; const TYPE_IN_NAMESPACES = ['structures', 'enums', 'metadataTypes', 'logics', 'interfaces']; /** * 添加到指定命名空间中 */ function addType2Namespace(app, node, namespacePrefix, type, options) { if (namespacePrefix === 'app') { app[type].push(node); } if (namespacePrefix === 'extensions') { handleDependency({ dependencies: app.dependencies, moduleType: 'extension', listName: type, options, node }); } else if (namespacePrefix === 'connectors') { handleDependency({ dependencies: app.connectorDependencies, moduleType: 'connector', listName: type, options, node }); } else if (namespacePrefix === 'apis') { if (type === 'interfaces') { // Interface 特殊处理一下 const interfaceParams = node.params.map((item) => { const name = item?.name?.replace('_r_', '-'); return new utils_1.naslTypes.InterfaceParam({ ...item.toJSON(), name, in: 'body', required: !!item?.required, }); }); node = new utils_1.naslTypes.Interface({ ...node.toJSON(), title: node.name, path: 'path', method: "POST", protocol: "HTTPS", params: interfaceParams }); } handleDependency({ dependencies: app.interfaceDependencies, moduleType: 'interface', listName: type, options, node }); } } exports.addType2Namespace = addType2Namespace; function addConnectionByName(app, connectionName, connectorName) { app.addConnection(new utils_1.naslTypes.Connection({ name: connectionName, namespace: `connector.${connectorName}`, })); } function parseNaturalTS(tsCode, appInfo = {}) { const plugins = [ ['@babel/plugin-proposal-decorators', { legacy: true }], '@babel/plugin-proposal-class-properties' ]; const root = babel.parseSync(tsCode, { filename: 'result.tsx', presets: [require('@babel/preset-typescript')], plugins }); const app = new utils_1.naslTypes.App(); const namespaceStatements = flatMapNamespaceStatements(root.program.body); let viewStack = []; namespaceStatements.forEach(({ ids: _ids, statement }, index) => { const idNames = _ids.map((id) => id.name); const idNamesStr = idNames.join('.'); if (!HEAD_NAMESPACES.includes(idNames[0])) (0, utils_1.throwError)(`不支持命名空间以${idNames[0]}开头`); let headNamespace = idNames[0]; let typeInNamespace; if (headNamespace === 'app') { typeInNamespace = idNames[1]; } else { if (!idNames[2]) { if (statement.type === 'TSDeclareFunction' && statement.id?.name === 'connect') { const paramType = (statement.params[0]?.typeAnnotation).typeAnnotation; if (paramType.type === 'TSLiteralType' && paramType.literal.type === 'StringLiteral') { const connectionName = paramType.literal.value; addConnectionByName(app, connectionName, idNames[1]); return; } else if (paramType.type !== 'TSUnionType') (0, utils_1.throwError)('连接必须使用字符串联合类型'); else { const connectionNames = paramType.types.map((type) => { if (type.type === 'TSLiteralType' && type.literal.type === 'StringLiteral') { return type.literal.value; } else { (0, utils_1.throwError)('连接必须使用字符串字面量'); } }); connectionNames.forEach((connectionName) => { addConnectionByName(app, connectionName, idNames[1]); }); return; } } else { (0, utils_1.throwError)(`不支持的命名空间:${idNamesStr}`); } } else { typeInNamespace = idNames[2]; } } let tailNamespace = idNames[idNames.length - 1]; let moduleName = headNamespace === 'app' ? '' : idNames[1]; const options = { moduleName }; if (idNames[1] === 'dataSources' && idNames[3] === 'entities') { let dataSource = app.dataSources[0]; if (dataSource) { if (dataSource.name !== idNames[2]) (0, utils_1.throwError)(`暂时不支持多数据源${dataSource.name},${idNames[2]}`); } else { dataSource = new utils_1.naslTypes.DataSource({ name: idNames[2], }); app.dataSources.push(dataSource); } if (statement.type === 'ClassDeclaration') { dataSource.entities.push((0, transform2Entity_1.transform2Entity)(statement)); } else if (statement.type === 'VariableDeclaration') { } else if (statement.type === 'ExpressionStatement' && statement.expression.type === 'CallExpression' && statement.expression.callee.type === 'MemberExpression' && statement.expression.callee.property.type === 'Identifier' && statement.expression.callee.property.name === '$mockData') { } else (0, utils_1.throwError)('实体命名空间中不支持的节点类型:' + statement.type); } else if (typeInNamespace === 'structures') { if (statement.type === 'ClassDeclaration') { addType2Namespace(app, (0, transform2Structure_1.transform2Structure)(statement), headNamespace, typeInNamespace, options); } else (0, utils_1.throwError)('数据结构命名空间中不支持的节点类型:' + statement.type); } else if (typeInNamespace === 'enums') { if (statement.type === 'ClassDeclaration') { addType2Namespace(app, (0, transform2Enum_1.transform2Enum)(statement, statement.leadingComments), headNamespace, typeInNamespace, options); } else (0, utils_1.throwError)('枚举命名空间中不支持的节点类型:' + statement.type); } else if (typeInNamespace === 'metadataTypes') { if (statement.type === 'TSTypeAliasDeclaration') { addType2Namespace(app, (0, transform2MetadataType_1.transform2MetadataType)(statement, statement.leadingComments), headNamespace, typeInNamespace, options); } else (0, utils_1.throwError)('元数据类型命名空间中不支持的节点类型:' + statement.type); } else if (typeInNamespace === 'logics') { options.logicType = statement.type === 'TSDeclareFunction' ? 'declare' : 'export'; if (statement.type === 'TSDeclareFunction') { addType2Namespace(app, (0, transform2GlobalLogicDeclaration_1.transform2GlobalLogicDeclaration)(statement), headNamespace, typeInNamespace, options); } else if (statement.type === 'FunctionDeclaration') { addType2Namespace(app, (0, transform2Logic_1.transform2Logic)(statement), headNamespace, typeInNamespace, options); } else (0, utils_1.throwError)('逻辑命名空间中不支持的节点类型:' + statement.type); } else if (['apis', 'extensions', 'connectors'].includes(headNamespace)) { // logics / interfaces if (tailNamespace === 'logics' || tailNamespace === 'interfaces') { options.logicType = statement.type === 'TSDeclareFunction' ? 'declare' : 'export'; const logic = (0, transform2Logic_1.transform2Logic)(statement); if (options.logicType === 'declare') { logic.body = []; } addType2Namespace(app, logic, headNamespace, tailNamespace, options); } else if (tailNamespace === 'enums' && statement.type === 'ClassDeclaration') { addType2Namespace(app, (0, transform2Enum_1.transform2Enum)(statement, statement.leadingComments), headNamespace, tailNamespace, options); } else if (tailNamespace === 'structures' && statement.type === 'ClassDeclaration') { addType2Namespace(app, (0, transform2Structure_1.transform2Structure)(statement), headNamespace, tailNamespace, options); } else if (headNamespace === 'connectors') { options.logicType = statement.type === 'TSDeclareFunction' ? 'declare' : 'export'; const logic = (0, transform2Logic_1.transform2Logic)(statement); if (options.logicType === 'declare') { logic.body = []; } addType2Namespace(app, logic, headNamespace, tailNamespace, options); } else { (0, utils_1.throwError)('不支持的命名空间:' + idNamesStr); } } else if (idNamesStr === 'app.backend.variables') { if (statement.type === 'VariableDeclaration') { if (!app.backend) { app.backend = new utils_1.naslTypes.Backend(); } app.backend.variables.push((0, transform2Variable_1.transform2BackendVariable)(statement)); } else (0, utils_1.throwError)('变量命名空间中不支持的节点类型:' + statement.type); } else if (idNames[1] === 'frontendTypes' && idNames[3] === 'frontends') { let frontendType = app.frontendTypes.find((item) => item.name === idNames[2]); if (!frontendType) { frontendType = new utils_1.naslTypes.FrontendType({ name: idNames[2], kind: idNames[2], frameworkKind: "vue3", frameworkUI: "ElementPlus", }); app.frontendTypes.push(frontendType); } let frontend = frontendType.frontends.find((item) => item.name === idNames[4]); if (!frontend) { frontend = new utils_1.naslTypes.Frontend({ type: idNames[2], name: idNames[4], title: idNames[4].toUpperCase() + '端', path: '/', theme: new utils_1.naslTypes.Theme({ name: 'default', title: '默认主题样式', }) }); frontendType.frontends.push(frontend); } if (idNames[5] === 'variables') { if (statement.type === 'VariableDeclaration') { frontend.variables.push((0, transform2Variable_1.transform2FrontendVariable)(statement)); } else (0, utils_1.throwError)('前端变量命名空间中不支持的节点类型:' + statement.type); } else if (idNames[5] === 'views') { if (statement.type === 'FunctionDeclaration') { let decorator; let prevStatement = namespaceStatements[index - 1]?.statement; if (prevStatement?.type === 'ExpressionStatement' && prevStatement.expression.type === 'CallExpression' && prevStatement.expression.callee.type === 'Identifier' && prevStatement.expression.callee.name === '$View') { decorator = prevStatement.expression; } const view = (0, parseNaturalTSXView_1.transform2View)(statement, decorator); const viewPathLength = (idNames.length - 4) / 2; let parentList; if (viewPathLength > viewStack.length) { parentList = viewStack[viewStack.length - 1]?.children || frontend.views; } else if (viewPathLength < viewStack.length) { viewStack.splice(viewPathLength - 1); parentList = viewStack[viewStack.length - 1]?.children || frontend.views; } else { viewStack.pop(); parentList = viewStack[viewStack.length - 1]?.children || frontend.views; } const saveView = parentList.find((item) => item.name === view.name); if (saveView) { if (utils_1.DEBUG) { throw new Error(`${idNamesStr} 中存在同名页面:${view.name}`); } else { delete view.children; Object.assign(saveView, view); viewStack.push(saveView); } } else { parentList.push(view); viewStack.push(view); } } } else if (statement.type === 'ExpressionStatement' && statement.expression.type === 'TaggedTemplateExpression') { const expression = statement.expression; if (expression.tag.type === 'Identifier' && expression.tag.name === '$theme') { if (expression.quasi.expressions.length > 0) { (0, utils_1.throwError)('不支持在 $theme 中使用动态表达式'); } const css = expression.quasi.quasis[0].value.raw; const variableMap = (0, transformThemeAndStyle_1.transformTheme)(css); frontend.theme.scopeVariableMap = variableMap; } else if (expression.tag.type === 'Identifier' && expression.tag.name === '$extraStyle') { if (expression.quasi.expressions.length > 0) { (0, utils_1.throwError)('不支持在 $style 中使用动态表达式'); } const css = expression.quasi.quasis[0].value.raw; const cssRules = (0, transformThemeAndStyle_1.transformStyle)(css); frontend.theme.cssRules = cssRules; } } else { (0, utils_1.throwError)('不支持的命名空间:' + idNamesStr); } } else { (0, utils_1.throwError)('不支持的命名空间:' + idNamesStr); } }); return app; } exports.parseNaturalTS = parseNaturalTS; //# sourceMappingURL=parseNaturalTS.js.map