UNPKG

typescript-transform-extensions

Version:

Transforms import and export extensions for compatibility with native ES Modules

124 lines 7.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var path_1 = __importDefault(require("path")); var typescript_1 = __importDefault(require("typescript")); var url_1 = __importDefault(require("url")); function transformer(program, config) { var _a; var compilerOptions = program.getCompilerOptions(); var extensions = (_a = config.extensions) !== null && _a !== void 0 ? _a : {}; return function (context) { return function (sourceFile) { var factory = context.factory; var fileName = sourceFile.fileName; var fileDir = typescript_1.default.normalizePath(path_1.default.dirname(fileName)); return typescript_1.default.visitEachChild(sourceFile, visit, context); /** * Visit and replace nodes with module specifiers */ function visit(node) { // - Update `require()` or `import()` if (isRequire(node) || isAsyncImport(node)) { return update(node, node.arguments[0].text, function (_path) { var _a; var res = (_a = factory === null || factory === void 0 ? void 0 : factory.updateCallExpression(node, node.expression, node.typeArguments, [_path])) !== null && _a !== void 0 ? _a : typescript_1.default.updateCall(node, node.expression, node.typeArguments, [_path]); var textNode = node.arguments[0]; var commentRanges = typescript_1.default.getLeadingCommentRanges(textNode.getFullText(), 0) || []; for (var _i = 0, commentRanges_1 = commentRanges; _i < commentRanges_1.length; _i++) { var range = commentRanges_1[_i]; var kind = range.kind, pos = range.pos, end = range.end, hasTrailingNewLine = range.hasTrailingNewLine; var caption = textNode .getFullText() .substr(pos, end) .replace( /* searchValue */ kind === typescript_1.default.SyntaxKind.MultiLineCommentTrivia ? // Comment range in a multi-line comment with more than one line erroneously includes the // node's text in the range. For that reason, we use the greedy selector in capture group // and dismiss anything after the final comment close tag /^\/\*(.+)\*\/.*/s : /^\/\/(.+)/s, /* replaceValue */ '$1'); typescript_1.default.addSyntheticLeadingComment(_path, kind, caption, hasTrailingNewLine); } return res; }); } // - Update `ExternalModuleReference`, e.g., `import foo = require('foo');` if ((typescript_1.default.isImportDeclaration(node) || typescript_1.default.isExportDeclaration(node)) && node.moduleSpecifier && typescript_1.default.isStringLiteral(node.moduleSpecifier)) { return update(node, node.moduleSpecifier.text, function (_path) { return factory ? Object.assign(node, { moduleSpecifier: _path }) : Object.assign(node, { moduleSpecifier: typescript_1.default.updateNode(_path, node.moduleSpecifier) }); }); } // - Update `ImportTypeNode`, e.g., `typeof import('./bar');` if (typescript_1.default.isImportTypeNode(node)) { var argument_1 = node.argument; if (!typescript_1.default.isStringLiteral(argument_1.literal)) return node; var text = argument_1.literal.text; return !text ? node : update(node, text, function (_path) { var _a; return ((_a = factory === null || factory === void 0 ? void 0 : factory.updateImportTypeNode(node, factory.updateLiteralTypeNode(argument_1, _path), node.qualifier, node.typeArguments, node.isTypeOf)) !== null && _a !== void 0 ? _a : typescript_1.default.updateImportTypeNode(node, typescript_1.default.updateLiteralTypeNode(argument_1, _path), node.qualifier, node.typeArguments, node.isTypeOf)); }); } return typescript_1.default.visitEachChild(node, visit, context); } function update(original, moduleName, updaterFn) { // - Have Compiler API attempt to resolve var _a = typescript_1.default.resolveModuleName(moduleName, fileName, compilerOptions, typescript_1.default.sys), failedLookupLocations = _a.failedLookupLocations, resolvedModule = _a.resolvedModule; var _path; if (!resolvedModule) { var maybeUrl = failedLookupLocations[0]; if (!isUrl(maybeUrl)) return original; _path = maybeUrl; } else if (resolvedModule.isExternalLibraryImport) { return original; } else { var extension = resolvedModule.extension, resolvedFileName = resolvedModule.resolvedFileName; var filePath = fileDir; var modulePath = path_1.default.dirname(resolvedFileName); _path = typescript_1.default.normalizePath(path_1.default.join(path_1.default.relative(filePath, modulePath), path_1.default.basename(resolvedFileName))); if (extension && extension in extensions) { _path = _path.replace(extension, extensions[extension]); } if (!_path) return original; _path = _path[0] === "." ? _path : "./" + _path; } return updaterFn(typescript_1.default.createLiteral(_path)); } }; }; } exports.default = transformer; // * ========================================================================== // * Helpers // * ========================================================================== //#region Helpers function isUrl(target) { return !!target && (!!url_1.default.parse(target).host || !!url_1.default.parse(target).hostname); } function isRequire(node) { return (typescript_1.default.isCallExpression(node) && typescript_1.default.isIdentifier(node.expression) && node.expression.text === 'require' && typescript_1.default.isStringLiteral(node.arguments[0]) && node.arguments.length === 1); } function isAsyncImport(node) { return (typescript_1.default.isCallExpression(node) && node.expression.kind === typescript_1.default.SyntaxKind.ImportKeyword && typescript_1.default.isStringLiteral(node.arguments[0]) && node.arguments.length === 1); } //#endregion //# sourceMappingURL=main.js.map