diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2b702364c0f28..16d1ceead070a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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); diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index e330825fa3fb9..c7cd25a9ad16b 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -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; } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index d2c13278596dc..1c84bf1dd7288 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -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, ); } diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 995de60bb2586..5bc851400923d 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -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, }); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 35e899e351a55..1b55b8adfc718 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -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; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index cd23e00365209..3f427c39e28d1 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -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)); } /** diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 7c7c43db639e7..daf67dbd6141a 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -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) { diff --git a/src/server/project.ts b/src/server/project.ts index bc84e76bd0e26..b3b3f14084c00 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -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): readonly string[] { +function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: readonly string[], cachedUnresolvedImportsPerFile: Map, 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); diff --git a/src/testRunner/tests.ts b/src/testRunner/tests.ts index c95ca207db5fb..c8fdca380df81 100644 --- a/src/testRunner/tests.ts +++ b/src/testRunner/tests.ts @@ -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"; diff --git a/src/testRunner/unittests/tsc/arbitraryExtensions.ts b/src/testRunner/unittests/tsc/arbitraryExtensions.ts new file mode 100644 index 0000000000000..5984ce2bdd3ff --- /dev/null +++ b/src/testRunner/unittests/tsc/arbitraryExtensions.ts @@ -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 +}); \ No newline at end of file diff --git a/tests/baselines/reference/tsc/arbitraryExtensions/reports-error-for-css-resolution.js b/tests/baselines/reference/tsc/arbitraryExtensions/reports-error-for-css-resolution.js new file mode 100644 index 0000000000000..3567befec5008 --- /dev/null +++ b/tests/baselines/reference/tsc/arbitraryExtensions/reports-error-for-css-resolution.js @@ -0,0 +1,67 @@ +Input:: +//// [/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +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. ======== +src/a.ts:1:16 - error TS2307: Cannot find module './b.css' or its corresponding type declarations. + +1 import {} from "./b.css"; +   ~~~~~~~~~ + +lib/lib.d.ts + Default library for target 'es5' +src/a.ts + Root file specified for compilation + +Found 1 error in src/a.ts:1 + +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 }); + + diff --git a/tests/baselines/reference/tsc/arbitraryExtensions/resolves-to-css-file.js b/tests/baselines/reference/tsc/arbitraryExtensions/resolves-to-css-file.js new file mode 100644 index 0000000000000..327dad03071a0 --- /dev/null +++ b/tests/baselines/reference/tsc/arbitraryExtensions/resolves-to-css-file.js @@ -0,0 +1,65 @@ +Input:: +//// [/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +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 }); + +