@lcap/nasl
Version:
NetEase Application Specific Language
438 lines • 21.2 kB
JavaScript
;
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