Skip to content

Commit ad341f4

Browse files
authored
Fix empty wildcard match on exports (#2264)
1 parent ed79f5d commit ad341f4

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

internal/modulespecifiers/specifiers.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,23 +1207,23 @@ func tryGetModuleNameFromExportsOrImports(
12071207
case MatchingModePattern:
12081208
leadingSlice, trailingSlice, _ := strings.Cut(pathOrPattern, "*")
12091209
caseSensitive := host.UseCaseSensitiveFileNames()
1210-
if canTryTsExtension && stringutil.HasPrefix(targetFilePath, leadingSlice, caseSensitive) && stringutil.HasSuffix(targetFilePath, trailingSlice, caseSensitive) {
1210+
if canTryTsExtension && stringutil.HasPrefixAndSuffixWithoutOverlap(targetFilePath, leadingSlice, trailingSlice, caseSensitive) {
12111211
starReplacement := targetFilePath[len(leadingSlice) : len(targetFilePath)-len(trailingSlice)]
12121212
return replaceFirstStar(packageName, starReplacement)
12131213
}
1214-
if len(extensionSwappedTarget) > 0 && stringutil.HasPrefix(extensionSwappedTarget, leadingSlice, caseSensitive) && stringutil.HasSuffix(extensionSwappedTarget, trailingSlice, caseSensitive) {
1214+
if len(extensionSwappedTarget) > 0 && stringutil.HasPrefixAndSuffixWithoutOverlap(extensionSwappedTarget, leadingSlice, trailingSlice, caseSensitive) {
12151215
starReplacement := extensionSwappedTarget[len(leadingSlice) : len(extensionSwappedTarget)-len(trailingSlice)]
12161216
return replaceFirstStar(packageName, starReplacement)
12171217
}
1218-
if !canTryTsExtension && stringutil.HasPrefix(targetFilePath, leadingSlice, caseSensitive) && stringutil.HasSuffix(targetFilePath, trailingSlice, caseSensitive) {
1218+
if !canTryTsExtension && stringutil.HasPrefixAndSuffixWithoutOverlap(targetFilePath, leadingSlice, trailingSlice, caseSensitive) {
12191219
starReplacement := targetFilePath[len(leadingSlice) : len(targetFilePath)-len(trailingSlice)]
12201220
return replaceFirstStar(packageName, starReplacement)
12211221
}
1222-
if len(outputFile) > 0 && stringutil.HasPrefix(outputFile, leadingSlice, caseSensitive) && stringutil.HasSuffix(outputFile, trailingSlice, caseSensitive) {
1222+
if len(outputFile) > 0 && stringutil.HasPrefixAndSuffixWithoutOverlap(outputFile, leadingSlice, trailingSlice, caseSensitive) {
12231223
starReplacement := outputFile[len(leadingSlice) : len(outputFile)-len(trailingSlice)]
12241224
return replaceFirstStar(packageName, starReplacement)
12251225
}
1226-
if len(declarationFile) > 0 && stringutil.HasPrefix(declarationFile, leadingSlice, caseSensitive) && stringutil.HasSuffix(declarationFile, trailingSlice, caseSensitive) {
1226+
if len(declarationFile) > 0 && stringutil.HasPrefixAndSuffixWithoutOverlap(declarationFile, leadingSlice, trailingSlice, caseSensitive) {
12271227
starReplacement := declarationFile[len(leadingSlice) : len(declarationFile)-len(trailingSlice)]
12281228
substituted := replaceFirstStar(packageName, starReplacement)
12291229
jsExtension := tryGetJSExtensionForFile(declarationFile, options)

internal/modulespecifiers/specifiers_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,53 @@ func TestContainsIgnoredPath(t *testing.T) {
256256
})
257257
}
258258
}
259+
260+
func TestTryGetModuleNameFromExportsOrImports(t *testing.T) {
261+
t.Parallel()
262+
t.Run("with exports pattern", func(t *testing.T) {
263+
t.Parallel()
264+
265+
tests := []struct {
266+
name string
267+
targetFilePath string
268+
expected string
269+
}{
270+
{
271+
name: "match",
272+
targetFilePath: "/pkg/src/things/thing1/index.ts",
273+
expected: "./src/things/thing1",
274+
},
275+
{
276+
name: "mismatch with matching leading and trailing strings",
277+
targetFilePath: "/pkg/src/things/index.ts",
278+
expected: "",
279+
},
280+
}
281+
282+
for _, tt := range tests {
283+
t.Run(tt.name, func(t *testing.T) {
284+
t.Parallel()
285+
result := tryGetModuleNameFromExportsOrImports(
286+
&core.CompilerOptions{},
287+
&mockModuleSpecifierGenerationHost{},
288+
tt.targetFilePath,
289+
"/pkg",
290+
"./src/things/*",
291+
packagejson.ExportsOrImports{
292+
JSONValue: packagejson.JSONValue{
293+
Type: packagejson.JSONValueTypeString,
294+
Value: "./src/things/*/index.js",
295+
},
296+
},
297+
[]string{},
298+
MatchingModePattern,
299+
false,
300+
false,
301+
)
302+
if result != tt.expected {
303+
t.Errorf("tryGetModuleNameFromExportsOrImports(targetFilePath = %q) = %v, expected %v", tt.targetFilePath, result, tt.expected)
304+
}
305+
})
306+
}
307+
})
308+
}

internal/stringutil/compare.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ func HasSuffix(s string, suffix string, caseSensitive bool) bool {
9191
return strings.EqualFold(s[len(s)-len(suffix):], suffix)
9292
}
9393

94+
func HasPrefixAndSuffixWithoutOverlap(s string, prefix string, suffix string, caseSensitive bool) bool {
95+
if len(prefix)+len(suffix) > len(s) {
96+
return false
97+
}
98+
99+
return HasPrefix(s, prefix, caseSensitive) && HasSuffix(s, suffix, caseSensitive)
100+
}
101+
94102
func CompareStringsCaseInsensitiveThenSensitive(a, b string) Comparison {
95103
cmp := CompareStringsCaseInsensitive(a, b)
96104
if cmp != ComparisonEqual {

0 commit comments

Comments
 (0)