oak-domain/lib/compiler/elementBuilder.js

145 lines
9.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = __importDefault(require("assert"));
const fs_1 = __importDefault(require("fs"));
const fs_extra_1 = require("fs-extra");
const ts = __importStar(require("typescript"));
const { factory } = ts;
const env_1 = require("./env");
/**
* 将element文件编译到每个entity的目录之下对文件中所定义的相关element增加$v/$g/$action等常用的props
* @param program
* @param printer
* @param inputDir
* @param file
* @param inputImportPath
* @returns
*/
function constructElementFile(program, printer, inputDir, file) {
const sourceFile = program.getSourceFile(`${inputDir}/${file}`);
const filePfx = file.slice(0, file.lastIndexOf('.'));
const statements = [];
if (process.env.IN_OAK_DOMAIN) {
statements.push(factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier("Element"))), factory.createStringLiteral(`${env_1.ELEMENT_PATH_IN_OAK_DOMAIN}/${filePfx}`), undefined));
}
else {
statements.push(factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier("Element"))), factory.createStringLiteral(`../../element/${filePfx}`), undefined));
}
/**
* import { FullAttr } from '../Schema';
* interface RefValueParams {
$v?: FullAttr;
$value?: FullAttr;
$g?: string;
$global?: string;
};
*/
statements.push(factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("FullAttr"))])), factory.createStringLiteral("../Schema"), undefined), factory.createInterfaceDeclaration(undefined, undefined, factory.createIdentifier("RefValueParams"), undefined, undefined, [
factory.createPropertySignature(undefined, factory.createIdentifier("$v"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(factory.createIdentifier("FullAttr"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("$value"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(factory.createIdentifier("FullAttr"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("$g"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier("$global"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword))
]));
/**
* import { Action } from '../Action';
* interface RefActionParams {
$a?: Action;
$action?: Action;
};
*/
statements.push(factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("Action"))])), factory.createStringLiteral("../Action"), undefined), factory.createInterfaceDeclaration(undefined, undefined, factory.createIdentifier("RefActionParams"), undefined, undefined, [
factory.createPropertySignature(undefined, factory.createIdentifier("$a"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(factory.createIdentifier("Action"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("$action"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(factory.createIdentifier("Action"), undefined))
]));
ts.forEachChild(sourceFile, (ele) => {
if (ts.isFunctionDeclaration(ele) && ts.isModifier(ele.modifiers[0]) && ts.SyntaxKind.ExportKeyword === ele.modifiers[0].kind) {
const fnName = ele.name.text;
(0, assert_1.default)(ele.parameters.length === 1, `[ELEMENT BUILDER]文件${file}的函数${fnName}有多于一个的参数`);
const [param] = ele.parameters;
(0, assert_1.default)(ts.isIdentifier(param.name) && param.name.text === 'props', `[ELEMENT BUILDER]文件${file}的函数${fnName}的参数名称不是props`);
const { type } = param;
(0, assert_1.default)(type);
const checker = program.getTypeChecker();
const attributes = checker.getTypeFromTypeNode(type);
const valueAttr = checker.getPropertyOfType(attributes, 'value');
const onChangeAttr = checker.getPropertyOfType(attributes, 'onChange');
const onClickAttr = checker.getPropertyOfType(attributes, 'onClick');
const intersectionNodes = [
factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(factory.createIdentifier("Parameters"), [factory.createTypeQueryNode(factory.createQualifiedName(factory.createIdentifier("Element"), factory.createIdentifier(fnName)))]), factory.createLiteralTypeNode(factory.createNumericLiteral("0")))
];
if (valueAttr) {
// 显示元件,加上$v和$g
intersectionNodes.push(factory.createTypeReferenceNode(factory.createIdentifier("RefValueParams"), undefined));
}
else if (onClickAttr) {
// 如果没有value但是有onClick是action组件加上$a
intersectionNodes.push(factory.createTypeReferenceNode(factory.createIdentifier("RefActionParams"), undefined));
}
statements.push(factory.createFunctionDeclaration(undefined, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], undefined, factory.createIdentifier(fnName), undefined, [factory.createParameterDeclaration(undefined, undefined, undefined, factory.createIdentifier("props"), undefined, factory.createIntersectionTypeNode(intersectionNodes), undefined)], factory.createTypeReferenceNode(factory.createIdentifier("ReturnType"), [factory.createTypeQueryNode(factory.createQualifiedName(factory.createIdentifier("Element"), factory.createIdentifier(fnName)))]), factory.createBlock([factory.createReturnStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("Element"), factory.createIdentifier(fnName)), undefined, [factory.createAsExpression(factory.createIdentifier("props"), factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(factory.createIdentifier("Parameters"), [factory.createTypeQueryNode(factory.createQualifiedName(factory.createIdentifier("Element"), factory.createIdentifier(fnName)))]), factory.createLiteralTypeNode(factory.createNumericLiteral("0"))))]))], true)));
}
});
const resultFile = ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS);
const result = printer.printNode(ts.EmitHint.Unspecified, factory.createSourceFile(statements, factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None), resultFile);
return result;
}
function makeElementFile(inputDir, filename, outputDir, program) {
// 对目录下面每个entity建立对应的element文件
const entities = fs_1.default.readdirSync(outputDir);
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
entities.forEach((ele) => {
if (fs_1.default.statSync(`${outputDir}/${ele}`).isDirectory()) {
const elementDir = `${outputDir}/${ele}/element`;
(0, fs_extra_1.ensureDirSync)(elementDir);
const outputFile = `${elementDir}/${filename}`;
if (fs_1.default.existsSync(outputFile) && process.env.NODE_ENV !== 'development') {
throw new Error(`${outputFile}已经存在`);
}
const content = constructElementFile(program, printer, inputDir, filename);
fs_1.default.writeFileSync(outputFile, content, { flag: 'w' });
}
});
}
function buildElements(inputDir, outputDir) {
const files = fs_1.default.readdirSync(inputDir);
if (!process.env.IN_OAK_DOMAIN) {
if (!fs_1.default.existsSync(`${outputDir}/element`)) {
fs_1.default.mkdirSync(`${outputDir}/element`);
}
(0, fs_extra_1.copySync)(inputDir, `${outputDir}/element`, { errorOnExist: true });
}
const fullFilenames = files.filter(ele => ele.endsWith('.tsx')).map(ele => `${inputDir}/${ele}`);
const program = ts.createProgram(fullFilenames, { allowJs: true });
files.forEach((filename) => {
if (filename.endsWith('.tsx')) {
makeElementFile(inputDir, filename, outputDir, program);
}
});
}
exports.default = buildElements;