UNPKG

maxxton-typescript-loadable-components-plugin

Version:

A custom transformer of typescript that is used to add some necessary properties to loadable-components.

76 lines (71 loc) 2.52 kB
/*! * Copyright 2019 acrazing <joking.young@gmail.com>. All rights reserved. * @since 2019-11-01 23:01:37 */ import * as ts from 'typescript'; import { createChunkName } from './properties/createChunkName'; import { createIsReady } from './properties/createIsReady'; import { createRequireAsync } from './properties/createRequireAsync'; import { createRequireSync } from './properties/createRequireSync'; import { createResolve } from './properties/createResolve'; import { State } from './State'; import { LoadableComponentsTransformerOptions } from './types'; import { getImportCallList, getRealExpression } from './utils'; const properties = [ createChunkName, createIsReady, createRequireAsync, createRequireSync, createResolve, ]; function visitLoadableComponents(state: State, node: ts.Node) { if (!ts.isCallExpression(node) || node.arguments.length === 0) { return node; } const loader = getRealExpression(node.arguments[0]); if (!ts.isFunctionExpression(loader) && !ts.isArrowFunction(loader)) { return node; } let identifier = getRealExpression(node.expression); if ( ts.isPropertyAccessExpression(identifier) && identifier.name.escapedText === 'lib' ) { identifier = getRealExpression(identifier.expression); } if (!ts.isIdentifier(identifier) || identifier.escapedText !== 'loadable') { return node; } const importList = getImportCallList(loader.body); if (importList.length === 0) { return node; } if (importList.length > 1) { throw new Error( 'loadable: multiple import calls inside `loadable()` function are not supported.', ); } const args = node.arguments.slice(); args[0] = ts.factory.createObjectLiteralExpression( properties.map((fn) => fn(state, importList[0], loader)), true, ); return ts.factory.createCallExpression(node.expression, void 0, args); } export function createLoadableComponentsTransformer( program: ts.Program | undefined, options: Partial<LoadableComponentsTransformerOptions>, ): ts.TransformerFactory<ts.SourceFile> { const state = new State(program, options); return (context) => { state.context = context; return (source) => { state.sourceFile = source; const visitor: ts.Visitor = (node) => { node = visitLoadableComponents(state, node); return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(source, visitor); }; }; }