UNPKG

@ainc/script

Version:

Script compiler for typescript

266 lines (227 loc) 7.35 kB
/** ***************************************** * Created by edonet@163.com * Created on 2021-07-17 16:02:55 ***************************************** */ 'use strict'; /** ***************************************** * 加载依赖 ***************************************** */ import * as babel from '@babel/core'; import transformTypescript from '@babel/plugin-transform-typescript'; import transformReactJSX from '@babel/plugin-transform-react-jsx'; import transformModulesCommonjs from '@babel/plugin-transform-modules-commonjs'; import proposalDynamicImport from '@babel/plugin-proposal-dynamic-import'; import proposalDecorators from '@babel/plugin-proposal-decorators'; import proposalClassProperties from '@babel/plugin-proposal-class-properties'; import proposalExportNamespaceFrom from '@babel/plugin-proposal-export-namespace-from'; import transformModulePath, { Options as ModulePathsOptions } from './helpers/module-paths-plugin'; import { compilerOptions } from './helpers/tsconfig'; /** ***************************************** * 解析路径配置 ***************************************** */ const modulePathsOptions = { baseUrl: compilerOptions.baseUrl, paths: compilerOptions.paths, alias: compilerOptions.alias, calls: [] as string[], useRelativePath: false, }; /** ***************************************** * 测试环境 ***************************************** */ if (process.env.BABEL_ENV === 'test') { modulePathsOptions.calls.push( 'jest.genMockFromModule', 'jest.mock', 'jest.unmock', 'jest.doMock', 'jest.dontMock', 'jest.setMock', 'jest.requireActual', 'jest.requireMock', ); } /** ***************************************** * 解析模块配置 ***************************************** */ const moduleEntries = ['index.js', 'index.ts']; const importInterop = compilerOptions.esModuleInterop ? 'babel' : 'none'; /** ***************************************** * 是否使用懒加载 ***************************************** */ function lazy(file: string): () => boolean { const isEntry = !!moduleEntries.find(name => file.endsWith(name)); // 返回匹配函数 return () => isEntry; } /** ***************************************** * 转换器 ***************************************** */ export interface Transform { (filename: string, code: string): string; } /** ***************************************** * 默认配置 ***************************************** */ const babelOptions: babel.TransformOptions = { ast: false, babelrc: false, babelrcRoots: false, configFile: false, comments: false, sourceMaps: 'inline', }; /** ***************************************** * 转换代码 ***************************************** */ export function transform(code: string, options: babel.TransformOptions): string { const result = babel.transformSync(code, options); // 返回结果 if (result) { return result.code || ''; } // 返回空 return ''; } /** ***************************************** * 转码【JavaScript】 ***************************************** */ export function transformJavaScript(filename: string, code: string): string { // 过滤第三方模块 if (filename.indexOf('node_modules') > -1) { return code; } // 过滤非ES6模块 if (code.indexOf('import ') === -1 && code.indexOf('export ') === -1) { return code; } // 转换代码 return transform(code, { ...babelOptions, filename, plugins: [ [proposalExportNamespaceFrom], [transformModulePath, modulePathsOptions], [transformModulesCommonjs, { lazy: lazy(filename), importInterop }], [proposalDynamicImport], [proposalDecorators, { legacy: true }], [proposalClassProperties, { loose: true }], ], }); } /** ***************************************** * 转码【TypeScript】 ***************************************** */ export function transformTypeScript(filename: string, code: string): string { return transform(code, { ...babelOptions, filename, plugins: [ [proposalExportNamespaceFrom], [transformTypescript, { isTSX: true, allowDeclareFields: true }], [transformModulePath, modulePathsOptions], [transformModulesCommonjs, { lazy: lazy(filename), importInterop }], [proposalDynamicImport], [proposalDecorators, { legacy: true }], [proposalClassProperties, { loose: true }], ], }); } /** ***************************************** * 转码【JSX】 ***************************************** */ export function transformJSXScript(filename: string, code: string): string { return transform(code, { ...babelOptions, filename, plugins: [ [proposalExportNamespaceFrom], [transformReactJSX], [transformModulePath, modulePathsOptions], [transformModulesCommonjs, { lazy: lazy(filename), importInterop }], [proposalDynamicImport], [proposalDecorators, { legacy: true }], [proposalClassProperties, { loose: true }], ], }); } /** ***************************************** * 转码【TSX】 ***************************************** */ export function transformTSXScript(filename: string, code: string): string { return transform(code, { ...babelOptions, filename, plugins: [ [proposalExportNamespaceFrom], [transformTypescript, { isTSX: true, allowDeclareFields: true }], [transformReactJSX], [transformModulePath, modulePathsOptions], [transformModulesCommonjs, { lazy: lazy(filename), importInterop }], [proposalDynamicImport], [proposalDecorators, { legacy: true }], [proposalClassProperties, { loose: true }], ], }); } /** ***************************************** * 转换配置 ***************************************** */ export interface TransformOptions extends babel.TransformOptions { typescript?: Record<string, unknown>; jsx?: Record<string, unknown>; modulePaths?: ModulePathsOptions; } /** ***************************************** * 转码脚本 ***************************************** */ export function transformScript(filename: string, code: string, options: TransformOptions = {}): string { const plugins = options.plugins || []; const opts = { ...babelOptions, ...options, filename, plugins }; // 添加语法插件 plugins.unshift( [proposalExportNamespaceFrom], ); // 添加模块解析 plugins.push( [transformTypescript, { isTSX: true, allowDeclareFields: true, ...opts.typescript }], [transformReactJSX, opts.jsx], [transformModulePath, { ...modulePathsOptions, ...opts.modulePaths }], [transformModulesCommonjs, { lazy: lazy(filename), importInterop }], [proposalDynamicImport], [proposalDecorators, { legacy: true }], [proposalClassProperties, { loose: true }], ); // 执行转换 return transform(code, opts); }