diff --git a/packages/typescript/schemas/jsconfig.schema.json b/packages/typescript/schemas/jsconfig.schema.json index 942fc702a92b7..1311a5187f14e 100644 --- a/packages/typescript/schemas/jsconfig.schema.json +++ b/packages/typescript/schemas/jsconfig.schema.json @@ -83,8 +83,10 @@ }, "extensions": { "type": "array", + "description": "Source extensions beginning with a dot and containing no other dots or path separators.", "items": { - "type": "string" + "type": "string", + "pattern": "^\\.[^./\\\\]+$" } }, "options": { diff --git a/packages/typescript/schemas/tsconfig.schema.json b/packages/typescript/schemas/tsconfig.schema.json index 6679e3ee65697..d6d154207fd06 100644 --- a/packages/typescript/schemas/tsconfig.schema.json +++ b/packages/typescript/schemas/tsconfig.schema.json @@ -83,8 +83,10 @@ }, "extensions": { "type": "array", + "description": "Source extensions beginning with a dot and containing no other dots or path separators.", "items": { - "type": "string" + "type": "string", + "pattern": "^\\.[^./\\\\]+$" } }, "options": { diff --git a/packages/vscode-typescript/src/contentMapperContributions.ts b/packages/vscode-typescript/src/contentMapperContributions.ts index d6c506a83f293..106dd658c98b8 100644 --- a/packages/vscode-typescript/src/contentMapperContributions.ts +++ b/packages/vscode-typescript/src/contentMapperContributions.ts @@ -53,7 +53,10 @@ export function validateContentMapperRegistration(contributorId: string, contrib if (contribution.extensions.length === 0 || contribution.extensions.some(extension => !isExtension(extension))) { throw new TypeError("Content mapper contributions require non-empty extensions beginning with '.' and containing no path separators."); } - if (contribution.extensions.some(extension => /\.(?:[cm]?[jt]s|[jt]sx|json)$/i.test(extension))) { + if (contribution.extensions.some(extension => !isSourceExtension(extension))) { + throw new TypeError("Content mapper source extensions must contain only one dot."); + } + if (contribution.extensions.some(extension => /^\.(?:[cm]?[jt]s|[jt]sx|json)$/i.test(extension))) { throw new TypeError("Content mapper extensions must not end in a built-in extension."); } const inferredProjectContribution = contribution.inferredProjectContribution; @@ -69,6 +72,9 @@ export function validateContentMapperRegistration(contributorId: string, contrib if (inferredProjectContribution?.manifest.outputExtensions && Object.entries(inferredProjectContribution.manifest.outputExtensions).some(([source, output]) => !isExtension(source) || !isExtension(output))) { throw new TypeError("Content mapper output extensions must be non-empty, begin with '.', and contain no path separators."); } + if (inferredProjectContribution?.manifest.outputExtensions && Object.keys(inferredProjectContribution.manifest.outputExtensions).some(source => !isSourceExtension(source))) { + throw new TypeError("Content mapper source extensions must contain only one dot."); + } } } @@ -76,6 +82,10 @@ function isExtension(value: string): boolean { return value.length > 1 && value.startsWith(".") && !/[\\/]/.test(value); } +function isSourceExtension(value: string): boolean { + return isExtension(value) && !value.slice(1).includes("."); +} + export function documentMatchesContentMapperContributions( document: { readonly uri: { readonly path: string; }; }, registrations: ReadonlyMap, diff --git a/packages/vscode-typescript/test/contentMapperContributions.test.ts b/packages/vscode-typescript/test/contentMapperContributions.test.ts index 57e3771d28765..6ce4e4488349f 100644 --- a/packages/vscode-typescript/test/contentMapperContributions.test.ts +++ b/packages/vscode-typescript/test/contentMapperContributions.test.ts @@ -38,17 +38,33 @@ describe("content mapper contributions", { concurrency: true }, () => { } }); - test("accepts compound extensions with non-reserved suffixes", () => { + test("accepts single-dot sources and compound output suffixes", () => { assert.doesNotThrow(() => validateContentMapperRegistration("mapper", [{ - extensions: [".y.z", ".component.tsx.vue"], + extensions: [".toml", ".vue"], + inferredProjectContribution: { + manifest: { ...documentedContribution.inferredProjectContribution.manifest, outputExtensions: { ".toml": ".part.js" } }, + }, }]) ); }); - test("rejects builtin extensions and compound extensions ending in them", () => { - for (const extension of [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json", ".d.ts", ".d.mts", ".d.cts"]) { - for (const source of [extension, extension.toUpperCase(), `.component${extension}`, `.component${extension.toUpperCase()}`]) { + test("rejects compound source extensions and output mapping keys", () => { + for (const extension of [".part.toml", ".y.z", ".d.ts", ".d.mts", ".d.cts"]) { + assert.throws(() => validateContentMapperRegistration("mapper", [{ extensions: [extension] }]), /only one dot/); + assert.throws(() => + validateContentMapperRegistration("mapper", [{ + ...documentedContribution, + inferredProjectContribution: { + manifest: { ...documentedContribution.inferredProjectContribution.manifest, outputExtensions: { [extension]: ".js" } }, + }, + }]), /only one dot/); + } + }); + + test("rejects builtin extensions", () => { + for (const extension of [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"]) { + for (const source of [extension, extension.toUpperCase()]) { assert.throws(() => validateContentMapperRegistration("mapper", [{ extensions: [source], @@ -62,7 +78,7 @@ describe("content mapper contributions", { concurrency: true }, () => { "publisher.extension", [{ extensions: [".vue"] }], ]]); - const document = { uri: { path: "/workspace/Component.VUE" } }; + const document = { uri: { path: "/workspace/Component.part.VUE" } }; assert.equal(documentMatchesContentMapperContributions(document, registrations), true); }); diff --git a/tools/scripts/tsc/options-schema.ts b/tools/scripts/tsc/options-schema.ts index cacc817c3349a..4c639f5e15246 100644 --- a/tools/scripts/tsc/options-schema.ts +++ b/tools/scripts/tsc/options-schema.ts @@ -110,7 +110,11 @@ function valueSchema(declaration: Declaration): JSONSchema { type: "object", properties: { package: { type: "string", minLength: 1 }, - extensions: { type: "array", items: { type: "string" } }, + extensions: { + type: "array", + description: "Source extensions beginning with a dot and containing no other dots or path separators.", + items: { type: "string", pattern: "^\\.[^./\\\\]+$" }, + }, options: { type: "object" }, }, required: ["package", "extensions"], diff --git a/tools/scripts/tsc/options.test.ts b/tools/scripts/tsc/options.test.ts index 67f6dfe7a98a1..7e9ad1964c606 100644 --- a/tools/scripts/tsc/options.test.ts +++ b/tools/scripts/tsc/options.test.ts @@ -373,7 +373,7 @@ test("schemas accept representative valid configs and reject malformed configs", { compilerOptions: { target: "ESNext", module: "NodeNext", moduleResolution: "BUNDLER", jsx: "React-JSX", newLine: "LF" } }, { compilerOptions: { paths: { "@/*": ["src/*"] }, plugins: [{ name: "some-plugin", customSetting: true }], moduleSuffixes: ["", ".native"] } }, { typeAcquisition: { enable: true, include: ["node"], exclude: [] } }, - { contentMappers: [{ package: "mapper", extensions: [".vue"], options: { customSetting: true } }] }, + { contentMappers: [{ package: "mapper", extensions: [".toml", ".vue"], options: { customSetting: true } }] }, { "$schema": "./tsconfig.schema.json", "tool-specific": { anything: true } }, ]; const invalid = [ @@ -402,6 +402,10 @@ test("schemas accept representative valid configs and reject malformed configs", { contentMappers: [{ package: "", extensions: [] }] }, { contentMappers: [{ package: "mapper" }] }, { contentMappers: [{ package: "mapper", extensions: [1] }] }, + { contentMappers: [{ package: "mapper", extensions: [".part.toml"] }] }, + { contentMappers: [{ package: "mapper", extensions: [".y.z"] }] }, + { contentMappers: [{ package: "mapper", extensions: [".vue/foo"] }] }, + { contentMappers: [{ package: "mapper", extensions: [".vue\\foo"] }] }, { contentMappers: [{ package: "mapper", extensions: [], options: null }] }, ]; for (const kind of ["tsconfig", "jsconfig"] as const) { diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 5cdbf40428c76..3d8fa69390f5c 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -15635,8 +15635,7 @@ func (c *Checker) resolveExternalModule( } else if resolvedUsingRewritableExtension && !shouldRewrite && (mappedSource || c.program.SourceFileMayBeEmitted(sourceFile, false)) { extension := tspath.GetAnyExtensionFromPath(moduleReference, nil, tspath.CaseSensitive) if mappedSource { - rewrite, _ := sourceFile.FileName().GetExtensionRewrite(rewrites, caseSensitivity) - extension = rewrite.Source + extension = sourceFile.FileName().AnyExtension(nil, caseSensitivity) } c.error( errorNode, diff --git a/tsc/internal/contentmapper/contentmapper.go b/tsc/internal/contentmapper/contentmapper.go index 158e6ee4be1b5..eac797ca4be76 100644 --- a/tsc/internal/contentmapper/contentmapper.go +++ b/tsc/internal/contentmapper/contentmapper.go @@ -73,11 +73,14 @@ func IsValidExtension(extension string) bool { return len(extension) > 1 && extension[0] == '.' && !strings.ContainsAny(extension, "/\\") } +func IsValidSourceExtension(extension string) bool { + return IsValidExtension(extension) && !strings.Contains(extension[1:], ".") +} + func HasReservedSourceExtension(extension string) bool { for _, extensions := range tspath.AllSupportedExtensionsWithJson { for _, nativeExtension := range extensions { - if len(extension) >= len(nativeExtension) && - strings.EqualFold(extension[len(extension)-len(nativeExtension):], nativeExtension) { + if strings.EqualFold(extension, nativeExtension) { return true } } diff --git a/tsc/internal/diagnostics/diagnosticMessages.generated.json b/tsc/internal/diagnostics/diagnosticMessages.generated.json index ae749e01b85b5..bb05d81e487d4 100644 --- a/tsc/internal/diagnostics/diagnosticMessages.generated.json +++ b/tsc/internal/diagnostics/diagnosticMessages.generated.json @@ -1959,6 +1959,7 @@ "The_typescript_contentMapper_outputExtensions_of_the_content_mapper_package_0_must_be_an_object_with_18122": "The 'typescript.contentMapper.outputExtensions' of the content mapper package '{0}' must be an object with string values.", "Content_mapper_extension_0_must_not_contain_path_separators_18123": "Content mapper extension '{0}' must not contain path separators.", "The_content_mapper_package_0_is_outside_the_open_workspace_and_will_not_be_loaded_18124": "The content mapper package '{0}' is outside the open workspace and will not be loaded.", + "Content_mapper_source_extension_0_must_contain_only_one_dot_18125": "Content mapper source extension '{0}' must contain only one dot.", "nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler_69010": "`nodenext` if `module` is `nodenext`; `node16` if `module` is `node16` or `node18`; otherwise, `bundler`.", "File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module_80001": "File is a CommonJS module; it may be converted to an ES module.", "This_constructor_function_may_be_converted_to_a_class_declaration_80002": "This constructor function may be converted to a class declaration.", diff --git a/tsc/internal/diagnostics/diagnosticMessages.json b/tsc/internal/diagnostics/diagnosticMessages.json index d4bf59ab839de..67c6b4d44ab42 100644 --- a/tsc/internal/diagnostics/diagnosticMessages.json +++ b/tsc/internal/diagnostics/diagnosticMessages.json @@ -8955,5 +8955,9 @@ "Content mapper extension '{0}' must not contain path separators.": { "category": "Error", "code": 18123 + }, + "Content mapper source extension '{0}' must contain only one dot.": { + "category": "Error", + "code": 18125 } } diff --git a/tsc/internal/diagnostics/diagnostics_generated.go b/tsc/internal/diagnostics/diagnostics_generated.go index 0e08cf23701b7..04ec5a53b25f5 100644 --- a/tsc/internal/diagnostics/diagnostics_generated.go +++ b/tsc/internal/diagnostics/diagnostics_generated.go @@ -3922,6 +3922,8 @@ var Content_mapper_extension_0_must_not_contain_path_separators = &Message{code: var The_content_mapper_package_0_is_outside_the_open_workspace_and_will_not_be_loaded = &Message{code: 18124, category: CategoryError, key: "The_content_mapper_package_0_is_outside_the_open_workspace_and_will_not_be_loaded_18124", text: "The content mapper package '{0}' is outside the open workspace and will not be loaded."} +var Content_mapper_source_extension_0_must_contain_only_one_dot = &Message{code: 18125, category: CategoryError, key: "Content_mapper_source_extension_0_must_contain_only_one_dot_18125", text: "Content mapper source extension '{0}' must contain only one dot."} + var X_nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler = &Message{code: 69010, category: CategoryMessage, key: "nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler_69010", text: "`nodenext` if `module` is `nodenext`; `node16` if `module` is `node16` or `node18`; otherwise, `bundler`."} var File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module = &Message{code: 80001, category: CategorySuggestion, key: "File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module_80001", text: "File is a CommonJS module; it may be converted to an ES module."} @@ -6423,6 +6425,7 @@ var allMessages = [...]**Message{ &The_typescript_contentMapper_outputExtensions_of_the_content_mapper_package_0_must_be_an_object_with_string_values, &Content_mapper_extension_0_must_not_contain_path_separators, &The_content_mapper_package_0_is_outside_the_open_workspace_and_will_not_be_loaded, + &Content_mapper_source_extension_0_must_contain_only_one_dot, &X_nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler, &File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module, &This_constructor_function_may_be_converted_to_a_class_declaration, diff --git a/tsc/internal/lsp/server.go b/tsc/internal/lsp/server.go index dcb020b0ca1b7..b9c2bfab6287a 100644 --- a/tsc/internal/lsp/server.go +++ b/tsc/internal/lsp/server.go @@ -2580,7 +2580,7 @@ func parseContentMapperContributions(values []*lsproto.ContentMapperContribution } } for source, output := range valueOrZero(manifest.OutputExtensions) { - if !contentmapper.IsValidExtension(source) || !contentmapper.IsValidExtension(output) { + if !contentmapper.IsValidSourceExtension(source) || !contentmapper.IsValidExtension(output) { return result, fmt.Errorf("content mapper contribution %q has invalid output extension mapping from %q to %q", identity, source, output) } } @@ -2622,10 +2622,7 @@ func parseContentMapperContributions(values []*lsproto.ContentMapperContribution } func isValidContributedContentMapperExtension(extension string) bool { - if !contentmapper.IsValidExtension(extension) { - return false - } - return !contentmapper.HasReservedSourceExtension(extension) + return contentmapper.IsValidSourceExtension(extension) && !contentmapper.HasReservedSourceExtension(extension) } func valueOrZero[T any](value *T) T { diff --git a/tsc/internal/lsp/server_contentmapper_internal_test.go b/tsc/internal/lsp/server_contentmapper_internal_test.go index 6f3af6a07c41e..6d63f445a5055 100644 --- a/tsc/internal/lsp/server_contentmapper_internal_test.go +++ b/tsc/internal/lsp/server_contentmapper_internal_test.go @@ -109,25 +109,35 @@ func TestParseContentMapperContributionsDefaultsOptionsToObject(t *testing.T) { assert.Equal(t, string(contributions.Mappers[0].Definition.Options), `{}`) } -func TestParseContentMapperContributionsCompoundExtensions(t *testing.T) { +func TestParseContentMapperContributionsSourceExtensions(t *testing.T) { t.Parallel() - for _, extension := range []string{".y.z", ".component.tsx.vue"} { + for _, extension := range []string{".toml", ".vue"} { + outputExtensions := map[string]string{extension: ".part.js"} contributions, err := parseContentMapperContributions([]*lsproto.ContentMapperContribution{{ ContributorId: "mapper", Extensions: []string{extension}, InferredProjectContribution: &lsproto.InferredProjectContentMapperContribution{ - Manifest: &lsproto.ContentMapperManifest{Name: "mapper", Exec: []string{"mapper"}}, + Manifest: &lsproto.ContentMapperManifest{Name: "mapper", Exec: []string{"mapper"}, OutputExtensions: &outputExtensions}, }, }}) assert.NilError(t, err) assert.DeepEqual(t, contributions.Extensions, []string{extension}) + assert.DeepEqual(t, contributions.Mappers[0].Definition.OutputExtensions, outputExtensions) } - for _, nativeExtension := range core.Flatten(tspath.AllSupportedExtensionsWithJson) { - for _, extension := range []string{".component" + nativeExtension, ".component" + strings.ToUpper(nativeExtension)} { - _, err := parseContentMapperContributions([]*lsproto.ContentMapperContribution{{ - ContributorId: "mapper", Extensions: []string{extension}, + for _, extension := range append(core.Flatten(tspath.AllSupportedExtensionsWithJson), ".part.toml", ".y.z") { + _, err := parseContentMapperContributions([]*lsproto.ContentMapperContribution{{ + ContributorId: "mapper", Extensions: []string{extension}, + }}) + assert.ErrorContains(t, err, "invalid extension") + outputExtensions := map[string]string{extension: ".js"} + if extension == ".part.toml" || extension == ".y.z" { + _, err = parseContentMapperContributions([]*lsproto.ContentMapperContribution{{ + ContributorId: "mapper", Extensions: []string{".toml"}, + InferredProjectContribution: &lsproto.InferredProjectContentMapperContribution{ + Manifest: &lsproto.ContentMapperManifest{Name: "mapper", Exec: []string{"mapper"}, OutputExtensions: &outputExtensions}, + }, }}) - assert.ErrorContains(t, err, "invalid extension") + assert.ErrorContains(t, err, "invalid output extension mapping") } } } diff --git a/tsc/internal/module/resolver.go b/tsc/internal/module/resolver.go index 4b59f0582f927..8f2bd92dac6e7 100644 --- a/tsc/internal/module/resolver.go +++ b/tsc/internal/module/resolver.go @@ -205,16 +205,12 @@ func (c resolutionCandidate) RelativeToDirectory(directory tspath.RootedDirector return relative } -func (c resolutionCandidate) SplitExtension(extraExtensions []string) (tspath.FileNameStem, string) { +func (c resolutionCandidate) SplitExtension() (tspath.FileNameStem, string) { fileName := tspath.RootedFilePathFromPath(c.path) extension := fileName.Extension() extensionless := c.RemoveFileExtension() if extensionless.AsString() == c.path.AsString() { - extension = fileName.LongestExtension(extraExtensions, tspath.CaseSensitive) - if extension == "" { - path := c.path.AsString() - extension = path[strings.LastIndex(path, "."):] - } + extension = fileName.AnyExtension(nil, tspath.CaseSensitive) extensionless = c.RemoveExtension(extension) } return extensionless, extension @@ -1642,7 +1638,7 @@ func (r *resolutionState) loadModuleFromFileNoImplicitExtensions(extensions exte if !strings.Contains(base, ".") { return continueSearching() // extensionless import, no lookups performed, since we don't support extensionless files } - extensionless, extension := candidate.SplitExtension(r.resolver.extraExtensions) + extensionless, extension := candidate.SplitExtension() if r.tracer != nil { r.tracer.write(diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension) } diff --git a/tsc/internal/outputpaths/outputpaths.go b/tsc/internal/outputpaths/outputpaths.go index a68837c1c36bb..ccbb74dfeaef6 100644 --- a/tsc/internal/outputpaths/outputpaths.go +++ b/tsc/internal/outputpaths/outputpaths.go @@ -116,7 +116,8 @@ func GetOutputJSFileName(inputFileName tspath.RootedFilePath, options *core.Comp } func isContentMappedFileName(fileName tspath.RootedFilePath, host OutputPathsHost) bool { - return fileName.LongestExtension(host.ContentMapperExtensions(), host.CaseSensitivity()) != "" + extensions := host.ContentMapperExtensions() + return len(extensions) > 0 && fileName.AnyExtension(extensions, host.CaseSensitivity()) != "" } func GetOutputJSFileNameWorker(inputFileName tspath.RootedFilePath, options *core.CompilerOptions, host OutputPathsHost) tspath.RootedFilePath { @@ -185,15 +186,8 @@ func getDeclarationEmitOutputFilePathForFileName(file tspath.RootedFilePath, opt func ChangeToDeclarationExtension(path tspath.RootedFilePath, host OutputPathsHost) tspath.RootedFilePath { if rewritten, ok := path.RewriteExtension(host.ContentMapperExtensionRewrites(), host.CaseSensitivity()); ok { - return changeToDeclarationExtension(rewritten) + path = rewritten } - if extension := path.LongestExtension(host.ContentMapperExtensions(), tspath.CaseSensitive); extension != "" { - return path.RemoveExtension(extension).AppendSuffix(".d" + extension + ".ts") - } - return changeToDeclarationExtension(path) -} - -func changeToDeclarationExtension(path tspath.RootedFilePath) tspath.RootedFilePath { pathWithoutExtension := path.RemoveFileExtension() if pathWithoutExtension.AsString() == path.AsString() { if extension := path.AnyExtension(nil, tspath.CaseSensitive); extension != "" { diff --git a/tsc/internal/outputpaths/outputpaths_test.go b/tsc/internal/outputpaths/outputpaths_test.go index 00f823d4b3b7d..52b2277d6df85 100644 --- a/tsc/internal/outputpaths/outputpaths_test.go +++ b/tsc/internal/outputpaths/outputpaths_test.go @@ -35,13 +35,13 @@ func TestContentMapperOutputExtensionCaseInsensitivePaths(t *testing.T) { t.Parallel() host := outputPathsHost{ commonSourceDirectory: "/src", - contentMapperExtensions: []string{".y.z"}, - contentMapperExtensionRewrites: []tspath.ExtensionRewrite{{Source: ".y.z", Target: ".mjs"}}, + contentMapperExtensions: []string{".vue"}, + contentMapperExtensionRewrites: []tspath.ExtensionRewrite{{Source: ".vue", Target: ".part.mjs"}}, } options := &core.CompilerOptions{OutDir: "/dist"} - fileName := tspath.RootedFilePath("/src/Widget.Y.Z") - assert.Equal(t, outputpaths.GetExternalOutputFileName(fileName, options, host), tspath.RootedFilePath("/dist/Widget.mjs")) - assert.Equal(t, outputpaths.GetOutputDeclarationFileNameWorker(fileName, options, host), tspath.RootedFilePath("/dist/Widget.d.mts")) + fileName := tspath.RootedFilePath("/src/Widget.part.VUE") + assert.Equal(t, outputpaths.GetExternalOutputFileName(fileName, options, host), tspath.RootedFilePath("/dist/Widget.part.part.mjs")) + assert.Equal(t, outputpaths.GetOutputDeclarationFileNameWorker(fileName, options, host), tspath.RootedFilePath("/dist/Widget.part.part.d.mts")) } func TestGetSourceFileNameInNewDirSourceMatchesCommonDirectory(t *testing.T) { @@ -179,6 +179,7 @@ func TestGetOutputFileNameAcrossRoots(t *testing.T) { } assert.Equal(t, outputpaths.GetOutputJSFileNameWorker(input, options, host), tspath.RootedFilePath("d:/shared.js")) + assert.Equal(t, outputpaths.GetOutputJSFileName(input, options, host), tspath.RootedFilePath("d:/shared.js")) assert.Equal(t, outputpaths.GetOutputDeclarationFileNameWorker(input, options, host), tspath.RootedFilePath("d:/shared.d.ts")) } diff --git a/tsc/internal/printer/helpers.go b/tsc/internal/printer/helpers.go index cf1cc14f9eadf..7997bd53368ba 100644 --- a/tsc/internal/printer/helpers.go +++ b/tsc/internal/printer/helpers.go @@ -553,8 +553,7 @@ var rewriteRelativeImportExtensionsHelper = &EmitHelper{ for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } diff --git a/tsc/internal/tsoptions/contentmappers.go b/tsc/internal/tsoptions/contentmappers.go index e3d2a4bc04c10..71f13c3a64116 100644 --- a/tsc/internal/tsoptions/contentmappers.go +++ b/tsc/internal/tsoptions/contentmappers.go @@ -104,6 +104,12 @@ func resolveContentMapperManifest(host ParseConfigHost, containingFile tspath.Ro output, ) } + if !contentmapper.IsValidSourceExtension(source) { + return contentmapper.Manifest{}, packageDirectory, ast.NewCompilerDiagnostic( + diagnostics.Content_mapper_source_extension_0_must_contain_only_one_dot, + source, + ) + } } return contentmapper.Manifest{Name: name, Version: version, Exec: exec, CompilerOptions: compilerOptions, DynamicConfig: dynamicConfig, DefaultOutputExtensions: outputExtensions}, packageDirectory, nil } diff --git a/tsc/internal/tsoptions/contentmappers_test.go b/tsc/internal/tsoptions/contentmappers_test.go index 68137b0ac1203..f76934028ab21 100644 --- a/tsc/internal/tsoptions/contentmappers_test.go +++ b/tsc/internal/tsoptions/contentmappers_test.go @@ -12,16 +12,6 @@ import ( "gotest.tools/v3/assert" ) -func TestGetContentMapperForFileNameUsesLongestExtension(t *testing.T) { - t.Parallel() - zMapper := &contentmapper.Mapper{Package: "z", Extensions: []string{".z"}} - yzMapper := &contentmapper.Mapper{Package: "yz", Extensions: []string{".y.z"}} - commandLine := &ParsedCommandLine{ParsedConfig: &ParsedOptions{ContentMappers: []*contentmapper.Mapper{zMapper, yzMapper}}} - - assert.Equal(t, commandLine.GetContentMapperForFileName("/src/Component.y.z"), yzMapper) - assert.Equal(t, commandLine.GetContentMapperForFileName("/src/Component.z"), zMapper) -} - func TestGetContentMapperForFileNameUsesHostCaseSensitivity(t *testing.T) { t.Parallel() mapper := &contentmapper.Mapper{Extensions: []string{".vue"}} @@ -34,8 +24,8 @@ func TestGetContentMapperForFileNameUsesHostCaseSensitivity(t *testing.T) { caseSensitivity: tspath.CaseSensitive, } - assert.Equal(t, insensitive.GetContentMapperForFileName("/src/Component.VUE"), mapper) - assert.Assert(t, sensitive.GetContentMapperForFileName("/src/Component.VUE") == nil) + assert.Equal(t, insensitive.GetContentMapperForFileName("/src/Component.part.VUE"), mapper) + assert.Assert(t, sensitive.GetContentMapperForFileName("/src/Component.part.VUE") == nil) } func TestGetOutputFileNamesExcludesMapperOwnedOutputs(t *testing.T) { @@ -59,42 +49,10 @@ func TestGetOutputFileNamesExcludesMapperOwnedOutputs(t *testing.T) { assert.DeepEqual(t, slices.Collect(commandLine.GetOutputFileNames()), []tspath.RootedFilePath{"/dist/Component.d.vue.ts"}) } -func TestContentMapperExtensionRewritesPreserveLongestExtension(t *testing.T) { - t.Parallel() - mapper := &contentmapper.Mapper{ - Extensions: []string{".z", ".y.z", ".identity.y.z", ".unmapped.y.z"}, - OutputExtensions: map[string]string{ - ".z": ".js", ".y.z": ".mjs", ".identity.y.z": ".identity.y.z", - }, - } - commandLine := NewParsedCommandLine( - &core.CompilerOptions{Declaration: core.TSTrue, OutDir: "/dist"}, - []tspath.RootedFilePath{"/src/Widget.y.z", "/src/Widget.identity.y.z", "/src/Widget.unmapped.y.z"}, - nil, - "/", - tspath.CaseSensitive, - ) - commandLine.ParsedConfig.ContentMappers = []*contentmapper.Mapper{mapper} - rewrites := commandLine.ContentMapperExtensionRewrites() - assert.Assert(t, slices.IsSortedFunc(rewrites, func(a, b tspath.ExtensionRewrite) int { - return len(b.Source) - len(a.Source) - })) - for _, file := range []string{"./Widget.identity.y.z", "./Widget.unmapped.y.z"} { - rewritten, ok := tspath.ToModuleSpecifier(file).RewriteExtension(rewrites, tspath.CaseSensitive) - assert.Assert(t, !ok) - assert.Equal(t, rewritten.AsString(), file) - } - assert.DeepEqual(t, slices.Collect(commandLine.GetOutputFileNames()), []tspath.RootedFilePath{ - "/dist/Widget.d.mts", - "/dist/Widget.d.identity.y.z.ts", - "/dist/Widget.d.unmapped.y.z.ts", - }) -} - func TestContentMapperExtensionRewritesAreCached(t *testing.T) { //nolint:paralleltest,tparallel // AllocsPerRun cannot run in parallel tests. mapper := &contentmapper.Mapper{ - Extensions: []string{".astro", ".y.z"}, - OutputExtensions: map[string]string{".astro": ".js", ".y.z": ".mjs"}, + Extensions: []string{".astro", ".vue", ".identity", ".unmapped"}, + OutputExtensions: map[string]string{".astro": ".js", ".vue": ".mjs", ".identity": ".identity"}, } commandLine := NewParsedCommandLine( &core.CompilerOptions{}, nil, nil, @@ -102,6 +60,7 @@ func TestContentMapperExtensionRewritesAreCached(t *testing.T) { //nolint:parall ) commandLine.ParsedConfig.ContentMappers = []*contentmapper.Mapper{mapper} rewrites := commandLine.ContentMapperExtensionRewrites() + assert.DeepEqual(t, rewrites, []tspath.ExtensionRewrite{{Source: ".astro", Target: ".js"}, {Source: ".vue", Target: ".mjs"}}) for range 10 { assert.Assert(t, &commandLine.ContentMapperExtensionRewrites()[0] == &rewrites[0]) } @@ -195,6 +154,28 @@ func TestResolveContentMapperManifestRejectsMalformedOutputExtensions(t *testing } } +func TestResolveContentMapperManifestSourceExtensions(t *testing.T) { + t.Parallel() + for _, source := range []string{".toml", ".vue", ".part.toml", ".y.z"} { + t.Run(source, func(t *testing.T) { + t.Parallel() + fs := vfstest.FromMap(map[string]string{ + "/project/node_modules/mapper/package.json": `{ + "name": "mapper", + "typescript": { "contentMapper": { "exec": ["run"], "outputExtensions": {"` + source + `": ".part.js"} } } + }`, + }, tspath.CaseSensitive) + _, _, diagnostic := resolveContentMapperManifest(NewDefaultParseConfigHost(fs), "/project/tsconfig.json", "mapper") + if source == ".toml" || source == ".vue" { + assert.Assert(t, diagnostic == nil) + } else { + assert.Assert(t, diagnostic != nil) + assert.Equal(t, diagnostic.Code(), diagnostics.Content_mapper_source_extension_0_must_contain_only_one_dot.Code()) + } + }) + } +} + func TestResolveContentMapperManifest(t *testing.T) { t.Parallel() diff --git a/tsc/internal/tsoptions/parsedcommandline.go b/tsc/internal/tsoptions/parsedcommandline.go index e5ada392c3033..2943c95f1c6b0 100644 --- a/tsc/internal/tsoptions/parsedcommandline.go +++ b/tsc/internal/tsoptions/parsedcommandline.go @@ -408,28 +408,17 @@ func (p *ParsedCommandLine) ContentMapperExtensionRewrites() []tspath.ExtensionR func (p *ParsedCommandLine) computeContentMapperExtensionRewrites() []tspath.ExtensionRewrite { var result []tspath.ExtensionRewrite - hasNonIdentityMapping := false ignoreCase := p.CaseSensitivity().IsCaseInsensitive() for _, mapper := range p.ContentMappers() { outputExtensions := mapper.Definition.OutputExtensions for _, source := range mapper.Definition.Extensions { target, ok := getContentMapperOutputExtension(outputExtensions, source, ignoreCase) if !ok || target == source || ignoreCase && strings.EqualFold(target, source) { - target = source - } else { - hasNonIdentityMapping = true + continue } result = append(result, tspath.ExtensionRewrite{Source: source, Target: target}) } } - if !hasNonIdentityMapping { - return nil - } - // Identity entries prevent shorter mappings from claiming a longer registered extension. - // The runtime helper uses the first match, so emit the longest extensions first. - slices.SortStableFunc(result, func(a, b tspath.ExtensionRewrite) int { - return len(b.Source) - len(a.Source) - }) return result } @@ -451,7 +440,7 @@ func getContentMapperOutputExtension(outputExtensions map[string]string, sourceE // or nil if no content mapper is registered for the file's extension. func (p *ParsedCommandLine) GetContentMapperForFileName(fileName tspath.RootedFilePath) *contentmapper.Mapper { caseSensitivity := p.CaseSensitivity() - extension := fileName.LongestExtension(p.ContentMapperExtensions(), caseSensitivity) + extension := fileName.AnyExtension(nil, caseSensitivity) for _, mapper := range p.ContentMappers() { if slices.ContainsFunc(mapper.Definition.Extensions, func(mapperExtension string) bool { return extension == mapperExtension || caseSensitivity.IsCaseInsensitive() && strings.EqualFold(extension, mapperExtension) diff --git a/tsc/internal/tsoptions/tsconfigparsing.go b/tsc/internal/tsoptions/tsconfigparsing.go index cb4c7d01d723d..a76af0256eca8 100644 --- a/tsc/internal/tsoptions/tsconfigparsing.go +++ b/tsc/internal/tsoptions/tsconfigparsing.go @@ -1356,6 +1356,8 @@ func parseJsonConfigFileContentWorker( errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_file_extension_0_must_begin_with_a, ext), contentMapperSourceFile, extNode)) case strings.ContainsAny(ext, "/\\"): errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_extension_0_must_not_contain_path_separators, ext), contentMapperSourceFile, extNode)) + case strings.Contains(ext[1:], "."): + errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_source_extension_0_must_contain_only_one_dot, ext), contentMapperSourceFile, extNode)) case contentmapper.HasReservedSourceExtension(ext): errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_file_extension_0_cannot_be_registered_because_it_ends_in_a_built_in_extension, ext), contentMapperSourceFile, extNode)) default: @@ -1376,6 +1378,8 @@ func parseJsonConfigFileContentWorker( errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_extension_0_must_not_contain_path_separators, sourceExtension), contentMapperSourceFile, outputExtensionsNode)) } else if !contentmapper.IsValidExtension(sourceExtension) { errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_output_extension_0_must_be_non_empty_and_begin_with_a, sourceExtension), contentMapperSourceFile, outputExtensionsNode)) + } else if !contentmapper.IsValidSourceExtension(sourceExtension) { + errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_source_extension_0_must_contain_only_one_dot, sourceExtension), contentMapperSourceFile, outputExtensionsNode)) } if strings.ContainsAny(outputExtension, "/\\") { errors = append(errors, setContentMapperDiagnosticLocation(ast.NewCompilerDiagnostic(diagnostics.Content_mapper_extension_0_must_not_contain_path_separators, outputExtension), contentMapperSourceFile, outputExtensionsNode)) diff --git a/tsc/internal/tsoptions/tsconfigparsing_test.go b/tsc/internal/tsoptions/tsconfigparsing_test.go index 7d9fa696bcb20..c2f4fad147528 100644 --- a/tsc/internal/tsoptions/tsconfigparsing_test.go +++ b/tsc/internal/tsoptions/tsconfigparsing_test.go @@ -1454,6 +1454,16 @@ func TestContentMappersValidation(t *testing.T) { contentMappers string expectedCode int32 }{ + { + name: "compound source extension", + contentMappers: `[{ "package": "x", "extensions": [".part.toml", ".y.z"] }]`, + expectedCode: diagnostics.Content_mapper_source_extension_0_must_contain_only_one_dot.Code(), + }, + { + name: "compound output extension source", + contentMappers: `[{ "package": "x", "extensions": [".toml"], "outputExtensions": {".part.toml": ".js"} }]`, + expectedCode: diagnostics.Content_mapper_source_extension_0_must_contain_only_one_dot.Code(), + }, { name: "extension without leading dot", contentMappers: `[{ "package": "vue-mapper", "extensions": ["vue"] }]`, @@ -1648,43 +1658,6 @@ func TestContentMapperExtensionValidationUsesHostCaseSensitivity(t *testing.T) { } } -func TestContentMapperCompoundExtensionValidation(t *testing.T) { - t.Parallel() - for _, caseSensitivity := range []tspath.CaseSensitivity{tspath.CaseInsensitive, tspath.CaseSensitive} { - extensions := []string{".y.z", ".component.tsx.vue"} - for _, extension := range core.Flatten(tspath.AllSupportedExtensionsWithJson) { - extensions = append(extensions, ".component"+extension, ".component"+strings.ToUpper(extension)) - } - for _, extension := range extensions { - t.Run(fmt.Sprintf("%s/caseSensitive=%t", extension, caseSensitivity.IsCaseSensitive()), func(t *testing.T) { - t.Parallel() - files := map[string]string{ - "/tsconfig.json": fmt.Sprintf(`{ "contentMappers": [{ "package": "mapper", "extensions": [%q] }] }`, extension), - "/app.ts": "export {};", - "/node_modules/mapper/package.json": `{ - "name": "mapper", - "typescript": { "contentMapper": { "exec": ["mapper"] } } - }`, - } - fs := tsoptionstest.NewVFS(files, caseSensitivity) - config := testConfig{ - jsonText: files["/tsconfig.json"], configFileName: "tsconfig.json", basePath: "/", - allFileList: files, existingOptions: &core.CompilerOptions{RunExternalCode: core.TSTrue}, - } - parsed := getParsedWithJsonSourceFileApi(config, fs, config.basePath) - if extension == ".y.z" || extension == ".component.tsx.vue" { - assert.Equal(t, len(parsed.Errors), 0) - assert.DeepEqual(t, parsed.ContentMapperExtensions(), []string{extension}) - } else { - assert.Equal(t, len(parsed.Errors), 1) - assert.Equal(t, parsed.Errors[0].Code(), diagnostics.Content_mapper_file_extension_0_cannot_be_registered_because_it_ends_in_a_built_in_extension.Code()) - assert.Equal(t, len(parsed.ContentMapperExtensions()), 0) - } - }) - } - } -} - func getParsedWithJsonSourceFileApi(config testConfig, fs vfs.FS, basePath tspath.RootedDirectoryPath) *tsoptions.ParsedCommandLine { configFileName := tspath.ToRootedFilePath(config.configFileName, basePath) path := fs.CaseSensitivity().PathKey(tspath.RootedPath(configFileName)) diff --git a/tsc/internal/tspath/extensionrewrite.go b/tsc/internal/tspath/extensionrewrite.go index 3802d2648f060..147eae4f2cce7 100644 --- a/tsc/internal/tspath/extensionrewrite.go +++ b/tsc/internal/tspath/extensionrewrite.go @@ -6,30 +6,21 @@ type ExtensionRewrite struct { } func getExtensionRewrite(path string, rewrites []ExtensionRewrite, caseSensitivity CaseSensitivity) (ExtensionRewrite, bool) { - var best ExtensionRewrite equal := caseSensitivity.getEqualityComparer() for _, rewrite := range rewrites { - if len(rewrite.Source) <= len(best.Source) || len(path) <= len(rewrite.Source) { + if len(path) <= len(rewrite.Source) { continue } if equal(path[len(path)-len(rewrite.Source):], rewrite.Source) { - best = rewrite + return rewrite, true } } - return best, best.Source != "" -} - -func (r ExtensionRewrite) isIdentity(caseSensitivity CaseSensitivity) bool { - return caseSensitivity.getEqualityComparer()(r.Source, r.Target) -} - -func (f RootedFilePath) GetExtensionRewrite(rewrites []ExtensionRewrite, caseSensitivity CaseSensitivity) (ExtensionRewrite, bool) { - return getExtensionRewrite(f.AsString(), rewrites, caseSensitivity) + return ExtensionRewrite{}, false } func (f RootedFilePath) RewriteExtension(rewrites []ExtensionRewrite, caseSensitivity CaseSensitivity) (RootedFilePath, bool) { - rewrite, ok := f.GetExtensionRewrite(rewrites, caseSensitivity) - if !ok || rewrite.isIdentity(caseSensitivity) { + rewrite, ok := getExtensionRewrite(f.AsString(), rewrites, caseSensitivity) + if !ok { return f, false } suffix := f.AsString()[len(f.AsString())-len(rewrite.Source):] @@ -38,7 +29,7 @@ func (f RootedFilePath) RewriteExtension(rewrites []ExtensionRewrite, caseSensit func (s ModuleSpecifier) RewriteExtension(rewrites []ExtensionRewrite, caseSensitivity CaseSensitivity) (ModuleSpecifier, bool) { rewrite, ok := getExtensionRewrite(s.AsString(), rewrites, caseSensitivity) - if !ok || rewrite.isIdentity(caseSensitivity) { + if !ok { return s, false } return ToModuleSpecifier(s.AsString()[:len(s.AsString())-len(rewrite.Source)] + rewrite.Target), true @@ -48,8 +39,6 @@ func (s ModuleSpecifier) ShouldRewriteExtension(rewrites []ExtensionRewrite, cas if !s.IsRelative() || IsDeclarationFileName(s.AsString()) { return false } - if rewrite, ok := getExtensionRewrite(s.AsString(), rewrites, caseSensitivity); ok { - return !rewrite.isIdentity(caseSensitivity) - } - return HasTSFileExtension(s.AsString()) + _, ok := getExtensionRewrite(s.AsString(), rewrites, caseSensitivity) + return ok || HasTSFileExtension(s.AsString()) } diff --git a/tsc/internal/tspath/extensionrewrite_test.go b/tsc/internal/tspath/extensionrewrite_test.go index 02c0581e0f318..a41654ceddde5 100644 --- a/tsc/internal/tspath/extensionrewrite_test.go +++ b/tsc/internal/tspath/extensionrewrite_test.go @@ -11,44 +11,37 @@ func TestRewriteExtension(t *testing.T) { t.Parallel() rewrites := []tspath.ExtensionRewrite{ {Source: ".z", Target: ".js"}, - {Source: ".y.z", Target: ".mjs"}, + {Source: ".vue", Target: ".part.mjs"}, } - rewritten, ok := tspath.ToModuleSpecifier("./Widget.y.z").RewriteExtension(rewrites, tspath.CaseSensitive) + rewritten, ok := tspath.ToModuleSpecifier("./Widget.part.vue").RewriteExtension(rewrites, tspath.CaseSensitive) assert.Assert(t, ok) - assert.Equal(t, rewritten, tspath.ToModuleSpecifier("./Widget.mjs")) + assert.Equal(t, rewritten, tspath.ToModuleSpecifier("./Widget.part.part.mjs")) - rewritten, ok = tspath.ToModuleSpecifier("./Widget.Y.Z").RewriteExtension(rewrites, tspath.CaseInsensitive) + rewritten, ok = tspath.ToModuleSpecifier("./Widget.part.VUE").RewriteExtension(rewrites, tspath.CaseInsensitive) assert.Assert(t, ok) - assert.Equal(t, rewritten, tspath.ToModuleSpecifier("./Widget.mjs")) + assert.Equal(t, rewritten, tspath.ToModuleSpecifier("./Widget.part.part.mjs")) rewritten, ok = tspath.ToModuleSpecifier(".y").RewriteExtension(rewrites, tspath.CaseSensitive) assert.Assert(t, !ok) assert.Equal(t, rewritten, tspath.ToModuleSpecifier(".y")) - - rewrites = append(rewrites, tspath.ExtensionRewrite{Source: ".identity.y.z", Target: ".identity.y.z"}) - rewritten, ok = tspath.ToModuleSpecifier("./Widget.IDENTITY.Y.Z").RewriteExtension(rewrites, tspath.CaseInsensitive) - assert.Assert(t, !ok) - assert.Equal(t, rewritten, tspath.ToModuleSpecifier("./Widget.IDENTITY.Y.Z")) - assert.Assert(t, !tspath.ToModuleSpecifier("./Widget.identity.y.z").ShouldRewriteExtension(rewrites, tspath.CaseSensitive)) } func TestRootedFilePathRewriteExtension(t *testing.T) { t.Parallel() rewrites := []tspath.ExtensionRewrite{ {Source: ".z", Target: ".js"}, - {Source: ".y.z", Target: ".mjs"}, - {Source: ".identity.y.z", Target: ".identity.y.z"}, + {Source: ".vue", Target: ".mjs"}, } for _, test := range []struct { path, expected string caseSensitivity tspath.CaseSensitivity changed bool }{ - {"/src/Widget.y.z", "/src/Widget.mjs", tspath.CaseSensitive, true}, - {"/src/Widget.Y.Z", "/src/Widget.mjs", tspath.CaseInsensitive, true}, - {"/src/Widget.Y.Z", "/src/Widget.Y.Z", tspath.CaseSensitive, false}, - {"/src/Widget.IDENTITY.Y.Z", "/src/Widget.IDENTITY.Y.Z", tspath.CaseInsensitive, false}, + {"/src/Widget.part.vue", "/src/Widget.part.mjs", tspath.CaseSensitive, true}, + {"/src/Widget.part.VUE", "/src/Widget.part.mjs", tspath.CaseInsensitive, true}, + {"/src/Widget.part.VUE", "/src/Widget.part.VUE", tspath.CaseSensitive, false}, + {"/src/Widget.part.IDENTITY", "/src/Widget.part.IDENTITY", tspath.CaseInsensitive, false}, {"/src/Widget.txt", "/src/Widget.txt", tspath.CaseSensitive, false}, } { file := tspath.RootedFilePathFromNormalized(test.path) diff --git a/tsc/internal/tspath/path.go b/tsc/internal/tspath/path.go index 8271a090d0a67..eeaa7604338db 100644 --- a/tsc/internal/tspath/path.go +++ b/tsc/internal/tspath/path.go @@ -927,20 +927,6 @@ func getAnyExtensionFromNormalizedPath(path string) string { return "" } -func GetLongestExtensionFromPath(path string, extensions []string, caseSensitivity CaseSensitivity) string { - path = RemoveTrailingDirectorySeparator(path) - comparer := caseSensitivity.getEqualityComparer() - longest := "" - for _, extension := range extensions { - if len(extension) > len(longest) { - if matched := tryGetExtensionFromPath(path, extension, comparer); matched != "" { - longest = matched - } - } - } - return longest -} - func getAnyExtensionFromPathWorker(path string, extensions []string, stringEqualityComparer func(a, b string) bool) string { for _, extension := range extensions { result := tryGetExtensionFromPath(path, extension, stringEqualityComparer) diff --git a/tsc/internal/tspath/path_test.go b/tsc/internal/tspath/path_test.go index fcbc8ca7b790b..9d81a267e032e 100644 --- a/tsc/internal/tspath/path_test.go +++ b/tsc/internal/tspath/path_test.go @@ -168,15 +168,6 @@ func TestGetDirectoryPath(t *testing.T) { assert.Equal(t, GetDirectoryPath("http://server/path/"), "http://server/") } -func TestGetLongestExtensionFromPath(t *testing.T) { - t.Parallel() - extensions := []string{".z", ".y.z", ".other"} - assert.Equal(t, GetLongestExtensionFromPath("/src/Component.y.z", extensions, CaseSensitive), ".y.z") - assert.Equal(t, GetLongestExtensionFromPath("/src/Component.z", extensions, CaseSensitive), ".z") - assert.Equal(t, GetLongestExtensionFromPath("/src/Component.y.Z", extensions, CaseSensitive), "") - assert.Equal(t, GetLongestExtensionFromPath("/src/Component.y.Z", extensions, CaseInsensitive), ".y.Z") -} - func TestRemoveAnyFileExtension(t *testing.T) { t.Parallel() assert.Equal(t, RemoveAnyFileExtension("/src/Component.vue"), "/src/Component") diff --git a/tsc/internal/tspath/rooted_path.go b/tsc/internal/tspath/rooted_path.go index b61a2d73cb983..59b620e6c8ae5 100644 --- a/tsc/internal/tspath/rooted_path.go +++ b/tsc/internal/tspath/rooted_path.go @@ -359,10 +359,6 @@ func (f RootedFilePath) AnyExtension(extensions []string, caseSensitivity CaseSe return GetAnyExtensionFromPath(string(f), extensions, caseSensitivity) } -func (f RootedFilePath) LongestExtension(extensions []string, caseSensitivity CaseSensitivity) string { - return GetLongestExtensionFromPath(string(f), extensions, caseSensitivity) -} - func (f RootedFilePath) HasExtension() bool { return strings.Contains(getBaseFileNameFromNormalized(string(f)), ".") } diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.contentmapper b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.contentmapper index e9e9c0f320e8b..958f64663c2f5 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.contentmapper +++ b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.contentmapper @@ -1,4 +1,4 @@ -//// [/component.y.z] (ScriptKind: ScriptKindTS, ContentMapper: [.y.z]) +//// [/component.part.toml] (ScriptKind: ScriptKindTS, ContentMapper: [.toml]) --- Original --- export interface ComponentProps { emoji: "😀"; label: string; } export declare const component: ComponentProps; diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js index 7babef9ea3cec..6459787e62851 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js +++ b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js @@ -7,26 +7,26 @@ "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"] } } } -//// [component.y.z] +//// [component.part.toml] const __VERSION = "1.0.0"; export interface ComponentProps { emoji: "😀"; label: string; } export declare const component: ComponentProps; export const emittedTarget = 7; //// [main.ts] -export { component } from "./component.y.z"; +export { component } from "./component.part.toml"; //// [main.js] -export { component } from "./component.y.z"; +export { component } from "./component.part.toml"; -//// [component.d.y.z.ts] +//// [component.part.d.toml.ts] export interface ComponentProps { emoji: "😀"; label: string; } export declare const component: ComponentProps; export declare const emittedTarget = 7; -//# sourceMappingURL=component.d.y.z.ts.map//// [main.d.ts] -export { component } from "./component.y.z"; +//# sourceMappingURL=component.part.d.toml.ts.map//// [main.d.ts] +export { component } from "./component.part.toml"; //# sourceMappingURL=main.d.ts.map \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js.map b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js.map index f94662d35f6ea..973d2dc70420f 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js.map +++ b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.js.map @@ -1,7 +1,7 @@ -//// [component.d.y.z.ts.map] -{"version":3,"file":"component.d.y.z.ts","sources":["component.y.z"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAAG,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;CAAE;AAC/D,MAAM,CAAC,OAAO,CAAC,MAAM,SAAS,EAAE,cAAc,CAAC;AAC/C,eAAO,MAAM,aAAa,I,CAAa"} -//// https://sokra.github.io/source-map-visualization#base64,ZXhwb3J0IGludGVyZmFjZSBDb21wb25lbnRQcm9wcyB7DQogICAgZW1vamk6ICLwn5iAIjsNCiAgICBsYWJlbDogc3RyaW5nOw0KfQ0KZXhwb3J0IGRlY2xhcmUgY29uc3QgY29tcG9uZW50OiBDb21wb25lbnRQcm9wczsNCmV4cG9ydCBkZWNsYXJlIGNvbnN0IGVtaXR0ZWRUYXJnZXQgPSA3Ow0KLy8jIHNvdXJjZU1hcHBpbmdVUkw9Y29tcG9uZW50LmQueS56LnRzLm1hcA==,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LmQueS56LnRzIiwic291cmNlcyI6WyJjb21wb25lbnQueS56Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sV0FBVyxjQUFjO0lBQUcsS0FBSyxFQUFFLElBQUksQ0FBQztJQUFDLEtBQUssRUFBRSxNQUFNLENBQUM7Q0FBRTtBQUMvRCxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sU0FBUyxFQUFFLGNBQWMsQ0FBQztBQUMvQyxlQUFPLE1BQU0sYUFBYSxJLENBQWEifQ==,ZXhwb3J0IGludGVyZmFjZSBDb21wb25lbnRQcm9wcyB7IGVtb2ppOiAi8J+YgCI7IGxhYmVsOiBzdHJpbmc7IH0KZXhwb3J0IGRlY2xhcmUgY29uc3QgY29tcG9uZW50OiBDb21wb25lbnRQcm9wczsKZXhwb3J0IGNvbnN0IGVtaXR0ZWRUYXJnZXQgPSAje3RhcmdldH07Cg== +//// [component.part.d.toml.ts.map] +{"version":3,"file":"component.part.d.toml.ts","sources":["component.part.toml"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAAG,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;CAAE;AAC/D,MAAM,CAAC,OAAO,CAAC,MAAM,SAAS,EAAE,cAAc,CAAC;AAC/C,eAAO,MAAM,aAAa,I,CAAa"} +//// https://sokra.github.io/source-map-visualization#base64,ZXhwb3J0IGludGVyZmFjZSBDb21wb25lbnRQcm9wcyB7DQogICAgZW1vamk6ICLwn5iAIjsNCiAgICBsYWJlbDogc3RyaW5nOw0KfQ0KZXhwb3J0IGRlY2xhcmUgY29uc3QgY29tcG9uZW50OiBDb21wb25lbnRQcm9wczsNCmV4cG9ydCBkZWNsYXJlIGNvbnN0IGVtaXR0ZWRUYXJnZXQgPSA3Ow0KLy8jIHNvdXJjZU1hcHBpbmdVUkw9Y29tcG9uZW50LnBhcnQuZC50b21sLnRzLm1hcA==,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LnBhcnQuZC50b21sLnRzIiwic291cmNlcyI6WyJjb21wb25lbnQucGFydC50b21sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sV0FBVyxjQUFjO0lBQUcsS0FBSyxFQUFFLElBQUksQ0FBQztJQUFDLEtBQUssRUFBRSxNQUFNLENBQUM7Q0FBRTtBQUMvRCxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sU0FBUyxFQUFFLGNBQWMsQ0FBQztBQUMvQyxlQUFPLE1BQU0sYUFBYSxJLENBQWEifQ==,ZXhwb3J0IGludGVyZmFjZSBDb21wb25lbnRQcm9wcyB7IGVtb2ppOiAi8J+YgCI7IGxhYmVsOiBzdHJpbmc7IH0KZXhwb3J0IGRlY2xhcmUgY29uc3QgY29tcG9uZW50OiBDb21wb25lbnRQcm9wczsKZXhwb3J0IGNvbnN0IGVtaXR0ZWRUYXJnZXQgPSAje3RhcmdldH07Cg== //// [main.d.ts.map] -{"version":3,"file":"main.d.ts","sources":["main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"} -//// https://sokra.github.io/source-map-visualization#base64,ZXhwb3J0IHsgY29tcG9uZW50IH0gZnJvbSAiLi9jb21wb25lbnQueS56IjsNCi8vIyBzb3VyY2VNYXBwaW5nVVJMPW1haW4uZC50cy5tYXA=,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5kLnRzIiwic291cmNlcyI6WyJtYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQyJ9,ZXhwb3J0IHsgY29tcG9uZW50IH0gZnJvbSAiLi9jb21wb25lbnQueS56Ijs= +{"version":3,"file":"main.d.ts","sources":["main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC"} +//// https://sokra.github.io/source-map-visualization#base64,ZXhwb3J0IHsgY29tcG9uZW50IH0gZnJvbSAiLi9jb21wb25lbnQucGFydC50b21sIjsNCi8vIyBzb3VyY2VNYXBwaW5nVVJMPW1haW4uZC50cy5tYXA=,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5kLnRzIiwic291cmNlcyI6WyJtYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQyJ9,ZXhwb3J0IHsgY29tcG9uZW50IH0gZnJvbSAiLi9jb21wb25lbnQucGFydC50b21sIjs= diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.sourcemap.txt b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.sourcemap.txt index 60288ed5c0960..2d88fca342b3b 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.sourcemap.txt +++ b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.sourcemap.txt @@ -1,12 +1,12 @@ =================================================================== -JsFile: component.d.y.z.ts -mapUrl: component.d.y.z.ts.map +JsFile: component.part.d.toml.ts +mapUrl: component.part.d.toml.ts.map sourceRoot: -sources: component.y.z +sources: component.part.toml =================================================================== ------------------------------------------------------------------- -emittedFile:/component.d.y.z.ts -sourceFile:component.y.z +emittedFile:/component.part.d.toml.ts +sourceFile:component.part.toml ------------------------------------------------------------------- >>>export interface ComponentProps { 1 > @@ -103,7 +103,7 @@ sourceFile:component.y.z 4 > ^^^^^^^^^^^^^ 5 > ^^^^ 6 > ^ -7 > ^^^-> +7 > ^^^^^^^^^-> 1 > > 2 >export @@ -120,7 +120,7 @@ sourceFile:component.y.z 5 >Emitted(6, 39) 6 >Emitted(6, 40) Source(3, 40) + SourceIndex(0) --- ->>>//# sourceMappingURL=component.d.y.z.ts.map=================================================================== +>>>//# sourceMappingURL=component.part.d.toml.ts.map=================================================================== JsFile: main.d.ts mapUrl: main.d.ts.map sourceRoot: @@ -130,30 +130,30 @@ sources: main.ts emittedFile:/main.d.ts sourceFile:main.ts ------------------------------------------------------------------- ->>>export { component } from "./component.y.z"; +>>>export { component } from "./component.part.toml"; 1 > 2 >^^^^^^^ 3 > ^^ 4 > ^^^^^^^^^ 5 > ^^ 6 > ^^^^^^ -7 > ^^^^^^^^^^^^^^^^^ -8 > ^ +7 > ^^^^^^^^^^^^^^^^^^^^^^^ +8 > ^ 1 > 2 >export 3 > { 4 > component 5 > } 6 > from -7 > "./component.y.z" -8 > ; +7 > "./component.part.toml" +8 > ; 1 >Emitted(1, 1) Source(1, 1) + SourceIndex(0) 2 >Emitted(1, 8) Source(1, 8) + SourceIndex(0) 3 >Emitted(1, 10) Source(1, 10) + SourceIndex(0) 4 >Emitted(1, 19) Source(1, 19) + SourceIndex(0) 5 >Emitted(1, 21) Source(1, 21) + SourceIndex(0) 6 >Emitted(1, 27) Source(1, 27) + SourceIndex(0) -7 >Emitted(1, 44) Source(1, 44) + SourceIndex(0) -8 >Emitted(1, 45) Source(1, 45) + SourceIndex(0) +7 >Emitted(1, 50) Source(1, 50) + SourceIndex(0) +8 >Emitted(1, 51) Source(1, 51) + SourceIndex(0) --- >>>//# sourceMappingURL=main.d.ts.map \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.symbols b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.symbols index 8483f26866862..cdfbba6833d27 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.symbols +++ b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.symbols @@ -1,22 +1,22 @@ //// [tests/cases/compiler/contentMapperDeclarationEmit.ts] //// -=== /component.y.z === +=== /component.part.toml === const __VERSION = "1.0.0"; ->__VERSION : Symbol(__VERSION, Decl(component.y.z, 0, 5)) +>__VERSION : Symbol(__VERSION, Decl(component.part.toml, 0, 5)) export interface ComponentProps { emoji: "😀"; label: string; } ->ComponentProps : Symbol(ComponentProps, Decl(component.y.z, 0, 26)) ->emoji : Symbol(ComponentProps.emoji, Decl(component.y.z, 1, 33)) ->label : Symbol(ComponentProps.label, Decl(component.y.z, 1, 46)) +>ComponentProps : Symbol(ComponentProps, Decl(component.part.toml, 0, 26)) +>emoji : Symbol(ComponentProps.emoji, Decl(component.part.toml, 1, 33)) +>label : Symbol(ComponentProps.label, Decl(component.part.toml, 1, 46)) export declare const component: ComponentProps; ->component : Symbol(component, Decl(component.y.z, 2, 20)) ->ComponentProps : Symbol(ComponentProps, Decl(component.y.z, 0, 26)) +>component : Symbol(component, Decl(component.part.toml, 2, 20)) +>ComponentProps : Symbol(ComponentProps, Decl(component.part.toml, 0, 26)) export const emittedTarget = 7; ->emittedTarget : Symbol(emittedTarget, Decl(component.y.z, 3, 12)) +>emittedTarget : Symbol(emittedTarget, Decl(component.part.toml, 3, 12)) === /main.ts === -export { component } from "./component.y.z"; +export { component } from "./component.part.toml"; >component : Symbol(component, Decl(main.ts, 0, 8)) diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.types b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.types index 10b5d8c0d4423..44ab3c7e19c78 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.types +++ b/tsc/testdata/baselines/reference/compiler/contentMapperDeclarationEmit.types @@ -1,6 +1,6 @@ //// [tests/cases/compiler/contentMapperDeclarationEmit.ts] //// -=== /component.y.z === +=== /component.part.toml === const __VERSION = "1.0.0"; >__VERSION : "1.0.0" >"1.0.0" : "1.0.0" @@ -17,6 +17,6 @@ export const emittedTarget = 7; >7 : 7 === /main.ts === -export { component } from "./component.y.z"; ->component : import("./component.y.z").ComponentProps +export { component } from "./component.part.toml"; +>component : import("./component.part.toml").ComponentProps diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.contentmapper b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.contentmapper index 0b70a1a5b418d..471af334c7abe 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.contentmapper +++ b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.contentmapper @@ -1,4 +1,4 @@ -//// [/Card.astro] (ScriptKind: ScriptKindTS, ContentMapper: [.astro .y.z]) +//// [/Card.astro] (ScriptKind: ScriptKindTS, ContentMapper: [.astro .vue]) --- Original --- export interface CardProps { title: string } export declare const Card: (props: CardProps) => string; @@ -7,7 +7,7 @@ const __VERSION = "1.0.0"; export interface CardProps { title: string } export declare const Card: (props: CardProps) => string; -//// [/Widget.y.z] (ScriptKind: ScriptKindTS, ContentMapper: [.astro .y.z]) +//// [/Widget.part.vue] (ScriptKind: ScriptKindTS, ContentMapper: [.astro .vue]) --- Original --- export declare const Widget: () => string; --- Transformed --- diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js index 081a200e3a1e1..7f162ca925664 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js +++ b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js @@ -7,7 +7,7 @@ "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"], - "outputExtensions": { ".astro": ".js", ".y.z": ".mjs" } + "outputExtensions": { ".astro": ".js", ".vue": ".mjs" } } } } @@ -17,7 +17,7 @@ const __VERSION = "1.0.0"; export interface CardProps { title: string } export declare const Card: (props: CardProps) => string; -//// [Widget.y.z] +//// [Widget.part.vue] const __VERSION = "1.0.0"; export declare const Widget: () => string; @@ -28,13 +28,13 @@ export const annotated: import("./Card.astro").CardProps = { title: "" }; import { annotated } from "./typed"; export { Card } from "./Card.astro"; export type { CardProps } from "./Card.astro"; -export { Widget } from "./Widget.y.z"; +export { Widget } from "./Widget.part.vue"; const path = "./Card.astro"; void import(path); export async function load() { return import("./Card.astro"); } -export const inferred = import("./Widget.y.z"); +export const inferred = import("./Widget.part.vue"); export const nested = { load: () => import("./Card.astro") }; export const copied = [annotated]; @@ -48,8 +48,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } @@ -61,11 +60,11 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte }; import { annotated } from "./typed"; export { Card } from "./Card.js"; -export { Widget } from "./Widget.mjs"; +export { Widget } from "./Widget.part.mjs"; const path = "./Card.astro"; -void import(__rewriteRelativeImportExtension(path, false, { ".astro": ".js", ".y.z": ".mjs" })); +void import(__rewriteRelativeImportExtension(path, false, { ".astro": ".js", ".vue": ".mjs" })); export async function load() { return import("./Card.js"); } -export const inferred = import("./Widget.mjs"); +export const inferred = import("./Widget.part.mjs"); export const nested = { load: () => import("./Card.js") }; export const copied = [annotated]; @@ -75,16 +74,16 @@ export interface CardProps { title: string; } export declare const Card: (props: CardProps) => string; -//# sourceMappingURL=Card.d.ts.map//// [Widget.d.mts] +//# sourceMappingURL=Card.d.ts.map//// [Widget.part.d.mts] export declare const Widget: () => string; -//# sourceMappingURL=Widget.d.mts.map//// [typed.d.ts] +//# sourceMappingURL=Widget.part.d.mts.map//// [typed.d.ts] export declare const annotated: import("./Card.js").CardProps; //# sourceMappingURL=typed.d.ts.map//// [main.d.ts] export { Card } from "./Card.js"; export type { CardProps } from "./Card.js"; -export { Widget } from "./Widget.mjs"; +export { Widget } from "./Widget.part.mjs"; export declare function load(): Promise; -export declare const inferred: Promise; +export declare const inferred: Promise; export declare const nested: { load: () => Promise; }; diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js.map b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js.map index a53aa97c5e4db..b79a58e580bfb 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js.map +++ b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.js.map @@ -1,8 +1,8 @@ //// [Card.d.ts.map] {"version":3,"file":"Card.d.ts","sources":["../Card.astro"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IAAG,KAAK,EAAE,MAAM,CAAA;CAAE;AAC5C,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,MAAM,CAAC"} -//// [Widget.d.mts.map] -{"version":3,"file":"Widget.d.mts","sources":["../Widget.y.z"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,CAAC,MAAM,MAAM,EAAE,MAAM,MAAM,CAAC"} +//// [Widget.part.d.mts.map] +{"version":3,"file":"Widget.part.d.mts","sources":["../Widget.part.vue"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,CAAC,MAAM,MAAM,EAAE,MAAM,MAAM,CAAC"} //// [main.d.ts.map] -{"version":3,"file":"main.d.ts","sources":["../main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAc,CAAC;AACpC,YAAY,EAAE,SAAS,EAAE,MAAM,WAAc,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAKtC,wBAAsB,IAAI,wCAAqC;AAC/D,eAAO,MAAM,QAAQ,wCAAyB,CAAC;AAC/C,eAAO,MAAM,MAAM;IAAK,IAAI;CAAgC,CAAC;AAC7D,eAAO,MAAM,MAAM,iCAAc,CAAC"} +{"version":3,"file":"main.d.ts","sources":["../main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAc,CAAC;AACpC,YAAY,EAAE,SAAS,EAAE,MAAM,WAAc,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAK3C,wBAAsB,IAAI,wCAAqC;AAC/D,eAAO,MAAM,QAAQ,6CAA8B,CAAC;AACpD,eAAO,MAAM,MAAM;IAAK,IAAI;CAAgC,CAAC;AAC7D,eAAO,MAAM,MAAM,iCAAc,CAAC"} //// [typed.d.ts.map] {"version":3,"file":"typed.d.ts","sources":["../typed.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,EAAE,OAAO,WAAc,EAAE,SAAyB,CAAC"} \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.sourcemap.txt b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.sourcemap.txt index 8872ed9edb086..3a5d65fa10e7f 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.sourcemap.txt +++ b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.sourcemap.txt @@ -94,14 +94,14 @@ sourceFile:../Card.astro 15>Emitted(4, 57) Source(2, 57) + SourceIndex(0) --- >>>//# sourceMappingURL=Card.d.ts.map=================================================================== -JsFile: Widget.d.mts -mapUrl: Widget.d.mts.map +JsFile: Widget.part.d.mts +mapUrl: Widget.part.d.mts.map sourceRoot: -sources: ../Widget.y.z +sources: ../Widget.part.vue =================================================================== ------------------------------------------------------------------- -emittedFile:/dist/Widget.d.mts -sourceFile:../Widget.y.z +emittedFile:/dist/Widget.part.d.mts +sourceFile:../Widget.part.vue ------------------------------------------------------------------- >>>export declare const Widget: () => string; 1 > @@ -138,7 +138,7 @@ sourceFile:../Widget.y.z 10>Emitted(1, 42) Source(1, 42) + SourceIndex(0) 11>Emitted(1, 43) Source(1, 43) + SourceIndex(0) --- ->>>//# sourceMappingURL=Widget.d.mts.map=================================================================== +>>>//# sourceMappingURL=Widget.part.d.mts.map=================================================================== JsFile: typed.d.ts mapUrl: typed.d.ts.map sourceRoot: @@ -227,6 +227,7 @@ sourceFile:../main.ts 6 > ^^^^^^ 7 > ^^^^^^^^^^^ 8 > ^ +9 > ^-> 1-> > 2 >export type @@ -245,40 +246,40 @@ sourceFile:../main.ts 7 >Emitted(2, 43) Source(3, 46) + SourceIndex(0) 8 >Emitted(2, 44) Source(3, 47) + SourceIndex(0) --- ->>>export { Widget } from "./Widget.mjs"; -1 > +>>>export { Widget } from "./Widget.part.mjs"; +1-> 2 >^^^^^^^ 3 > ^^ 4 > ^^^^^^ 5 > ^^ 6 > ^^^^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> -1 > +7 > ^^^^^^^^^^^^^^^^^^^ +8 > ^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^-> +1-> > 2 >export 3 > { 4 > Widget 5 > } 6 > from -7 > "./Widget.y.z" -8 > ; -1 >Emitted(3, 1) Source(4, 1) + SourceIndex(0) +7 > "./Widget.part.vue" +8 > ; +1->Emitted(3, 1) Source(4, 1) + SourceIndex(0) 2 >Emitted(3, 8) Source(4, 8) + SourceIndex(0) 3 >Emitted(3, 10) Source(4, 10) + SourceIndex(0) 4 >Emitted(3, 16) Source(4, 16) + SourceIndex(0) 5 >Emitted(3, 18) Source(4, 18) + SourceIndex(0) 6 >Emitted(3, 24) Source(4, 24) + SourceIndex(0) -7 >Emitted(3, 38) Source(4, 38) + SourceIndex(0) -8 >Emitted(3, 39) Source(4, 39) + SourceIndex(0) +7 >Emitted(3, 43) Source(4, 43) + SourceIndex(0) +8 >Emitted(3, 44) Source(4, 44) + SourceIndex(0) --- >>>export declare function load(): Promise; 1-> 2 >^^^^^^^^^^^^^^^^^^^^^^^^ 3 > ^^^^ 4 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -5 > ^^^-> +5 > ^^^^^^^^-> 1-> > >const path = "./Card.astro"; @@ -293,26 +294,26 @@ sourceFile:../main.ts 3 >Emitted(4, 29) Source(9, 27) + SourceIndex(0) 4 >Emitted(4, 69) Source(9, 64) + SourceIndex(0) --- ->>>export declare const inferred: Promise; +>>>export declare const inferred: Promise; 1-> 2 >^^^^^^^^^^^^^^^ 3 > ^^^^^^ 4 > ^^^^^^^^ -5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^ +5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^ 1-> > 2 >export 3 > const 4 > inferred -5 > = import("./Widget.y.z") -6 > ; +5 > = import("./Widget.part.vue") +6 > ; 1->Emitted(5, 1) Source(10, 1) + SourceIndex(0) 2 >Emitted(5, 16) Source(10, 8) + SourceIndex(0) 3 >Emitted(5, 22) Source(10, 14) + SourceIndex(0) 4 >Emitted(5, 30) Source(10, 22) + SourceIndex(0) -5 >Emitted(5, 70) Source(10, 47) + SourceIndex(0) -6 >Emitted(5, 71) Source(10, 48) + SourceIndex(0) +5 >Emitted(5, 75) Source(10, 52) + SourceIndex(0) +6 >Emitted(5, 76) Source(10, 53) + SourceIndex(0) --- >>>export declare const nested: { 1 > diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.symbols b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.symbols index fa2590bec3d3e..f75998f798127 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.symbols +++ b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.symbols @@ -13,12 +13,12 @@ export declare const Card: (props: CardProps) => string; >props : Symbol(props, Decl(Card.astro, 2, 28)) >CardProps : Symbol(CardProps, Decl(Card.astro, 0, 26)) -=== /Widget.y.z === +=== /Widget.part.vue === const __VERSION = "1.0.0"; ->__VERSION : Symbol(__VERSION, Decl(Widget.y.z, 0, 5)) +>__VERSION : Symbol(__VERSION, Decl(Widget.part.vue, 0, 5)) export declare const Widget: () => string; ->Widget : Symbol(Widget, Decl(Widget.y.z, 1, 20)) +>Widget : Symbol(Widget, Decl(Widget.part.vue, 1, 20)) === /typed.ts === export const annotated: import("./Card.astro").CardProps = { title: "" }; @@ -36,7 +36,7 @@ export { Card } from "./Card.astro"; export type { CardProps } from "./Card.astro"; >CardProps : Symbol(CardProps, Decl(main.ts, 2, 13)) -export { Widget } from "./Widget.y.z"; +export { Widget } from "./Widget.part.vue"; >Widget : Symbol(Widget, Decl(main.ts, 3, 8)) const path = "./Card.astro"; @@ -49,9 +49,9 @@ export async function load() { return import("./Card.astro"); } >load : Symbol(load, Decl(main.ts, 6, 18)) >"./Card.astro" : Symbol("./Card.astro", Decl(Card.astro, 0, 0)) -export const inferred = import("./Widget.y.z"); +export const inferred = import("./Widget.part.vue"); >inferred : Symbol(inferred, Decl(main.ts, 9, 12)) ->"./Widget.y.z" : Symbol("./Widget.y.z", Decl(Widget.y.z, 0, 0)) +>"./Widget.part.vue" : Symbol("./Widget.part.vue", Decl(Widget.part.vue, 0, 0)) export const nested = { load: () => import("./Card.astro") }; >nested : Symbol(nested, Decl(main.ts, 10, 12)) diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.types b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.types index 802cb9c2a5077..5b8e1077279f5 100644 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.types +++ b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensions.types @@ -12,7 +12,7 @@ export declare const Card: (props: CardProps) => string; >Card : (props: CardProps) => string >props : CardProps -=== /Widget.y.z === +=== /Widget.part.vue === const __VERSION = "1.0.0"; >__VERSION : "1.0.0" >"1.0.0" : "1.0.0" @@ -37,7 +37,7 @@ export { Card } from "./Card.astro"; export type { CardProps } from "./Card.astro"; >CardProps : import("./Card.astro").CardProps -export { Widget } from "./Widget.y.z"; +export { Widget } from "./Widget.part.vue"; >Widget : () => string const path = "./Card.astro"; @@ -54,10 +54,10 @@ export async function load() { return import("./Card.astro"); } >import("./Card.astro") : Promise >"./Card.astro" : "./Card.astro" -export const inferred = import("./Widget.y.z"); ->inferred : Promise ->import("./Widget.y.z") : Promise ->"./Widget.y.z" : "./Widget.y.z" +export const inferred = import("./Widget.part.vue"); +>inferred : Promise +>import("./Widget.part.vue") : Promise +>"./Widget.part.vue" : "./Widget.part.vue" export const nested = { load: () => import("./Card.astro") }; >nested : { load: () => Promise; } diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.contentmapper b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.contentmapper deleted file mode 100644 index 4bbc986eb4c37..0000000000000 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.contentmapper +++ /dev/null @@ -1,31 +0,0 @@ -//// [/Widget.z] (ScriptKind: ScriptKindTS, ContentMapper: [.z .y.z .identity.y.z .unmapped.y.z]) ---- Original --- -export const short = 1; ---- Transformed --- -const __VERSION = "1.0.0"; -export const short = 1; - -//// [/Widget.y.z] (ScriptKind: ScriptKindTS, ContentMapper: [.z .y.z .identity.y.z .unmapped.y.z]) ---- Original --- -export const long = 1; ---- Transformed --- -const __VERSION = "1.0.0"; -export const long = 1; - -//// [/Widget.identity.y.z] (ScriptKind: ScriptKindTS, ContentMapper: [.z .y.z .identity.y.z .unmapped.y.z]) ---- Original --- -export const identity = 1; ---- Transformed --- -const __VERSION = "1.0.0"; -export const identity = 1; - -//// [/Widget.unmapped.y.z] (ScriptKind: ScriptKindTS, ContentMapper: [.z .y.z .identity.y.z .unmapped.y.z]) ---- Original --- -export const unmapped = 1; ---- Transformed --- -const __VERSION = "1.0.0"; -export const unmapped = 1; - -=== Diagnostics === - - diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.js b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.js deleted file mode 100644 index 0d24af0fb0dc3..0000000000000 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.js +++ /dev/null @@ -1,78 +0,0 @@ -//// [tests/cases/compiler/contentMapperOutputExtensionsOverlap.ts] //// - -//// [package.json] -{ - "name": "mapper", - "version": "1.0.0", - "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"] } } -} - -//// [Widget.z] -const __VERSION = "1.0.0"; -export const short = 1; - -//// [Widget.y.z] -const __VERSION = "1.0.0"; -export const long = 1; - -//// [Widget.identity.y.z] -const __VERSION = "1.0.0"; -export const identity = 1; - -//// [Widget.unmapped.y.z] -const __VERSION = "1.0.0"; -export const unmapped = 1; - -//// [main.ts] -export { short } from "./Widget.z"; -export { long } from "./Widget.y.z"; -export { identity } from "./Widget.identity.y.z"; -export { unmapped } from "./Widget.unmapped.y.z"; -export function literal() { return import("./Widget.y.z"); } -export function dynamic(path: string) { return import(path); } -export const inferred = import("./Widget.y.z"); - - -//// [main.js] -var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx, extraExtensions, ignoreCase) { - if (typeof path === "string" && /^\.\.?\//.test(path)) { - if (extraExtensions) { - for (var extension in extraExtensions) { - var suffix = path.slice(-extension.length); - if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; - } - } - } - 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; -}; -export { short } from "./Widget.js"; -export { long } from "./Widget.mjs"; -export { identity } from "./Widget.identity.y.z"; -export { unmapped } from "./Widget.unmapped.y.z"; -export function literal() { return import("./Widget.mjs"); } -export function dynamic(path) { return import(__rewriteRelativeImportExtension(path, false, { ".identity.y.z": ".identity.y.z", ".unmapped.y.z": ".unmapped.y.z", ".y.z": ".mjs", ".z": ".js" })); } -export const inferred = import("./Widget.mjs"); - - -//// [Widget.d.ts] -export declare const short = 1; -//// [Widget.d.mts] -export declare const long = 1; -//// [Widget.d.identity.y.z.ts] -export declare const identity = 1; -//// [Widget.d.unmapped.y.z.ts] -export declare const unmapped = 1; -//// [main.d.ts] -export { short } from "./Widget.js"; -export { long } from "./Widget.mjs"; -export { identity } from "./Widget.identity.y.z"; -export { unmapped } from "./Widget.unmapped.y.z"; -export declare function literal(): Promise; -export declare function dynamic(path: string): Promise; -export declare const inferred: Promise; diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.symbols b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.symbols deleted file mode 100644 index b187b5a7659e2..0000000000000 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.symbols +++ /dev/null @@ -1,56 +0,0 @@ -//// [tests/cases/compiler/contentMapperOutputExtensionsOverlap.ts] //// - -=== /Widget.z === -const __VERSION = "1.0.0"; ->__VERSION : Symbol(__VERSION, Decl(Widget.z, 0, 5)) - -export const short = 1; ->short : Symbol(short, Decl(Widget.z, 1, 12)) - -=== /Widget.y.z === -const __VERSION = "1.0.0"; ->__VERSION : Symbol(__VERSION, Decl(Widget.y.z, 0, 5)) - -export const long = 1; ->long : Symbol(long, Decl(Widget.y.z, 1, 12)) - -=== /Widget.identity.y.z === -const __VERSION = "1.0.0"; ->__VERSION : Symbol(__VERSION, Decl(Widget.identity.y.z, 0, 5)) - -export const identity = 1; ->identity : Symbol(identity, Decl(Widget.identity.y.z, 1, 12)) - -=== /Widget.unmapped.y.z === -const __VERSION = "1.0.0"; ->__VERSION : Symbol(__VERSION, Decl(Widget.unmapped.y.z, 0, 5)) - -export const unmapped = 1; ->unmapped : Symbol(unmapped, Decl(Widget.unmapped.y.z, 1, 12)) - -=== /main.ts === -export { short } from "./Widget.z"; ->short : Symbol(short, Decl(main.ts, 0, 8)) - -export { long } from "./Widget.y.z"; ->long : Symbol(long, Decl(main.ts, 1, 8)) - -export { identity } from "./Widget.identity.y.z"; ->identity : Symbol(identity, Decl(main.ts, 2, 8)) - -export { unmapped } from "./Widget.unmapped.y.z"; ->unmapped : Symbol(unmapped, Decl(main.ts, 3, 8)) - -export function literal() { return import("./Widget.y.z"); } ->literal : Symbol(literal, Decl(main.ts, 3, 49)) ->"./Widget.y.z" : Symbol("./Widget.y.z", Decl(Widget.y.z, 0, 0)) - -export function dynamic(path: string) { return import(path); } ->dynamic : Symbol(dynamic, Decl(main.ts, 4, 60)) ->path : Symbol(path, Decl(main.ts, 5, 24)) ->path : Symbol(path, Decl(main.ts, 5, 24)) - -export const inferred = import("./Widget.y.z"); ->inferred : Symbol(inferred, Decl(main.ts, 6, 12)) ->"./Widget.y.z" : Symbol("./Widget.y.z", Decl(Widget.y.z, 0, 0)) - diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.types b/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.types deleted file mode 100644 index f758afb5c4380..0000000000000 --- a/tsc/testdata/baselines/reference/compiler/contentMapperOutputExtensionsOverlap.types +++ /dev/null @@ -1,67 +0,0 @@ -//// [tests/cases/compiler/contentMapperOutputExtensionsOverlap.ts] //// - -=== /Widget.z === -const __VERSION = "1.0.0"; ->__VERSION : "1.0.0" ->"1.0.0" : "1.0.0" - -export const short = 1; ->short : 1 ->1 : 1 - -=== /Widget.y.z === -const __VERSION = "1.0.0"; ->__VERSION : "1.0.0" ->"1.0.0" : "1.0.0" - -export const long = 1; ->long : 1 ->1 : 1 - -=== /Widget.identity.y.z === -const __VERSION = "1.0.0"; ->__VERSION : "1.0.0" ->"1.0.0" : "1.0.0" - -export const identity = 1; ->identity : 1 ->1 : 1 - -=== /Widget.unmapped.y.z === -const __VERSION = "1.0.0"; ->__VERSION : "1.0.0" ->"1.0.0" : "1.0.0" - -export const unmapped = 1; ->unmapped : 1 ->1 : 1 - -=== /main.ts === -export { short } from "./Widget.z"; ->short : 1 - -export { long } from "./Widget.y.z"; ->long : 1 - -export { identity } from "./Widget.identity.y.z"; ->identity : 1 - -export { unmapped } from "./Widget.unmapped.y.z"; ->unmapped : 1 - -export function literal() { return import("./Widget.y.z"); } ->literal : () => Promise ->import("./Widget.y.z") : Promise ->"./Widget.y.z" : "./Widget.y.z" - -export function dynamic(path: string) { return import(path); } ->dynamic : (path: string) => Promise ->path : string ->import(path) : Promise ->path : string - -export const inferred = import("./Widget.y.z"); ->inferred : Promise ->import("./Widget.y.z") : Promise ->"./Widget.y.z" : "./Widget.y.z" - diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.contentmapper b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.contentmapper new file mode 100644 index 0000000000000..1708ef2162ad0 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.contentmapper @@ -0,0 +1,17 @@ +//// [/Widget.part.toml] (ScriptKind: ScriptKindTS, ContentMapper: [.toml .vue]) +--- Original --- +export const config = 1; +--- Transformed --- +const __VERSION = "1.0.0"; +export const config = 1; + +//// [/Widget.part.vue] (ScriptKind: ScriptKindTS, ContentMapper: [.toml .vue]) +--- Original --- +export const component = 2; +--- Transformed --- +const __VERSION = "1.0.0"; +export const component = 2; + +=== Diagnostics === + + diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.errors.txt b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.errors.txt new file mode 100644 index 0000000000000..ffa6b426cdc9e --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.errors.txt @@ -0,0 +1,44 @@ +/tsconfig.json(11,41): error TS18125: Content mapper source extension '.part.toml' must contain only one dot. +/tsconfig.json(11,55): error TS18125: Content mapper source extension '.y.z' must contain only one dot. +/tsconfig.json(12,29): error TS18119: Content mapper output extension mapping source '.y.z' is not registered by this content mapper. +/tsconfig.json(12,29): error TS18125: Content mapper source extension '.y.z' must contain only one dot. + + +==== /tsconfig.json (4 errors) ==== + { + "compilerOptions": { + "module": "preserve", + "declaration": true, + "rewriteRelativeImportExtensions": true, + "allowArbitraryExtensions": true, + "outDir": "/dist" + }, + "contentMappers": [{ + "package": "mapper", + "extensions": [".toml", ".vue", ".part.toml", ".y.z"], + ~~~~~~~~~~~~ +!!! error TS18125: Content mapper source extension '.part.toml' must contain only one dot. + ~~~~~~ +!!! error TS18125: Content mapper source extension '.y.z' must contain only one dot. + "outputExtensions": { ".vue": ".part.js", ".y.z": ".js" } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS18119: Content mapper output extension mapping source '.y.z' is not registered by this content mapper. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS18125: Content mapper source extension '.y.z' must contain only one dot. + }] + } + +==== /main.ts (0 errors) ==== + export { config } from "./Widget.part.toml"; + export { component } from "./Widget.part.vue"; + export { blob } from "./blob.toml"; + +==== /blob.d.toml.ts (0 errors) ==== + export declare const blob: number; + +==== /node_modules/mapper/package.json (0 errors) ==== + { + "name": "mapper", + "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"] } } + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.js b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.js new file mode 100644 index 0000000000000..157f14a478a30 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.js @@ -0,0 +1,39 @@ +//// [tests/cases/compiler/contentMapperSingleDotExtensions.ts] //// + +//// [package.json] +{ + "name": "mapper", + "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"] } } +} + +//// [Widget.part.toml] +const __VERSION = "1.0.0"; +export const config = 1; + +//// [Widget.part.vue] +const __VERSION = "1.0.0"; +export const component = 2; + +//// [main.ts] +export { config } from "./Widget.part.toml"; +export { component } from "./Widget.part.vue"; +export { blob } from "./blob.toml"; + +//// [blob.d.toml.ts] +export declare const blob: number; + + +//// [main.js] +export { config } from "./Widget.part.toml"; +export { component } from "./Widget.part.part.js"; +export { blob } from "./blob.toml"; + + +//// [Widget.part.d.toml.ts] +export declare const config = 1; +//// [Widget.part.part.d.ts] +export declare const component = 2; +//// [main.d.ts] +export { config } from "./Widget.part.toml"; +export { component } from "./Widget.part.part.js"; +export { blob } from "./blob.toml"; diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.symbols b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.symbols new file mode 100644 index 0000000000000..52c336712bea0 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.symbols @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/contentMapperSingleDotExtensions.ts] //// + +=== /Widget.part.toml === +const __VERSION = "1.0.0"; +>__VERSION : Symbol(__VERSION, Decl(Widget.part.toml, 0, 5)) + +export const config = 1; +>config : Symbol(config, Decl(Widget.part.toml, 1, 12)) + +=== /Widget.part.vue === +const __VERSION = "1.0.0"; +>__VERSION : Symbol(__VERSION, Decl(Widget.part.vue, 0, 5)) + +export const component = 2; +>component : Symbol(component, Decl(Widget.part.vue, 1, 12)) + +=== /main.ts === +export { config } from "./Widget.part.toml"; +>config : Symbol(config, Decl(main.ts, 0, 8)) + +export { component } from "./Widget.part.vue"; +>component : Symbol(component, Decl(main.ts, 1, 8)) + +export { blob } from "./blob.toml"; +>blob : Symbol(blob, Decl(main.ts, 2, 8)) + +=== /blob.d.toml.ts === +export declare const blob: number; +>blob : Symbol(blob, Decl(blob.d.toml.ts, 0, 20)) + diff --git a/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.types b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.types new file mode 100644 index 0000000000000..636ebf1531537 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/contentMapperSingleDotExtensions.types @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/contentMapperSingleDotExtensions.ts] //// + +=== /Widget.part.toml === +const __VERSION = "1.0.0"; +>__VERSION : "1.0.0" +>"1.0.0" : "1.0.0" + +export const config = 1; +>config : 1 +>1 : 1 + +=== /Widget.part.vue === +const __VERSION = "1.0.0"; +>__VERSION : "1.0.0" +>"1.0.0" : "1.0.0" + +export const component = 2; +>component : 2 +>2 : 2 + +=== /main.ts === +export { config } from "./Widget.part.toml"; +>config : 1 + +export { component } from "./Widget.part.vue"; +>component : 2 + +export { blob } from "./blob.toml"; +>blob : number + +=== /blob.d.toml.ts === +export declare const blob: number; +>blob : number + diff --git a/tsc/testdata/baselines/reference/compiler/rewriteRelativeImportExtensionsDynamicImportCjs.js b/tsc/testdata/baselines/reference/compiler/rewriteRelativeImportExtensionsDynamicImportCjs.js index 8a294aff4eebf..69159673798d6 100644 --- a/tsc/testdata/baselines/reference/compiler/rewriteRelativeImportExtensionsDynamicImportCjs.js +++ b/tsc/testdata/baselines/reference/compiler/rewriteRelativeImportExtensionsDynamicImportCjs.js @@ -29,8 +29,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } diff --git a/tsc/testdata/baselines/reference/conformance/emit(jsx=preserve).js b/tsc/testdata/baselines/reference/conformance/emit(jsx=preserve).js index a3c8b755a428d..7905092d9bac5 100644 --- a/tsc/testdata/baselines/reference/conformance/emit(jsx=preserve).js +++ b/tsc/testdata/baselines/reference/conformance/emit(jsx=preserve).js @@ -62,8 +62,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } @@ -95,8 +94,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } diff --git a/tsc/testdata/baselines/reference/conformance/emit(jsx=react).js b/tsc/testdata/baselines/reference/conformance/emit(jsx=react).js index b23dbd2cad792..cbaddc65b0cf5 100644 --- a/tsc/testdata/baselines/reference/conformance/emit(jsx=react).js +++ b/tsc/testdata/baselines/reference/conformance/emit(jsx=react).js @@ -62,8 +62,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } @@ -95,8 +94,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } diff --git a/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=commonjs).js b/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=commonjs).js index f88f314fe5349..f8326f22ce3ad 100644 --- a/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=commonjs).js +++ b/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=commonjs).js @@ -56,8 +56,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } @@ -114,8 +113,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } diff --git a/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=nodenext).js b/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=nodenext).js index c93a9954b8cd0..942ccf43baef2 100644 --- a/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=nodenext).js +++ b/tsc/testdata/baselines/reference/conformance/emitModuleCommonJS(module=nodenext).js @@ -23,8 +23,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } @@ -48,8 +47,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte for (var extension in extraExtensions) { var suffix = path.slice(-extension.length); if (suffix === extension || ignoreCase && suffix.toLowerCase() === extension.toLowerCase()) { - var output = extraExtensions[extension]; - return output === extension ? path : path.slice(0, -extension.length) + output; + return path.slice(0, -extension.length) + extraExtensions[extension]; } } } diff --git a/tsc/testdata/tests/cases/compiler/contentMapperDeclarationEmit.ts b/tsc/testdata/tests/cases/compiler/contentMapperDeclarationEmit.ts index 073eb8ae03474..fa1bcd433daa0 100644 --- a/tsc/testdata/tests/cases/compiler/contentMapperDeclarationEmit.ts +++ b/tsc/testdata/tests/cases/compiler/contentMapperDeclarationEmit.ts @@ -10,7 +10,7 @@ "declarationMap": true }, "contentMappers": [ - { "package": "mapper", "extensions": [".y.z"] } + { "package": "mapper", "extensions": [".toml"] } ] } @@ -21,10 +21,10 @@ "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"] } } } -// @Filename: /component.y.z +// @Filename: /component.part.toml export interface ComponentProps { emoji: "😀"; label: string; } export declare const component: ComponentProps; export const emittedTarget = #{target}; // @Filename: /main.ts -export { component } from "./component.y.z"; \ No newline at end of file +export { component } from "./component.part.toml"; \ No newline at end of file diff --git a/tsc/testdata/tests/cases/compiler/contentMapperOutputExtensions.ts b/tsc/testdata/tests/cases/compiler/contentMapperOutputExtensions.ts index 5227946832da6..98e881befdff1 100644 --- a/tsc/testdata/tests/cases/compiler/contentMapperOutputExtensions.ts +++ b/tsc/testdata/tests/cases/compiler/contentMapperOutputExtensions.ts @@ -13,7 +13,7 @@ "outDir": "/dist" }, "contentMappers": [ - { "package": "mapper", "extensions": [".astro", ".y.z"] } + { "package": "mapper", "extensions": [".astro", ".vue"] } ] } @@ -24,7 +24,7 @@ "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"], - "outputExtensions": { ".astro": ".js", ".y.z": ".mjs" } + "outputExtensions": { ".astro": ".js", ".vue": ".mjs" } } } } @@ -33,7 +33,7 @@ export interface CardProps { title: string } export declare const Card: (props: CardProps) => string; -// @Filename: /Widget.y.z +// @Filename: /Widget.part.vue export declare const Widget: () => string; // @Filename: /typed.ts @@ -43,12 +43,12 @@ export const annotated: import("./Card.astro").CardProps = { title: "" }; import { annotated } from "./typed"; export { Card } from "./Card.astro"; export type { CardProps } from "./Card.astro"; -export { Widget } from "./Widget.y.z"; +export { Widget } from "./Widget.part.vue"; const path = "./Card.astro"; void import(path); export async function load() { return import("./Card.astro"); } -export const inferred = import("./Widget.y.z"); +export const inferred = import("./Widget.part.vue"); export const nested = { load: () => import("./Card.astro") }; export const copied = [annotated]; diff --git a/tsc/testdata/tests/cases/compiler/contentMapperOutputExtensionsOverlap.ts b/tsc/testdata/tests/cases/compiler/contentMapperOutputExtensionsOverlap.ts deleted file mode 100644 index 8b5f08bc2c68d..0000000000000 --- a/tsc/testdata/tests/cases/compiler/contentMapperOutputExtensionsOverlap.ts +++ /dev/null @@ -1,50 +0,0 @@ -// @runExternalCode: true - -// @Filename: /tsconfig.json -{ - "compilerOptions": { - "target": "esnext", - "module": "preserve", - "rewriteRelativeImportExtensions": true, - "declaration": true, - "rootDir": "/", - "outDir": "/dist" - }, - "contentMappers": [{ - "package": "mapper", - "extensions": [".z", ".y.z", ".identity.y.z", ".unmapped.y.z"], - "outputExtensions": { - ".z": ".js", - ".y.z": ".mjs", - ".identity.y.z": ".identity.y.z" - } - }] -} - -// @Filename: /node_modules/mapper/package.json -{ - "name": "mapper", - "version": "1.0.0", - "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"] } } -} - -// @Filename: /Widget.z -export const short = 1; - -// @Filename: /Widget.y.z -export const long = 1; - -// @Filename: /Widget.identity.y.z -export const identity = 1; - -// @Filename: /Widget.unmapped.y.z -export const unmapped = 1; - -// @Filename: /main.ts -export { short } from "./Widget.z"; -export { long } from "./Widget.y.z"; -export { identity } from "./Widget.identity.y.z"; -export { unmapped } from "./Widget.unmapped.y.z"; -export function literal() { return import("./Widget.y.z"); } -export function dynamic(path: string) { return import(path); } -export const inferred = import("./Widget.y.z"); diff --git a/tsc/testdata/tests/cases/compiler/contentMapperSingleDotExtensions.ts b/tsc/testdata/tests/cases/compiler/contentMapperSingleDotExtensions.ts new file mode 100644 index 0000000000000..29d72e16f0f0d --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/contentMapperSingleDotExtensions.ts @@ -0,0 +1,37 @@ +// @runExternalCode: true + +// @Filename: /tsconfig.json +{ + "compilerOptions": { + "module": "preserve", + "declaration": true, + "rewriteRelativeImportExtensions": true, + "allowArbitraryExtensions": true, + "outDir": "/dist" + }, + "contentMappers": [{ + "package": "mapper", + "extensions": [".toml", ".vue", ".part.toml", ".y.z"], + "outputExtensions": { ".vue": ".part.js", ".y.z": ".js" } + }] +} + +// @Filename: /node_modules/mapper/package.json +{ + "name": "mapper", + "typescript": { "contentMapper": { "exec": ["compiler-test-mapper"] } } +} + +// @Filename: /Widget.part.toml +export const config = 1; + +// @Filename: /Widget.part.vue +export const component = 2; + +// @Filename: /main.ts +export { config } from "./Widget.part.toml"; +export { component } from "./Widget.part.vue"; +export { blob } from "./blob.toml"; + +// @Filename: /blob.d.toml.ts +export declare const blob: number;