ts-morph常用语法

760 阅读1分钟

它封装了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 | 返回一个字符串
      
    })
  })

参考资料