mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Rewrite relative import extensions with flag (#59767)
This commit is contained in:
+50
-1
@@ -248,6 +248,7 @@ import {
|
||||
getAllJSDocTags,
|
||||
getAllowSyntheticDefaultImports,
|
||||
getAncestor,
|
||||
getAnyExtensionFromPath,
|
||||
getAssignedExpandoInitializer,
|
||||
getAssignmentDeclarationKind,
|
||||
getAssignmentDeclarationPropertyAccessKind,
|
||||
@@ -259,6 +260,7 @@ import {
|
||||
getCombinedLocalAndExportSymbolFlags,
|
||||
getCombinedModifierFlags,
|
||||
getCombinedNodeFlags,
|
||||
getCommonSourceDirectoryOfConfig,
|
||||
getContainingClass,
|
||||
getContainingClassExcludingClassDecorators,
|
||||
getContainingClassStaticBlock,
|
||||
@@ -352,6 +354,8 @@ import {
|
||||
getPropertyAssignmentAliasLikeExpression,
|
||||
getPropertyNameForPropertyNameNode,
|
||||
getPropertyNameFromType,
|
||||
getRelativePathFromDirectory,
|
||||
getRelativePathFromFile,
|
||||
getResolutionDiagnostic,
|
||||
getResolutionModeOverride,
|
||||
getResolveJsonModule,
|
||||
@@ -414,6 +418,7 @@ import {
|
||||
hasSyntacticModifiers,
|
||||
hasType,
|
||||
HeritageClause,
|
||||
hostGetCanonicalFileName,
|
||||
Identifier,
|
||||
identifierToKeywordKind,
|
||||
IdentifierTypePredicate,
|
||||
@@ -693,6 +698,7 @@ import {
|
||||
isParenthesizedTypeNode,
|
||||
isPartOfParameterDeclaration,
|
||||
isPartOfTypeNode,
|
||||
isPartOfTypeOnlyImportOrExportDeclaration,
|
||||
isPartOfTypeQuery,
|
||||
isPlainJsFile,
|
||||
isPrefixUnaryExpression,
|
||||
@@ -994,6 +1000,7 @@ import {
|
||||
ShorthandPropertyAssignment,
|
||||
shouldAllowImportingTsExtension,
|
||||
shouldPreserveConstEnums,
|
||||
shouldRewriteModuleSpecifier,
|
||||
Signature,
|
||||
SignatureDeclaration,
|
||||
SignatureFlags,
|
||||
@@ -1007,6 +1014,7 @@ import {
|
||||
skipTypeParentheses,
|
||||
some,
|
||||
SourceFile,
|
||||
sourceFileMayBeEmitted,
|
||||
SpreadAssignment,
|
||||
SpreadElement,
|
||||
startsWith,
|
||||
@@ -4665,6 +4673,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
error(errorNode, Diagnostics.An_import_path_can_only_end_with_a_0_extension_when_allowImportingTsExtensions_is_enabled, tsExtension);
|
||||
}
|
||||
}
|
||||
else if (
|
||||
compilerOptions.rewriteRelativeImportExtensions
|
||||
&& !(location.flags & NodeFlags.Ambient)
|
||||
&& !isDeclarationFileName(moduleReference)
|
||||
&& !isLiteralImportTypeNode(location)
|
||||
&& !isPartOfTypeOnlyImportOrExportDeclaration(location)
|
||||
) {
|
||||
const shouldRewrite = shouldRewriteModuleSpecifier(moduleReference, compilerOptions);
|
||||
if (!resolvedModule.resolvedUsingTsExtension && shouldRewrite) {
|
||||
error(
|
||||
errorNode,
|
||||
Diagnostics.This_relative_import_path_is_unsafe_to_rewrite_because_it_looks_like_a_file_name_but_actually_resolves_to_0,
|
||||
getRelativePathFromFile(getNormalizedAbsolutePath(currentSourceFile.fileName, host.getCurrentDirectory()), resolvedModule.resolvedFileName, hostGetCanonicalFileName(host)),
|
||||
);
|
||||
}
|
||||
else if (resolvedModule.resolvedUsingTsExtension && !shouldRewrite && sourceFileMayBeEmitted(sourceFile, host)) {
|
||||
error(
|
||||
errorNode,
|
||||
Diagnostics.This_import_uses_a_0_extension_to_resolve_to_an_input_TypeScript_file_but_will_not_be_rewritten_during_emit_because_it_is_not_a_relative_path,
|
||||
getAnyExtensionFromPath(moduleReference),
|
||||
);
|
||||
}
|
||||
else if (resolvedModule.resolvedUsingTsExtension && shouldRewrite) {
|
||||
const redirect = host.getResolvedProjectReferenceToRedirect(sourceFile.path);
|
||||
if (redirect) {
|
||||
const ignoreCase = !host.useCaseSensitiveFileNames();
|
||||
const ownRootDir = host.getCommonSourceDirectory();
|
||||
const otherRootDir = getCommonSourceDirectoryOfConfig(redirect.commandLine, ignoreCase);
|
||||
const rootDirPath = getRelativePathFromDirectory(ownRootDir, otherRootDir, ignoreCase);
|
||||
const outDirPath = getRelativePathFromDirectory(compilerOptions.outDir || ownRootDir, redirect.commandLine.options.outDir || otherRootDir, ignoreCase);
|
||||
if (rootDirPath !== outDirPath) {
|
||||
error(
|
||||
errorNode,
|
||||
Diagnostics.This_import_path_is_unsafe_to_rewrite_because_it_resolves_to_another_project_and_the_relative_path_between_the_projects_output_files_is_not_the_same_as_the_relative_path_between_its_input_files,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceFile.symbol) {
|
||||
if (errorNode && resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) {
|
||||
@@ -50871,6 +50918,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return ["__propKey"];
|
||||
case ExternalEmitHelpers.AddDisposableResourceAndDisposeResources:
|
||||
return ["__addDisposableResource", "__disposeResources"];
|
||||
case ExternalEmitHelpers.RewriteRelativeImportExtension:
|
||||
return ["__rewriteRelativeImportExtension"];
|
||||
default:
|
||||
return Debug.fail("Unrecognized helper");
|
||||
}
|
||||
@@ -52911,7 +52960,7 @@ function createBasicNodeBuilderModuleSpecifierResolutionHost(host: TypeCheckerHo
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
getSymlinkCache: maybeBind(host, host.getSymlinkCache),
|
||||
getPackageJsonInfoCache: () => host.getPackageJsonInfoCache?.(),
|
||||
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
|
||||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
redirectTargetsMap: host.redirectTargetsMap,
|
||||
getProjectReferenceRedirect: fileName => host.getProjectReferenceRedirect(fileName),
|
||||
isSourceOfProjectReferenceRedirect: fileName => host.isSourceOfProjectReferenceRedirect(fileName),
|
||||
|
||||
@@ -1177,6 +1177,15 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
|
||||
defaultValueDescription: false,
|
||||
transpileOptionValue: undefined,
|
||||
},
|
||||
{
|
||||
name: "rewriteRelativeImportExtensions",
|
||||
type: "boolean",
|
||||
affectsSemanticDiagnostics: true,
|
||||
affectsBuildInfo: true,
|
||||
category: Diagnostics.Modules,
|
||||
description: Diagnostics.Rewrite_ts_tsx_mts_and_cts_file_extensions_in_relative_import_paths_to_their_JavaScript_equivalent_in_output_files,
|
||||
defaultValueDescription: false,
|
||||
},
|
||||
{
|
||||
name: "resolvePackageJsonExports",
|
||||
type: "boolean",
|
||||
|
||||
@@ -3964,6 +3964,18 @@
|
||||
"category": "Error",
|
||||
"code": 2875
|
||||
},
|
||||
"This relative import path is unsafe to rewrite because it looks like a file name, but actually resolves to \"{0}\".": {
|
||||
"category": "Error",
|
||||
"code": 2876
|
||||
},
|
||||
"This import uses a '{0}' extension to resolve to an input TypeScript file, but will not be rewritten during emit because it is not a relative path.": {
|
||||
"category": "Error",
|
||||
"code": 2877
|
||||
},
|
||||
"This import path is unsafe to rewrite because it resolves to another project, and the relative path between the projects' output files is not the same as the relative path between its input files.": {
|
||||
"category": "Error",
|
||||
"code": 2878
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -5947,6 +5959,10 @@
|
||||
"category": "Message",
|
||||
"code": 6420
|
||||
},
|
||||
"Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files.": {
|
||||
"category": "Message",
|
||||
"code": 6421
|
||||
},
|
||||
|
||||
"The expected type comes from property '{0}' which is declared here on type '{1}'": {
|
||||
"category": "Message",
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
isCallExpression,
|
||||
isComputedPropertyName,
|
||||
isIdentifier,
|
||||
JsxEmit,
|
||||
memoize,
|
||||
ObjectLiteralElementLike,
|
||||
ParameterDeclaration,
|
||||
@@ -139,6 +140,8 @@ export interface EmitHelperFactory {
|
||||
// 'using' helpers
|
||||
createAddDisposableResourceHelper(envBinding: Expression, value: Expression, async: boolean): Expression;
|
||||
createDisposeResourcesHelper(envBinding: Expression): Expression;
|
||||
// --rewriteRelativeImportExtensions helpers
|
||||
createRewriteRelativeImportExtensionsHelper(expression: Expression): Expression;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -189,6 +192,8 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel
|
||||
// 'using' helpers
|
||||
createAddDisposableResourceHelper,
|
||||
createDisposeResourcesHelper,
|
||||
// --rewriteRelativeImportExtensions helpers
|
||||
createRewriteRelativeImportExtensionsHelper,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -682,6 +687,17 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel
|
||||
context.requestEmitHelper(disposeResourcesHelper);
|
||||
return factory.createCallExpression(getUnscopedHelperName("__disposeResources"), /*typeArguments*/ undefined, [envBinding]);
|
||||
}
|
||||
|
||||
function createRewriteRelativeImportExtensionsHelper(expression: Expression) {
|
||||
context.requestEmitHelper(rewriteRelativeImportExtensionsHelper);
|
||||
return factory.createCallExpression(
|
||||
getUnscopedHelperName("__rewriteRelativeImportExtension"),
|
||||
/*typeArguments*/ undefined,
|
||||
context.getCompilerOptions().jsx === JsxEmit.Preserve
|
||||
? [expression, factory.createTrue()]
|
||||
: [expression],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -1422,6 +1438,21 @@ const disposeResourcesHelper: UnscopedEmitHelper = {
|
||||
});`,
|
||||
};
|
||||
|
||||
const rewriteRelativeImportExtensionsHelper: UnscopedEmitHelper = {
|
||||
name: "typescript:rewriteRelativeImportExtensions",
|
||||
importName: "__rewriteRelativeImportExtension",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
||||
if (typeof path === "string" && /^\\.\\.?\\//.test(path)) {
|
||||
return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
||||
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
||||
});
|
||||
}
|
||||
return path;
|
||||
};`,
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export const asyncSuperHelper: EmitHelper = {
|
||||
name: "typescript:async-super",
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
forEach,
|
||||
forEachAncestorDirectory,
|
||||
formatMessage,
|
||||
getAllowImportingTsExtensions,
|
||||
getAllowJSCompilerOption,
|
||||
getAnyExtensionFromPath,
|
||||
getBaseFileName,
|
||||
@@ -1484,7 +1485,7 @@ export function resolveModuleName(moduleName: string, containingFile: string, co
|
||||
* 'typings' entry or file 'index' with some supported extension
|
||||
* - Classic loader will only try to interpret '/a/b/c' as file.
|
||||
*/
|
||||
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
|
||||
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonValue?: string) => Resolved | undefined;
|
||||
|
||||
/**
|
||||
* Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to
|
||||
@@ -2094,13 +2095,14 @@ function loadModuleFromFileNoImplicitExtensions(extensions: Extensions, candidat
|
||||
* module specifiers written in source files - and so it always allows the
|
||||
* candidate to end with a TS extension (but will also try substituting a JS extension for a TS extension).
|
||||
*/
|
||||
function loadFileNameFromPackageJsonField(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
function loadFileNameFromPackageJsonField(extensions: Extensions, candidate: string, packageJsonValue: string | undefined, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
if (
|
||||
extensions & Extensions.TypeScript && fileExtensionIsOneOf(candidate, supportedTSImplementationExtensions) ||
|
||||
extensions & Extensions.Declaration && fileExtensionIsOneOf(candidate, supportedDeclarationExtensions)
|
||||
) {
|
||||
const result = tryFile(candidate, onlyRecordFailures, state);
|
||||
return result !== undefined ? { path: candidate, ext: tryExtractTSExtension(candidate) as Extension, resolvedUsingTsExtension: undefined } : undefined;
|
||||
const ext = tryExtractTSExtension(candidate) as Extension;
|
||||
return result !== undefined ? { path: candidate, ext, resolvedUsingTsExtension: packageJsonValue ? !endsWith(packageJsonValue, ext) : undefined } : undefined;
|
||||
}
|
||||
|
||||
if (state.isConfigLookup && extensions === Extensions.Json && fileExtensionIs(candidate, Extension.Json)) {
|
||||
@@ -2316,7 +2318,7 @@ function loadEntrypointsFromExportMap(
|
||||
}
|
||||
const resolvedTarget = combinePaths(scope.packageDirectory, target);
|
||||
const finalPath = getNormalizedAbsolutePath(resolvedTarget, state.host.getCurrentDirectory?.());
|
||||
const result = loadFileNameFromPackageJsonField(extensions, finalPath, /*onlyRecordFailures*/ false, state);
|
||||
const result = loadFileNameFromPackageJsonField(extensions, finalPath, target, /*onlyRecordFailures*/ false, state);
|
||||
if (result) {
|
||||
entrypoints = appendIfUnique(entrypoints, result, (a, b) => a.path === b.path);
|
||||
return true;
|
||||
@@ -2487,7 +2489,7 @@ function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: st
|
||||
}
|
||||
|
||||
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
|
||||
const fromFile = loadFileNameFromPackageJsonField(extensions, candidate, onlyRecordFailures, state);
|
||||
const fromFile = loadFileNameFromPackageJsonField(extensions, candidate, /*packageJsonValue*/ undefined, onlyRecordFailures, state);
|
||||
if (fromFile) {
|
||||
return noPackageId(fromFile);
|
||||
}
|
||||
@@ -2790,7 +2792,7 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo
|
||||
const finalPath = toAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath);
|
||||
const inputLink = tryLoadInputFileForPath(finalPath, subpath, combinePaths(scope.packageDirectory, "package.json"), isImports);
|
||||
if (inputLink) return inputLink;
|
||||
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, finalPath, /*onlyRecordFailures*/ false, state), state));
|
||||
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, finalPath, target, /*onlyRecordFailures*/ false, state), state));
|
||||
}
|
||||
else if (typeof target === "object" && target !== null) { // eslint-disable-line no-restricted-syntax
|
||||
if (!Array.isArray(target)) {
|
||||
@@ -2936,7 +2938,7 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo
|
||||
if (!extensionIsOk(extensions, possibleExt)) continue;
|
||||
const possibleInputWithInputExtension = changeAnyExtension(possibleInputBase, possibleExt, ext, !useCaseSensitiveFileNames(state));
|
||||
if (state.host.fileExists(possibleInputWithInputExtension)) {
|
||||
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, possibleInputWithInputExtension, /*onlyRecordFailures*/ false, state), state));
|
||||
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, possibleInputWithInputExtension, /*packageJsonValue*/ undefined, /*onlyRecordFailures*/ false, state), state));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3333,7 +3335,7 @@ function resolveFromTypeRoot(moduleName: string, state: ModuleResolutionState) {
|
||||
// so this function doesn't check them to avoid propagating errors.
|
||||
/** @internal */
|
||||
export function shouldAllowImportingTsExtension(compilerOptions: CompilerOptions, fromFileName?: string): boolean {
|
||||
return !!compilerOptions.allowImportingTsExtensions || !!fromFileName && isDeclarationFileName(fromFileName);
|
||||
return getAllowImportingTsExtensions(compilerOptions) || !!fromFileName && isDeclarationFileName(fromFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-49
@@ -99,8 +99,8 @@ import {
|
||||
flatten,
|
||||
forEach,
|
||||
forEachAncestorDirectory,
|
||||
forEachChild,
|
||||
forEachChildRecursively,
|
||||
forEachDynamicImportOrRequireCall,
|
||||
forEachEmittedFile,
|
||||
forEachEntry,
|
||||
forEachKey,
|
||||
@@ -162,7 +162,6 @@ import {
|
||||
hasExtension,
|
||||
HasInvalidatedLibResolutions,
|
||||
HasInvalidatedResolutions,
|
||||
hasJSDocNodes,
|
||||
hasJSFileExtension,
|
||||
hasJsonModuleEmitEnabled,
|
||||
hasProperty,
|
||||
@@ -200,7 +199,6 @@ import {
|
||||
isImportTypeNode,
|
||||
isInJSFile,
|
||||
isJSDocImportTag,
|
||||
isLiteralImportTypeNode,
|
||||
isModifier,
|
||||
isModuleDeclaration,
|
||||
isObjectLiteralExpression,
|
||||
@@ -3521,7 +3519,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
|
||||
if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) {
|
||||
collectDynamicImportOrRequireOrJsDocImportCalls(file);
|
||||
forEachDynamicImportOrRequireCall(file, /*includeTypeSpaceImports*/ true, /*requireStringLiteralLikeArgument*/ true, (node, moduleSpecifier) => {
|
||||
setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
|
||||
imports = append(imports, moduleSpecifier);
|
||||
});
|
||||
}
|
||||
|
||||
file.imports = imports || emptyArray;
|
||||
@@ -3584,50 +3585,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collectDynamicImportOrRequireOrJsDocImportCalls(file: SourceFile) {
|
||||
const r = /import|require/g;
|
||||
while (r.exec(file.text) !== null) { // eslint-disable-line no-restricted-syntax
|
||||
const node = getNodeAtPosition(file, r.lastIndex);
|
||||
if (isJavaScriptFile && isRequireCall(node, /*requireStringLiteralLikeArgument*/ true)) {
|
||||
setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
|
||||
imports = append(imports, node.arguments[0]);
|
||||
}
|
||||
// we have to check the argument list has length of at least 1. We will still have to process these even though we have parsing error.
|
||||
else if (isImportCall(node) && node.arguments.length >= 1 && isStringLiteralLike(node.arguments[0])) {
|
||||
setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
|
||||
imports = append(imports, node.arguments[0]);
|
||||
}
|
||||
else if (isLiteralImportTypeNode(node)) {
|
||||
setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
|
||||
imports = append(imports, node.argument.literal);
|
||||
}
|
||||
else if (isJavaScriptFile && isJSDocImportTag(node)) {
|
||||
const moduleNameExpr = getExternalModuleName(node);
|
||||
if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text) {
|
||||
setParentRecursive(node, /*incremental*/ false);
|
||||
imports = append(imports, moduleNameExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a token if position is in [start-of-leading-trivia, end), includes JSDoc only in JS files */
|
||||
function getNodeAtPosition(sourceFile: SourceFile, position: number): Node {
|
||||
let current: Node = sourceFile;
|
||||
const getContainingChild = (child: Node) => {
|
||||
if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) {
|
||||
return child;
|
||||
}
|
||||
};
|
||||
while (true) {
|
||||
const child = isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild);
|
||||
if (!child) {
|
||||
return current;
|
||||
}
|
||||
current = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getLibFileFromReference(ref: FileReference) {
|
||||
@@ -4557,7 +4514,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
}
|
||||
|
||||
if (options.allowImportingTsExtensions && !(options.noEmit || options.emitDeclarationOnly)) {
|
||||
if (options.allowImportingTsExtensions && !(options.noEmit || options.emitDeclarationOnly || options.rewriteRelativeImportExtensions)) {
|
||||
createOptionValueDiagnostic("allowImportingTsExtensions", Diagnostics.Option_allowImportingTsExtensions_can_only_be_used_when_either_noEmit_or_emitDeclarationOnly_is_set);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import {
|
||||
addEmitHelpers,
|
||||
addRange,
|
||||
append,
|
||||
Bundle,
|
||||
CallExpression,
|
||||
chainBundle,
|
||||
createEmptyExports,
|
||||
createExternalHelpersImportDeclarationIfNeeded,
|
||||
@@ -12,6 +14,7 @@ import {
|
||||
ExportDeclaration,
|
||||
Expression,
|
||||
ExpressionStatement,
|
||||
forEachDynamicImportOrRequireCall,
|
||||
GeneratedIdentifierFlags,
|
||||
getEmitFlags,
|
||||
getEmitModuleKind,
|
||||
@@ -31,17 +34,22 @@ import {
|
||||
isExternalModuleImportEqualsDeclaration,
|
||||
isExternalModuleIndicator,
|
||||
isIdentifier,
|
||||
isInJSFile,
|
||||
isNamespaceExport,
|
||||
isSourceFile,
|
||||
isStatement,
|
||||
isStringLiteralLike,
|
||||
ModifierFlags,
|
||||
ModuleKind,
|
||||
Node,
|
||||
NodeFlags,
|
||||
NodeId,
|
||||
rangeContainsRange,
|
||||
rewriteModuleSpecifier,
|
||||
ScriptTarget,
|
||||
setOriginalNode,
|
||||
setTextRange,
|
||||
shouldRewriteModuleSpecifier,
|
||||
singleOrMany,
|
||||
some,
|
||||
SourceFile,
|
||||
@@ -73,6 +81,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
|
||||
context.enableSubstitution(SyntaxKind.Identifier);
|
||||
|
||||
const noSubstitution = new Set<NodeId>();
|
||||
let importsAndRequiresToRewriteOrShim: CallExpression[] | undefined;
|
||||
let helperNameSubstitutions: Map<string, Identifier> | undefined;
|
||||
let currentSourceFile: SourceFile | undefined;
|
||||
let importRequireStatements: [ImportDeclaration, VariableStatement] | undefined;
|
||||
@@ -86,7 +95,15 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
|
||||
if (isExternalModule(node) || getIsolatedModules(compilerOptions)) {
|
||||
currentSourceFile = node;
|
||||
importRequireStatements = undefined;
|
||||
if (compilerOptions.rewriteRelativeImportExtensions && (currentSourceFile.flags & NodeFlags.PossiblyContainsDynamicImport || isInJSFile(node))) {
|
||||
forEachDynamicImportOrRequireCall(node, /*includeTypeSpaceImports*/ false, /*requireStringLiteralLikeArgument*/ false, node => {
|
||||
if (!isStringLiteralLike(node.arguments[0]) || shouldRewriteModuleSpecifier(node.arguments[0].text, compilerOptions)) {
|
||||
importsAndRequiresToRewriteOrShim = append(importsAndRequiresToRewriteOrShim, node);
|
||||
}
|
||||
});
|
||||
}
|
||||
let result = updateExternalModule(node);
|
||||
addEmitHelpers(result, context.readEmitHelpers());
|
||||
currentSourceFile = undefined;
|
||||
if (importRequireStatements) {
|
||||
result = factory.updateSourceFile(
|
||||
@@ -135,11 +152,53 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
const exportDecl = node as ExportDeclaration;
|
||||
return visitExportDeclaration(exportDecl);
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return visitImportDeclaration(node as ImportDeclaration);
|
||||
case SyntaxKind.CallExpression:
|
||||
if (node === importsAndRequiresToRewriteOrShim?.[0]) {
|
||||
return visitImportOrRequireCall(importsAndRequiresToRewriteOrShim.shift()!);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (importsAndRequiresToRewriteOrShim?.length && rangeContainsRange(node, importsAndRequiresToRewriteOrShim[0])) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitImportDeclaration(node: ImportDeclaration): VisitResult<ImportDeclaration> {
|
||||
if (!compilerOptions.rewriteRelativeImportExtensions) {
|
||||
return node;
|
||||
}
|
||||
const updatedModuleSpecifier = rewriteModuleSpecifier(node.moduleSpecifier, compilerOptions);
|
||||
if (updatedModuleSpecifier === node.moduleSpecifier) {
|
||||
return node;
|
||||
}
|
||||
return factory.updateImportDeclaration(
|
||||
node,
|
||||
node.modifiers,
|
||||
node.importClause,
|
||||
updatedModuleSpecifier,
|
||||
node.attributes,
|
||||
);
|
||||
}
|
||||
|
||||
function visitImportOrRequireCall(node: CallExpression): VisitResult<Expression> {
|
||||
return factory.updateCallExpression(
|
||||
node,
|
||||
node.expression,
|
||||
node.typeArguments,
|
||||
[
|
||||
isStringLiteralLike(node.arguments[0])
|
||||
? rewriteModuleSpecifier(node.arguments[0], compilerOptions)
|
||||
: emitHelpers().createRewriteRelativeImportExtensionsHelper(node.arguments[0]),
|
||||
...node.arguments.slice(1),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a `require()` call to import an external module.
|
||||
*
|
||||
@@ -149,7 +208,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
|
||||
const moduleName = getExternalModuleNameLiteral(factory, importNode, Debug.checkDefined(currentSourceFile), host, resolver, compilerOptions);
|
||||
const args: Expression[] = [];
|
||||
if (moduleName) {
|
||||
args.push(moduleName);
|
||||
args.push(rewriteModuleSpecifier(moduleName, compilerOptions));
|
||||
}
|
||||
if (getEmitModuleKind(compilerOptions) === ModuleKind.Preserve) {
|
||||
return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, args);
|
||||
@@ -270,14 +329,21 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
|
||||
}
|
||||
|
||||
function visitExportDeclaration(node: ExportDeclaration) {
|
||||
// `export * as ns` only needs to be transformed in ES2015
|
||||
if (compilerOptions.module !== undefined && compilerOptions.module > ModuleKind.ES2015) {
|
||||
return node;
|
||||
}
|
||||
|
||||
// Either ill-formed or don't need to be tranformed.
|
||||
if (!node.exportClause || !isNamespaceExport(node.exportClause) || !node.moduleSpecifier) {
|
||||
return node;
|
||||
const updatedModuleSpecifier = rewriteModuleSpecifier(node.moduleSpecifier, compilerOptions);
|
||||
if (
|
||||
(compilerOptions.module !== undefined && compilerOptions.module > ModuleKind.ES2015)
|
||||
|| !node.exportClause || !isNamespaceExport(node.exportClause) || !node.moduleSpecifier
|
||||
) {
|
||||
// Either ill-formed or don't need to be tranformed.
|
||||
return (!node.moduleSpecifier || updatedModuleSpecifier === node.moduleSpecifier) ? node :
|
||||
factory.updateExportDeclaration(
|
||||
node,
|
||||
node.modifiers,
|
||||
node.isTypeOnly,
|
||||
node.exportClause,
|
||||
updatedModuleSpecifier,
|
||||
node.attributes,
|
||||
);
|
||||
}
|
||||
|
||||
const oldIdentifier = node.exportClause.name;
|
||||
@@ -291,7 +357,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
|
||||
synthName,
|
||||
),
|
||||
),
|
||||
node.moduleSpecifier,
|
||||
updatedModuleSpecifier!,
|
||||
node.attributes,
|
||||
);
|
||||
setOriginalNode(importDecl, node.exportClause);
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
firstOrUndefined,
|
||||
flattenDestructuringAssignment,
|
||||
FlattenLevel,
|
||||
forEachDynamicImportOrRequireCall,
|
||||
ForInStatement,
|
||||
ForOfStatement,
|
||||
ForStatement,
|
||||
@@ -114,6 +115,7 @@ import {
|
||||
isSpreadElement,
|
||||
isStatement,
|
||||
isStringLiteral,
|
||||
isStringLiteralLike,
|
||||
isVariableDeclaration,
|
||||
isVariableDeclarationList,
|
||||
LabeledStatement,
|
||||
@@ -136,11 +138,13 @@ import {
|
||||
PrefixUnaryExpression,
|
||||
reduceLeft,
|
||||
removeAllComments,
|
||||
rewriteModuleSpecifier,
|
||||
ScriptTarget,
|
||||
setEmitFlags,
|
||||
setOriginalNode,
|
||||
setTextRange,
|
||||
ShorthandPropertyAssignment,
|
||||
shouldRewriteModuleSpecifier,
|
||||
singleOrMany,
|
||||
some,
|
||||
SourceFile,
|
||||
@@ -213,6 +217,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
|
||||
let currentSourceFile: SourceFile; // The current file.
|
||||
let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
|
||||
let importsAndRequiresToRewriteOrShim: CallExpression[] | undefined;
|
||||
const noSubstitution: boolean[] = []; // Set of nodes for which substitution rules should be ignored.
|
||||
let needUMDDynamicImportHelper: boolean;
|
||||
|
||||
@@ -236,6 +241,13 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
currentSourceFile = node;
|
||||
currentModuleInfo = collectExternalModuleInfo(context, node);
|
||||
moduleInfoMap[getOriginalNodeId(node)] = currentModuleInfo;
|
||||
if (compilerOptions.rewriteRelativeImportExtensions) {
|
||||
forEachDynamicImportOrRequireCall(node, /*includeTypeSpaceImports*/ false, /*requireStringLiteralLikeArgument*/ false, node => {
|
||||
if (!isStringLiteralLike(node.arguments[0]) || shouldRewriteModuleSpecifier(node.arguments[0].text, compilerOptions)) {
|
||||
importsAndRequiresToRewriteOrShim = append(importsAndRequiresToRewriteOrShim, node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Perform the transformation.
|
||||
const transformModule = getTransformModuleDelegate(moduleKind);
|
||||
@@ -783,7 +795,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
function visitorWorker(node: Node, valueIsDiscarded: boolean): VisitResult<Node> {
|
||||
// This visitor does not need to descend into the tree if there is no dynamic import, destructuring assignment, or update expression
|
||||
// as export/import statements are only transformed at the top level of a file.
|
||||
if (!(node.transformFlags & (TransformFlags.ContainsDynamicImport | TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsUpdateExpressionForIdentifier))) {
|
||||
if (!(node.transformFlags & (TransformFlags.ContainsDynamicImport | TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsUpdateExpressionForIdentifier)) && !importsAndRequiresToRewriteOrShim?.length) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -797,8 +809,15 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
case SyntaxKind.PartiallyEmittedExpression:
|
||||
return visitPartiallyEmittedExpression(node as PartiallyEmittedExpression, valueIsDiscarded);
|
||||
case SyntaxKind.CallExpression:
|
||||
const needsRewrite = node === firstOrUndefined(importsAndRequiresToRewriteOrShim);
|
||||
if (needsRewrite) {
|
||||
importsAndRequiresToRewriteOrShim!.shift();
|
||||
}
|
||||
if (isImportCall(node) && host.shouldTransformImportCall(currentSourceFile)) {
|
||||
return visitImportCallExpression(node);
|
||||
return visitImportCallExpression(node, needsRewrite);
|
||||
}
|
||||
else if (needsRewrite) {
|
||||
return shimOrRewriteImportOrRequireCall(node as CallExpression);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
@@ -1170,14 +1189,34 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitImportCallExpression(node: ImportCall): Expression {
|
||||
function shimOrRewriteImportOrRequireCall(node: CallExpression): CallExpression {
|
||||
return factory.updateCallExpression(
|
||||
node,
|
||||
node.expression,
|
||||
/*typeArguments*/ undefined,
|
||||
visitNodes(node.arguments, (arg: Expression) => {
|
||||
if (arg === node.arguments[0]) {
|
||||
return isStringLiteralLike(arg)
|
||||
? rewriteModuleSpecifier(arg, compilerOptions)
|
||||
: emitHelpers().createRewriteRelativeImportExtensionsHelper(arg);
|
||||
}
|
||||
return visitor(arg);
|
||||
}, isExpression),
|
||||
);
|
||||
}
|
||||
|
||||
function visitImportCallExpression(node: ImportCall, rewriteOrShim: boolean): Expression {
|
||||
if (moduleKind === ModuleKind.None && languageVersion >= ScriptTarget.ES2020) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions);
|
||||
const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor, isExpression);
|
||||
// Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output.
|
||||
const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument;
|
||||
const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text)
|
||||
? externalModuleName
|
||||
: firstArgument && rewriteOrShim
|
||||
? isStringLiteral(firstArgument) ? rewriteModuleSpecifier(firstArgument, compilerOptions) : emitHelpers().createRewriteRelativeImportExtensionsHelper(firstArgument)
|
||||
: firstArgument;
|
||||
const containsLexicalThis = !!(node.transformFlags & TransformFlags.ContainsLexicalThis);
|
||||
switch (compilerOptions.module) {
|
||||
case ModuleKind.AMD:
|
||||
@@ -1500,7 +1539,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
const moduleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions);
|
||||
const args: Expression[] = [];
|
||||
if (moduleName) {
|
||||
args.push(moduleName);
|
||||
args.push(rewriteModuleSpecifier(moduleName, compilerOptions));
|
||||
}
|
||||
|
||||
return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, args);
|
||||
|
||||
@@ -2343,7 +2343,14 @@ export function transformTypeScript(context: TransformationContext): Transformer
|
||||
// never elide `export <whatever> from <whereever>` declarations -
|
||||
// they should be kept for sideffects/untyped exports, even when the
|
||||
// type checker doesn't know about any exports
|
||||
return node;
|
||||
return factory.updateExportDeclaration(
|
||||
node,
|
||||
node.modifiers,
|
||||
node.isTypeOnly,
|
||||
node.exportClause,
|
||||
node.moduleSpecifier,
|
||||
node.attributes,
|
||||
);
|
||||
}
|
||||
|
||||
// Elide the export declaration if all of its named exports are elided.
|
||||
@@ -2422,8 +2429,10 @@ export function transformTypeScript(context: TransformationContext): Transformer
|
||||
}
|
||||
|
||||
if (isExternalModuleImportEqualsDeclaration(node)) {
|
||||
const isReferenced = shouldEmitAliasDeclaration(node);
|
||||
return isReferenced ? visitEachChild(node, visitor, context) : undefined;
|
||||
if (!shouldEmitAliasDeclaration(node)) {
|
||||
return undefined;
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
if (!shouldEmitImportEqualsDeclaration(node)) {
|
||||
|
||||
@@ -7,11 +7,13 @@ import {
|
||||
BindingElement,
|
||||
Bundle,
|
||||
cast,
|
||||
changeExtension,
|
||||
ClassDeclaration,
|
||||
ClassElement,
|
||||
ClassExpression,
|
||||
ClassLikeDeclaration,
|
||||
ClassStaticBlockDeclaration,
|
||||
CompilerOptions,
|
||||
CompoundAssignmentOperator,
|
||||
CoreTransformationContext,
|
||||
createExternalHelpersImportDeclarationIfNeeded,
|
||||
@@ -21,6 +23,7 @@ import {
|
||||
ExportDeclaration,
|
||||
ExportSpecifier,
|
||||
Expression,
|
||||
factory,
|
||||
filter,
|
||||
formatGeneratedName,
|
||||
FunctionDeclaration,
|
||||
@@ -33,6 +36,7 @@ import {
|
||||
getNodeForGeneratedName,
|
||||
getNodeId,
|
||||
getOriginalNode,
|
||||
getOutputExtension,
|
||||
hasDecorators,
|
||||
hasStaticModifier,
|
||||
hasSyntacticModifier,
|
||||
@@ -61,6 +65,7 @@ import {
|
||||
isPrivateIdentifier,
|
||||
isPropertyDeclaration,
|
||||
isStatic,
|
||||
isStringLiteral,
|
||||
isStringLiteralLike,
|
||||
isSuperCall,
|
||||
isTryStatement,
|
||||
@@ -83,6 +88,9 @@ import {
|
||||
PrivateIdentifierAutoAccessorPropertyDeclaration,
|
||||
PrivateIdentifierMethodDeclaration,
|
||||
PropertyDeclaration,
|
||||
setOriginalNode,
|
||||
setTextRange,
|
||||
shouldRewriteModuleSpecifier,
|
||||
skipParentheses,
|
||||
some,
|
||||
SourceFile,
|
||||
@@ -863,3 +871,16 @@ function isSimpleParameter(node: ParameterDeclaration) {
|
||||
export function isSimpleParameterList(nodes: NodeArray<ParameterDeclaration>): boolean {
|
||||
return every(nodes, isSimpleParameter);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function rewriteModuleSpecifier(node: Expression, compilerOptions: CompilerOptions): Expression;
|
||||
/** @internal */
|
||||
export function rewriteModuleSpecifier(node: Expression | undefined, compilerOptions: CompilerOptions): Expression | undefined;
|
||||
/** @internal */
|
||||
export function rewriteModuleSpecifier(node: Expression | undefined, compilerOptions: CompilerOptions): Expression | undefined {
|
||||
if (!node || !isStringLiteral(node) || !shouldRewriteModuleSpecifier(node.text, compilerOptions)) {
|
||||
return node;
|
||||
}
|
||||
const updatedText = changeExtension(node.text, getOutputExtension(node.text, compilerOptions));
|
||||
return updatedText !== node.text ? setOriginalNode(setTextRange(factory.createStringLiteral(updatedText, node.singleQuote), node), node) : node;
|
||||
}
|
||||
|
||||
@@ -5016,7 +5016,7 @@ export interface EmitResult {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface TypeCheckerHost extends ModuleSpecifierResolutionHost {
|
||||
export interface TypeCheckerHost extends ModuleSpecifierResolutionHost, SourceFileMayBeEmittedHost {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
@@ -7451,6 +7451,7 @@ export interface CompilerOptions {
|
||||
removeComments?: boolean;
|
||||
resolvePackageJsonExports?: boolean;
|
||||
resolvePackageJsonImports?: boolean;
|
||||
rewriteRelativeImportExtensions?: boolean;
|
||||
rootDir?: string;
|
||||
rootDirs?: string[];
|
||||
skipLibCheck?: boolean;
|
||||
@@ -8468,6 +8469,7 @@ export const enum ExternalEmitHelpers {
|
||||
SetFunctionName = 1 << 22, // __setFunctionName (used by class fields and ECMAScript decorators)
|
||||
PropKey = 1 << 23, // __propKey (used by class fields and ECMAScript decorators)
|
||||
AddDisposableResourceAndDisposeResources = 1 << 24, // __addDisposableResource and __disposeResources (used by ESNext transformations)
|
||||
RewriteRelativeImportExtension = 1 << 25, // __rewriteRelativeImportExtension (used by --rewriteRelativeImportExtensions)
|
||||
|
||||
FirstEmitHelper = Extends,
|
||||
LastEmitHelper = AddDisposableResourceAndDisposeResources,
|
||||
@@ -9890,7 +9892,7 @@ export interface HasCurrentDirectory {
|
||||
|
||||
/** @internal */
|
||||
export interface ModuleSpecifierResolutionHost {
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
fileExists(path: string): boolean;
|
||||
getCurrentDirectory(): string;
|
||||
directoryExists?(path: string): boolean;
|
||||
|
||||
@@ -298,6 +298,7 @@ import {
|
||||
isJSDocAugmentsTag,
|
||||
isJSDocFunctionType,
|
||||
isJSDocImplementsTag,
|
||||
isJSDocImportTag,
|
||||
isJSDocLinkLike,
|
||||
isJSDocMemberName,
|
||||
isJSDocNameReference,
|
||||
@@ -4302,6 +4303,11 @@ export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyVal
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function shouldRewriteModuleSpecifier(specifier: string, compilerOptions: CompilerOptions): boolean {
|
||||
return !!compilerOptions.rewriteRelativeImportExtensions && pathIsRelative(specifier) && !isDeclarationFileName(specifier);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration | JSDocImportTag): Expression | undefined {
|
||||
switch (node.kind) {
|
||||
@@ -7854,6 +7860,16 @@ export function getLinesBetweenPositionAndNextNonWhitespaceCharacter(pos: number
|
||||
return getLinesBetweenPositions(sourceFile, pos, Math.min(stopPos, nextPos));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function rangeContainsRange(r1: TextRange, r2: TextRange): boolean {
|
||||
return startEndContainsRange(r1.pos, r1.end, r2);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function startEndContainsRange(start: number, end: number, range: TextRange): boolean {
|
||||
return start <= range.pos && end >= range.end;
|
||||
}
|
||||
|
||||
function getPreviousNonWhitespacePosition(pos: number, stopPos = 0, sourceFile: SourceFile) {
|
||||
while (pos-- > stopPos) {
|
||||
if (!isWhiteSpaceLike(sourceFile.text.charCodeAt(pos))) {
|
||||
@@ -8900,6 +8916,12 @@ function createComputedCompilerOptions<T extends Record<string, CompilerOptionKe
|
||||
}
|
||||
|
||||
const _computedOptions = createComputedCompilerOptions({
|
||||
allowImportingTsExtensions: {
|
||||
dependencies: ["rewriteRelativeImportExtensions"],
|
||||
computeValue: compilerOptions => {
|
||||
return !!(compilerOptions.allowImportingTsExtensions || compilerOptions.rewriteRelativeImportExtensions);
|
||||
},
|
||||
},
|
||||
target: {
|
||||
dependencies: ["module"],
|
||||
computeValue: compilerOptions => {
|
||||
@@ -9128,6 +9150,8 @@ const _computedOptions = createComputedCompilerOptions({
|
||||
/** @internal */
|
||||
export const computedOptions: Record<string, { dependencies: readonly string[]; computeValue: (options: CompilerOptions) => CompilerOptionsValue; }> = _computedOptions;
|
||||
|
||||
/** @internal */
|
||||
export const getAllowImportingTsExtensions: (compilerOptions: CompilerOptions) => boolean = _computedOptions.allowImportingTsExtensions.computeValue;
|
||||
/** @internal */
|
||||
export const getEmitScriptTarget: (compilerOptions: CompilerOptions) => ScriptTarget = _computedOptions.target.computeValue;
|
||||
/** @internal */
|
||||
@@ -12004,3 +12028,50 @@ export const nodeCoreModules: Set<string> = new Set([
|
||||
...unprefixedNodeCoreModulesList.map(name => `node:${name}`),
|
||||
...exclusivelyPrefixedNodeCoreModules,
|
||||
]);
|
||||
|
||||
/** @internal */
|
||||
export function forEachDynamicImportOrRequireCall<IncludeTypeSpaceImports extends boolean, RequireStringLiteralLikeArgument extends boolean>(
|
||||
file: SourceFile,
|
||||
includeTypeSpaceImports: IncludeTypeSpaceImports,
|
||||
requireStringLiteralLikeArgument: RequireStringLiteralLikeArgument,
|
||||
cb: (node: CallExpression | (IncludeTypeSpaceImports extends false ? never : JSDocImportTag | ImportTypeNode), argument: RequireStringLiteralLikeArgument extends true ? StringLiteralLike : Expression) => void,
|
||||
): void {
|
||||
const isJavaScriptFile = isInJSFile(file);
|
||||
const r = /import|require/g;
|
||||
while (r.exec(file.text) !== null) { // eslint-disable-line no-restricted-syntax
|
||||
const node = getNodeAtPosition(file, r.lastIndex, /*includeJSDoc*/ includeTypeSpaceImports);
|
||||
if (isJavaScriptFile && isRequireCall(node, requireStringLiteralLikeArgument)) {
|
||||
cb(node, node.arguments[0] as RequireStringLiteralLikeArgument extends true ? StringLiteralLike : Expression);
|
||||
}
|
||||
else if (isImportCall(node) && node.arguments.length >= 1 && (!requireStringLiteralLikeArgument || isStringLiteralLike(node.arguments[0]))) {
|
||||
cb(node, node.arguments[0] as RequireStringLiteralLikeArgument extends true ? StringLiteralLike : Expression);
|
||||
}
|
||||
else if (includeTypeSpaceImports && isLiteralImportTypeNode(node)) {
|
||||
(cb as (node: CallExpression | JSDocImportTag | ImportTypeNode, argument: StringLiteralLike) => void)(node, node.argument.literal);
|
||||
}
|
||||
else if (includeTypeSpaceImports && isJSDocImportTag(node)) {
|
||||
const moduleNameExpr = getExternalModuleName(node);
|
||||
if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text) {
|
||||
(cb as (node: CallExpression | JSDocImportTag | ImportTypeNode, argument: StringLiteralLike) => void)(node, moduleNameExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a token if position is in [start-of-leading-trivia, end), includes JSDoc only in JS files */
|
||||
function getNodeAtPosition(sourceFile: SourceFile, position: number, includeJSDoc: boolean): Node {
|
||||
const isJavaScriptFile = isInJSFile(sourceFile);
|
||||
let current: Node = sourceFile;
|
||||
const getContainingChild = (child: Node) => {
|
||||
if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) {
|
||||
return child;
|
||||
}
|
||||
};
|
||||
while (true) {
|
||||
const child = isJavaScriptFile && includeJSDoc && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild);
|
||||
if (!child) {
|
||||
return current;
|
||||
}
|
||||
current = child;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,6 +1553,10 @@ export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnl
|
||||
return isTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node);
|
||||
}
|
||||
|
||||
export function isPartOfTypeOnlyImportOrExportDeclaration(node: Node): boolean {
|
||||
return findAncestor(node, isTypeOnlyImportOrExportDeclaration) !== undefined;
|
||||
}
|
||||
|
||||
export function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken {
|
||||
return node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind);
|
||||
}
|
||||
|
||||
@@ -320,6 +320,7 @@ import {
|
||||
PseudoBigInt,
|
||||
pseudoBigIntToString,
|
||||
QualifiedName,
|
||||
rangeContainsRange,
|
||||
RefactorContext,
|
||||
removeFileExtension,
|
||||
removeSuffix,
|
||||
@@ -917,11 +918,6 @@ export function getLineStartPositionForPosition(position: number, sourceFile: So
|
||||
return lineStarts[line];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function rangeContainsRange(r1: TextRange, r2: TextRange): boolean {
|
||||
return startEndContainsRange(r1.pos, r1.end, r2);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function rangeContainsRangeExclusive(r1: TextRange, r2: TextRange): boolean {
|
||||
return rangeContainsPositionExclusive(r1, r2.pos) && rangeContainsPositionExclusive(r1, r2.end);
|
||||
@@ -937,11 +933,6 @@ export function rangeContainsPositionExclusive(r: TextRange, pos: number): boole
|
||||
return r.pos < pos && pos < r.end;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function startEndContainsRange(start: number, end: number, range: TextRange): boolean {
|
||||
return start <= range.pos && end >= range.end;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function rangeContainsStartEnd(range: TextRange, start: number, end: number): boolean {
|
||||
return range.pos <= start && range.end >= end;
|
||||
@@ -2468,7 +2459,7 @@ export function createModuleSpecifierResolutionHost(program: Program, host: Lang
|
||||
fileExists: fileName => program.fileExists(fileName),
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
readFile: maybeBind(host, host.readFile),
|
||||
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
|
||||
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames) || program.useCaseSensitiveFileNames,
|
||||
getSymlinkCache: maybeBind(host, host.getSymlinkCache) || program.getSymlinkCache,
|
||||
getModuleSpecifierCache: maybeBind(host, host.getModuleSpecifierCache),
|
||||
getPackageJsonInfoCache: () => program.getModuleResolutionCache()?.getPackageJsonInfoCache(),
|
||||
|
||||
Reference in New Issue
Block a user