typescript-react-loadable-plugin
Version:
A react-loadable plugin to add modules & webpack for typescript
159 lines • 6.84 kB
JavaScript
/*!
* Copyright 2019 acrazing <joking.young@gmail.com>. All rights reserved.
* @since 2019-10-31 19:19:08
*/
import { __read, __values } from "tslib";
import ts from 'typescript';
import vm from 'vm';
import { State } from './State';
var webpackCommentRegExp = new RegExp(/(^|\W)webpack[A-Z]+[A-Za-z]+:/);
function createResolveWeak(id) {
return ts.createCall(ts.createPropertyAccess(ts.createIdentifier('require'), 'resolveWeak'), void 0, [ts.createStringLiteral(id)]);
}
// TODO: parse require.ensure
function parseLoader(state, loader) {
var moduleIds = new Set();
var webpackIds = new Set();
var visitor = function (node) {
var e_1, _a;
if (ts.isCallExpression(node) &&
node.expression.kind === ts.SyntaxKind.ImportKeyword) {
var arg0 = node.arguments[0];
if (ts.isStringLiteral(arg0)) {
webpackIds.add(arg0.text);
var chunkName = '';
if (state.webpackChunkName) {
var commentRanges = ts.getLeadingCommentRanges(state.sourceFile.text, arg0.pos) || [];
try {
for (var commentRanges_1 = __values(commentRanges), commentRanges_1_1 = commentRanges_1.next(); !commentRanges_1_1.done; commentRanges_1_1 = commentRanges_1.next()) {
var range = commentRanges_1_1.value;
var comment = state.sourceFile.text.substring(range.pos, range.end);
if (range.kind === ts.SyntaxKind.SingleLineCommentTrivia) {
comment = comment.substr(2);
}
else {
comment = comment.substr(2, comment.length - 4);
}
if (webpackCommentRegExp.test(comment)) {
try {
var commentValue = vm.runInNewContext("({ " + comment + " })");
if (typeof commentValue.webpackChunkName === 'string') {
chunkName = commentValue.webpackChunkName;
break;
}
}
catch (e) {
throw new Error(e + " while parse webpack comment chunk: " + comment);
}
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (commentRanges_1_1 && !commentRanges_1_1.done && (_a = commentRanges_1.return)) _a.call(commentRanges_1);
}
finally { if (e_1) throw e_1.error; }
}
if (!chunkName) {
chunkName = state.getWebpackChunkName(arg0.text, state.sourceContext);
ts.addSyntheticLeadingComment(arg0, ts.SyntaxKind.MultiLineCommentTrivia, " webpackChunkName: " + JSON.stringify(chunkName) + " ", false);
}
}
if (state.moduleKind === 'webpackChunkName') {
moduleIds.add(chunkName);
}
else {
moduleIds.add(arg0.text);
}
}
}
return ts.visitEachChild(node, visitor, state.transformContext);
};
return [ts.visitNode(loader, visitor), moduleIds, webpackIds];
}
function transformReactLoadable(state, config) {
var loader = void 0;
var modules = void 0;
var webpack = void 0;
var properties = config.properties.slice();
properties.forEach(function (node) {
if (node.name) {
var name_1 = ts.isIdentifier(node.name)
? node.name.escapedText
: ts.isStringLiteral(node.name)
? node.name.text
: void 0;
switch (name_1) {
case 'loader':
loader = node;
break;
case 'modules':
modules = node;
break;
case 'webpack':
webpack = node;
break;
}
}
});
if (!loader) {
return config;
}
if ((modules || !state.modules) && (webpack || !state.webpack)) {
return config;
}
var _a = __read(parseLoader(state, loader), 3), moduleIds = _a[1], webpackIds = _a[2];
if (!modules && state.modules) {
properties.push(ts.createPropertyAssignment('modules', ts.createArrayLiteral(state.moduleKind === 'webpackModuleId'
? Array.from(moduleIds, createResolveWeak)
: Array.from(moduleIds, function (id) { return ts.createStringLiteral(id); }))));
}
if (!webpack && state.webpack) {
properties.push(ts.createPropertyAssignment('webpack', ts.createArrowFunction(void 0, void 0, [], void 0, void 0, ts.createArrayLiteral(Array.from(webpackIds, createResolveWeak)))));
}
return ts.createObjectLiteral(properties, true);
}
export function getRealExpression(node) {
return ts.isParenthesizedExpression(node)
? getRealExpression(node.expression)
: ts.isAsExpression(node)
? getRealExpression(node.expression)
: node;
}
function visitReactLoadable(state, node) {
if (!ts.isCallExpression(node) || node.arguments.length !== 1) {
return node;
}
var config = getRealExpression(node.arguments[0]);
if (!ts.isObjectLiteralExpression(config)) {
return node;
}
var identifier = getRealExpression(node.expression);
if (ts.isPropertyAccessExpression(identifier) &&
identifier.name.escapedText === 'Map') {
identifier = getRealExpression(identifier.expression);
}
if (!ts.isIdentifier(identifier) ||
!state.identifiers.has(identifier.escapedText)) {
return node;
}
return ts.createCall(node.expression, node.typeArguments, [
transformReactLoadable(state, config),
]);
}
export function createReactLoadableTransformer(program, options) {
var state = new State(options);
return function (context) {
state.transformContext = context;
return function (source) {
state.setSourceFile(source);
var visitor = function (node) {
node = visitReactLoadable(state, node);
return ts.visitEachChild(node, visitor, context);
};
return ts.visitNode(source, visitor);
};
};
}
//# sourceMappingURL=createReactLoadableTransformer.js.map