ttsc 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/ttsc/api_compile.go +106 -116
- package/cmd/ttsc/api_transform.go +54 -51
- package/cmd/ttsc/main.go +103 -121
- package/driver/program.go +7 -1
- package/go.mod +2 -0
- package/lib/compiler/internal/compileProjectInMemory.js +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.js +110 -16
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.js +21 -1
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscPlugin.d.ts +10 -0
- package/lib/structures/ITtscPlugin.js.map +1 -1
- package/package.json +9 -9
- package/shim/ast/lint.go +2 -5
- package/shim/ast/surface.go +685 -0
- package/shim/printer/go.mod +5 -0
- package/shim/printer/shim.go +23 -0
- package/src/compiler/internal/compileProjectInMemory.ts +1 -1
- package/src/compiler/internal/transformProjectInMemory.ts +1 -1
- package/src/plugin/internal/buildSourcePlugin.ts +195 -19
- package/src/plugin/internal/loadProjectPlugins.ts +34 -1
- package/src/structures/ITtscPlugin.ts +11 -0
- package/utility/host.go +12 -2
- package/cmd/ttsc/main_test.go +0 -288
- package/driver/rewrite_test.go +0 -52
- package/utility/host_test.go +0 -162
package/cmd/ttsc/main_test.go
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"bytes"
|
|
5
|
-
"os"
|
|
6
|
-
"path/filepath"
|
|
7
|
-
"strings"
|
|
8
|
-
"testing"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
// withCapture replaces stdout/stderr with buffers for the duration of fn.
|
|
12
|
-
// Keeps each test hermetic.
|
|
13
|
-
func withCapture(fn func()) (out, errOut string) {
|
|
14
|
-
var outBuf, errBuf bytes.Buffer
|
|
15
|
-
prevOut, prevErr := stdout, stderr
|
|
16
|
-
stdout = &outBuf
|
|
17
|
-
stderr = &errBuf
|
|
18
|
-
defer func() {
|
|
19
|
-
stdout = prevOut
|
|
20
|
-
stderr = prevErr
|
|
21
|
-
}()
|
|
22
|
-
fn()
|
|
23
|
-
return outBuf.String(), errBuf.String()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
func TestRunNoArgsAttemptsProjectBuild(t *testing.T) {
|
|
27
|
-
out, errOut := withCapture(func() {
|
|
28
|
-
if code := run(nil); code == 0 {
|
|
29
|
-
t.Errorf("expected no-args run without a local tsconfig to fail")
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
if strings.Contains(out, "Usage:") {
|
|
33
|
-
t.Errorf("no-args ttsc must build the project, not print help; got %q", out)
|
|
34
|
-
}
|
|
35
|
-
if !strings.Contains(errOut, "tsconfig") {
|
|
36
|
-
t.Errorf("expected no-args build to look for tsconfig, got stderr %q", errOut)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
func TestRunHelpVariants(t *testing.T) {
|
|
41
|
-
for _, flag := range []string{"-h", "--help", "help"} {
|
|
42
|
-
t.Run(flag, func(t *testing.T) {
|
|
43
|
-
out, _ := withCapture(func() {
|
|
44
|
-
if code := run([]string{flag}); code != 0 {
|
|
45
|
-
t.Errorf("expected exit 0, got %d", code)
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
if !strings.Contains(out, "demo") {
|
|
49
|
-
t.Errorf("help text should list demo subcommand, got %q", out)
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
func TestRunVersion(t *testing.T) {
|
|
56
|
-
for _, flag := range []string{"-v", "--version", "version"} {
|
|
57
|
-
t.Run(flag, func(t *testing.T) {
|
|
58
|
-
out, _ := withCapture(func() {
|
|
59
|
-
if code := run([]string{flag}); code != 0 {
|
|
60
|
-
t.Errorf("expected exit 0, got %d", code)
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
if !strings.Contains(out, "ttsc ") {
|
|
64
|
-
t.Errorf("expected version banner, got %q", out)
|
|
65
|
-
}
|
|
66
|
-
// Include useful debug bits
|
|
67
|
-
for _, tag := range []string{"commit", "go"} {
|
|
68
|
-
if !strings.Contains(out, tag) {
|
|
69
|
-
t.Errorf("expected %q substring in version output, got %q", tag, out)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
func TestRunUnknownCommandExits2(t *testing.T) {
|
|
77
|
-
_, errOut := withCapture(func() {
|
|
78
|
-
if code := run([]string{"fly-to-mars"}); code != 2 {
|
|
79
|
-
t.Errorf("expected exit 2, got %d", code)
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
if !strings.Contains(errOut, "unknown command") {
|
|
83
|
-
t.Errorf("expected error text, got %q", errOut)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
func TestRunBuildBlocksSemanticDiagnosticsBeforeEmit(t *testing.T) {
|
|
88
|
-
root := t.TempDir()
|
|
89
|
-
writeProjectFile(t, root, "tsconfig.json", `{
|
|
90
|
-
"compilerOptions": {
|
|
91
|
-
"module": "commonjs",
|
|
92
|
-
"target": "es2020",
|
|
93
|
-
"outDir": "bin",
|
|
94
|
-
"strict": true
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
`)
|
|
98
|
-
writeProjectFile(t, root, "index.ts", `const value: string = 123;
|
|
99
|
-
console.log(value);
|
|
100
|
-
`)
|
|
101
|
-
|
|
102
|
-
_, errOut := withCapture(func() {
|
|
103
|
-
if code := runBuild([]string{"--cwd", root, "--emit"}); code != 2 {
|
|
104
|
-
t.Errorf("expected exit 2, got %d", code)
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
if !strings.Contains(errOut, "Type 'number' is not assignable to type 'string'") {
|
|
108
|
-
t.Errorf("expected semantic diagnostic, got %q", errOut)
|
|
109
|
-
}
|
|
110
|
-
if !strings.Contains(errOut, "\x1b[91merror\x1b[0m") || !strings.Contains(errOut, "TS2322") {
|
|
111
|
-
t.Errorf("expected colored TypeScript-style diagnostic header, got %q", errOut)
|
|
112
|
-
}
|
|
113
|
-
if !strings.Contains(errOut, "\x1b[7m1\x1b[0m") || !strings.Contains(errOut, "~~~~~") {
|
|
114
|
-
t.Errorf("expected source context with highlighted span, got %q", errOut)
|
|
115
|
-
}
|
|
116
|
-
if _, err := os.Stat(filepath.Join(root, "bin", "index.js")); !os.IsNotExist(err) {
|
|
117
|
-
t.Errorf("expected no emitted JS, stat err=%v", err)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
func TestRunBuildAllowsUnusedTypeParametersOnOverloadSignatures(t *testing.T) {
|
|
122
|
-
root := t.TempDir()
|
|
123
|
-
writeProjectFile(t, root, "tsconfig.json", `{
|
|
124
|
-
"compilerOptions": {
|
|
125
|
-
"module": "commonjs",
|
|
126
|
-
"target": "es2020",
|
|
127
|
-
"outDir": "bin",
|
|
128
|
-
"strict": true,
|
|
129
|
-
"noUnusedLocals": true,
|
|
130
|
-
"noUnusedParameters": true
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
`)
|
|
134
|
-
writeProjectFile(t, root, "index.ts", `export function marker<T>(input: unknown): string;
|
|
135
|
-
export function marker(input: unknown): string {
|
|
136
|
-
return String(input);
|
|
137
|
-
}
|
|
138
|
-
`)
|
|
139
|
-
|
|
140
|
-
_, errOut := withCapture(func() {
|
|
141
|
-
if code := runBuild([]string{"--cwd", root, "--emit", "--quiet"}); code != 0 {
|
|
142
|
-
t.Errorf("expected exit 0, got %d", code)
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
if strings.Contains(errOut, "declared but never used") || strings.Contains(errOut, "All type parameters are unused") {
|
|
146
|
-
t.Errorf("overload signature type parameters must not fail noUnused checks, got %q", errOut)
|
|
147
|
-
}
|
|
148
|
-
if _, err := os.Stat(filepath.Join(root, "bin", "index.js")); err != nil {
|
|
149
|
-
t.Errorf("expected emitted JS, stat err=%v", err)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
func TestRunBuildBlocksUnusedParametersBeforeEmit(t *testing.T) {
|
|
154
|
-
root := t.TempDir()
|
|
155
|
-
writeProjectFile(t, root, "tsconfig.json", `{
|
|
156
|
-
"compilerOptions": {
|
|
157
|
-
"module": "commonjs",
|
|
158
|
-
"target": "es2020",
|
|
159
|
-
"outDir": "bin",
|
|
160
|
-
"strict": true,
|
|
161
|
-
"noUnusedParameters": true
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
`)
|
|
165
|
-
writeProjectFile(t, root, "index.ts", `export function run(unused: string): number {
|
|
166
|
-
return 1;
|
|
167
|
-
}
|
|
168
|
-
`)
|
|
169
|
-
|
|
170
|
-
_, errOut := withCapture(func() {
|
|
171
|
-
if code := runBuild([]string{"--cwd", root, "--emit"}); code != 2 {
|
|
172
|
-
t.Errorf("expected exit 2, got %d", code)
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
if !strings.Contains(errOut, "'unused' is declared but its value is never read") &&
|
|
176
|
-
!strings.Contains(errOut, "'unused' is declared but never used") {
|
|
177
|
-
t.Errorf("expected unused parameter diagnostic, got %q", errOut)
|
|
178
|
-
}
|
|
179
|
-
if _, err := os.Stat(filepath.Join(root, "bin", "index.js")); !os.IsNotExist(err) {
|
|
180
|
-
t.Errorf("expected no emitted JS, stat err=%v", err)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
func TestRunBuildBlocksSyntacticDiagnosticsBeforeEmit(t *testing.T) {
|
|
185
|
-
root := t.TempDir()
|
|
186
|
-
writeProjectFile(t, root, "tsconfig.json", `{
|
|
187
|
-
"compilerOptions": {
|
|
188
|
-
"module": "commonjs",
|
|
189
|
-
"target": "es2020",
|
|
190
|
-
"outDir": "bin"
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
`)
|
|
194
|
-
writeProjectFile(t, root, "index.ts", `console.log("before");
|
|
195
|
-
const = ;
|
|
196
|
-
`)
|
|
197
|
-
|
|
198
|
-
_, errOut := withCapture(func() {
|
|
199
|
-
if code := runBuild([]string{"--cwd", root, "--emit"}); code != 2 {
|
|
200
|
-
t.Errorf("expected exit 2, got %d", code)
|
|
201
|
-
}
|
|
202
|
-
})
|
|
203
|
-
if !strings.Contains(errOut, "Variable declaration expected") {
|
|
204
|
-
t.Errorf("expected syntactic diagnostic, got %q", errOut)
|
|
205
|
-
}
|
|
206
|
-
if _, err := os.Stat(filepath.Join(root, "bin", "index.js")); !os.IsNotExist(err) {
|
|
207
|
-
t.Errorf("expected no emitted JS, stat err=%v", err)
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
func writeProjectFile(t *testing.T, root string, name string, contents string) {
|
|
212
|
-
t.Helper()
|
|
213
|
-
file := filepath.Join(root, name)
|
|
214
|
-
if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil {
|
|
215
|
-
t.Fatal(err)
|
|
216
|
-
}
|
|
217
|
-
if err := os.WriteFile(file, []byte(contents), 0o644); err != nil {
|
|
218
|
-
t.Fatal(err)
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
func TestRunDemoString(t *testing.T) {
|
|
223
|
-
out, _ := withCapture(func() {
|
|
224
|
-
if code := run([]string{"demo", "--type=string"}); code != 0 {
|
|
225
|
-
t.Errorf("expected exit 0, got %d", code)
|
|
226
|
-
}
|
|
227
|
-
})
|
|
228
|
-
want := `(input) => "string" === typeof input`
|
|
229
|
-
if !strings.Contains(out, want) {
|
|
230
|
-
t.Errorf("expected demo output to contain %q, got:\n%s", want, out)
|
|
231
|
-
}
|
|
232
|
-
if !strings.Contains(out, "demo<string>") {
|
|
233
|
-
t.Errorf("expected comment prefix in demo output, got:\n%s", out)
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
func TestRunDemoEveryAtomic(t *testing.T) {
|
|
238
|
-
cases := map[string]string{
|
|
239
|
-
"boolean": `"boolean" === typeof input`,
|
|
240
|
-
"number": `"number" === typeof input`,
|
|
241
|
-
"bigint": `"bigint" === typeof input`,
|
|
242
|
-
"any": `(input) => true`,
|
|
243
|
-
}
|
|
244
|
-
for typ, expected := range cases {
|
|
245
|
-
t.Run(typ, func(t *testing.T) {
|
|
246
|
-
out, _ := withCapture(func() {
|
|
247
|
-
if code := run([]string{"demo", "--type=" + typ}); code != 0 {
|
|
248
|
-
t.Errorf("expected exit 0 for %s, got %d", typ, code)
|
|
249
|
-
}
|
|
250
|
-
})
|
|
251
|
-
if !strings.Contains(out, expected) {
|
|
252
|
-
t.Errorf("for --type=%s, want %q in output:\n%s", typ, expected, out)
|
|
253
|
-
}
|
|
254
|
-
})
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
func TestRunDemoUnknownTypeExits2(t *testing.T) {
|
|
259
|
-
_, errOut := withCapture(func() {
|
|
260
|
-
if code := run([]string{"demo", "--type=object"}); code != 2 {
|
|
261
|
-
t.Errorf("expected exit 2 for unknown type, got %d", code)
|
|
262
|
-
}
|
|
263
|
-
})
|
|
264
|
-
if !strings.Contains(errOut, "unknown --type") {
|
|
265
|
-
t.Errorf("expected diagnostic text, got %q", errOut)
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
func TestDemoArrowEveryAtomic(t *testing.T) {
|
|
270
|
-
cases := map[string]string{
|
|
271
|
-
"string": `"string" === typeof input`,
|
|
272
|
-
"number": `"number" === typeof input`,
|
|
273
|
-
"boolean": `"boolean" === typeof input`,
|
|
274
|
-
"bigint": `"bigint" === typeof input`,
|
|
275
|
-
"any": `(input) => true`,
|
|
276
|
-
}
|
|
277
|
-
for name, want := range cases {
|
|
278
|
-
t.Run(name, func(t *testing.T) {
|
|
279
|
-
arrow, err := demoArrow(name)
|
|
280
|
-
if err != nil {
|
|
281
|
-
t.Fatalf("unexpected err: %v", err)
|
|
282
|
-
}
|
|
283
|
-
if !strings.Contains(arrow, want) {
|
|
284
|
-
t.Errorf("for %s want %q, got %q", name, want, arrow)
|
|
285
|
-
}
|
|
286
|
-
})
|
|
287
|
-
}
|
|
288
|
-
}
|
package/driver/rewrite_test.go
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
package driver
|
|
2
|
-
|
|
3
|
-
import "testing"
|
|
4
|
-
|
|
5
|
-
func TestSpliceCallConsumesRegexLiteralWithClosingParen(t *testing.T) {
|
|
6
|
-
got := spliceForTest(t, `const out = plugin.make(/\)/, "ok");`)
|
|
7
|
-
want := `const out = replacement;`
|
|
8
|
-
if got != want {
|
|
9
|
-
t.Fatalf("unexpected rewrite:\nwant: %s\n got: %s", want, got)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
func TestSpliceCallIgnoresClosingParenInsideBlockComment(t *testing.T) {
|
|
14
|
-
got := spliceForTest(t, `const out = plugin.make(1 /* ) */, 2);`)
|
|
15
|
-
want := `const out = replacement;`
|
|
16
|
-
if got != want {
|
|
17
|
-
t.Fatalf("unexpected rewrite:\nwant: %s\n got: %s", want, got)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
func TestSpliceCallIgnoresClosingParenInsideLineComment(t *testing.T) {
|
|
22
|
-
got := spliceForTest(t, "const out = plugin.make(\n 1, // )\n 2\n);")
|
|
23
|
-
want := `const out = replacement;`
|
|
24
|
-
if got != want {
|
|
25
|
-
t.Fatalf("unexpected rewrite:\nwant: %s\n got: %s", want, got)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
func TestSpliceCallKeepsDivisionOutsideRegexMode(t *testing.T) {
|
|
30
|
-
got := spliceForTest(t, `const out = plugin.make(total / divisor, 2);`)
|
|
31
|
-
want := `const out = replacement;`
|
|
32
|
-
if got != want {
|
|
33
|
-
t.Fatalf("unexpected rewrite:\nwant: %s\n got: %s", want, got)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
func spliceForTest(t *testing.T, text string) string {
|
|
38
|
-
t.Helper()
|
|
39
|
-
got, _, ok, err := spliceCall(text, Rewrite{
|
|
40
|
-
RootName: "plugin",
|
|
41
|
-
Method: "make",
|
|
42
|
-
Replacement: "replacement",
|
|
43
|
-
ConsumeParens: true,
|
|
44
|
-
}, 0)
|
|
45
|
-
if err != nil {
|
|
46
|
-
t.Fatal(err)
|
|
47
|
-
}
|
|
48
|
-
if !ok {
|
|
49
|
-
t.Fatal("rewrite did not match")
|
|
50
|
-
}
|
|
51
|
-
return got
|
|
52
|
-
}
|
package/utility/host_test.go
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
package utility
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"os"
|
|
5
|
-
"path/filepath"
|
|
6
|
-
"strings"
|
|
7
|
-
"testing"
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
func TestFilterHostArgsKeepsUtilityFlagsAndDropsHostOnlyFlags(t *testing.T) {
|
|
11
|
-
got := filterHostArgs([]string{
|
|
12
|
-
"--cwd", "/workspace/project",
|
|
13
|
-
"--cache-dir", ".ttsc",
|
|
14
|
-
"--emit",
|
|
15
|
-
"--binary=/tmp/tsgo",
|
|
16
|
-
"--plugins-json", "[]",
|
|
17
|
-
"src/main.ts",
|
|
18
|
-
"--",
|
|
19
|
-
"--cwd", "ignored",
|
|
20
|
-
})
|
|
21
|
-
want := []string{
|
|
22
|
-
"--cwd", "/workspace/project",
|
|
23
|
-
"--emit",
|
|
24
|
-
"--plugins-json", "[]",
|
|
25
|
-
"src/main.ts",
|
|
26
|
-
}
|
|
27
|
-
if !equalStringSlices(got, want) {
|
|
28
|
-
t.Fatalf("filtered args mismatch:\nwant: %#v\n got: %#v", want, got)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
func TestParseBannerFormatsAndSanitizesJSDoc(t *testing.T) {
|
|
33
|
-
banner, err := parseBanner(map[string]any{
|
|
34
|
-
"text": "first\r\nsecond */\n\n",
|
|
35
|
-
}, t.TempDir(), "tsconfig.json")
|
|
36
|
-
if err != nil {
|
|
37
|
-
t.Fatal(err)
|
|
38
|
-
}
|
|
39
|
-
if !strings.Contains(banner, " * first\n * second * /\n") {
|
|
40
|
-
t.Fatalf("banner was not normalized and sanitized:\n%s", banner)
|
|
41
|
-
}
|
|
42
|
-
if strings.Contains(banner, "second */") {
|
|
43
|
-
t.Fatalf("banner must not preserve raw JSDoc terminator:\n%s", banner)
|
|
44
|
-
}
|
|
45
|
-
if !strings.HasSuffix(banner, "*/\n") {
|
|
46
|
-
t.Fatalf("banner must end with a closed JSDoc block:\n%s", banner)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
func TestFindBannerConfigFileUsesTsconfigDirectoryWhenOutsideCwd(t *testing.T) {
|
|
51
|
-
cwd := seedHostTestProject(t, map[string]string{
|
|
52
|
-
"banner.config.cjs": `module.exports = { text: "cwd banner" };` + "\n",
|
|
53
|
-
})
|
|
54
|
-
wrapper := seedHostTestProject(t, map[string]string{
|
|
55
|
-
"banner.config.cjs": `module.exports = { text: "wrapper banner" };` + "\n",
|
|
56
|
-
"tsconfig.json": "{}",
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
discovered, err := findBannerConfigFile(cwd, filepath.Join(wrapper, "tsconfig.json"))
|
|
60
|
-
if err != nil {
|
|
61
|
-
t.Fatalf("findBannerConfigFile: %v", err)
|
|
62
|
-
}
|
|
63
|
-
if discovered != filepath.Join(wrapper, "banner.config.cjs") {
|
|
64
|
-
t.Fatalf("unexpected discovery path: %s", discovered)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
func TestResolveBannerTextRejectsEmptyObjectText(t *testing.T) {
|
|
69
|
-
_, err := resolveBannerText(map[string]any{
|
|
70
|
-
"text": " ",
|
|
71
|
-
}, t.TempDir(), "tsconfig.json")
|
|
72
|
-
if err == nil || !strings.Contains(err.Error(), "non-empty string") {
|
|
73
|
-
t.Fatalf("expected non-empty string error, got %v", err)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
func TestPathsRewriterResolvesIndexAndModuleExtensions(t *testing.T) {
|
|
78
|
-
root := normalizePath(t.TempDir())
|
|
79
|
-
source := normalizePath(filepath.Join(root, "src", "consumer", "main.ts"))
|
|
80
|
-
index := normalizePath(filepath.Join(root, "src", "modules", "index.ts"))
|
|
81
|
-
module := normalizePath(filepath.Join(root, "src", "modules", "esm.mts"))
|
|
82
|
-
rewriter := &pathsRewriter{
|
|
83
|
-
basePath: root,
|
|
84
|
-
outDir: normalizePath(filepath.Join(root, "dist")),
|
|
85
|
-
rootDir: normalizePath(filepath.Join(root, "src")),
|
|
86
|
-
patterns: []pathsPattern{
|
|
87
|
-
{pattern: "@lib/*", targets: []string{"src/modules/*"}},
|
|
88
|
-
},
|
|
89
|
-
sourceFiles: map[string]string{
|
|
90
|
-
index: index,
|
|
91
|
-
stripKnownSourceExtension(index): index,
|
|
92
|
-
module: module,
|
|
93
|
-
stripKnownSourceExtension(module): module,
|
|
94
|
-
},
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
rewritten, ok := rewriter.rewrite(source, "@lib")
|
|
98
|
-
if ok || rewritten != "@lib" {
|
|
99
|
-
t.Fatalf("non-matching pattern should stay unchanged, got %q ok=%v", rewritten, ok)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
rewritten, ok = rewriter.rewrite(source, "@lib/index")
|
|
103
|
-
if !ok || rewritten != "../modules/index.js" {
|
|
104
|
-
t.Fatalf("index rewrite mismatch: %q ok=%v", rewritten, ok)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
rewritten, ok = rewriter.rewrite(source, "@lib/esm")
|
|
108
|
-
if !ok || rewritten != "../modules/esm.mjs" {
|
|
109
|
-
t.Fatalf("module extension rewrite mismatch: %q ok=%v", rewritten, ok)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
func TestStripConfigurationDefaultsAndValidation(t *testing.T) {
|
|
114
|
-
strip, err := parseStrip(map[string]any{})
|
|
115
|
-
if err != nil {
|
|
116
|
-
t.Fatal(err)
|
|
117
|
-
}
|
|
118
|
-
if !strip.stripDebugger || !strip.matchesCall("console.log") || !strip.matchesCall("assert.equal") {
|
|
119
|
-
t.Fatalf("default strip config did not enable expected patterns: %#v", strip)
|
|
120
|
-
}
|
|
121
|
-
if strip.matchesCall("console.info") || strip.matchesCall("assert") {
|
|
122
|
-
t.Fatalf("default strip config matched too broadly")
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if _, err := parseStrip(map[string]any{"statements": []any{"debugger", "with"}}); err == nil {
|
|
126
|
-
t.Fatal("unsupported statement pattern must fail")
|
|
127
|
-
}
|
|
128
|
-
if _, err := parseCallPattern("assert.*.deep"); err == nil {
|
|
129
|
-
t.Fatal("middle wildcard call pattern must fail")
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
func TestSourceExtensionHelpersPreferCompoundExtensions(t *testing.T) {
|
|
134
|
-
cases := map[string]string{
|
|
135
|
-
"types.d.ts": "types",
|
|
136
|
-
"types.d.mts": "types",
|
|
137
|
-
"module.test.ts": "module.test",
|
|
138
|
-
"entry.jsx": "entry",
|
|
139
|
-
}
|
|
140
|
-
for input, want := range cases {
|
|
141
|
-
t.Run(input, func(t *testing.T) {
|
|
142
|
-
if got := stripKnownSourceExtension(input); got != want {
|
|
143
|
-
t.Fatalf("stripKnownSourceExtension(%q) = %q, want %q", input, got, want)
|
|
144
|
-
}
|
|
145
|
-
})
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
func seedHostTestProject(t *testing.T, files map[string]string) string {
|
|
150
|
-
t.Helper()
|
|
151
|
-
root := t.TempDir()
|
|
152
|
-
for name, text := range files {
|
|
153
|
-
file := filepath.Join(root, filepath.FromSlash(name))
|
|
154
|
-
if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil {
|
|
155
|
-
t.Fatal(err)
|
|
156
|
-
}
|
|
157
|
-
if err := os.WriteFile(file, []byte(text), 0o644); err != nil {
|
|
158
|
-
t.Fatal(err)
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return root
|
|
162
|
-
}
|