@ainc/script
Version:
Script compiler for typescript
196 lines • 7.16 kB
JavaScript
/**
*****************************************
* Created by edonet@163.com
* Created on 2021-08-14 11:03:15
*****************************************
*/
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformer = void 0;
/**
*****************************************
* 加载依赖
*****************************************
*/
const ts = require("typescript");
/**
*****************************************
* 获取工厂
*****************************************
*/
const factory = ts.factory;
/**
*****************************************
* 判断是否为入口文件
*****************************************
*/
function isMainFile(path) {
return path.endsWith('index.ts') || path.endsWith('index.js');
}
/**
*****************************************
* 判断标识值
*****************************************
*/
function isIdentifierValueOf(node, value) {
return ts.isIdentifier(node) && node.text === value;
}
/**
*****************************************
* 判断是否为载入函数
*****************************************
*/
function isRequireCallExpression(node) {
return node ? ts.isCallExpression(node) && isIdentifierValueOf(node.expression, 'require') : false;
}
/**
*****************************************
* 判断是否为导出标识
*****************************************
*/
function isExportIdentifier(node) {
return ts.isIdentifier(node) && ts.isExportDeclaration(getOriginalNode(node));
}
/**
*****************************************
* 获取源节点
*****************************************
*/
function getOriginalNode(node) {
return node.original ? getOriginalNode(node.original) : node;
}
/**
*****************************************
* 创建函数调用声明
*****************************************
*/
function createCallExpression(name, args) {
return factory.createCallExpression(name, [], args || []);
}
/**
*****************************************
* 创建匿名函数表达式
*****************************************
*/
function createAnonymousFunctionExpression(statements) {
return factory.createFunctionExpression(undefined, undefined, undefined, [], [], undefined, factory.createBlock(statements, false));
}
/**
*****************************************
* 创建懒加载函数表达式
*****************************************
*/
function createLazyRequireFunctionExpression(name, call) {
const moduleId = factory.createIdentifier('__exports');
const moduleDecl = factory.createVariableDeclaration(moduleId, undefined, undefined, call);
// 创建函数
return createAnonymousFunctionExpression([
factory.createVariableStatement(undefined, factory.createVariableDeclarationList([moduleDecl], ts.NodeFlags.None)),
factory.createExpressionStatement(factory.createBinaryExpression(name, factory.createToken(ts.SyntaxKind.EqualsToken), createAnonymousFunctionExpression([factory.createReturnStatement(moduleId)]))),
factory.createReturnStatement(moduleId),
]);
}
/**
*****************************************
* 创建属性定义声明
*****************************************
*/
function createObjectDefinePropertyExpression(target, prop, initializer) {
return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), undefined, [
target,
factory.createStringLiteral(prop),
factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier('enumerable'), factory.createTrue()),
factory.createPropertyAssignment(factory.createIdentifier('get'), initializer),
], false),
]);
}
/**
*****************************************
* 转换文件内容
*****************************************
*/
function transformSourceFile(sourceFile, context) {
const moduleSymbols = new Set();
// 访问文件子节点
function visitNode(node) {
// 处理载入标识
if (ts.isIdentifier(node) && moduleSymbols.has(node)) {
return createCallExpression(node);
}
// 返回节点
return ts.visitEachChild(node, visitNode, context);
}
// 访问变量声明
function visitVariableDeclaration(node) {
// 判断非声明语句
if (!ts.isVariableDeclaration(node)) {
return ts.visitEachChild(node, visitVariableDeclaration, context);
}
// 获取初始初化声明
const call = node.initializer;
const name = node.name;
// 判断非载入函数初始化
if (!call || !isRequireCallExpression(call) || !isExportIdentifier(name)) {
return ts.visitEachChild(node, visitNode, context);
}
// 添加标识
moduleSymbols.add(name);
// 替换声明节点
return factory.updateVariableDeclaration(node, name, node.exclamationToken, node.type, createLazyRequireFunctionExpression(name, call));
}
// 访问赋值表达式
function visitBinaryExpression(node) {
// 判断非载入函数初始化
if (!ts.isBinaryExpression(node) || !isRequireCallExpression(node.right)) {
return ts.visitEachChild(node, visitNode, context);
}
// 获取表达式值
const expr = node.left;
const call = node.right;
// 判断非导出属性
if (!ts.isPropertyAccessExpression(expr) || !isIdentifierValueOf(expr.expression, 'exports')) {
return ts.visitEachChild(node, visitNode, context);
}
// 创建赋值语句
return createObjectDefinePropertyExpression(expr.expression, expr.name.text, createAnonymousFunctionExpression([factory.createReturnStatement(call)]));
}
// 访问文件子节点
function visitSourceFile(node) {
// 处理载入函数
if (ts.isVariableStatement(node)) {
return ts.visitEachChild(node, visitVariableDeclaration, context);
}
// 处理二元表达式
if (ts.isExpressionStatement(node)) {
return ts.visitEachChild(node, visitBinaryExpression, context);
}
// 处理载入标识
if (moduleSymbols.size) {
return ts.visitEachChild(node, visitNode, context);
}
// 返回节点
return node;
}
// 访问节点
return ts.visitEachChild(sourceFile, visitSourceFile, context);
}
/**
*****************************************
* 转换器
*****************************************
*/
function transformer(context) {
const { target, module: moduleKind } = context.getCompilerOptions();
const isCommonJS = !moduleKind || moduleKind === ts.ModuleKind.CommonJS;
// 不做处理
if (!target || !isCommonJS) {
return sourceFile => sourceFile;
}
// 转换文件节点
return (sourceFile) => {
return isMainFile(sourceFile.fileName) ? transformSourceFile(sourceFile, context) : sourceFile;
};
}
exports.transformer = transformer;
//# sourceMappingURL=module-export-transformer.js.map