@ttsc/unplugin 0.28.3 → 0.28.5
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 +70 -8
- package/lib/api.js +3 -0
- package/lib/api.js.map +1 -1
- package/lib/api.mjs +1 -0
- package/lib/api.mjs.map +1 -1
- package/lib/core/index.d.cts +17 -6
- package/lib/core/index.d.mts +17 -6
- package/lib/core/index.d.ts +17 -6
- package/lib/core/index.js +117 -21
- package/lib/core/index.js.map +1 -1
- package/lib/core/index.mjs +115 -21
- package/lib/core/index.mjs.map +1 -1
- package/lib/core/transform.d.cts +93 -25
- package/lib/core/transform.d.mts +93 -25
- package/lib/core/transform.d.ts +93 -25
- package/lib/core/transform.js +803 -121
- package/lib/core/transform.js.map +1 -1
- package/lib/core/transform.mjs +804 -122
- package/lib/core/transform.mjs.map +1 -1
- package/lib/core/tsconfigPaths.d.cts +61 -0
- package/lib/core/tsconfigPaths.d.mts +61 -0
- package/lib/core/tsconfigPaths.d.ts +61 -0
- package/lib/core/tsconfigPaths.js +190 -7
- package/lib/core/tsconfigPaths.js.map +1 -1
- package/lib/core/tsconfigPaths.mjs +188 -8
- package/lib/core/tsconfigPaths.mjs.map +1 -1
- package/lib/next.d.cts +27 -10
- package/lib/next.d.mts +27 -10
- package/lib/next.d.ts +27 -10
- package/lib/next.js +229 -8
- package/lib/next.js.map +1 -1
- package/lib/next.mjs +229 -8
- package/lib/next.mjs.map +1 -1
- package/lib/turbopack.d.cts +5 -4
- package/lib/turbopack.d.mts +5 -4
- package/lib/turbopack.d.ts +5 -4
- package/lib/turbopack.js +13 -7
- package/lib/turbopack.js.map +1 -1
- package/lib/turbopack.mjs +14 -8
- package/lib/turbopack.mjs.map +1 -1
- package/package.json +3 -3
- package/src/core/index.ts +122 -21
- package/src/core/transform.ts +1073 -132
- package/src/core/tsconfigPaths.ts +254 -8
- package/src/next.ts +262 -10
- package/src/turbopack.ts +13 -9
package/lib/core/index.mjs
CHANGED
|
@@ -5,12 +5,17 @@ import { resolveOptions } from './options.mjs';
|
|
|
5
5
|
import { createTtscTransformCache, stripQuery, transformTtsc, beginTtscTransformBuild, resetTtscTransformCache, isDeclarationFile } from './transform.mjs';
|
|
6
6
|
export { collectExternalInputHashes, collectProjectInputHashes, isProjectWalkPath } from './transform.mjs';
|
|
7
7
|
import { createViteServeMissingInputWatch } from './viteServe.mjs';
|
|
8
|
+
export { mergeMembershipPolicyOverlay, readProjectMembershipPolicy } from './tsconfigPaths.mjs';
|
|
8
9
|
|
|
9
10
|
const name = "ttsc-unplugin";
|
|
10
11
|
/**
|
|
11
|
-
* Matches
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Matches the TypeScript source extensions the ttsc transform handles: `.ts`,
|
|
13
|
+
* `.tsx`, `.mts`, `.cts` and their `x` forms. JavaScript is deliberately not
|
|
14
|
+
* among them, so a `.js` module reaches no adapter's transform.
|
|
15
|
+
*
|
|
16
|
+
* Shared with the Bun adapter (`bun.ts`) and the standalone Turbopack loader
|
|
17
|
+
* (`turbopack.ts`) through {@link isTransformTarget}, so the filter is defined
|
|
18
|
+
* once and every adapter answers the same way.
|
|
14
19
|
*/
|
|
15
20
|
const sourceFilePattern = /\.[cm]?tsx?$/;
|
|
16
21
|
/** Matches any path segment that is a `node_modules` directory (cross-platform). */
|
|
@@ -24,13 +29,15 @@ const virtualModulePattern = /\0/;
|
|
|
24
29
|
* Unplugin factory that wires the ttsc transform pipeline into any supported
|
|
25
30
|
* bundler (Vite, Rollup, Rolldown, webpack, Rspack, esbuild, Farm).
|
|
26
31
|
*
|
|
27
|
-
* The factory resolves raw options once, creates
|
|
28
|
-
* and captures Vite alias configuration via the
|
|
29
|
-
* that path aliases are forwarded to the
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* The factory resolves raw options once, creates one transform cache for the
|
|
33
|
+
* whole plugin instance, and captures Vite alias configuration via the
|
|
34
|
+
* `vite.configResolved` hook so that path aliases are forwarded to the
|
|
35
|
+
* generated tsconfig overlay. A host with a real `buildStart` opens a delivery
|
|
36
|
+
* pass there and keeps its generation across passes; a watching Vite
|
|
37
|
+
* development server keeps persistent validation instead, because its one
|
|
38
|
+
* `buildStart` spans later HMR edits and so cannot mark a pass, while a dev
|
|
39
|
+
* server configured without a watcher takes the pass lifecycle with them,
|
|
40
|
+
* having declared it will observe no edit at all.
|
|
34
41
|
*/
|
|
35
42
|
const unpluginFactory = (rawOptions = {}) => {
|
|
36
43
|
const options = resolveOptions(rawOptions);
|
|
@@ -39,11 +46,16 @@ const unpluginFactory = (rawOptions = {}) => {
|
|
|
39
46
|
let aliases;
|
|
40
47
|
let viteCommand;
|
|
41
48
|
let viteWatching = true;
|
|
49
|
+
// Whether a build-mode session is driven by Rollup's watcher. `build.watch`
|
|
50
|
+
// is `null` for an ordinary build and an object under `--watch`, which is the
|
|
51
|
+
// axis the disposal boundary actually turns on: only a watching build repeats
|
|
52
|
+
// its build phase, and only a watching build ends at `closeWatcher`.
|
|
53
|
+
let viteBuildWatching = false;
|
|
42
54
|
// A restart can start the replacement plugin container before closing the
|
|
43
55
|
// old one, and Vite calls buildEnd even for a container that never started.
|
|
44
56
|
// Track the stable per-container PluginContext identity so that unstarted
|
|
45
57
|
// old containers cannot dispose a replacement's freshly initialized cache.
|
|
46
|
-
|
|
58
|
+
let viteBuildOwners = new WeakSet();
|
|
47
59
|
let viteBuildLifecycles = 0;
|
|
48
60
|
return {
|
|
49
61
|
name,
|
|
@@ -66,6 +78,13 @@ const unpluginFactory = (rawOptions = {}) => {
|
|
|
66
78
|
// (samchon/ttsc#1246).
|
|
67
79
|
viteWatching =
|
|
68
80
|
config.server?.watch !== null;
|
|
81
|
+
// Read on the same principle as the line above, from the half of the
|
|
82
|
+
// config that governs a build rather than a server. The comparison is
|
|
83
|
+
// loose where the server's is strict because the two defaults differ:
|
|
84
|
+
// `server.watch` is an object unless explicitly `null`, while
|
|
85
|
+
// `build.watch` is absent or `null` unless `--watch` supplies one.
|
|
86
|
+
viteBuildWatching =
|
|
87
|
+
config.build?.watch != null;
|
|
69
88
|
},
|
|
70
89
|
// Vite serve funnels every transform-context `addWatchFile()` into the
|
|
71
90
|
// module's added-import graph (`_addedImports`), which import-analysis
|
|
@@ -76,18 +95,84 @@ const unpluginFactory = (rawOptions = {}) => {
|
|
|
76
95
|
configureServer(server) {
|
|
77
96
|
missingInputs.attach(server);
|
|
78
97
|
},
|
|
79
|
-
// Vite calls buildEnd when the dev server
|
|
80
|
-
// poller and, once the last
|
|
81
|
-
// generation-owned filesystem
|
|
98
|
+
// Vite calls buildEnd when the dev server closes, and Rollup calls it at
|
|
99
|
+
// the end of every build phase; drop every poller and, once the last
|
|
100
|
+
// overlapping container has closed, every generation-owned filesystem
|
|
101
|
+
// tracker as well.
|
|
102
|
+
//
|
|
103
|
+
// Disposing here is right wherever the end of a build phase is also the
|
|
104
|
+
// end of the session: a dev server, and an ordinary one-shot build. It is
|
|
105
|
+
// wrong for a watching build, whose watcher repeats build phases, so it
|
|
106
|
+
// means "this pass ended" there — measured as
|
|
107
|
+
// `buildStart -> buildEnd -> ... -> buildStart -> buildEnd` across
|
|
108
|
+
// `vite build --watch` rebuilds. Disposing on that repeat discarded the
|
|
109
|
+
// generation once per rebuild independently of the `buildStart` clear, so
|
|
110
|
+
// fixing one of the two sites alone left this host recompiling the whole
|
|
111
|
+
// project per edit (samchon/ttsc#1301). The watching build hands its
|
|
112
|
+
// teardown to `closeWatcher` below instead.
|
|
82
113
|
buildEnd() {
|
|
83
114
|
missingInputs.dispose();
|
|
84
115
|
if (viteBuildOwners.delete(this)) {
|
|
85
116
|
viteBuildLifecycles -= 1;
|
|
86
117
|
}
|
|
87
|
-
if (viteBuildLifecycles === 0
|
|
118
|
+
if (viteBuildLifecycles === 0 &&
|
|
119
|
+
(viteCommand === "serve" || !viteBuildWatching)) {
|
|
120
|
+
resetTtscTransformCache(transformCache);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
// The watching build's real teardown, and the only hook in a
|
|
124
|
+
// `vite build --watch` trace that fires exactly once: buildEnd,
|
|
125
|
+
// writeBundle and closeBundle all repeat per rebuild there. A generation
|
|
126
|
+
// retained across passes owns directory watchers, so this is where they
|
|
127
|
+
// are released. Vite's dev server drives no Rollup watcher and an
|
|
128
|
+
// ordinary build closes its bundle instead, so neither reaches here;
|
|
129
|
+
// a host that fired both would simply reset twice, which is idempotent.
|
|
130
|
+
//
|
|
131
|
+
// The container bookkeeping is cleared with the cache, and the owner set
|
|
132
|
+
// is replaced rather than merely zeroed alongside it. A watcher closed
|
|
133
|
+
// mid-rebuild leaves a container still registered, and its later
|
|
134
|
+
// `buildEnd` would then decrement a counter that is already zero and
|
|
135
|
+
// strand it below zero, after which the disposal above could never fire
|
|
136
|
+
// again for this plugin instance.
|
|
137
|
+
closeWatcher() {
|
|
138
|
+
viteBuildOwners = new WeakSet();
|
|
139
|
+
viteBuildLifecycles = 0;
|
|
140
|
+
resetTtscTransformCache(transformCache);
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
// Rollup and Rolldown carry none of the Vite block's hooks, so before this
|
|
144
|
+
// they had no disposal site at all. They get both halves of the same
|
|
145
|
+
// boundary: a watching session ends at `closeWatcher`, and a one-shot build
|
|
146
|
+
// ends when its build phase does. `this.meta.watchMode` separates the two
|
|
147
|
+
// there, the way `build.watch` does for Vite, so a one-shot build is not
|
|
148
|
+
// left without a site the way `vite build` was (samchon/ttsc#1301).
|
|
149
|
+
// unplugin merges each of these blocks only into its own adapter, so the
|
|
150
|
+
// Vite adapter never receives them.
|
|
151
|
+
//
|
|
152
|
+
// A `buildEnd` at the top level instead of inside a block would be a
|
|
153
|
+
// regression rather than a shorthand: unplugin forwards a top-level one to
|
|
154
|
+
// esbuild's `onEnd` and to webpack's and Rspack's `hooks.emit`, each of
|
|
155
|
+
// which repeats per rebuild, so those hosts would start discarding a valid
|
|
156
|
+
// generation on every edit, which is samchon/ttsc#1300 again.
|
|
157
|
+
rollup: {
|
|
158
|
+
buildEnd() {
|
|
159
|
+
if (this.meta?.watchMode !== true) {
|
|
160
|
+
resetTtscTransformCache(transformCache);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
closeWatcher() {
|
|
164
|
+
resetTtscTransformCache(transformCache);
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
rolldown: {
|
|
168
|
+
buildEnd() {
|
|
169
|
+
if (this.meta?.watchMode !== true) {
|
|
88
170
|
resetTtscTransformCache(transformCache);
|
|
89
171
|
}
|
|
90
172
|
},
|
|
173
|
+
closeWatcher() {
|
|
174
|
+
resetTtscTransformCache(transformCache);
|
|
175
|
+
},
|
|
91
176
|
},
|
|
92
177
|
buildStart() {
|
|
93
178
|
if (viteCommand !== undefined && !viteBuildOwners.has(this)) {
|
|
@@ -101,14 +186,18 @@ const unpluginFactory = (rawOptions = {}) => {
|
|
|
101
186
|
// no client is hot-updated. Validating each delivery there does not buy
|
|
102
187
|
// freshness, it buys incoherence — modules delivered before an edit and
|
|
103
188
|
// after it would come from two different compilations of one program —
|
|
104
|
-
// while costing a full derived-input proof per delivered module. The
|
|
105
|
-
//
|
|
106
|
-
//
|
|
189
|
+
// while costing a full derived-input proof per delivered module. The pass
|
|
190
|
+
// lifecycle settles each module's first delivery against the generation
|
|
191
|
+
// the session started from, exactly as a build does, and still
|
|
107
192
|
// revalidates a module this session already delivered. A one-shot suite
|
|
108
193
|
// configures precisely this server (`vitest --run` sets `server.watch =
|
|
109
194
|
// null`) and is the workload behind samchon/ttsc#970
|
|
110
195
|
// (samchon/ttsc#1260). The neighbouring watch-registration decision reads
|
|
111
196
|
// the same two properties for the same reason.
|
|
197
|
+
//
|
|
198
|
+
// Opening a pass no longer discards the generation, so the `else` branch
|
|
199
|
+
// is what every host with a repeating `buildStart` takes without paying a
|
|
200
|
+
// whole-project transform per rebuild (samchon/ttsc#1300).
|
|
112
201
|
if (viteCommand === "serve" && viteWatching) {
|
|
113
202
|
resetTtscTransformCache(transformCache);
|
|
114
203
|
}
|
|
@@ -174,10 +263,15 @@ const unpluginFactory = (rawOptions = {}) => {
|
|
|
174
263
|
};
|
|
175
264
|
const unplugin = createUnplugin(unpluginFactory);
|
|
176
265
|
/**
|
|
177
|
-
* Returns `true` when the module id refers to a real TypeScript
|
|
178
|
-
*
|
|
266
|
+
* Returns `true` when the module id refers to a real TypeScript source file
|
|
267
|
+
* that should be processed by the ttsc transform.
|
|
268
|
+
*
|
|
269
|
+
* TypeScript only. {@link sourceFilePattern} deliberately excludes JavaScript,
|
|
270
|
+
* so a `.js` module reaches no adapter's transform, and this docstring used to
|
|
271
|
+
* say otherwise while the pattern it is built from said the truth
|
|
272
|
+
* (samchon/ttsc#1309).
|
|
179
273
|
*
|
|
180
|
-
*
|
|
274
|
+
* Also excluded: virtual modules (NUL prefix), `.d.ts` declaration files, and
|
|
181
275
|
* anything inside `node_modules`.
|
|
182
276
|
*/
|
|
183
277
|
function isTransformTarget(id) {
|
package/lib/core/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../src/core/index.ts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/core/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/lib/core/transform.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ import type { ITtscCompilerTransformation } from "ttsc";
|
|
|
3
3
|
import { type FilesystemPathIdentityContext, type FilesystemPathIdentityOperations } from "ttsc/path-identity";
|
|
4
4
|
import type { TransformResult } from "unplugin";
|
|
5
5
|
import type { ResolvedTtscUnpluginOptions } from "./options.cjs";
|
|
6
|
+
import { type ITtscProjectMembershipPolicy } from "./tsconfigPaths.cjs";
|
|
6
7
|
/**
|
|
7
8
|
* The normalised transform result type that this module produces.
|
|
8
9
|
*
|
|
@@ -11,22 +12,31 @@ import type { ResolvedTtscUnpluginOptions } from "./options.cjs";
|
|
|
11
12
|
* `undefined`.
|
|
12
13
|
*/
|
|
13
14
|
export type TtscTransformResult = Exclude<TransformResult, string | null | undefined>;
|
|
14
|
-
/**
|
|
15
|
-
* Normalised alias entry used when building the `paths` overlay for the
|
|
16
|
-
* generated tsconfig. Derived from either a Vite array alias or a webpack/
|
|
17
|
-
* Rspack object alias.
|
|
18
|
-
*/
|
|
19
|
-
export interface TtscTransformAlias {
|
|
20
|
-
/** The alias key (module specifier prefix). */
|
|
21
|
-
find: string;
|
|
22
|
-
/** Absolute or cwd-relative path that the alias points to. */
|
|
23
|
-
replacement: string;
|
|
24
|
-
}
|
|
25
|
-
/** One directory's cheap project-membership identity at generation time. */
|
|
15
|
+
/** One directory's project-membership identity at generation time. */
|
|
26
16
|
interface TtscProjectDirectorySnapshot {
|
|
27
17
|
/** Absolute directory spelling used by the project walk. */
|
|
28
18
|
path: string;
|
|
29
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Whether this directory's subtree can hold a program input.
|
|
21
|
+
*
|
|
22
|
+
* A directory that cannot is still walked and still watched, so a source
|
|
23
|
+
* appearing in it later is noticed, but it takes no part in the membership
|
|
24
|
+
* comparison. That is what lets a bundler create its output directory and
|
|
25
|
+
* fill it without voiding a generation no compiler input touched, for any
|
|
26
|
+
* output directory rather than for fifteen names (samchon/ttsc#1307).
|
|
27
|
+
*/
|
|
28
|
+
relevant: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Digest of the entries the walk itself considers: every immediate child the
|
|
31
|
+
* ignore list does not drop, with its kind.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately not the directory's own metadata. A directory's stamp moves
|
|
34
|
+
* whenever _any_ entry is added or removed, including the ones the walk
|
|
35
|
+
* exists to ignore, so a bundler emitting into `dist/` — or merely creating
|
|
36
|
+
* that directory for the first time — moved the project root's stamp and
|
|
37
|
+
* voided a generation that no compiler input had touched. The ignore list
|
|
38
|
+
* only protects the generation if the membership proof honours it too.
|
|
39
|
+
*/
|
|
30
40
|
signature: string;
|
|
31
41
|
}
|
|
32
42
|
/** Generation-scoped directory watchers used to detect membership changes. */
|
|
@@ -117,6 +127,28 @@ export interface TtscCachedProjectTransform {
|
|
|
117
127
|
* transform.
|
|
118
128
|
*/
|
|
119
129
|
inputHashes: Record<string, string>;
|
|
130
|
+
/**
|
|
131
|
+
* What the resolved configuration admitted into this generation's program.
|
|
132
|
+
*
|
|
133
|
+
* Recorded per generation rather than read per validation because it is a
|
|
134
|
+
* property of the configuration the compile ran under, so a later delivery
|
|
135
|
+
* must judge membership by the same rule the compile did. A tsconfig edit
|
|
136
|
+
* that changes the rule also changes a declared input, which replaces the
|
|
137
|
+
* generation and its policy together.
|
|
138
|
+
*/
|
|
139
|
+
membershipPolicy: ITtscProjectMembershipPolicy;
|
|
140
|
+
/**
|
|
141
|
+
* Files already reported as absent from the program, and the pass that
|
|
142
|
+
* reporting belongs to, so the notice is one per file per pass rather than
|
|
143
|
+
* one per delivery.
|
|
144
|
+
*/
|
|
145
|
+
missingOutputReported?: Set<string>;
|
|
146
|
+
missingOutputEpoch?: number;
|
|
147
|
+
/**
|
|
148
|
+
* The project config this generation compiled, so a module the program does
|
|
149
|
+
* not contain can be told which program that was.
|
|
150
|
+
*/
|
|
151
|
+
tsconfig: string;
|
|
120
152
|
/**
|
|
121
153
|
* Metadata signature of each {@link inputHashes} entry whose hash was proven
|
|
122
154
|
* against an unracing read of the file on disk, in a tick the observed
|
|
@@ -179,10 +211,35 @@ export interface TtscCachedProjectTransform {
|
|
|
179
211
|
projectRoot: string;
|
|
180
212
|
/** Raw compiler output returned by {@link TtscCompiler.transform}. */
|
|
181
213
|
result: ITtscCompilerTransformation;
|
|
214
|
+
/**
|
|
215
|
+
* The delivery epoch this generation is currently settled against, or
|
|
216
|
+
* `undefined` for a generation no epoch has proven.
|
|
217
|
+
*
|
|
218
|
+
* Set when the generation is compiled, and again whenever a later epoch's
|
|
219
|
+
* first delivery proves the whole generation still matches the filesystem.
|
|
220
|
+
* While it equals the cache's current epoch, each module's first delivery is
|
|
221
|
+
* settled by the supplied source alone, exactly as it was when every pass
|
|
222
|
+
* compiled its own generation (samchon/ttsc#1300).
|
|
223
|
+
*/
|
|
224
|
+
deliveryEpoch?: number;
|
|
225
|
+
/**
|
|
226
|
+
* Whether this generation's non-error diagnostics have been surfaced at all,
|
|
227
|
+
* and the epoch they were last surfaced in.
|
|
228
|
+
*
|
|
229
|
+
* The diagnostics describe one compile of one program, so they belong to the
|
|
230
|
+
* generation rather than to a delivery; a pass that reuses a retained
|
|
231
|
+
* generation still surfaces them once, because a build's warnings are part of
|
|
232
|
+
* what that build reports (samchon/ttsc#1304). The two fields are separate so
|
|
233
|
+
* a persistent host, whose epoch is `undefined`, still reports the first
|
|
234
|
+
* time.
|
|
235
|
+
*/
|
|
236
|
+
diagnosticsReported?: boolean;
|
|
237
|
+
diagnosticsEpoch?: number;
|
|
182
238
|
/**
|
|
183
239
|
* Files already delivered from this generation, keyed by filesystem identity.
|
|
184
|
-
*
|
|
185
|
-
* module's first delivery inside the current
|
|
240
|
+
* A cache with a delivery epoch uses this to skip persistent validation only
|
|
241
|
+
* for a module's first delivery inside the current pass; the set is cleared
|
|
242
|
+
* whenever a new epoch's gate re-proves the generation.
|
|
186
243
|
*/
|
|
187
244
|
servedFiles?: Set<string>;
|
|
188
245
|
/**
|
|
@@ -251,20 +308,31 @@ export declare function normalizeHostInputName(name: string, caseSensitive: bool
|
|
|
251
308
|
/** Create an empty persistent transform cache with isolated filesystem reads. */
|
|
252
309
|
export declare function createTtscTransformCache(operations?: Partial<TtscTransformFilesystemOperations>): TtscTransformCache;
|
|
253
310
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
311
|
+
* Open a new delivery pass, enabling constant-time first delivery for every
|
|
312
|
+
* module this pass asks for.
|
|
313
|
+
*
|
|
314
|
+
* This deliberately retains the cached generation. The pass boundary is a
|
|
315
|
+
* statement about _deliveries_ — each module is requested at most once inside
|
|
316
|
+
* it — not about whether the compiled program is still correct, which the
|
|
317
|
+
* generation's own recorded snapshot answers and which
|
|
318
|
+
* {@link matchesCachedSource} proves once at the pass's first delivery. Clearing
|
|
319
|
+
* here instead made a host whose `buildStart` repeats recompile the whole
|
|
320
|
+
* project on every rebuild even when no compiler input had changed
|
|
321
|
+
* (samchon/ttsc#1300). Use {@link resetTtscTransformCache} to actually discard a
|
|
322
|
+
* generation and its watchers.
|
|
256
323
|
*
|
|
257
|
-
* Hosts without a guaranteed
|
|
258
|
-
*
|
|
324
|
+
* Hosts without a guaranteed pass boundary use persistent validation unless
|
|
325
|
+
* they have another immutable lifecycle. Bun runtime setup, for example,
|
|
259
326
|
* defines one process-scoped module-loading session.
|
|
260
327
|
*/
|
|
261
328
|
export declare function beginTtscTransformBuild(cache: TtscTransformCache): void;
|
|
262
329
|
/**
|
|
263
|
-
*
|
|
330
|
+
* Discard every generation, dispose its watchers, and return the cache to
|
|
331
|
+
* persistent validation mode.
|
|
264
332
|
*
|
|
265
|
-
* This is
|
|
266
|
-
*
|
|
267
|
-
*
|
|
333
|
+
* This is the unconditional lifecycle boundary, and it is distinct from
|
|
334
|
+
* {@link beginTtscTransformBuild}: a pass ending is not a reason to throw a
|
|
335
|
+
* proven compile away, while a session ending is.
|
|
268
336
|
*/
|
|
269
337
|
export declare function resetTtscTransformCache(cache: TtscTransformCache): void;
|
|
270
338
|
/**
|
|
@@ -402,7 +470,7 @@ export declare function createTransformResult(source: string, code: string): Tts
|
|
|
402
470
|
* slash path. Exported so hosts without a per-build boundary (`@ttsc/metro`)
|
|
403
471
|
* can fold the identical input universe into their own cache fingerprints.
|
|
404
472
|
*/
|
|
405
|
-
export declare function collectProjectInputHashes(projectRoot: string, identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations): Record<string, string>;
|
|
473
|
+
export declare function collectProjectInputHashes(projectRoot: string, identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations, policy?: ITtscProjectMembershipPolicy): Record<string, string>;
|
|
406
474
|
/**
|
|
407
475
|
* Report whether an absolute `file` belongs to the project walk universe of
|
|
408
476
|
* `root`: it lies under `root`, every component exists without traversing a
|
|
@@ -412,7 +480,7 @@ export declare function collectProjectInputHashes(projectRoot: string, identitie
|
|
|
412
480
|
* Missing paths and files reached through symlinks or Windows junctions are
|
|
413
481
|
* out-of-walk inputs that only the reference graph can prove relevant.
|
|
414
482
|
*/
|
|
415
|
-
export declare function isProjectWalkPath(root: string, file: string, _identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations): boolean;
|
|
483
|
+
export declare function isProjectWalkPath(root: string, file: string, _identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations, policy?: ITtscProjectMembershipPolicy): boolean;
|
|
416
484
|
/**
|
|
417
485
|
* Hash a list of absolute out-of-walk input paths: content SHA-256 for a
|
|
418
486
|
* readable file, a stable directory-kind digest for a directory candidate, and
|
package/lib/core/transform.d.mts
CHANGED
|
@@ -3,6 +3,7 @@ import type { ITtscCompilerTransformation } from "ttsc";
|
|
|
3
3
|
import { type FilesystemPathIdentityContext, type FilesystemPathIdentityOperations } from "ttsc/path-identity";
|
|
4
4
|
import type { TransformResult } from "unplugin";
|
|
5
5
|
import type { ResolvedTtscUnpluginOptions } from "./options.mjs";
|
|
6
|
+
import { type ITtscProjectMembershipPolicy } from "./tsconfigPaths.mjs";
|
|
6
7
|
/**
|
|
7
8
|
* The normalised transform result type that this module produces.
|
|
8
9
|
*
|
|
@@ -11,22 +12,31 @@ import type { ResolvedTtscUnpluginOptions } from "./options.mjs";
|
|
|
11
12
|
* `undefined`.
|
|
12
13
|
*/
|
|
13
14
|
export type TtscTransformResult = Exclude<TransformResult, string | null | undefined>;
|
|
14
|
-
/**
|
|
15
|
-
* Normalised alias entry used when building the `paths` overlay for the
|
|
16
|
-
* generated tsconfig. Derived from either a Vite array alias or a webpack/
|
|
17
|
-
* Rspack object alias.
|
|
18
|
-
*/
|
|
19
|
-
export interface TtscTransformAlias {
|
|
20
|
-
/** The alias key (module specifier prefix). */
|
|
21
|
-
find: string;
|
|
22
|
-
/** Absolute or cwd-relative path that the alias points to. */
|
|
23
|
-
replacement: string;
|
|
24
|
-
}
|
|
25
|
-
/** One directory's cheap project-membership identity at generation time. */
|
|
15
|
+
/** One directory's project-membership identity at generation time. */
|
|
26
16
|
interface TtscProjectDirectorySnapshot {
|
|
27
17
|
/** Absolute directory spelling used by the project walk. */
|
|
28
18
|
path: string;
|
|
29
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Whether this directory's subtree can hold a program input.
|
|
21
|
+
*
|
|
22
|
+
* A directory that cannot is still walked and still watched, so a source
|
|
23
|
+
* appearing in it later is noticed, but it takes no part in the membership
|
|
24
|
+
* comparison. That is what lets a bundler create its output directory and
|
|
25
|
+
* fill it without voiding a generation no compiler input touched, for any
|
|
26
|
+
* output directory rather than for fifteen names (samchon/ttsc#1307).
|
|
27
|
+
*/
|
|
28
|
+
relevant: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Digest of the entries the walk itself considers: every immediate child the
|
|
31
|
+
* ignore list does not drop, with its kind.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately not the directory's own metadata. A directory's stamp moves
|
|
34
|
+
* whenever _any_ entry is added or removed, including the ones the walk
|
|
35
|
+
* exists to ignore, so a bundler emitting into `dist/` — or merely creating
|
|
36
|
+
* that directory for the first time — moved the project root's stamp and
|
|
37
|
+
* voided a generation that no compiler input had touched. The ignore list
|
|
38
|
+
* only protects the generation if the membership proof honours it too.
|
|
39
|
+
*/
|
|
30
40
|
signature: string;
|
|
31
41
|
}
|
|
32
42
|
/** Generation-scoped directory watchers used to detect membership changes. */
|
|
@@ -117,6 +127,28 @@ export interface TtscCachedProjectTransform {
|
|
|
117
127
|
* transform.
|
|
118
128
|
*/
|
|
119
129
|
inputHashes: Record<string, string>;
|
|
130
|
+
/**
|
|
131
|
+
* What the resolved configuration admitted into this generation's program.
|
|
132
|
+
*
|
|
133
|
+
* Recorded per generation rather than read per validation because it is a
|
|
134
|
+
* property of the configuration the compile ran under, so a later delivery
|
|
135
|
+
* must judge membership by the same rule the compile did. A tsconfig edit
|
|
136
|
+
* that changes the rule also changes a declared input, which replaces the
|
|
137
|
+
* generation and its policy together.
|
|
138
|
+
*/
|
|
139
|
+
membershipPolicy: ITtscProjectMembershipPolicy;
|
|
140
|
+
/**
|
|
141
|
+
* Files already reported as absent from the program, and the pass that
|
|
142
|
+
* reporting belongs to, so the notice is one per file per pass rather than
|
|
143
|
+
* one per delivery.
|
|
144
|
+
*/
|
|
145
|
+
missingOutputReported?: Set<string>;
|
|
146
|
+
missingOutputEpoch?: number;
|
|
147
|
+
/**
|
|
148
|
+
* The project config this generation compiled, so a module the program does
|
|
149
|
+
* not contain can be told which program that was.
|
|
150
|
+
*/
|
|
151
|
+
tsconfig: string;
|
|
120
152
|
/**
|
|
121
153
|
* Metadata signature of each {@link inputHashes} entry whose hash was proven
|
|
122
154
|
* against an unracing read of the file on disk, in a tick the observed
|
|
@@ -179,10 +211,35 @@ export interface TtscCachedProjectTransform {
|
|
|
179
211
|
projectRoot: string;
|
|
180
212
|
/** Raw compiler output returned by {@link TtscCompiler.transform}. */
|
|
181
213
|
result: ITtscCompilerTransformation;
|
|
214
|
+
/**
|
|
215
|
+
* The delivery epoch this generation is currently settled against, or
|
|
216
|
+
* `undefined` for a generation no epoch has proven.
|
|
217
|
+
*
|
|
218
|
+
* Set when the generation is compiled, and again whenever a later epoch's
|
|
219
|
+
* first delivery proves the whole generation still matches the filesystem.
|
|
220
|
+
* While it equals the cache's current epoch, each module's first delivery is
|
|
221
|
+
* settled by the supplied source alone, exactly as it was when every pass
|
|
222
|
+
* compiled its own generation (samchon/ttsc#1300).
|
|
223
|
+
*/
|
|
224
|
+
deliveryEpoch?: number;
|
|
225
|
+
/**
|
|
226
|
+
* Whether this generation's non-error diagnostics have been surfaced at all,
|
|
227
|
+
* and the epoch they were last surfaced in.
|
|
228
|
+
*
|
|
229
|
+
* The diagnostics describe one compile of one program, so they belong to the
|
|
230
|
+
* generation rather than to a delivery; a pass that reuses a retained
|
|
231
|
+
* generation still surfaces them once, because a build's warnings are part of
|
|
232
|
+
* what that build reports (samchon/ttsc#1304). The two fields are separate so
|
|
233
|
+
* a persistent host, whose epoch is `undefined`, still reports the first
|
|
234
|
+
* time.
|
|
235
|
+
*/
|
|
236
|
+
diagnosticsReported?: boolean;
|
|
237
|
+
diagnosticsEpoch?: number;
|
|
182
238
|
/**
|
|
183
239
|
* Files already delivered from this generation, keyed by filesystem identity.
|
|
184
|
-
*
|
|
185
|
-
* module's first delivery inside the current
|
|
240
|
+
* A cache with a delivery epoch uses this to skip persistent validation only
|
|
241
|
+
* for a module's first delivery inside the current pass; the set is cleared
|
|
242
|
+
* whenever a new epoch's gate re-proves the generation.
|
|
186
243
|
*/
|
|
187
244
|
servedFiles?: Set<string>;
|
|
188
245
|
/**
|
|
@@ -251,20 +308,31 @@ export declare function normalizeHostInputName(name: string, caseSensitive: bool
|
|
|
251
308
|
/** Create an empty persistent transform cache with isolated filesystem reads. */
|
|
252
309
|
export declare function createTtscTransformCache(operations?: Partial<TtscTransformFilesystemOperations>): TtscTransformCache;
|
|
253
310
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
311
|
+
* Open a new delivery pass, enabling constant-time first delivery for every
|
|
312
|
+
* module this pass asks for.
|
|
313
|
+
*
|
|
314
|
+
* This deliberately retains the cached generation. The pass boundary is a
|
|
315
|
+
* statement about _deliveries_ — each module is requested at most once inside
|
|
316
|
+
* it — not about whether the compiled program is still correct, which the
|
|
317
|
+
* generation's own recorded snapshot answers and which
|
|
318
|
+
* {@link matchesCachedSource} proves once at the pass's first delivery. Clearing
|
|
319
|
+
* here instead made a host whose `buildStart` repeats recompile the whole
|
|
320
|
+
* project on every rebuild even when no compiler input had changed
|
|
321
|
+
* (samchon/ttsc#1300). Use {@link resetTtscTransformCache} to actually discard a
|
|
322
|
+
* generation and its watchers.
|
|
256
323
|
*
|
|
257
|
-
* Hosts without a guaranteed
|
|
258
|
-
*
|
|
324
|
+
* Hosts without a guaranteed pass boundary use persistent validation unless
|
|
325
|
+
* they have another immutable lifecycle. Bun runtime setup, for example,
|
|
259
326
|
* defines one process-scoped module-loading session.
|
|
260
327
|
*/
|
|
261
328
|
export declare function beginTtscTransformBuild(cache: TtscTransformCache): void;
|
|
262
329
|
/**
|
|
263
|
-
*
|
|
330
|
+
* Discard every generation, dispose its watchers, and return the cache to
|
|
331
|
+
* persistent validation mode.
|
|
264
332
|
*
|
|
265
|
-
* This is
|
|
266
|
-
*
|
|
267
|
-
*
|
|
333
|
+
* This is the unconditional lifecycle boundary, and it is distinct from
|
|
334
|
+
* {@link beginTtscTransformBuild}: a pass ending is not a reason to throw a
|
|
335
|
+
* proven compile away, while a session ending is.
|
|
268
336
|
*/
|
|
269
337
|
export declare function resetTtscTransformCache(cache: TtscTransformCache): void;
|
|
270
338
|
/**
|
|
@@ -402,7 +470,7 @@ export declare function createTransformResult(source: string, code: string): Tts
|
|
|
402
470
|
* slash path. Exported so hosts without a per-build boundary (`@ttsc/metro`)
|
|
403
471
|
* can fold the identical input universe into their own cache fingerprints.
|
|
404
472
|
*/
|
|
405
|
-
export declare function collectProjectInputHashes(projectRoot: string, identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations): Record<string, string>;
|
|
473
|
+
export declare function collectProjectInputHashes(projectRoot: string, identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations, policy?: ITtscProjectMembershipPolicy): Record<string, string>;
|
|
406
474
|
/**
|
|
407
475
|
* Report whether an absolute `file` belongs to the project walk universe of
|
|
408
476
|
* `root`: it lies under `root`, every component exists without traversing a
|
|
@@ -412,7 +480,7 @@ export declare function collectProjectInputHashes(projectRoot: string, identitie
|
|
|
412
480
|
* Missing paths and files reached through symlinks or Windows junctions are
|
|
413
481
|
* out-of-walk inputs that only the reference graph can prove relevant.
|
|
414
482
|
*/
|
|
415
|
-
export declare function isProjectWalkPath(root: string, file: string, _identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations): boolean;
|
|
483
|
+
export declare function isProjectWalkPath(root: string, file: string, _identities?: FilesystemPathIdentityContext, filesystem?: TtscTransformFilesystemOperations, policy?: ITtscProjectMembershipPolicy): boolean;
|
|
416
484
|
/**
|
|
417
485
|
* Hash a list of absolute out-of-walk input paths: content SHA-256 for a
|
|
418
486
|
* readable file, a stable directory-kind digest for a directory candidate, and
|