它封装了TypeScript编译器API,能够简化访问、操作Typescript AST。
下文简单介绍一些常用的API,持续补充...
Init
import { Project, ScriptKind, SyntaxKind } from 'ts-morph';
import { mkdtemp } from 'node:fs/promises';
const project = new Project({
compilerOptions: {},
});
async function createTempSourceFile() {
const dir = await mkdtemp(join(tmpdir(), 'k-'));
console.log(dir)
return dir;
}
const tempFile = await createTempSourceFile();
const file_str = readFileSync(resolve('./src/index.tsx'), 'utf-8');
const sourceFile = project.createSourceFile(tempFile, file_str, {
scriptKind: ScriptKind.TSX,
});
常见用法
获取import引入
// code:
// import * as React from 'react';
// import { cva, type VariantProps } from 'class-variance-authority';
const importDeclarations = sourceFile.getImportDeclarations();
for (const importDeclaration of importDeclarations) {
// 获取模块标识符 gets: react
const moduleSpecifier = importDeclaration.getModuleSpecifierValue()
// 获取命名空间导入 gets: React
const namespaceImport = importDeclaration.getNamespaceImport().getText()
// 获取命名导入 gets: [ImportSpecifier]
const namedImports = importDeclaration.getNamedImports()
// gets: cva
const text = namedImports[0].getText();
console.log('namedImports', namedImports)
}
获取string/number类型
// codes:
const alertVariants = cva(
'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
{
variants: {
variant: {
kiki: 1,
default: 'bg-background text-foreground',
destructive:
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
},
},
defaultVariants: {
variant: 'default',
},
}
);
// SyntaxKind.StringLiteral
sourceFile.getDescendantsOfKind(SyntaxKind.NumericLiteral).forEach((node) => {
const value = node.getText();
console.log('NumericLiteral', value);
});
获取Object
// 会逐层遍历
sourceFile.getDescendantsOfKind(SyntaxKind.PropertyAssignment).forEach((node) => {
console.log('getname', node.getName()); // variants
console.log('text',node.getText()); // { variants: { ... } }
// 判断是否string类型,除了该用法还有node.isKind方法
const classnames = node.getInitializerIfKind(SyntaxKind.StringLiteral);
if (classnames) {
console.log('gettext', classnames.getText());
}
})
获取function
// codes:
function a (c: String, d) {
console.log(0)
}
sourceFile.getDescendantsOfKind(SyntaxKind.FunctionDeclaration).forEach((node) => {
// node.getBodyText(); gets: ('console.log(0)');
// node.getName(); gets: a
console.log('parameters', node.getParameters()) // [ ParameterDeclaration ]
const params = node.getParameters()[0].getText(); // c: String
})
获取expression表达式
console.log(1)
sourceFile
.getDescendantsOfKind(SyntaxKind.CallExpression)
.filter((node) => node.getExpression().getText() === "cva")
node.getExpression().getText() ===> console.log
获取doc
// codes:
/**
* 这是一个用于演示的方法
* @param c 'desc'
* @param d - 11
* @returns 返回一个字符串
*/
function a (c: String, d) {
console.log(0)
}
sourceFile.getDescendantsOfKind(SyntaxKind.FunctionDeclaration).forEach((node) => {
const doc = node.getJsDocs()[0];
const desc = doc.getDescription();
console.log('desc', desc); // \n 这是一个用于演示的方法
doc.getTags().forEach((tag) => {
const name = tag.getTagName();
const value = tag.getComment();
console.log('name', name); // --> param | returns
console.log('value', value); // --> 'desc' | - 11 | 返回一个字符串
})
})