ttsc 0.8.0 → 0.9.0
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/README.md +75 -66
- package/cmd/ttsc/api_compile.go +5 -1
- package/driver/program.go +23 -1
- package/driver/rewrite.go +126 -9
- package/driver/rewrite_test.go +52 -0
- package/lib/TtscCompiler.js +28 -46
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/buildNativeCompiler.js +8 -38
- package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +36 -63
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/readProjectConfig.js +108 -60
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/project/resolveProjectConfig.js +15 -45
- package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
- package/lib/compiler/internal/resolveBinary.js +10 -40
- package/lib/compiler/internal/resolveBinary.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.js +21 -48
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.js +14 -44
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +7 -0
- package/lib/compiler/internal/runBuild.js +47 -66
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +18 -48
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +41 -75
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/launcher/internal/getCompilerVersionText.js +7 -37
- package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +48 -69
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +53 -64
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +328 -57
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +8 -0
- package/lib/plugin/internal/buildSourcePlugin.js +179 -125
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +2 -0
- package/lib/plugin/internal/loadProjectPlugins.js +197 -9
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +16 -3
- package/lib/structures/ITtscCompilerResult.d.ts +4 -0
- package/lib/structures/ITtscCompilerTransformation.d.ts +2 -0
- package/lib/structures/ITtscPluginFactoryContext.d.ts +6 -3
- package/lib/structures/ITtscProjectPluginConfig.d.ts +8 -7
- package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +2 -0
- package/lib/structures/internal/ITtscProjectLocatorOptions.d.ts +2 -0
- package/lib/structures/internal/TtscCommonOptions.d.ts +2 -0
- package/package.json +9 -14
- package/shim/diagnosticwriter/lint.go +8 -0
- package/src/TtscCompiler.ts +20 -5
- package/src/compiler/internal/buildNativeCompiler.ts +2 -2
- package/src/compiler/internal/compileProjectInMemory.ts +21 -16
- package/src/compiler/internal/project/readProjectConfig.ts +134 -35
- package/src/compiler/internal/project/resolveProjectConfig.ts +2 -2
- package/src/compiler/internal/resolveBinary.ts +2 -2
- package/src/compiler/internal/resolveEmittedJavaScript.ts +11 -7
- package/src/compiler/internal/resolveTsgo.ts +2 -2
- package/src/compiler/internal/runBuild.ts +34 -21
- package/src/compiler/internal/runSingleFileEmit.ts +3 -3
- package/src/compiler/internal/transformProjectInMemory.ts +37 -37
- package/src/launcher/internal/getCompilerVersionText.ts +2 -2
- package/src/launcher/internal/prepareExecution.ts +14 -4
- package/src/launcher/internal/runTtsc.ts +30 -4
- package/src/launcher/internal/runTtsx.ts +377 -26
- package/src/plugin/internal/buildSourcePlugin.ts +127 -32
- package/src/plugin/internal/loadProjectPlugins.ts +266 -10
- package/src/structures/ITtscCompilerContext.ts +17 -3
- package/src/structures/ITtscCompilerResult.ts +5 -0
- package/src/structures/ITtscCompilerTransformation.ts +3 -0
- package/src/structures/ITtscPluginFactoryContext.ts +6 -3
- package/src/structures/ITtscProjectPluginConfig.ts +8 -7
- package/src/structures/internal/ITtscParsedProjectConfig.ts +2 -0
- package/src/structures/internal/ITtscProjectLocatorOptions.ts +2 -0
- package/src/structures/internal/TtscCommonOptions.ts +2 -0
- package/utility/host.go +610 -18
- package/utility/host_test.go +162 -0
- package/test/compiler.test.ts +0 -422
- package/test/platform.test.ts +0 -12
- package/test/project.test.ts +0 -197
- package/test/source-build.test.ts +0 -45
- package/test/tsgo.test.ts +0 -69
package/README.md
CHANGED
|
@@ -9,23 +9,27 @@
|
|
|
9
9
|
[](https://github.com/samchon/ttsc/tree/master/docs)
|
|
10
10
|
[](https://discord.gg/E94XhzrUCZ)
|
|
11
11
|
|
|
12
|
-
A `typescript-go` toolchain for compiler-powered
|
|
12
|
+
A `typescript-go` toolchain for compiler-powered plugins and type-safe execution.
|
|
13
13
|
|
|
14
14
|
- **`ttsc`**: build, check, and transform.
|
|
15
15
|
- **`ttsx`**: execute TypeScript with type checking.
|
|
16
|
-
-
|
|
16
|
+
- native TypeScript-Go execution instead of transpile-only runners.
|
|
17
17
|
- type checking that `tsx` does not provide.
|
|
18
|
-
- **
|
|
18
|
+
- **plugin support**: compiler-powered libraries, such as `typia`.
|
|
19
19
|
- `@ttsc/lint`: lint violations as TS compile errors.
|
|
20
20
|
|
|
21
21
|
## Setup
|
|
22
22
|
|
|
23
|
+
### Install
|
|
24
|
+
|
|
23
25
|
Install the native TypeScript preview package with `ttsc`:
|
|
24
26
|
|
|
25
27
|
```bash
|
|
26
|
-
npm
|
|
28
|
+
npm install -D ttsc @typescript/native-preview
|
|
27
29
|
```
|
|
28
30
|
|
|
31
|
+
### Commands
|
|
32
|
+
|
|
29
33
|
Run TypeScript directly with `ttsx` (CLI command):
|
|
30
34
|
|
|
31
35
|
```bash
|
|
@@ -40,37 +44,46 @@ npx ttsc --noEmit
|
|
|
40
44
|
npx ttsc --watch
|
|
41
45
|
```
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
### Bundlers
|
|
48
|
+
|
|
49
|
+
Use `@ttsc/unplugin` when a bundler owns your build.
|
|
50
|
+
|
|
51
|
+
It runs `ttsc` plugins inside supported bundlers.
|
|
44
52
|
|
|
45
53
|
```bash
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
npm install -D ttsc @typescript/native-preview
|
|
55
|
+
npm install -D @ttsc/unplugin
|
|
48
56
|
```
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"config": {
|
|
61
|
-
"no-var": "error",
|
|
62
|
-
"no-explicit-any": "warning",
|
|
63
|
-
"no-non-null-assertion": "off"
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
{ "transform": "@ttsc/paths" },
|
|
67
|
-
{ "transform": "typia/lib/transform" }
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
|
-
}
|
|
58
|
+
Minimal Vite setup:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// vite.config.ts
|
|
62
|
+
import ttsc from "@ttsc/unplugin/vite";
|
|
63
|
+
import { defineConfig } from "vite";
|
|
64
|
+
|
|
65
|
+
export default defineConfig({
|
|
66
|
+
plugins: [ttsc()],
|
|
67
|
+
});
|
|
71
68
|
```
|
|
72
69
|
|
|
73
|
-
|
|
70
|
+
Supported bundlers:
|
|
71
|
+
|
|
72
|
+
- Vite
|
|
73
|
+
- Rollup
|
|
74
|
+
- Rolldown
|
|
75
|
+
- esbuild
|
|
76
|
+
- Webpack
|
|
77
|
+
- Rspack
|
|
78
|
+
- Next.js
|
|
79
|
+
- Farm
|
|
80
|
+
- Bun
|
|
81
|
+
|
|
82
|
+
See [`@ttsc/unplugin`](https://github.com/samchon/ttsc/tree/master/packages/unplugin) for full setup and adapter options.
|
|
83
|
+
|
|
84
|
+
## Plugins
|
|
85
|
+
|
|
86
|
+
Plugins let libraries add compile-time checks, transforms, and type-driven code generation to normal `ttsc` and `ttsx` runs.
|
|
74
87
|
|
|
75
88
|
```bash
|
|
76
89
|
# compile
|
|
@@ -80,9 +93,7 @@ npx ttsc
|
|
|
80
93
|
npx ttsx src/index.ts
|
|
81
94
|
```
|
|
82
95
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
## What Is a Transform?
|
|
96
|
+
### Transform Example
|
|
86
97
|
|
|
87
98
|
A transform uses TypeScript types to generate JavaScript before runtime.
|
|
88
99
|
|
|
@@ -107,50 +118,48 @@ interface IMember {
|
|
|
107
118
|
}
|
|
108
119
|
```
|
|
109
120
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
`ttsc` applies this transform at build time; `ttsx` applies the same transform when running the file.
|
|
139
|
-
|
|
140
|
-
## List of Plugins
|
|
121
|
+
The transform replaces `typia.is<IMember>()` with dedicated JavaScript checks at build time:
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
import * as __typia_transform__isFormatUuid from "typia/lib/internal/_isFormatUuid";
|
|
125
|
+
import * as __typia_transform__isFormatEmail from "typia/lib/internal/_isFormatEmail";
|
|
126
|
+
import * as __typia_transform__isTypeUint32 from "typia/lib/internal/_isTypeUint32";
|
|
127
|
+
import typia from "typia";
|
|
128
|
+
import { v4 } from "uuid";
|
|
129
|
+
const matched = (() => {
|
|
130
|
+
const _io0 = (input) =>
|
|
131
|
+
"string" === typeof input.id &&
|
|
132
|
+
__typia_transform__isFormatUuid._isFormatUuid(input.id) &&
|
|
133
|
+
"string" === typeof input.email &&
|
|
134
|
+
__typia_transform__isFormatEmail._isFormatEmail(input.email) &&
|
|
135
|
+
"number" === typeof input.age &&
|
|
136
|
+
__typia_transform__isTypeUint32._isTypeUint32(input.age) &&
|
|
137
|
+
19 < input.age &&
|
|
138
|
+
input.age <= 100;
|
|
139
|
+
return (input) => "object" === typeof input && null !== input && _io0(input);
|
|
140
|
+
})()({
|
|
141
|
+
id: v4(),
|
|
142
|
+
email: "samchon.github@gmail.com",
|
|
143
|
+
age: 30,
|
|
144
|
+
});
|
|
145
|
+
console.log(matched); // true
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### List of Plugins
|
|
141
149
|
|
|
142
150
|
`ttsc` ships a few small utility plugins in this repository.
|
|
143
151
|
|
|
144
|
-
- [`@ttsc/banner`](https://github.com/samchon/ttsc/tree/master/packages/banner): adds `@packageDocumentation` JSDoc banners
|
|
145
|
-
- [`@ttsc/lint`](https://github.com/samchon/ttsc/tree/master/packages/lint):
|
|
152
|
+
- [`@ttsc/banner`](https://github.com/samchon/ttsc/tree/master/packages/banner): adds `@packageDocumentation` JSDoc banners.
|
|
153
|
+
- [`@ttsc/lint`](https://github.com/samchon/ttsc/tree/master/packages/lint): reports lint violations as TypeScript compile errors.
|
|
146
154
|
- [`@ttsc/paths`](https://github.com/samchon/ttsc/tree/master/packages/paths): rewrites source path aliases so JS and declaration emit receive relative imports.
|
|
147
155
|
- [`@ttsc/strip`](https://github.com/samchon/ttsc/tree/master/packages/strip): removes configured calls and `debugger` statements.
|
|
156
|
+
- [`@ttsc/unplugin`](https://github.com/samchon/ttsc/tree/master/packages/unplugin): runs `ttsc` plugins inside bundlers supported by `unplugin`.
|
|
148
157
|
|
|
149
158
|
Plugin authors should start from the [`Guide Documents`](https://github.com/samchon/ttsc/tree/master/docs).
|
|
150
159
|
|
|
151
160
|
Ecosystem plugins are listed below; PRs adding `ttsc` plugins are welcome.
|
|
152
161
|
|
|
153
|
-
- [
|
|
162
|
+
- [`nestia`](https://github.com/samchon/nestia): generates NestJS routes, OpenAPI, and SDKs.
|
|
154
163
|
- [`typia`](https://github.com/samchon/typia): generates validators, serializers, and type-driven runtime code.
|
|
155
164
|
|
|
156
165
|
## References
|
package/cmd/ttsc/api_compile.go
CHANGED
|
@@ -144,8 +144,12 @@ func toAPICompileDiagnostic(diag driver.Diagnostic) apiCompileDiagnostic {
|
|
|
144
144
|
func apiOutputKey(cwd, fileName string) string {
|
|
145
145
|
// Relative keys are the API contract for files inside the project. Absolute
|
|
146
146
|
// keys are preserved for uncommon compiler outputs outside cwd.
|
|
147
|
-
if rel, err := filepath.Rel(cwd, fileName); err == nil && !
|
|
147
|
+
if rel, err := filepath.Rel(cwd, fileName); err == nil && !isOutsideRelativePath(rel) {
|
|
148
148
|
return filepath.ToSlash(rel)
|
|
149
149
|
}
|
|
150
150
|
return filepath.ToSlash(fileName)
|
|
151
151
|
}
|
|
152
|
+
|
|
153
|
+
func isOutsideRelativePath(rel string) bool {
|
|
154
|
+
return rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator))
|
|
155
|
+
}
|
package/driver/program.go
CHANGED
|
@@ -343,7 +343,7 @@ func (fs sourcePreambleFS) ReadFile(filePath string) (string, bool) {
|
|
|
343
343
|
if !ok || !isSourcePreambleTarget(filePath) {
|
|
344
344
|
return contents, ok
|
|
345
345
|
}
|
|
346
|
-
return fs.preamble
|
|
346
|
+
return ApplySourcePreamble(contents, fs.preamble), true
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
func (fs sourcePreambleFS) WriteFile(filePath string, data string) error {
|
|
@@ -377,6 +377,28 @@ func isSourcePreambleTarget(filePath string) bool {
|
|
|
377
377
|
return false
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
// ApplySourcePreamble inserts a generated source preamble without moving the
|
|
381
|
+
// file's BOM or hashbang away from the first bytes of the physical output.
|
|
382
|
+
func ApplySourcePreamble(text string, preamble string) string {
|
|
383
|
+
if preamble == "" {
|
|
384
|
+
return text
|
|
385
|
+
}
|
|
386
|
+
bom := ""
|
|
387
|
+
rest := text
|
|
388
|
+
if strings.HasPrefix(rest, "\ufeff") {
|
|
389
|
+
bom = "\ufeff"
|
|
390
|
+
rest = strings.TrimPrefix(rest, "\ufeff")
|
|
391
|
+
}
|
|
392
|
+
if strings.HasPrefix(rest, "#!") {
|
|
393
|
+
end := strings.IndexByte(rest, '\n')
|
|
394
|
+
if end < 0 {
|
|
395
|
+
return bom + rest + "\n" + preamble
|
|
396
|
+
}
|
|
397
|
+
return bom + rest[:end+1] + preamble + rest[end+1:]
|
|
398
|
+
}
|
|
399
|
+
return bom + preamble + rest
|
|
400
|
+
}
|
|
401
|
+
|
|
380
402
|
// SourceFiles exposes the program's user-authored source files (declaration
|
|
381
403
|
// files filtered out).
|
|
382
404
|
func (p *Program) SourceFiles() []*ast.SourceFile {
|
package/driver/rewrite.go
CHANGED
|
@@ -316,26 +316,143 @@ func matchParen(text string, pos int) (int, bool) {
|
|
|
316
316
|
return 0, false
|
|
317
317
|
}
|
|
318
318
|
depth := 1
|
|
319
|
+
lastSignificant := byte('(')
|
|
319
320
|
for i := pos + 1; i < len(text); i++ {
|
|
320
|
-
|
|
321
|
+
ch := text[i]
|
|
322
|
+
switch ch {
|
|
323
|
+
case ' ', '\t', '\n', '\r', '\f':
|
|
324
|
+
continue
|
|
321
325
|
case '(':
|
|
322
326
|
depth++
|
|
327
|
+
lastSignificant = ch
|
|
323
328
|
case ')':
|
|
324
329
|
depth--
|
|
325
330
|
if depth == 0 {
|
|
326
331
|
return i, true
|
|
327
332
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
333
|
+
lastSignificant = ch
|
|
334
|
+
case '"', '\'':
|
|
335
|
+
end, ok := skipQuoted(text, i, ch)
|
|
336
|
+
if !ok {
|
|
337
|
+
return 0, false
|
|
338
|
+
}
|
|
339
|
+
i = end
|
|
340
|
+
lastSignificant = 'x'
|
|
341
|
+
case '`':
|
|
342
|
+
end, ok := skipTemplate(text, i)
|
|
343
|
+
if !ok {
|
|
344
|
+
return 0, false
|
|
345
|
+
}
|
|
346
|
+
i = end
|
|
347
|
+
lastSignificant = 'x'
|
|
348
|
+
case '/':
|
|
349
|
+
if i+1 < len(text) {
|
|
350
|
+
switch text[i+1] {
|
|
351
|
+
case '/':
|
|
352
|
+
i = skipLineComment(text, i+2)
|
|
353
|
+
continue
|
|
354
|
+
case '*':
|
|
355
|
+
end, ok := skipBlockComment(text, i+2)
|
|
356
|
+
if !ok {
|
|
357
|
+
return 0, false
|
|
358
|
+
}
|
|
359
|
+
i = end
|
|
360
|
+
continue
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if canStartRegexLiteral(lastSignificant) {
|
|
364
|
+
end, ok := skipRegexLiteral(text, i)
|
|
365
|
+
if !ok {
|
|
366
|
+
return 0, false
|
|
334
367
|
}
|
|
335
|
-
|
|
368
|
+
i = end
|
|
369
|
+
lastSignificant = 'x'
|
|
370
|
+
continue
|
|
371
|
+
}
|
|
372
|
+
lastSignificant = ch
|
|
373
|
+
default:
|
|
374
|
+
lastSignificant = ch
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return 0, false
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
func skipQuoted(text string, pos int, quote byte) (int, bool) {
|
|
381
|
+
for i := pos + 1; i < len(text); i++ {
|
|
382
|
+
switch text[i] {
|
|
383
|
+
case '\\':
|
|
384
|
+
i++
|
|
385
|
+
case quote:
|
|
386
|
+
return i, true
|
|
387
|
+
case '\n', '\r':
|
|
388
|
+
return 0, false
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return 0, false
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
func skipTemplate(text string, pos int) (int, bool) {
|
|
395
|
+
for i := pos + 1; i < len(text); i++ {
|
|
396
|
+
switch text[i] {
|
|
397
|
+
case '\\':
|
|
398
|
+
i++
|
|
399
|
+
case '`':
|
|
400
|
+
return i, true
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return 0, false
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
func skipLineComment(text string, pos int) int {
|
|
407
|
+
for i := pos; i < len(text); i++ {
|
|
408
|
+
if text[i] == '\n' || text[i] == '\r' {
|
|
409
|
+
return i
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return len(text) - 1
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
func skipBlockComment(text string, pos int) (int, bool) {
|
|
416
|
+
for i := pos; i+1 < len(text); i++ {
|
|
417
|
+
if text[i] == '*' && text[i+1] == '/' {
|
|
418
|
+
return i + 1, true
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return 0, false
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
func canStartRegexLiteral(previous byte) bool {
|
|
425
|
+
return strings.ContainsRune("([{=,:;!&|?+-*~^<>%", rune(previous))
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
func skipRegexLiteral(text string, pos int) (int, bool) {
|
|
429
|
+
inClass := false
|
|
430
|
+
for i := pos + 1; i < len(text); i++ {
|
|
431
|
+
switch text[i] {
|
|
432
|
+
case '\\':
|
|
433
|
+
i++
|
|
434
|
+
case '[':
|
|
435
|
+
inClass = true
|
|
436
|
+
case ']':
|
|
437
|
+
inClass = false
|
|
438
|
+
case '/':
|
|
439
|
+
if inClass {
|
|
440
|
+
continue
|
|
441
|
+
}
|
|
442
|
+
for i+1 < len(text) && isRegexFlag(text[i+1]) {
|
|
443
|
+
i++
|
|
336
444
|
}
|
|
337
|
-
i
|
|
445
|
+
return i, true
|
|
446
|
+
case '\n', '\r':
|
|
447
|
+
return 0, false
|
|
338
448
|
}
|
|
339
449
|
}
|
|
340
450
|
return 0, false
|
|
341
451
|
}
|
|
452
|
+
|
|
453
|
+
func isRegexFlag(ch byte) bool {
|
|
454
|
+
return ch == '_' ||
|
|
455
|
+
ch == '$' ||
|
|
456
|
+
unicode.IsLetter(rune(ch)) ||
|
|
457
|
+
unicode.IsDigit(rune(ch))
|
|
458
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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/lib/TtscCompiler.js
CHANGED
|
@@ -1,41 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
35
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
6
|
exports.TtscCompiler = void 0;
|
|
37
|
-
const
|
|
38
|
-
const
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
39
9
|
const compileProjectInMemory_1 = require("./compiler/internal/compileProjectInMemory");
|
|
40
10
|
const resolveProjectConfig_1 = require("./compiler/internal/project/resolveProjectConfig");
|
|
41
11
|
const resolveBinary_1 = require("./compiler/internal/resolveBinary");
|
|
@@ -93,6 +63,7 @@ class TtscCompiler {
|
|
|
93
63
|
cacheDir: this.resolvePluginCacheDir(),
|
|
94
64
|
cwd: execution.cwd,
|
|
95
65
|
entries: this.context.plugins,
|
|
66
|
+
projectRoot: execution.projectRoot,
|
|
96
67
|
tsconfig: execution.tsconfig,
|
|
97
68
|
});
|
|
98
69
|
return loaded.nativePlugins.map((plugin) => plugin.binary);
|
|
@@ -118,9 +89,9 @@ class TtscCompiler {
|
|
|
118
89
|
const envCacheDir = this.context.env?.TTSC_CACHE_DIR ?? process.env.TTSC_CACHE_DIR;
|
|
119
90
|
const projectRoot = this.resolveCleanProjectRoot();
|
|
120
91
|
return removeExistingDirectories([
|
|
121
|
-
...(envCacheDir ? [
|
|
122
|
-
|
|
123
|
-
|
|
92
|
+
...(envCacheDir ? [node_path_1.default.resolve(envCacheDir, "plugins")] : []),
|
|
93
|
+
node_path_1.default.join(projectRoot, "node_modules", ".ttsc"),
|
|
94
|
+
node_path_1.default.join(projectRoot, ".ttsc"),
|
|
124
95
|
]);
|
|
125
96
|
}
|
|
126
97
|
/**
|
|
@@ -175,7 +146,9 @@ class TtscCompiler {
|
|
|
175
146
|
});
|
|
176
147
|
return {
|
|
177
148
|
cwd,
|
|
178
|
-
projectRoot:
|
|
149
|
+
projectRoot: this.context.projectRoot
|
|
150
|
+
? node_path_1.default.resolve(cwd, this.context.projectRoot)
|
|
151
|
+
: node_path_1.default.dirname(tsconfig),
|
|
179
152
|
tsconfig,
|
|
180
153
|
};
|
|
181
154
|
}
|
|
@@ -191,15 +164,15 @@ class TtscCompiler {
|
|
|
191
164
|
}
|
|
192
165
|
}
|
|
193
166
|
resolveCwd() {
|
|
194
|
-
return
|
|
167
|
+
return node_path_1.default.resolve(this.context.cwd ?? process.cwd());
|
|
195
168
|
}
|
|
196
169
|
resolveCacheDir() {
|
|
197
170
|
if (!this.context.cacheDir) {
|
|
198
171
|
return undefined;
|
|
199
172
|
}
|
|
200
|
-
return
|
|
173
|
+
return node_path_1.default.isAbsolute(this.context.cacheDir)
|
|
201
174
|
? this.context.cacheDir
|
|
202
|
-
:
|
|
175
|
+
: node_path_1.default.resolve(this.resolveCwd(), this.context.cacheDir);
|
|
203
176
|
}
|
|
204
177
|
resolvePluginCacheDir() {
|
|
205
178
|
return this.resolveCacheDir() ?? this.context.env?.TTSC_CACHE_DIR;
|
|
@@ -209,10 +182,10 @@ exports.TtscCompiler = TtscCompiler;
|
|
|
209
182
|
function removeExistingDirectories(directories) {
|
|
210
183
|
const removed = [];
|
|
211
184
|
for (const directory of [...new Set(directories)]) {
|
|
212
|
-
if (!
|
|
185
|
+
if (!node_fs_1.default.existsSync(directory)) {
|
|
213
186
|
continue;
|
|
214
187
|
}
|
|
215
|
-
|
|
188
|
+
node_fs_1.default.rmSync(directory, { recursive: true, force: true });
|
|
216
189
|
removed.push(directory);
|
|
217
190
|
}
|
|
218
191
|
return removed;
|
|
@@ -241,8 +214,11 @@ function runTransformation(task) {
|
|
|
241
214
|
}
|
|
242
215
|
function toCompilerResult(project) {
|
|
243
216
|
const { output, result } = project;
|
|
244
|
-
if (result.status === 0 && result.diagnostics
|
|
217
|
+
if (result.status === 0 && !hasErrorDiagnostics(result.diagnostics)) {
|
|
245
218
|
return {
|
|
219
|
+
...(result.diagnostics.length === 0
|
|
220
|
+
? {}
|
|
221
|
+
: { diagnostics: result.diagnostics }),
|
|
246
222
|
output,
|
|
247
223
|
type: "success",
|
|
248
224
|
};
|
|
@@ -267,8 +243,11 @@ function createProcessDiagnostic(result) {
|
|
|
267
243
|
}
|
|
268
244
|
function toCompilerTransformation(project) {
|
|
269
245
|
const { result, typescript } = project;
|
|
270
|
-
if (result.status === 0 && result.diagnostics
|
|
246
|
+
if (result.status === 0 && !hasErrorDiagnostics(result.diagnostics)) {
|
|
271
247
|
return {
|
|
248
|
+
...(result.diagnostics.length === 0
|
|
249
|
+
? {}
|
|
250
|
+
: { diagnostics: result.diagnostics }),
|
|
272
251
|
type: "success",
|
|
273
252
|
typescript,
|
|
274
253
|
};
|
|
@@ -281,6 +260,9 @@ function toCompilerTransformation(project) {
|
|
|
281
260
|
typescript,
|
|
282
261
|
};
|
|
283
262
|
}
|
|
263
|
+
function hasErrorDiagnostics(diagnostics) {
|
|
264
|
+
return diagnostics.some((diagnostic) => diagnostic.category === "error");
|
|
265
|
+
}
|
|
284
266
|
function normalizeError(error) {
|
|
285
267
|
if (!(error instanceof Error)) {
|
|
286
268
|
return error;
|
package/lib/TtscCompiler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TtscCompiler.js","sourceRoot":"","sources":["../src/TtscCompiler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TtscCompiler.js","sourceRoot":"","sources":["../src/TtscCompiler.ts"],"names":[],"mappings":"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"}
|