Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ type Program interface {
GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData
GetJSXRuntimeImportSpecifier(path tspath.Path) (moduleReference string, specifier *ast.Node)
GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node
SourceFileMayBeEmitted(sourceFile *ast.SourceFile, forceDtsEmit bool) bool
IsSourceFromProjectReference(path tspath.Path) bool
GetSourceAndProjectReference(path tspath.Path) *tsoptions.SourceAndProjectReference
}
Expand Down Expand Up @@ -14498,6 +14499,34 @@ func (c *Checker) resolveExternalModule(location *ast.Node, moduleReference stri
tsExtension,
)
}
} else if c.compilerOptions.RewriteRelativeImportExtensions.IsTrue() &&
location.Flags&ast.NodeFlagsAmbient == 0 &&
!tspath.IsDeclarationFileName(moduleReference) &&
!ast.IsLiteralImportTypeNode(location) &&
!ast.IsPartOfTypeOnlyImportOrExportDeclaration(location) {
shouldRewrite := core.ShouldRewriteModuleSpecifier(moduleReference, c.compilerOptions)
if !resolvedModule.ResolvedUsingTsExtension && shouldRewrite {
relativeToSourceFile := tspath.GetRelativePathFromFile(
tspath.GetNormalizedAbsolutePath(importingSourceFile.FileName(), c.program.GetCurrentDirectory()),
resolvedModule.ResolvedFileName,
tspath.ComparePathsOptions{
UseCaseSensitiveFileNames: c.program.UseCaseSensitiveFileNames(),
CurrentDirectory: c.program.GetCurrentDirectory(),
},
)
c.error(
errorNode,
diagnostics.This_relative_import_path_is_unsafe_to_rewrite_because_it_looks_like_a_file_name_but_actually_resolves_to_0,
relativeToSourceFile,
)
} else if resolvedModule.ResolvedUsingTsExtension && !shouldRewrite && c.program.SourceFileMayBeEmitted(sourceFile, false) {
c.error(
errorNode,
diagnostics.This_import_uses_a_0_extension_to_resolve_to_an_input_TypeScript_file_but_will_not_be_rewritten_during_emit_because_it_is_not_a_relative_path,
tspath.GetAnyExtensionFromPath(moduleReference, nil, false),
)
}
// TODO: Add project reference check when GetResolvedProjectReferenceToRedirect is implemented
}
}

Expand Down
4 changes: 4 additions & 0 deletions internal/compiler/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,10 @@ func (p *Program) GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node {
return p.importHelpersImportSpecifiers[path]
}

func (p *Program) SourceFileMayBeEmitted(sourceFile *ast.SourceFile, forceDtsEmit bool) bool {
return sourceFileMayBeEmitted(sourceFile, &emitHost{program: p}, forceDtsEmit)
}

var plainJSErrors = collections.NewSetFromItems(
// binder errors
diagnostics.Cannot_redeclare_block_scoped_variable_0.Code(),
Expand Down
4 changes: 4 additions & 0 deletions internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -559,3 +559,7 @@ func IndexAfter(s string, pattern string, startIndex int) int {
return matched + startIndex
}
}

func ShouldRewriteModuleSpecifier(specifier string, compilerOptions *CompilerOptions) bool {
return compilerOptions.RewriteRelativeImportExtensions.IsTrue() && tspath.PathIsRelative(specifier) && !tspath.IsDeclarationFileName(specifier) && tspath.HasTSFileExtension(specifier)
}
2 changes: 2 additions & 0 deletions internal/outputpaths/outputpaths.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,5 @@ func getDeclarationEmitExtensionForPath(fileName string) string {
}
return tspath.ExtensionDts
}


6 changes: 1 addition & 5 deletions internal/transformers/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func tryRenameExternalModule(factory *printer.NodeFactory, moduleName *ast.Liter
}

func rewriteModuleSpecifier(emitContext *printer.EmitContext, node *ast.Expression, compilerOptions *core.CompilerOptions) *ast.Expression {
if node == nil || !ast.IsStringLiteral(node) || !shouldRewriteModuleSpecifier(node.Text(), compilerOptions) {
if node == nil || !ast.IsStringLiteral(node) || !core.ShouldRewriteModuleSpecifier(node.Text(), compilerOptions) {
return node
}
updatedText := tspath.ChangeExtension(node.Text(), outputpaths.GetOutputExtension(node.Text(), compilerOptions.Jsx))
Expand All @@ -350,10 +350,6 @@ func rewriteModuleSpecifier(emitContext *printer.EmitContext, node *ast.Expressi
return node
}

func shouldRewriteModuleSpecifier(specifier string, compilerOptions *core.CompilerOptions) bool {
return compilerOptions.RewriteRelativeImportExtensions.IsTrue() && tspath.PathIsRelative(specifier) && !tspath.IsDeclarationFileName(specifier) && tspath.HasTSFileExtension(specifier)
}

func singleOrMany(nodes []*ast.Node, factory *printer.NodeFactory) *ast.Node {
if len(nodes) == 1 {
return nodes[0]
Expand Down
4 changes: 2 additions & 2 deletions internal/tsoptions/declscompiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -810,8 +810,8 @@ var commonOptionsWithBuild = []*CommandLineOption{
AffectsSemanticDiagnostics: true,
AffectsBuildInfo: true,
Category: diagnostics.Modules,
// description: diagnostics.Rewrite_ts_tsx_mts_and_cts_file_extensions_in_relative_import_paths_to_their_JavaScript_equivalent_in_output_files,
DefaultValueDescription: false,
Description: diagnostics.Rewrite_ts_tsx_mts_and_cts_file_extensions_in_relative_import_paths_to_their_JavaScript_equivalent_in_output_files,
DefaultValueDescription: false,
},
{
Name: "resolvePackageJsonExports",
Expand Down
13 changes: 13 additions & 0 deletions internal/tspath/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,10 @@ func GetRelativePathFromDirectory(fromDirectory string, to string, options Compa
return GetPathFromPathComponents(pathComponents)
}

func GetRelativePathFromFile(from string, to string, options ComparePathsOptions) string {
return EnsurePathIsNonModuleName(GetRelativePathFromDirectory(GetDirectoryPath(from), to, options))
}

func ConvertToRelativePath(absoluteOrRelativePath string, options ComparePathsOptions) string {
if !IsRootedDiskPath(absoluteOrRelativePath) {
return absoluteOrRelativePath
Expand Down Expand Up @@ -768,6 +772,15 @@ func PathIsRelative(path string) bool {
return false
}

// EnsurePathIsNonModuleName ensures a path is either absolute (prefixed with `/` or `c:`) or dot-relative (prefixed
// with `./` or `../`) so as not to be confused with an unprefixed module name.
func EnsurePathIsNonModuleName(path string) string {
if !PathIsAbsolute(path) && !PathIsRelative(path) {
return "./" + path
}
return path
}

func IsExternalModuleNameRelative(moduleName string) bool {
// TypeScript 1.0 spec (April 2014): 11.2.1
// An external module name is "relative" if the first term is "." or "..".
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
index.ts(1,22): error TS2876: This relative import path is unsafe to rewrite because it looks like a file name, but actually resolves to "./foo.ts/index.ts".


==== index.ts (1 errors) ====
import foo = require("./foo.ts"); // Error
~~~~~~~~~~
!!! error TS2876: This relative import path is unsafe to rewrite because it looks like a file name, but actually resolves to "./foo.ts/index.ts".
import type _foo = require("./foo.ts"); // Ok

==== foo.ts/index.ts (0 errors) ====
export = {};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
index.ts(1,22): error TS2876: This relative import path is unsafe to rewrite because it looks like a file name, but actually resolves to "./foo.ts/index.ts".


==== index.ts (1 errors) ====
import foo = require("./foo.ts"); // Error
~~~~~~~~~~
!!! error TS2876: This relative import path is unsafe to rewrite because it looks like a file name, but actually resolves to "./foo.ts/index.ts".
import type _foo = require("./foo.ts"); // Ok

==== foo.ts/index.ts (0 errors) ====
export = {};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/index.ts(2,16): error TS2877: This import uses a '.ts' extension to resolve to an input TypeScript file, but will not be rewritten during emit because it is not a relative path.


==== /package.json (0 errors) ====
{
"name": "pkg",
"type": "module",
"imports": {
"#foo.ts": "./foo.ts",
"#internal/*": "./internal/*"
},
"exports": {
"./*.ts": {
"source": "./*.ts",
"default": "./*.js"
}
}
}

==== /foo.ts (0 errors) ====
export {};

==== /internal/foo.ts (0 errors) ====
export {};

==== /index.ts (1 errors) ====
import {} from "#foo.ts"; // Ok
import {} from "#internal/foo.ts"; // Error
~~~~~~~~~~~~~~~~~~
!!! error TS2877: This import uses a '.ts' extension to resolve to an input TypeScript file, but will not be rewritten during emit because it is not a relative path.
import {} from "pkg/foo.ts"; // Ok

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/index.ts(2,16): error TS2877: This import uses a '.ts' extension to resolve to an input TypeScript file, but will not be rewritten during emit because it is not a relative path.


==== /package.json (0 errors) ====
{
"name": "pkg",
"type": "module",
"imports": {
"#foo.ts": "./foo.ts",
"#internal/*": "./internal/*"
},
"exports": {
"./*.ts": {
"source": "./*.ts",
"default": "./*.js"
}
}
}

==== /foo.ts (0 errors) ====
export {};

==== /internal/foo.ts (0 errors) ====
export {};

==== /index.ts (1 errors) ====
import {} from "#foo.ts"; // Ok
import {} from "#internal/foo.ts"; // Error
~~~~~~~~~~~~~~~~~~
!!! error TS2877: This import uses a '.ts' extension to resolve to an input TypeScript file, but will not be rewritten during emit because it is not a relative path.
import {} from "pkg/foo.ts"; // Ok

This file was deleted.

Loading