ttsc 0.19.0 → 0.19.2
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 +68 -186
- package/cmd/graphdump/main.go +21 -1
- package/cmd/ttsc/api_compile.go +3 -13
- package/cmd/ttsc/api_transform.go +13 -0
- package/cmd/ttscgraph/dump.go +40 -1
- package/cmd/ttscgraph/serve.go +194 -25
- package/cmd/ttscgraph/serve_error_response_still_names_its_mode_test.go +73 -0
- package/cmd/ttscgraph/serve_protocol_fails_the_stream_on_an_unaddressable_request_line_test.go +43 -0
- package/cmd/ttscgraph/serve_protocol_version_matches_the_typescript_client_test.go +48 -0
- package/cmd/ttscgraph/serve_snapshot_proves_its_program_without_a_second_read_test.go +109 -0
- package/driver/graph.go +133 -0
- package/internal/graph/diagnostics.go +6 -5
- package/internal/graph/dump.go +69 -17
- package/internal/graph/dump_diagnostics_ride_the_generation_that_built_it_test.go +79 -0
- package/internal/graph/dump_evidence_skips_leading_trivia_test.go +1 -1
- package/internal/graph/dump_is_a_function_of_the_source_test.go +1 -1
- package/internal/graph/dump_never_serializes_a_list_as_null_test.go +76 -0
- package/internal/graph/dump_schema_version_matches_the_typescript_client_test.go +48 -0
- package/internal/graph/dump_serializes_the_full_graph_test.go +21 -7
- package/internal/graph/node_modifiers_emit_union_strings_test.go +1 -1
- package/internal/graph/provenance.go +312 -0
- package/lib/TtscCompiler.js +9 -4
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.d.ts +4 -0
- package/lib/compiler/internal/transformProjectInMemory.js +67 -12
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/structures/ITtscCompilerTransformation.d.ts +98 -0
- package/package.json +8 -8
- package/shim/compiler/incremental.go +58 -0
- package/shim/core/shim.go +5 -0
- package/src/TtscCompiler.ts +19 -4
- package/src/compiler/internal/transformProjectInMemory.ts +106 -12
- package/src/structures/ITtscCompilerTransformation.ts +107 -0
- package/tools/shim_audit/baseline.json +2 -1
- package/tools/shim_audit/main.go +17 -0
- package/utility/host.go +17 -15
- package/cmd/ttscgraph/serve_protocol_rejects_invalid_request_line_test.go +0 -43
package/README.md
CHANGED
|
@@ -9,135 +9,104 @@ A `typescript-go` toolchain for compiler-powered plugins and type-safe execution
|
|
|
9
9
|
- **`ttsc`**: build, check, and transform.
|
|
10
10
|
- **`ttsx`**: execute TypeScript with type checking.
|
|
11
11
|
- [**`@ttsc/lint`**](https://github.com/samchon/ttsc/tree/master/packages/lint): lint violations as compiler errors.
|
|
12
|
-
- [**`@ttsc/graph`**](https://github.com/samchon/ttsc/tree/master/packages/graph): MCP code graph that
|
|
12
|
+
- [**`@ttsc/graph`**](https://github.com/samchon/ttsc/tree/master/packages/graph): MCP code graph that reduces agent token usage.
|
|
13
13
|
- **plugin support**: compiler-powered libraries, such as `typia`.
|
|
14
14
|
|
|
15
15
|
## Setup
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Install `ttsc`, `@ttsc/lint`, and the native TypeScript compiler:
|
|
17
|
+
`ttsc` is a drop-in replacement for `tsc`. It reads the same `tsconfig.json`, takes the same flags, and emits the same JavaScript, then runs your plugins in the pass that type-checks the project.
|
|
20
18
|
|
|
21
19
|
```bash
|
|
22
|
-
npm install -D ttsc
|
|
20
|
+
npm install -D ttsc typescript
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
### Commands
|
|
26
|
-
|
|
27
|
-
Run TypeScript directly with `ttsx` (CLI command):
|
|
28
|
-
|
|
29
23
|
```bash
|
|
30
|
-
npx ttsx src/index.ts
|
|
24
|
+
npx ttsx src/index.ts # run a file, type-checked first
|
|
25
|
+
npx ttsc # build
|
|
26
|
+
npx ttsc --noEmit # check only
|
|
27
|
+
npx ttsc --watch # rebuild on save
|
|
31
28
|
```
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
`ttsx` runs a file the way `tsx` or `ts-node` does, but it type-checks the whole project first, so a type error stops the run before anything executes.
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
npx ttsc
|
|
37
|
-
npx ttsc --noEmit
|
|
38
|
-
npx ttsc --watch
|
|
39
|
-
```
|
|
32
|
+
That covers the CLI. The integrations each have a short guide:
|
|
40
33
|
|
|
41
|
-
|
|
34
|
+
- [`@ttsc/unplugin`](https://ttsc.dev/docs/setup/unplugin): Vite, Rollup, Rolldown, esbuild, webpack, Rspack, Next.js, Turbopack, Farm, and Bun.
|
|
35
|
+
- [`@ttsc/metro`](https://ttsc.dev/docs/setup/metro): React Native and Expo.
|
|
36
|
+
- [`@ttsc/vscode`](https://ttsc.dev/docs/setup/vscode): live editor diagnostics.
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
npx ttsc format
|
|
45
|
-
```
|
|
38
|
+
## Lint
|
|
46
39
|
|
|
47
|
-
|
|
40
|
+
Lint and format at compiler speed: up to 800x faster than ESLint.
|
|
48
41
|
|
|
49
|
-
|
|
42
|
+
`@ttsc/lint` replaces ESLint and Prettier with rules that run inside the type-check. It shares one AST pass with the compiler, so linting and formatting add almost nothing to the build you already run.
|
|
50
43
|
|
|
51
|
-
|
|
44
|
+
Configuration is a single file. Each rule takes `"error"`, `"warning"`, or `"off"`, and the `format` block mirrors `.prettierrc`.
|
|
52
45
|
|
|
53
46
|
```bash
|
|
54
|
-
npm install -D
|
|
55
|
-
npm install -D @ttsc/unplugin
|
|
47
|
+
npm install -D @ttsc/lint
|
|
56
48
|
```
|
|
57
49
|
|
|
58
|
-
Minimal Vite setup:
|
|
59
|
-
|
|
60
50
|
```ts
|
|
61
|
-
//
|
|
62
|
-
import
|
|
63
|
-
import { defineConfig } from "vite";
|
|
64
|
-
|
|
65
|
-
export default defineConfig({
|
|
66
|
-
plugins: [ttsc()],
|
|
67
|
-
});
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Supported bundlers:
|
|
71
|
-
|
|
72
|
-
- Vite
|
|
73
|
-
- Rollup
|
|
74
|
-
- Rolldown
|
|
75
|
-
- esbuild
|
|
76
|
-
- Webpack
|
|
77
|
-
- Rspack
|
|
78
|
-
- Next.js
|
|
79
|
-
- Turbopack
|
|
80
|
-
- Farm
|
|
81
|
-
- Bun
|
|
82
|
-
|
|
83
|
-
See [`@ttsc/unplugin`](https://github.com/samchon/ttsc/tree/master/packages/unplugin) for full setup and adapter options.
|
|
51
|
+
// lint.config.ts
|
|
52
|
+
import type { ITtscLintConfig } from "@ttsc/lint";
|
|
84
53
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
54
|
+
export default {
|
|
55
|
+
rules: {
|
|
56
|
+
"no-var": "error",
|
|
57
|
+
"prefer-const": "error",
|
|
58
|
+
"typescript/no-explicit-any": "warning",
|
|
59
|
+
},
|
|
60
|
+
format: {
|
|
61
|
+
printWidth: 100,
|
|
62
|
+
singleQuote: true,
|
|
63
|
+
trailingComma: "all",
|
|
64
|
+
},
|
|
65
|
+
} satisfies ITtscLintConfig;
|
|
92
66
|
```
|
|
93
67
|
|
|
94
|
-
|
|
68
|
+
Violations surface as compiler diagnostics, in the same stream as type errors, so the CI step that already runs `ttsc --noEmit` gates lint without a second job:
|
|
95
69
|
|
|
96
|
-
```
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
module.exports = withTtsc(getDefaultConfig(__dirname));
|
|
70
|
+
```ts
|
|
71
|
+
// src/index.ts
|
|
72
|
+
var count = 3;
|
|
73
|
+
let total = count;
|
|
102
74
|
```
|
|
103
75
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
76
|
+
```text
|
|
77
|
+
$ npx ttsc --noEmit
|
|
78
|
+
src/index.ts:2:5 - error TS17397: [prefer-const] Use const instead of let.
|
|
107
79
|
|
|
108
|
-
|
|
80
|
+
2 let total = count;
|
|
81
|
+
~~~~~~~~~~~~~
|
|
109
82
|
|
|
110
|
-
|
|
83
|
+
src/index.ts:1:1 - error TS11966: [no-var] Unexpected var, use let or const instead.
|
|
111
84
|
|
|
112
|
-
|
|
113
|
-
|
|
85
|
+
1 var count = 3;
|
|
86
|
+
~~~~~~~~~~~~~~
|
|
114
87
|
```
|
|
115
88
|
|
|
116
|
-
|
|
89
|
+
Clean the project in place:
|
|
117
90
|
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"editor.formatOnSave": true
|
|
122
|
-
}
|
|
91
|
+
```bash
|
|
92
|
+
npx ttsc fix # lint autofixes + format edits
|
|
93
|
+
npx ttsc format # format edits only, never changes behavior
|
|
123
94
|
```
|
|
124
95
|
|
|
125
|
-
|
|
96
|
+
The rule catalog and every `format` key are in the [Lint & Format guide](https://ttsc.dev/docs/lint).
|
|
126
97
|
|
|
127
|
-
|
|
98
|
+
## Graph
|
|
128
99
|
|
|
129
|
-
|
|
100
|
+
Your coding agent answers from the compiler, spending roughly 90% fewer tokens.
|
|
130
101
|
|
|
131
|
-
`@ttsc/graph` gives
|
|
102
|
+
`@ttsc/graph` is an MCP server that gives the agent a compiler-resolved graph of your project: what calls what, what a change would touch, and where to start reading. The agent asks the type checker instead of grepping and re-reading files.
|
|
132
103
|
|
|
133
|
-
|
|
104
|
+
Register it with your MCP client. For Claude Code, a `.mcp.json` in the project root:
|
|
134
105
|
|
|
135
106
|
```bash
|
|
136
107
|
npm install -D ttsc @ttsc/graph typescript
|
|
137
108
|
```
|
|
138
109
|
|
|
139
|
-
Point your agent's MCP client at it. For Claude Code:
|
|
140
|
-
|
|
141
110
|
```json
|
|
142
111
|
{
|
|
143
112
|
"mcpServers": {
|
|
@@ -149,119 +118,32 @@ Point your agent's MCP client at it. For Claude Code:
|
|
|
149
118
|
}
|
|
150
119
|
```
|
|
151
120
|
|
|
152
|
-
On
|
|
121
|
+
On the agent-cost benchmark, Claude agents answer reading zero files, cutting tokens by roughly 90% and tool calls by 93% to 96%. The design and per-repository numbers are in the [Code Graph guide](https://ttsc.dev/docs/graph) and the [benchmark](https://ttsc.dev/docs/benchmark/graph).
|
|
153
122
|
|
|
154
|
-
|
|
123
|
+

|
|
155
124
|
|
|
156
125
|
## Plugins
|
|
157
126
|
|
|
158
|
-
|
|
127
|
+
A plugin hooks the compile to add checks, transforms, or type-driven code generation, all driven by the types the checker has already resolved. It runs on every `ttsc` build and `ttsx` run, with no extra step.
|
|
159
128
|
|
|
160
|
-
|
|
161
|
-
# compile
|
|
162
|
-
npx ttsc
|
|
163
|
-
|
|
164
|
-
# execute
|
|
165
|
-
npx ttsx src/index.ts
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Transform Example
|
|
169
|
-
|
|
170
|
-
A transform uses TypeScript types to generate JavaScript before runtime.
|
|
129
|
+
[typia](https://typia.io) is the canonical one. Ask it for a validator of any type, and the transform writes the implementation at build time:
|
|
171
130
|
|
|
172
131
|
```ts
|
|
173
|
-
import typia, { tags } from "typia";
|
|
174
|
-
import { v4 } from "uuid";
|
|
175
|
-
|
|
176
|
-
const matched: boolean = typia.is<IMember>({
|
|
177
|
-
id: v4(),
|
|
178
|
-
email: "samchon.github@gmail.com",
|
|
179
|
-
age: 30,
|
|
180
|
-
});
|
|
181
|
-
console.log(matched); // true
|
|
182
|
-
|
|
183
|
-
interface IMember {
|
|
184
|
-
id: string & tags.Format<"uuid">;
|
|
185
|
-
email: string & tags.Format<"email">;
|
|
186
|
-
age: number &
|
|
187
|
-
tags.Type<"uint32"> &
|
|
188
|
-
tags.ExclusiveMinimum<19> &
|
|
189
|
-
tags.Maximum<100>;
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
The transform replaces `typia.is<IMember>()` with dedicated JavaScript checks at build time:
|
|
194
|
-
|
|
195
|
-
```js
|
|
196
132
|
import typia from "typia";
|
|
197
|
-
import * as __typia_transform__isFormatEmail from "typia/lib/internal/_isFormatEmail";
|
|
198
|
-
import * as __typia_transform__isFormatUuid from "typia/lib/internal/_isFormatUuid";
|
|
199
|
-
import * as __typia_transform__isTypeUint32 from "typia/lib/internal/_isTypeUint32";
|
|
200
|
-
import { v4 } from "uuid";
|
|
201
|
-
|
|
202
|
-
const matched = (() => {
|
|
203
|
-
const _io0 = (input) =>
|
|
204
|
-
"string" === typeof input.id &&
|
|
205
|
-
__typia_transform__isFormatUuid._isFormatUuid(input.id) &&
|
|
206
|
-
"string" === typeof input.email &&
|
|
207
|
-
__typia_transform__isFormatEmail._isFormatEmail(input.email) &&
|
|
208
|
-
"number" === typeof input.age &&
|
|
209
|
-
__typia_transform__isTypeUint32._isTypeUint32(input.age) &&
|
|
210
|
-
19 < input.age &&
|
|
211
|
-
input.age <= 100;
|
|
212
|
-
return (input) => "object" === typeof input && null !== input && _io0(input);
|
|
213
|
-
})()({
|
|
214
|
-
id: v4(),
|
|
215
|
-
email: "samchon.github@gmail.com",
|
|
216
|
-
age: 30,
|
|
217
|
-
});
|
|
218
|
-
console.log(matched); // true
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
## Programmatic API
|
|
222
|
-
|
|
223
|
-
Embed `ttsc` from another Node tool with the `TtscCompiler` class:
|
|
224
|
-
|
|
225
|
-
```ts
|
|
226
|
-
import { TtscCompiler } from "ttsc";
|
|
227
133
|
|
|
228
|
-
const
|
|
229
|
-
const result = compiler.compile();
|
|
230
|
-
|
|
231
|
-
if (result.type === "success") {
|
|
232
|
-
for (const [path, text] of Object.entries(result.output)) {
|
|
233
|
-
// path is project-relative ("dist/index.js", "dist/index.d.ts", ...)
|
|
234
|
-
console.log(path, text.length);
|
|
235
|
-
}
|
|
236
|
-
} else if (result.type === "failure") {
|
|
237
|
-
for (const d of result.diagnostics) {
|
|
238
|
-
console.error(`${d.file}:${d.line}:${d.character} ${d.messageText}`);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
134
|
+
export const isStringArray = typia.createIs<string[]>();
|
|
241
135
|
```
|
|
242
136
|
|
|
243
|
-
|
|
137
|
+
No schema, no decorator. The call compiles to a plain function:
|
|
244
138
|
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const code = await service.transformFile("src/index.ts");
|
|
251
|
-
await service.updateFile("src/index.ts", "export const x: number = 2;\n");
|
|
252
|
-
const next = await service.transformFile("src/index.ts");
|
|
253
|
-
} finally {
|
|
254
|
-
service.dispose();
|
|
255
|
-
}
|
|
139
|
+
```js
|
|
140
|
+
export const isStringArray = (() => {
|
|
141
|
+
return (input) =>
|
|
142
|
+
Array.isArray(input) && input.every((elem) => "string" === typeof elem);
|
|
143
|
+
})();
|
|
256
144
|
```
|
|
257
145
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
See the [Programmatic API guide](https://ttsc.dev/docs/ttsc/api) for the full lifecycle, plugin overrides, and patterns. For browser embedding, see [`@ttsc/wasm`](https://github.com/samchon/ttsc/tree/master/packages/wasm) and the higher-level [`@ttsc/playground`](https://github.com/samchon/ttsc/tree/master/packages/playground) package.
|
|
261
|
-
|
|
262
|
-
### List of Plugins
|
|
263
|
-
|
|
264
|
-
`ttsc` ships a few small utility plugins in this repository.
|
|
146
|
+
Utility plugins shipped in this repository:
|
|
265
147
|
|
|
266
148
|
- [`@ttsc/banner`](https://github.com/samchon/ttsc/tree/master/packages/banner): adds `@packageDocumentation` JSDoc banners.
|
|
267
149
|
- [`@ttsc/lint`](https://github.com/samchon/ttsc/tree/master/packages/lint): lints and formats TypeScript source.
|
|
@@ -271,13 +153,13 @@ See the [Programmatic API guide](https://ttsc.dev/docs/ttsc/api) for the full li
|
|
|
271
153
|
- [`@ttsc/unplugin`](https://github.com/samchon/ttsc/tree/master/packages/unplugin): runs `ttsc` plugins inside bundlers supported by `unplugin`.
|
|
272
154
|
- [`@ttsc/metro`](https://github.com/samchon/ttsc/tree/master/packages/metro): runs `ttsc` plugins inside Metro for React Native and Expo.
|
|
273
155
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
Ecosystem plugins are listed below; PRs adding `ttsc` plugins are welcome.
|
|
156
|
+
Ecosystem plugins; PRs adding yours are welcome:
|
|
277
157
|
|
|
278
158
|
- [`nestia`](https://github.com/samchon/nestia): generates NestJS routes, OpenAPI, and SDKs.
|
|
279
159
|
- [`typia`](https://github.com/samchon/typia): generates validators, serializers, and type-driven runtime code.
|
|
280
160
|
|
|
161
|
+
To write your own, start from [Plugin Development](https://ttsc.dev/docs/development).
|
|
162
|
+
|
|
281
163
|
## Sponsors
|
|
282
164
|
|
|
283
165
|
[](https://github.com/sponsors/samchon)
|
package/cmd/graphdump/main.go
CHANGED
|
@@ -50,7 +50,27 @@ func run() int {
|
|
|
50
50
|
|
|
51
51
|
g := graph.Build(prog)
|
|
52
52
|
ignored := graph.GitIgnoredFiles(root, g)
|
|
53
|
-
|
|
53
|
+
texts := graph.SourceTexts(prog)
|
|
54
|
+
// The viewer pipeline reduces nodes and edges and never asks whether the build
|
|
55
|
+
// universe moved or whether the disk still matches, so this tool pays for
|
|
56
|
+
// neither. It names its producer and digests what the checker read, and it
|
|
57
|
+
// declares exactly that and no more: a reader learns the universe and the disk
|
|
58
|
+
// digests are absent, rather than reading an empty universe as "nothing
|
|
59
|
+
// changed" or an empty diskDigest as "the file could not be read". The shipped
|
|
60
|
+
// `ttscgraph dump` is the one that proves the whole contract.
|
|
61
|
+
data, err := graph.MarshalDump(g, root, *tsconfig, ignored, texts, graph.DumpOrigin{
|
|
62
|
+
Provenance: graph.NewProvenance(
|
|
63
|
+
root,
|
|
64
|
+
// No version: this tool is built from the tree on demand and never
|
|
65
|
+
// stamped, and an invented one would be worse than an absent one.
|
|
66
|
+
graph.Producer{Tool: "graphdump", Typescript: graph.TypescriptVersion()},
|
|
67
|
+
[]string{graph.CapabilitySourceDigests},
|
|
68
|
+
nil,
|
|
69
|
+
nil,
|
|
70
|
+
texts,
|
|
71
|
+
nil,
|
|
72
|
+
),
|
|
73
|
+
}, *pretty)
|
|
54
74
|
if err != nil {
|
|
55
75
|
fmt.Fprintf(os.Stderr, "graphdump: %v\n", err)
|
|
56
76
|
return 1
|
package/cmd/ttsc/api_compile.go
CHANGED
|
@@ -10,8 +10,6 @@ import (
|
|
|
10
10
|
"encoding/json"
|
|
11
11
|
"flag"
|
|
12
12
|
"fmt"
|
|
13
|
-
"path/filepath"
|
|
14
|
-
"strings"
|
|
15
13
|
|
|
16
14
|
shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
|
|
17
15
|
|
|
@@ -146,16 +144,8 @@ func toAPICompileDiagnostic(diag driver.Diagnostic) apiCompileDiagnostic {
|
|
|
146
144
|
// generated file. Files inside cwd use a slash-separated relative path (the
|
|
147
145
|
// API contract). Files outside cwd — rare, e.g. a monorepo output rooted
|
|
148
146
|
// above the project — are returned as an absolute slash path instead.
|
|
147
|
+
// Delegates to the driver so every envelope section (typescript, graph)
|
|
148
|
+
// shares one key implementation and consumers can join sections by key.
|
|
149
149
|
func apiOutputKey(cwd, fileName string) string {
|
|
150
|
-
|
|
151
|
-
return filepath.ToSlash(rel)
|
|
152
|
-
}
|
|
153
|
-
return filepath.ToSlash(fileName)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// isOutsideRelativePath reports whether the result of filepath.Rel points
|
|
157
|
-
// above the base directory (starts with ".."), meaning the file lives outside
|
|
158
|
-
// the project root and cannot safely be expressed as a project-relative path.
|
|
159
|
-
func isOutsideRelativePath(rel string) bool {
|
|
160
|
-
return rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator))
|
|
150
|
+
return driver.TransformOutputKey(cwd, fileName)
|
|
161
151
|
}
|
|
@@ -20,6 +20,12 @@ type apiTransformResult struct {
|
|
|
20
20
|
// Program facade, keyed the same way api-compile keys emitted files.
|
|
21
21
|
Diagnostics []apiCompileDiagnostic `json:"diagnostics,omitempty"`
|
|
22
22
|
TypeScript map[string]string `json:"typescript"`
|
|
23
|
+
// Graph is the host-owned reference graph of the loaded program (direct
|
|
24
|
+
// resolved reference edges, global-scope files, tsconfig extends chain),
|
|
25
|
+
// keyed like TypeScript. Consumers use it to register every file whose
|
|
26
|
+
// content can influence a transformed module, so bundler caches invalidate
|
|
27
|
+
// soundly without per-plugin reporting.
|
|
28
|
+
Graph *driver.TransformGraph `json:"graph,omitempty"`
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
// runAPITransform implements the `api-transform` sub-command. It loads the
|
|
@@ -63,8 +69,14 @@ func runAPITransform(args []string) int {
|
|
|
63
69
|
return 2
|
|
64
70
|
}
|
|
65
71
|
typescript := map[string]string{}
|
|
72
|
+
var graph *driver.TransformGraph
|
|
66
73
|
if prog != nil {
|
|
67
74
|
defer prog.Close()
|
|
75
|
+
// Compute the reference graph before SourceFiles() runs linked plugin
|
|
76
|
+
// hooks: those mutate parsed ASTs in place, and the graph must describe
|
|
77
|
+
// the original source's resolved references — the transform's inputs —
|
|
78
|
+
// not the mutated output.
|
|
79
|
+
graph = driver.NewTransformGraph(prog, cwd)
|
|
68
80
|
for _, file := range prog.SourceFiles() {
|
|
69
81
|
typescript[apiOutputKey(cwd, file.FileName())] = file.Text()
|
|
70
82
|
}
|
|
@@ -74,6 +86,7 @@ func runAPITransform(args []string) int {
|
|
|
74
86
|
result := apiTransformResult{
|
|
75
87
|
Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
|
|
76
88
|
TypeScript: typescript,
|
|
89
|
+
Graph: graph,
|
|
77
90
|
}
|
|
78
91
|
for _, diag := range diags {
|
|
79
92
|
result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
|
package/cmd/ttscgraph/dump.go
CHANGED
|
@@ -59,6 +59,12 @@ func runDump(args []string) int {
|
|
|
59
59
|
|
|
60
60
|
g := graph.Build(prog)
|
|
61
61
|
ignored := graph.GitIgnoredFiles(cwd, g)
|
|
62
|
+
texts := graph.SourceTexts(prog)
|
|
63
|
+
origin, err := dumpOrigin(prog, cwd, texts)
|
|
64
|
+
if err != nil {
|
|
65
|
+
fmt.Fprintf(stderr, "ttscgraph: %v\n", err)
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
62
68
|
// Stream the document out instead of marshalling it into one byte slice and
|
|
63
69
|
// then copying that slice into a string: on VS Code the dump is 323 MB, so
|
|
64
70
|
// the string conversion alone was a second full copy of it, for nothing. The
|
|
@@ -69,7 +75,8 @@ func runDump(args []string) int {
|
|
|
69
75
|
cwd,
|
|
70
76
|
tsconfig,
|
|
71
77
|
ignored,
|
|
72
|
-
|
|
78
|
+
texts,
|
|
79
|
+
origin,
|
|
73
80
|
*prettyFlag,
|
|
74
81
|
); err != nil {
|
|
75
82
|
fmt.Fprintf(stderr, "ttscgraph: %v\n", err)
|
|
@@ -77,3 +84,35 @@ func runDump(args []string) int {
|
|
|
77
84
|
}
|
|
78
85
|
return 0
|
|
79
86
|
}
|
|
87
|
+
|
|
88
|
+
// dumpOrigin assembles the one-shot command's snapshot evidence. A dump written
|
|
89
|
+
// to a file outlives the process that made it and is read by tooling that never
|
|
90
|
+
// saw the project, so it carries the same provenance a served snapshot does:
|
|
91
|
+
// without it the file is a pile of facts with no way to tell which program, or
|
|
92
|
+
// which day, they describe.
|
|
93
|
+
func dumpOrigin(prog *driver.Program, cwd string, texts map[string]string) (graph.DumpOrigin, error) {
|
|
94
|
+
configs, err := parsedConfigs(prog)
|
|
95
|
+
if err != nil {
|
|
96
|
+
return graph.DumpOrigin{}, err
|
|
97
|
+
}
|
|
98
|
+
configHashes, err := hashFiles(configFiles(configs))
|
|
99
|
+
if err != nil {
|
|
100
|
+
return graph.DumpOrigin{}, err
|
|
101
|
+
}
|
|
102
|
+
_, diskDigests, err := hashProgramSources(prog)
|
|
103
|
+
if err != nil {
|
|
104
|
+
return graph.DumpOrigin{}, err
|
|
105
|
+
}
|
|
106
|
+
return graph.DumpOrigin{
|
|
107
|
+
Provenance: graph.NewProvenance(
|
|
108
|
+
cwd,
|
|
109
|
+
serveProducer(),
|
|
110
|
+
fullSnapshotCapabilities,
|
|
111
|
+
fileDigests(configHashes),
|
|
112
|
+
rootFileEntries(projectRootFilesFromConfigs(configs, false)),
|
|
113
|
+
texts,
|
|
114
|
+
diskDigests,
|
|
115
|
+
),
|
|
116
|
+
Diagnostics: graph.NewDiagnostics(prog, cwd),
|
|
117
|
+
}, nil
|
|
118
|
+
}
|