@ainc/script
Version:
Script compiler for typescript
140 lines (113 loc) • 4.3 kB
text/typescript
/**
*****************************************
* Created by edonet@163.com
* Created on 2021-07-07 22:35:20
*****************************************
*/
'use strict';
/**
*****************************************
* 加载依赖
*****************************************
*/
import * as ts from 'typescript';
import { cwd } from '@ainc/fs/dist/cwd';
import { dirname } from '@ainc/fs/dist/dirname';
import { relative } from '@ainc/fs/dist/relative';
import { isBuiltinModule } from './isBuiltinModule';
/**
*****************************************
* 扩展类型
*****************************************
*/
declare module 'typescript' {
interface SourceFile {
resolvedModules: ts.ESMap<string, ts.ResolvedModuleFull>;
}
}
/**
*****************************************
* 定义转换器
*****************************************
*/
export function transformer(context: ts.TransformationContext): ts.Transformer<ts.SourceFile> {
const calls = ['import', 'require', 'require.resolve'];
const factory = context.factory;
const compilerOptions = context.getCompilerOptions();
// 转换文件节点
return (sourceFile: ts.SourceFile) => {
const { fileName, resolvedModules } = sourceFile;
const file = cwd(fileName);
const dir = dirname(file);
// 解析模块
function resolveModule(id: string): void | ts.ResolvedModuleFull {
const cached = resolvedModules.get(id);
// 返回缓存
if (cached) {
return cached;
}
// 解析模块
const { resolvedModule } = ts.resolveModuleName(id, file, compilerOptions, ts.sys);
// 解析失败
if (!resolvedModule) {
return;
}
// 更新缓存
resolvedModules.set(id, resolvedModule);
// 返回结果
return resolvedModule;
}
// 访问模块节点
function visitModuleSpecifier(node: ts.Node): ts.Node {
if (ts.isStringLiteral(node)) {
const { text } = node || {};
// 不处理相对模块
if (text && !isBuiltinModule(text) && text.charAt(0) !== '.') {
const resolved = resolveModule(text);
// 不处理外部模块
if (resolved && !resolved.isExternalLibraryImport) {
const { resolvedFileName, extension } = resolved;
// 生成节点
return factory.createStringLiteral(
relative(dir, cwd(resolvedFileName.slice(0, - extension.length)))
);
}
}
}
// 返回原节点
return node;
}
// 访问调用节点
function visitCallDeclaration(node: ts.Node): ts.Node {
if (ts.isCallExpression(node)) {
const id = node.expression.getText();
// 匹配函数名且只有一个参数时处理
if (calls.includes(id) && node.arguments.length === 1 && ts.isStringLiteral(node.arguments[0])) {
return factory.updateCallExpression(
node,
node.expression,
node.typeArguments,
ts.visitNodes(node.arguments, visitModuleSpecifier),
);
}
}
// 访问子节点
return ts.visitEachChild(node, visitCallDeclaration, context);
}
// 访问文件子节点
function visitSourceFile(node: ts.Node): ts.Node {
// 处理载入节点
if (ts.isImportDeclaration(node)) {
return ts.visitEachChild(node, visitModuleSpecifier, context);
}
// 处理抛出节点
if (ts.isExportDeclaration(node)) {
return ts.visitEachChild(node, visitModuleSpecifier, context);
}
// 返回节点
return visitCallDeclaration(node);
}
// 访问文件子节点
return ts.visitEachChild(sourceFile, visitSourceFile, context);
};
}