Allow adding arbitrary extension files to program without d.ts files bein on the disk
This commit is contained in:
Родитель
a9ae9eeb23
Коммит
bd787bd907
|
@ -905,7 +905,7 @@ import {
|
|||
removeExtension,
|
||||
removePrefix,
|
||||
replaceElement,
|
||||
resolutionExtensionIsTSOrJson,
|
||||
resolutionExtensionIsTSOrJsonOrArbitrary,
|
||||
ResolutionMode,
|
||||
ResolvedModuleFull,
|
||||
ResolvedType,
|
||||
|
@ -4874,7 +4874,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
}
|
||||
|
||||
if (sourceFile.symbol) {
|
||||
if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) {
|
||||
if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJsonOrArbitrary(resolvedModule.extension, compilerOptions)) {
|
||||
errorOnImplicitAnyModule(/*isError*/ false, errorNode, currentSourceFile, mode, resolvedModule, moduleReference);
|
||||
}
|
||||
if (moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext) {
|
||||
|
@ -4957,7 +4957,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
}
|
||||
|
||||
// May be an untyped module. If so, ignore resolutionDiagnostic.
|
||||
if (resolvedModule && !resolutionExtensionIsTSOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) {
|
||||
if (resolvedModule && !resolutionExtensionIsTSOrJsonOrArbitrary(resolvedModule.extension, compilerOptions) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) {
|
||||
if (isForAugmentation) {
|
||||
const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented;
|
||||
error(errorNode, diag, moduleReference, resolvedModule!.resolvedFileName);
|
||||
|
|
|
@ -35,6 +35,7 @@ import {
|
|||
forEach,
|
||||
forEachAncestorDirectory,
|
||||
formatMessage,
|
||||
getAllowArbitraryExtensions,
|
||||
getBaseFileName,
|
||||
GetCanonicalFileName,
|
||||
getCommonSourceDirectory,
|
||||
|
@ -98,6 +99,8 @@ import {
|
|||
startsWith,
|
||||
stringContains,
|
||||
supportedDeclarationExtensions,
|
||||
supportedJSExtensionsFlat,
|
||||
supportedTSExtensionsFlat,
|
||||
supportedTSImplementationExtensions,
|
||||
toPath,
|
||||
tryExtractTSExtension,
|
||||
|
@ -179,7 +182,9 @@ const enum Extensions {
|
|||
TypeScript = 1 << 0, // '.ts', '.tsx', '.mts', '.cts'
|
||||
JavaScript = 1 << 1, // '.js', '.jsx', '.mjs', '.cjs'
|
||||
Declaration = 1 << 2, // '.d.ts', etc.
|
||||
Json = 1 << 3, // '.json'
|
||||
Json = 1 << 3, // '.json'
|
||||
|
||||
Arbitrary = 1 << 4,
|
||||
|
||||
ImplementationFiles = TypeScript | JavaScript,
|
||||
}
|
||||
|
@ -190,6 +195,7 @@ function formatExtensions(extensions: Extensions) {
|
|||
if (extensions & Extensions.JavaScript) result.push("JavaScript");
|
||||
if (extensions & Extensions.Declaration) result.push("Declaration");
|
||||
if (extensions & Extensions.Json) result.push("JSON");
|
||||
if (extensions & Extensions.Arbitrary) result.push("Arbitrary");
|
||||
return result.join(", ");
|
||||
}
|
||||
|
||||
|
@ -1636,6 +1642,9 @@ function nodeNextModuleNameResolverWorker(features: NodeResolutionFeatures, modu
|
|||
if (getResolveJsonModule(compilerOptions)) {
|
||||
extensions |= Extensions.Json;
|
||||
}
|
||||
if (getAllowArbitraryExtensions(compilerOptions)) {
|
||||
extensions |= Extensions.Arbitrary;
|
||||
}
|
||||
return nodeModuleNameResolverWorker(features | esmMode, moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference);
|
||||
}
|
||||
|
||||
|
@ -1658,6 +1667,9 @@ export function bundlerModuleNameResolver(moduleName: string, containingFile: st
|
|||
if (getResolveJsonModule(compilerOptions)) {
|
||||
extensions |= Extensions.Json;
|
||||
}
|
||||
if (getAllowArbitraryExtensions(compilerOptions)) {
|
||||
extensions |= Extensions.Arbitrary;
|
||||
}
|
||||
return nodeModuleNameResolverWorker(getNodeResolutionFeatures(compilerOptions), moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference);
|
||||
}
|
||||
|
||||
|
@ -1671,11 +1683,17 @@ export function nodeModuleNameResolver(moduleName: string, containingFile: strin
|
|||
else if (compilerOptions.noDtsResolution) {
|
||||
extensions = Extensions.ImplementationFiles;
|
||||
if (getResolveJsonModule(compilerOptions)) extensions |= Extensions.Json;
|
||||
if (getAllowArbitraryExtensions(compilerOptions)) {
|
||||
extensions |= Extensions.Arbitrary;
|
||||
}
|
||||
}
|
||||
else {
|
||||
extensions = getResolveJsonModule(compilerOptions)
|
||||
? Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration | Extensions.Json
|
||||
: Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration;
|
||||
if (getAllowArbitraryExtensions(compilerOptions)) {
|
||||
extensions |= Extensions.Arbitrary;
|
||||
}
|
||||
}
|
||||
return nodeModuleNameResolverWorker(NodeResolutionFeatures.None, moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, extensions, !!isConfigLookup, redirectedReference);
|
||||
}
|
||||
|
@ -1712,6 +1730,8 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa
|
|||
trace(host, Diagnostics.Resolving_in_0_mode_with_conditions_1, features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", conditions.map(c => `'${c}'`).join(", "));
|
||||
}
|
||||
|
||||
const originalExtensions = extensions;
|
||||
extensions = extensions & ~Extensions.Arbitrary;
|
||||
let result;
|
||||
if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node10) {
|
||||
const priorityExtensions = extensions & (Extensions.TypeScript | Extensions.Declaration);
|
||||
|
@ -1725,6 +1745,11 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa
|
|||
result = tryResolve(extensions, state);
|
||||
}
|
||||
|
||||
if (originalExtensions !== extensions) {
|
||||
// try arbitary extension
|
||||
result ??= tryResolve(Extensions.Arbitrary, state);
|
||||
}
|
||||
|
||||
// For non-relative names that resolved to JS but no types in modes that look up an "import" condition in package.json "exports",
|
||||
// try again with "exports" disabled to try to detect if this is likely a configuration error in a dependency's package.json.
|
||||
let legacyResult;
|
||||
|
@ -2016,6 +2041,7 @@ function tryAddingExtensions(candidate: string, extensions: Extensions, original
|
|||
|| undefined;
|
||||
default:
|
||||
return extensions & Extensions.Declaration && !isDeclarationFileName(candidate + originalExtension) && tryExtension(`.d${originalExtension}.ts`)
|
||||
|| !!originalExtension && extensions & Extensions.Arbitrary && !some(supportedTSExtensionsFlat, ext => endsWith(originalExtension, ext)) && !some(supportedJSExtensionsFlat, ext => endsWith(originalExtension, ext)) && tryExtension(originalExtension)
|
||||
|| undefined;
|
||||
|
||||
}
|
||||
|
@ -2355,6 +2381,7 @@ function extensionIsOk(extensions: Extensions, extension: string): boolean {
|
|||
|| extensions & Extensions.TypeScript && (extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts || extension === Extension.Cts)
|
||||
|| extensions & Extensions.Declaration && (extension === Extension.Dts || extension === Extension.Dmts || extension === Extension.Dcts)
|
||||
|| extensions & Extensions.Json && extension === Extension.Json
|
||||
|| extensions & Extensions.Arbitrary && !!extension
|
||||
|| false;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ import {
|
|||
getTsConfigObjectLiteralExpression,
|
||||
getTsConfigPropArray,
|
||||
getTsConfigPropArrayElementValue,
|
||||
hasArbitraryExtension,
|
||||
HasChangedAutomaticTypeDirectiveNames,
|
||||
hasChangesInResolutions,
|
||||
hasExtension,
|
||||
|
@ -266,7 +267,7 @@ import {
|
|||
removeFileExtension,
|
||||
removePrefix,
|
||||
removeSuffix,
|
||||
resolutionExtensionIsTSOrJson,
|
||||
resolutionExtensionIsTSOrJsonOrArbitrary,
|
||||
ResolutionMode,
|
||||
resolveConfigFileProjectName,
|
||||
ResolvedConfigFileName,
|
||||
|
@ -1484,6 +1485,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
|
||||
const host = createProgramOptions.host || createCompilerHost(options);
|
||||
const configParsingHost = parseConfigHostFromCompilerHostLike(host);
|
||||
const createArbitrarySourceFile: CompilerHost["getSourceFile"] = host.getDeclarationFileForArbitraryExtension?.bind(host) ||
|
||||
((fileName, languageVersionOrOptions) => createSourceFile(fileName + ".d.ts", "export {}", languageVersionOrOptions, /*setParentNodes*/ true));
|
||||
|
||||
let skipDefaultLib = options.noLib;
|
||||
const getDefaultLibraryFileName = memoize(() => host.getDefaultLibFileName(options));
|
||||
|
@ -3373,7 +3376,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void {
|
||||
getSourceFileFromReferenceWorker(
|
||||
fileName,
|
||||
fileName => findSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217
|
||||
fileName => findSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId, /*isArbitraryExtensionFile*/ false), // TODO: GH#18217
|
||||
(diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args),
|
||||
reason
|
||||
);
|
||||
|
@ -3406,13 +3409,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined, isArbitraryExtensionFile: boolean): SourceFile | undefined {
|
||||
tracing?.push(tracing.Phase.Program, "findSourceFile", {
|
||||
fileName,
|
||||
isDefaultLib: isDefaultLib || undefined,
|
||||
fileIncludeKind: (FileIncludeKind as any)[reason.kind],
|
||||
});
|
||||
const result = findSourceFileWorker(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
|
||||
const result = findSourceFileWorker(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId, isArbitraryExtensionFile);
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
@ -3429,9 +3432,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
{ languageVersion, impliedNodeFormat: result, setExternalModuleIndicator };
|
||||
}
|
||||
|
||||
function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined, isArbitraryExtensionFile: boolean): SourceFile | undefined {
|
||||
const path = toPath(fileName);
|
||||
if (useSourceOfProjectReferenceRedirect) {
|
||||
if (useSourceOfProjectReferenceRedirect && !isArbitraryExtensionFile) {
|
||||
let source = getSourceOfProjectReferenceRedirect(path);
|
||||
// If preserveSymlinks is true, module resolution wont jump the symlink
|
||||
// but the resolved real path may be the .d.ts from project reference
|
||||
|
@ -3447,7 +3450,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
}
|
||||
if (source) {
|
||||
const file = isString(source) ?
|
||||
findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) :
|
||||
findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId, /*isArbitraryExtensionFile*/ false) :
|
||||
undefined;
|
||||
if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined);
|
||||
return file;
|
||||
|
@ -3520,12 +3523,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
|
||||
// We haven't looked for this file, do so now and cache result
|
||||
const sourceFileOptions = getCreateSourceFileOptions(fileName, moduleResolutionCache, host, options);
|
||||
const file = host.getSourceFile(
|
||||
debugger;
|
||||
const file = (!isArbitraryExtensionFile ? host.getSourceFile : createArbitrarySourceFile)(
|
||||
fileName,
|
||||
sourceFileOptions,
|
||||
hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]),
|
||||
shouldCreateNewSourceFile || (oldProgram?.getSourceFileByPath(toPath(fileName))?.impliedNodeFormat !== sourceFileOptions.impliedNodeFormat)
|
||||
);
|
||||
if (isArbitraryExtensionFile && file) file.isDeclarationFile = true;
|
||||
|
||||
if (packageId) {
|
||||
const packageIdKey = packageIdToString(packageId);
|
||||
|
@ -3868,9 +3873,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
}
|
||||
|
||||
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
|
||||
const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension);
|
||||
const isJsFile = !resolutionExtensionIsTSOrJsonOrArbitrary(resolution.extension, options);
|
||||
const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile;
|
||||
const resolvedFileName = resolution.resolvedFileName;
|
||||
const isArbitraryExtensionFile = hasArbitraryExtension(resolution.extension);
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
currentNodeModulesDepth++;
|
||||
|
@ -3902,6 +3908,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
/*ignoreNoDefaultLib*/ false,
|
||||
{ kind: FileIncludeKind.Import, file: file.path, index, },
|
||||
resolution.packageId,
|
||||
isArbitraryExtensionFile,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ import {
|
|||
Program,
|
||||
removeSuffix,
|
||||
removeTrailingDirectorySeparator,
|
||||
resolutionExtensionIsTSOrJson,
|
||||
resolutionExtensionIsTSOrJsonOrArbitrary,
|
||||
ResolutionLoader,
|
||||
ResolutionMode,
|
||||
ResolvedModuleWithFailedLookupLocations,
|
||||
|
@ -684,7 +684,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
|||
options,
|
||||
),
|
||||
getResolutionWithResolvedFileName: getResolvedModule,
|
||||
shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension),
|
||||
shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJsonOrArbitrary(resolution.resolvedModule.extension, options),
|
||||
logChanges: logChangesWhenResolvingModule,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7647,6 +7647,7 @@ export type HasInvalidatedResolutions = (sourceFile: Path) => boolean;
|
|||
export type HasChangedAutomaticTypeDirectiveNames = () => boolean;
|
||||
|
||||
export interface CompilerHost extends ModuleResolutionHost {
|
||||
getDeclarationFileForArbitraryExtension?(arbitraryExtensionFileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
|
|
|
@ -8464,6 +8464,14 @@ export function getResolveJsonModule(compilerOptions: CompilerOptions) {
|
|||
return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Bundler;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getAllowArbitraryExtensions(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions.allowArbitraryExtensions !== undefined) {
|
||||
return compilerOptions.allowArbitraryExtensions;
|
||||
}
|
||||
return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Bundler;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getEmitDeclarations(compilerOptions: CompilerOptions): boolean {
|
||||
return !!(compilerOptions.declaration || compilerOptions.composite);
|
||||
|
@ -9298,9 +9306,17 @@ export function extensionIsTS(ext: string): boolean {
|
|||
return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts || ext === Extension.Cts || ext === Extension.Mts || ext === Extension.Dmts || ext === Extension.Dcts || (startsWith(ext, ".d.") && endsWith(ext, ".ts"));
|
||||
}
|
||||
|
||||
export function hasArbitraryExtension(ext: string) {
|
||||
return !some(supportedTSExtensionsFlat, tsExt => endsWith(ext, tsExt)) &&
|
||||
!some(supportedJSExtensionsFlat, jsExt => endsWith(ext, jsExt)) &&
|
||||
!endsWith(ext, Extension.Json);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function resolutionExtensionIsTSOrJson(ext: string) {
|
||||
return extensionIsTS(ext) || ext === Extension.Json;
|
||||
export function resolutionExtensionIsTSOrJsonOrArbitrary(ext: string, options: CompilerOptions) {
|
||||
return extensionIsTS(ext) ||
|
||||
ext === Extension.Json ||
|
||||
getAllowArbitraryExtensions(options) && !some(supportedJSExtensionsFlat, jsExt => endsWith(ext, jsExt));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -644,7 +644,7 @@ export class TestState {
|
|||
if (!ts.isAnySupportedFileExtension(fileName)
|
||||
|| Harness.getConfigNameFromFileName(fileName)
|
||||
// Can't get a Program in Server tests
|
||||
|| this.testType !== FourSlashTestType.Server && !ts.getAllowJSCompilerOption(this.getProgram().getCompilerOptions()) && !ts.resolutionExtensionIsTSOrJson(ts.extensionFromPath(fileName))
|
||||
|| this.testType !== FourSlashTestType.Server && !ts.getAllowJSCompilerOption(this.getProgram().getCompilerOptions()) && !ts.resolutionExtensionIsTSOrJsonOrArbitrary(ts.extensionFromPath(fileName))
|
||||
|| ts.getBaseFileName(fileName) === "package.json") return;
|
||||
const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion);
|
||||
if (errors.length) {
|
||||
|
|
|
@ -95,7 +95,7 @@ import {
|
|||
ProjectReference,
|
||||
removeFileExtension,
|
||||
ResolutionCache,
|
||||
resolutionExtensionIsTSOrJson,
|
||||
resolutionExtensionIsTSOrJsonOrArbitrary,
|
||||
ResolvedModuleWithFailedLookupLocations,
|
||||
ResolvedProjectReference,
|
||||
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
|
||||
|
@ -2109,17 +2109,17 @@ function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile:
|
|||
tracing?.push(tracing.Phase.Session, "getUnresolvedImports", { count: sourceFiles.length });
|
||||
const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName()));
|
||||
const result = sortAndDeduplicate(flatMap(sourceFiles, sourceFile =>
|
||||
extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile)));
|
||||
extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile, program.getCompilerOptions())));
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: readonly string[], cachedUnresolvedImportsPerFile: Map<Path, readonly string[]>): readonly string[] {
|
||||
function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: readonly string[], cachedUnresolvedImportsPerFile: Map<Path, readonly string[]>, options: CompilerOptions): readonly string[] {
|
||||
return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => {
|
||||
if (!file.resolvedModules) return emptyArray;
|
||||
let unresolvedImports: string[] | undefined;
|
||||
file.resolvedModules.forEach(({ resolvedModule }, name) => {
|
||||
// pick unresolved non-relative names
|
||||
if ((!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) &&
|
||||
if ((!resolvedModule || !resolutionExtensionIsTSOrJsonOrArbitrary(resolvedModule.extension, options)) &&
|
||||
!isExternalModuleNameRelative(name) &&
|
||||
!ambientModules.some(m => m === name)) {
|
||||
unresolvedImports = append(unresolvedImports, parsePackageName(name).packageName);
|
||||
|
|
|
@ -99,6 +99,7 @@ import "./unittests/tsbuildWatch/projectsBuilding";
|
|||
import "./unittests/tsbuildWatch/publicApi";
|
||||
import "./unittests/tsbuildWatch/reexport";
|
||||
import "./unittests/tsbuildWatch/watchEnvironment";
|
||||
import "./unittests/tsc/arbitraryExtensions";
|
||||
import "./unittests/tsc/cancellationToken";
|
||||
import "./unittests/tsc/composite";
|
||||
import "./unittests/tsc/declarationEmit";
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import {
|
||||
loadProjectFromFiles,
|
||||
verifyTsc,
|
||||
} from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: arbitraryExtensions::", () => {
|
||||
|
||||
verifyTsc({
|
||||
scenario: "arbitraryExtensions",
|
||||
subScenario: "reports error for css resolution",
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/a.ts": `import {} from "./b.css";`,
|
||||
"/src/b.css": "random content",
|
||||
}),
|
||||
commandLineArgs: ["/src/a.ts", "--explainFiles", "--traceResolution"],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "arbitraryExtensions",
|
||||
subScenario: "resolves to css file",
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/a.ts": `import {} from "./b.css";`,
|
||||
"/src/b.css": "random content",
|
||||
}),
|
||||
commandLineArgs: ["/src/a.ts", "--explainFiles", "--traceResolution", "--allowArbitraryExtensions"],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
// May be always try arbitraryextension and report error depending on options ?
|
||||
|
||||
// TODO:: try other flags, watchMode, incremental, program reuse, host.getDeclarationForArbitraryExtensionFile
|
||||
// editor scenarios, module specifier
|
||||
});
|
|
@ -0,0 +1,67 @@
|
|||
Input::
|
||||
//// [/lib/lib.d.ts]
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface Boolean {}
|
||||
interface Function {}
|
||||
interface CallableFunction {}
|
||||
interface NewableFunction {}
|
||||
interface IArguments {}
|
||||
interface Number { toExponential: any; }
|
||||
interface Object {}
|
||||
interface RegExp {}
|
||||
interface String { charAt: any; }
|
||||
interface Array<T> { length: number; [n: number]: T; }
|
||||
interface ReadonlyArray<T> {}
|
||||
declare const console: { log(msg: any): void; };
|
||||
|
||||
//// [/src/a.ts]
|
||||
import {} from "./b.css";
|
||||
|
||||
//// [/src/b.css]
|
||||
random content
|
||||
|
||||
|
||||
|
||||
Output::
|
||||
/lib/tsc /src/a.ts --explainFiles --traceResolution
|
||||
======== Resolving module './b.css' from '/src/a.ts'. ========
|
||||
Module resolution kind is not specified, using 'Node10'.
|
||||
Loading module as file / folder, candidate module location '/src/b.css', target file types: TypeScript, Declaration.
|
||||
File name '/src/b.css' has a '.css' extension - stripping it.
|
||||
File '/src/b.d.css.ts' does not exist.
|
||||
File '/src/b.css.ts' does not exist.
|
||||
File '/src/b.css.tsx' does not exist.
|
||||
File '/src/b.css.d.ts' does not exist.
|
||||
Directory '/src/b.css' does not exist, skipping all lookups in it.
|
||||
Loading module as file / folder, candidate module location '/src/b.css', target file types: JavaScript.
|
||||
File name '/src/b.css' has a '.css' extension - stripping it.
|
||||
File '/src/b.css.js' does not exist.
|
||||
File '/src/b.css.jsx' does not exist.
|
||||
Directory '/src/b.css' does not exist, skipping all lookups in it.
|
||||
======== Module name './b.css' was not resolved. ========
|
||||
[96msrc/a.ts[0m:[93m1[0m:[93m16[0m - [91merror[0m[90m TS2307: [0mCannot find module './b.css' or its corresponding type declarations.
|
||||
|
||||
[7m1[0m import {} from "./b.css";
|
||||
[7m [0m [91m ~~~~~~~~~[0m
|
||||
|
||||
lib/lib.d.ts
|
||||
Default library for target 'es5'
|
||||
src/a.ts
|
||||
Root file specified for compilation
|
||||
|
||||
Found 1 error in src/a.ts[90m:1[0m
|
||||
|
||||
exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated
|
||||
Program root files: ["/src/a.ts"]
|
||||
Program options: {"explainFiles":true,"traceResolution":true}
|
||||
Program structureReused: Not
|
||||
Program files::
|
||||
/lib/lib.d.ts
|
||||
/src/a.ts
|
||||
|
||||
|
||||
//// [/src/a.js]
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
Input::
|
||||
//// [/lib/lib.d.ts]
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface Boolean {}
|
||||
interface Function {}
|
||||
interface CallableFunction {}
|
||||
interface NewableFunction {}
|
||||
interface IArguments {}
|
||||
interface Number { toExponential: any; }
|
||||
interface Object {}
|
||||
interface RegExp {}
|
||||
interface String { charAt: any; }
|
||||
interface Array<T> { length: number; [n: number]: T; }
|
||||
interface ReadonlyArray<T> {}
|
||||
declare const console: { log(msg: any): void; };
|
||||
|
||||
//// [/src/a.ts]
|
||||
import {} from "./b.css";
|
||||
|
||||
//// [/src/b.css]
|
||||
random content
|
||||
|
||||
|
||||
|
||||
Output::
|
||||
/lib/tsc /src/a.ts --explainFiles --traceResolution --allowArbitraryExtensions
|
||||
======== Resolving module './b.css' from '/src/a.ts'. ========
|
||||
Module resolution kind is not specified, using 'Node10'.
|
||||
Loading module as file / folder, candidate module location '/src/b.css', target file types: TypeScript, Declaration.
|
||||
File name '/src/b.css' has a '.css' extension - stripping it.
|
||||
File '/src/b.d.css.ts' does not exist.
|
||||
File '/src/b.css.ts' does not exist.
|
||||
File '/src/b.css.tsx' does not exist.
|
||||
File '/src/b.css.d.ts' does not exist.
|
||||
Directory '/src/b.css' does not exist, skipping all lookups in it.
|
||||
Loading module as file / folder, candidate module location '/src/b.css', target file types: JavaScript.
|
||||
File name '/src/b.css' has a '.css' extension - stripping it.
|
||||
File '/src/b.css.js' does not exist.
|
||||
File '/src/b.css.jsx' does not exist.
|
||||
Directory '/src/b.css' does not exist, skipping all lookups in it.
|
||||
Loading module as file / folder, candidate module location '/src/b.css', target file types: Arbitrary.
|
||||
File name '/src/b.css' has a '.css' extension - stripping it.
|
||||
File '/src/b.css' exists - use it as a name resolution result.
|
||||
======== Module name './b.css' was successfully resolved to '/src/b.css'. ========
|
||||
lib/lib.d.ts
|
||||
Default library for target 'es5'
|
||||
src/b.css
|
||||
Imported via "./b.css" from file 'src/a.ts'
|
||||
src/a.ts
|
||||
Root file specified for compilation
|
||||
exitCode:: ExitStatus.Success
|
||||
Program root files: ["/src/a.ts"]
|
||||
Program options: {"explainFiles":true,"traceResolution":true,"allowArbitraryExtensions":true}
|
||||
Program structureReused: Not
|
||||
Program files::
|
||||
/lib/lib.d.ts
|
||||
/src/b.css
|
||||
/src/a.ts
|
||||
|
||||
|
||||
//// [/src/a.js]
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче