@lcap/builder
Version:
lcap builder utils
303 lines (302 loc) • 14.3 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;
};
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;