UNPKG

@lcap/builder

Version:
303 lines (302 loc) 14.3 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; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable no-param-reassign */ /* eslint-disable global-require */ const babel = __importStar(require("@babel/core")); const generator_1 = __importDefault(require("@babel/generator")); const traverse_1 = __importDefault(require("@babel/traverse")); const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const lodash_1 = require("lodash"); const exec_1 = require("../utils/exec"); const logger_1 = __importDefault(require("../utils/logger")); const babel_utils_1 = require("../utils/babel-utils"); function putComponentMap(components, componentMap = {}) { if (!Array.isArray(components)) { return; } components.forEach((comp) => { componentMap[comp.name] = comp; if (comp.children && comp.children.length > 0) { putComponentMap(comp.children, componentMap); } }); } function getDtsPath(options) { const isExtension = options.type === 'extension'; const tsPath = isExtension ? 'nasl.extension.d.ts' : `${options.destDir}/nasl.ui.d.ts`; return path_1.default.resolve(options.rootPath, tsPath); } function getMetaInfo(options) { return __awaiter(this, void 0, void 0, function* () { const isExtension = options.type === 'extension'; const dstPath = getDtsPath(options); if (!fs_extra_1.default.existsSync(dstPath)) { return { code: '', componentMap: {}, }; } const tsCode = yield fs_extra_1.default.readFile(dstPath, 'utf-8'); let componentList = []; const componentMap = {}; if (isExtension) { const moduleJSON = fs_extra_1.default.readJSONSync(path_1.default.resolve(options.rootPath, 'nasl.extension.json'), 'utf-8'); if (moduleJSON.frontends && moduleJSON.frontends.length > 0) { moduleJSON.frontends.forEach((fe) => { if (Array.isArray(fe.viewComponents)) { fe.viewComponents.forEach((comp) => { const i = componentList.findIndex((c) => c.name === comp.name); if (i === -1) { componentList.push(comp); } }); } }); } } else { componentList = fs_extra_1.default.readJSONSync(path_1.default.resolve(options.rootPath, options.destDir, 'nasl.ui.json'), 'utf-8'); } putComponentMap(componentList, componentMap); return { code: tsCode, componentMap, componentList: componentList.map((c) => [c].concat(c.children || [])).flat(), }; }); } function getBlocks(title, description) { const blocks = []; if (title && title !== 'undefined') { blocks.push(` * ${title}`); } if (description && description !== 'undefined') { blocks.push(` * ${description}`); } return blocks; } function addExportAndComment(ast, componentMap) { (0, traverse_1.default)(ast, { ClassDeclaration(np) { var _a; if (!np.node.id || np.node.id.type !== 'Identifier') { return; } const classNode = np.node; if (np.parent.type !== 'ExportNamedDeclaration') { const exportAST = { type: 'ExportNamedDeclaration', specifiers: [], declaration: classNode, }; np.replaceWith(exportAST); } const className = ((_a = classNode.id) === null || _a === void 0 ? void 0 : _a.name) || ''; const componentInfo = componentMap[className.endsWith('Options') ? className.replace(/Options$/, '') : className]; if (!componentInfo) { return; } const superClassName = (0, babel_utils_1.getNodeCode)(classNode.superClass); if (superClassName.endsWith('ViewComponent')) { classNode.body.body.forEach((n) => { if (n.type === 'TSDeclareMethod' && n.kind === 'method' && n.key.type === 'Identifier') { const methodName = n.key.name; const methodInfo = componentInfo.methods.find((m) => m.name === methodName); if (methodInfo) { const blocks = getBlocks(methodInfo.title, methodInfo.description); if (methodInfo.params && methodInfo.params.length > 0) { blocks.push(...methodInfo.params.map((p) => ` * @param ${p.name} - ${p.description || ''}`)); } if (blocks.length > 0) { n.leadingComments = [ { type: 'CommentBlock', value: `*\n${blocks.join('\n')}\n `, }, ]; } } } else if (n.type === 'ClassProperty' && n.key.type === 'Identifier') { const propName = n.key.name; const propInfo = componentInfo.readableProps.find((p) => p.name === propName); if (propInfo) { const blocks = getBlocks(propInfo.title, propInfo.description || ''); if (blocks.length > 0) { n.leadingComments = [ { type: 'CommentBlock', value: `*\n${blocks.join('\n')}\n `, }, ]; } } } }); } else if (superClassName.endsWith('ViewComponentOptions')) { classNode.body.body.forEach((n) => { if (n.type !== 'ClassProperty' || (n.key.type !== 'Identifier' && n.key.type !== 'StringLiteral')) { return; } const propName = n.key.type === 'Identifier' ? n.key.name : n.key.value; let propInfo = componentInfo.props.find((p) => p.name === propName); if (!propInfo && propName.startsWith('on')) { const eventName = propName.replace(/^on(\w+)/, ($0, $1) => { return $1.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); }); propInfo = componentInfo.events.find((e) => e.name === eventName); } else if (!propInfo && propName.startsWith('slot')) { const slotName = (0, babel_utils_1.getSlotName)(propName); propInfo = componentInfo.slots.find((slot) => slot.name === slotName); } if (propInfo) { const blocks = getBlocks(propInfo.title, propInfo.description); if (blocks.length > 0) { n.leadingComments = [ { type: 'CommentBlock', value: `*\n${blocks.join('\n')}\n `, }, ]; } } // slot () => nasl.collection.List 转成 Array if (propName.startsWith('slot') && n.typeAnnotation && n.typeAnnotation.type === 'TSTypeAnnotation' && n.typeAnnotation.typeAnnotation.type === 'TSFunctionType' && n.typeAnnotation.typeAnnotation.typeAnnotation && n.typeAnnotation.typeAnnotation.typeAnnotation.type === 'TSTypeAnnotation' && n.typeAnnotation.typeAnnotation.typeAnnotation.typeAnnotation.type === 'TSTypeReference') { const code = (0, babel_utils_1.getNodeCode)(n.typeAnnotation.typeAnnotation.typeAnnotation.typeAnnotation.typeName); if (code.startsWith('nasl.collection.List')) { n.typeAnnotation.typeAnnotation.typeAnnotation.typeAnnotation.typeName = { type: 'Identifier', name: 'Array', }; } } }); } }, }); } function addExtendsClassProperties(ast, componentMap, componentList) { const componentASTList = []; (0, traverse_1.default)(ast, { ClassDeclaration(np) { var _a; if (!np.node.id || np.node.id.type !== 'Identifier') { return; } const classNode = np.node; const className = ((_a = classNode.id) === null || _a === void 0 ? void 0 : _a.name) || ''; if (componentMap[className]) { componentASTList.push(np.node); } }, }); componentList.forEach((comp) => { const { name, extends: extendList = [] } = comp; const componentAST = componentASTList.find((compAst) => { var _a; return ((_a = compAst.id) === null || _a === void 0 ? void 0 : _a.name) === name; }); if (!componentAST || !Array.isArray(extendList) || extendList.length === 0) { return; } extendList.map((exd) => { if (typeof exd === 'string') { return { name: exd, }; } return exd; }).forEach((exd) => { const { name: extendName } = exd; const extendComponentAST = componentASTList.find((compAst) => { var _a; return ((_a = compAst.id) === null || _a === void 0 ? void 0 : _a.name) === extendName; }); if (!extendComponentAST || !extendComponentAST.body.body) { return; } const properties = extendComponentAST.body.body.filter((n) => (n.type === 'ClassProperty' || n.type === 'TSDeclareMethod') && (n.key.name !== 'constructor')); if (properties.length === 0) { return; } const bodyList = componentAST.body.body; properties.forEach((property) => { if (property.key.type !== 'Identifier') { return; } const propName = property.key.name; const i = bodyList.findIndex((n) => (n.type === 'ClassProperty' || n.type === 'TSDeclareMethod') && n.key.type === 'Identifier' && n.key.name === propName); if (i !== -1) { return; } bodyList.push((0, lodash_1.cloneDeep)(property)); }); }); }); } function transformTsCode(tsCode, componentMap, componentList) { const ast = babel.parse(tsCode, { filename: 'result.ts', presets: [require('@babel/preset-typescript')], plugins: [ [require('@babel/plugin-proposal-decorators'), { legacy: true }], // 'babel-plugin-parameter-decorator' ], rootMode: 'root', root: __dirname, }); addExportAndComment(ast, componentMap); addExtendsClassProperties(ast, componentMap, componentList); const { code } = (0, generator_1.default)(ast); return code; } function buildDeclaration(options) { return __awaiter(this, void 0, void 0, function* () { logger_1.default.start('开始编译 api.ts'); (0, exec_1.execSync)('npx tsc -p tsconfig.api.json'); const { code, componentMap = {}, componentList = [] } = yield getMetaInfo(options); if (code) { const dtsCode = transformTsCode(code, componentMap, componentList); fs_extra_1.default.writeFileSync(getDtsPath(options), dtsCode); } logger_1.default.success('编译 api.ts 成功!'); }); } exports.default = buildDeclaration;