UNPKG

ts-import-plugin

Version:
164 lines 6.84 kB
import * as ts from 'typescript'; import { join as pathJoin, sep } from 'path'; function join(...params) { /* istanbul ignore if */ if (sep === '\\') { const ret = pathJoin(...params); return ret.replace(/\\/g, '/'); } /* istanbul ignore next */ return pathJoin(...params); } // camel2Dash camel2Underline // borrow from https://github.com/ant-design/babel-plugin-import function camel2Dash(_str) { const str = _str[0].toLowerCase() + _str.substr(1); return str.replace(/([A-Z])/g, ($1) => `-${$1.toLowerCase()}`); } function camel2Underline(_str) { const str = _str[0].toLowerCase() + _str.substr(1); return str.replace(/([A-Z])/g, ($1) => `_${$1.toLowerCase()}`); } function getImportedStructs(node) { const structs = new Set(); node.forEachChild((importChild) => { if (!ts.isImportClause(importChild)) { return; } // not allow default import, or mixed default and named import // e.g. import foo from 'bar' // e.g. import foo, { bar as baz } from 'x' // and must namedBindings exist if (importChild.name || !importChild.namedBindings) { return; } // not allow namespace import // e.g. import * as _ from 'lodash' if (!ts.isNamedImports(importChild.namedBindings)) { return; } importChild.namedBindings.forEachChild((namedBinding) => { // ts.NamedImports.elements will always be ts.ImportSpecifier const importSpecifier = namedBinding; // import { foo } from 'bar' if (!importSpecifier.propertyName) { structs.add({ importName: importSpecifier.name.text }); return; } // import { foo as bar } from 'baz' structs.add({ importName: importSpecifier.propertyName.text, variableName: importSpecifier.name.text, }); }); }); return structs; } function createDistAst(context, struct, options) { const astNodes = []; const { libraryName, libraryOverride } = options; const _importName = struct.importName; const importName = options.camel2UnderlineComponentName ? camel2Underline(_importName) : options.camel2DashComponentName ? camel2Dash(_importName) : _importName; const libraryDirectory = typeof options.libraryDirectory === 'function' ? options.libraryDirectory(_importName) : join(options.libraryDirectory || '', importName); /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production' && libraryDirectory == null) { console.warn(`custom libraryDirectory resolve a ${libraryDirectory} path`); } const importPath = !libraryOverride ? join(libraryName, libraryDirectory) : libraryDirectory; let canResolveImportPath = true; try { require.resolve(importPath, { paths: [process.cwd(), ...options.resolveContext], }); } catch (e) { canResolveImportPath = false; if (options.failIfNotFound) { throw new Error(`Can not find component for library: ${options.libraryName} in ${importPath}`); } astNodes.push(context.factory.createImportDeclaration(undefined, context.factory.createImportClause(false, undefined, context.factory.createNamedImports([ context.factory.createImportSpecifier(false, undefined, context.factory.createIdentifier(_importName)), ])), context.factory.createStringLiteral(libraryName))); } if (canResolveImportPath) { const scriptNode = context.factory.createImportDeclaration(undefined, context.factory.createImportClause(false, struct.variableName || !options.transformToDefaultImport ? undefined : context.factory.createIdentifier(struct.importName), struct.variableName ? context.factory.createNamedImports([ context.factory.createImportSpecifier(false, options.transformToDefaultImport ? context.factory.createIdentifier('default') : context.factory.createIdentifier(struct.importName), context.factory.createIdentifier(struct.variableName)), ]) : options.transformToDefaultImport ? undefined : context.factory.createNamedImports([ context.factory.createImportSpecifier(false, undefined, context.factory.createIdentifier(struct.importName)), ])), context.factory.createStringLiteral(importPath)); astNodes.push(scriptNode); if (options.style) { const { style } = options; let stylePath; if (typeof style === 'function') { stylePath = style(importPath); } else { // eslint-disable-next-line no-restricted-syntax stylePath = `${importPath}/style/${style === true ? 'index' : style}.js`; } if (stylePath) { const styleNode = context.factory.createImportDeclaration(undefined, undefined, context.factory.createStringLiteral(stylePath)); astNodes.push(styleNode); } } } return astNodes; } const defaultOptions = { libraryName: 'antd', libraryDirectory: 'lib', style: false, camel2DashComponentName: true, camel2UnderlineComponentName: false, transformToDefaultImport: true, resolveContext: [], libraryOverride: false, failIfNotFound: false, }; export function createTransformer(_options = {}) { const mergeDefault = (options) => ({ ...defaultOptions, ...options }); const optionsArray = Array.isArray(_options) ? _options.map((options) => mergeDefault(options)) : [mergeDefault(_options)]; return (context) => { const visitor = (node) => { if (ts.isSourceFile(node)) { return ts.visitEachChild(node, visitor, context); } if (!ts.isImportDeclaration(node)) { return node; } const importedLibName = node.moduleSpecifier.text; const options = optionsArray.find((_) => _.libraryName === importedLibName); if (!options) { return node; } const structs = getImportedStructs(node); if (structs.size === 0) { return node; } return Array.from(structs).reduce((acc, struct) => { const nodes = createDistAst(context, struct, options); return acc.concat(nodes); }, []); }; return (node) => ts.visitNode(node, visitor); }; } export default createTransformer; //# sourceMappingURL=index.js.map