@rohal12/twee-ts 2.0.0 → 2.1.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/dist/bin/twee-ts.js +47 -32
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/{diagnostic-text-BRddVulf.cjs → diagnostic-text-Bj-UQ0Jl.cjs} +4283 -3739
- package/dist/diagnostic-text-Bj-UQ0Jl.cjs.map +1 -0
- package/dist/{diagnostic-text-CebYCTPQ.js → diagnostic-text-DMVZfBh9.js} +4260 -3770
- package/dist/diagnostic-text-DMVZfBh9.js.map +1 -0
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +3 -3
- package/dist/{lint-VayZI_jp.js → lint-BkpfLGuP.js} +3 -3
- package/dist/{lint-VayZI_jp.js.map → lint-BkpfLGuP.js.map} +1 -1
- package/dist/plugins/rollup.cjs +9 -4
- package/dist/plugins/rollup.cjs.map +1 -1
- package/dist/plugins/rollup.d.cts +6 -0
- package/dist/plugins/rollup.d.ts +6 -0
- package/dist/plugins/rollup.js +9 -4
- package/dist/plugins/rollup.js.map +1 -1
- package/dist/plugins/vite.cjs +453 -154
- package/dist/plugins/vite.cjs.map +1 -1
- package/dist/plugins/vite.js +453 -154
- package/dist/plugins/vite.js.map +1 -1
- package/dist/{watch-targets-C0Anuw17.cjs → watch-targets-BrEYmUwU.cjs} +84 -16
- package/dist/watch-targets-BrEYmUwU.cjs.map +1 -0
- package/dist/{watch-targets-BI7jYrwa.js → watch-targets-DzvPyWDo.js} +79 -17
- package/dist/watch-targets-DzvPyWDo.js.map +1 -0
- package/package.json +2 -2
- package/dist/diagnostic-text-BRddVulf.cjs.map +0 -1
- package/dist/diagnostic-text-CebYCTPQ.js.map +0 -1
- package/dist/watch-targets-BI7jYrwa.js.map +0 -1
- package/dist/watch-targets-C0Anuw17.cjs.map +0 -1
package/dist/plugins/vite.cjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/*! @rohal12/twee-ts (Unlicense). Bundles third-party code under its own licence: see THIRD_PARTY_NOTICES. */
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_diagnostic_text = require("../diagnostic-text-
|
|
4
|
-
const require_watch_targets = require("../watch-targets-
|
|
3
|
+
const require_diagnostic_text = require("../diagnostic-text-Bj-UQ0Jl.cjs");
|
|
4
|
+
const require_watch_targets = require("../watch-targets-BrEYmUwU.cjs");
|
|
5
5
|
let node_path = require("node:path");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_util = require("node:util");
|
|
8
|
+
let node_url = require("node:url");
|
|
8
9
|
let vite = require("vite");
|
|
10
|
+
let node_module = require("node:module");
|
|
9
11
|
//#region src/plugins/vite-glob.ts
|
|
10
12
|
/**
|
|
11
13
|
* The folders an entry's `import.meta.glob()` calls read. Vite replaces each call with the files that match it
|
|
@@ -15,8 +17,8 @@ let vite = require("vite");
|
|
|
15
17
|
*
|
|
16
18
|
* A scope is a superset of what the glob matches: a file added to it or removed from it may not match (a negated
|
|
17
19
|
* pattern, a name the wildcards leave out), which only bundles again for nothing. The calls are read with acorn as Vite reads them: patterns are
|
|
18
|
-
* string literals, template literals without expressions, or arrays of those
|
|
19
|
-
*
|
|
20
|
+
* string literals, template literals without expressions, or arrays of those. Options are static literal data,
|
|
21
|
+
* including computed keys and repeated members; expressions outside that subset are diagnosed, never evaluated.
|
|
20
22
|
*
|
|
21
23
|
* Code that is a module is read whole, so only real calls count. Code that is not (yet) one, as a plugin may hand
|
|
22
24
|
* on a component file or TypeScript it transforms later, is read the way Vite's import-glob reads every module:
|
|
@@ -33,18 +35,6 @@ const MODULE_OPTIONS = {
|
|
|
33
35
|
function mayHoldGlob(code) {
|
|
34
36
|
return code.includes("import.meta.glob");
|
|
35
37
|
}
|
|
36
|
-
function isNode(value) {
|
|
37
|
-
return require_diagnostic_text.isRecord(value) && typeof value["type"] === "string";
|
|
38
|
-
}
|
|
39
|
-
/** Every node below `root`, `root` first, in source order. */
|
|
40
|
-
function* nodesOf(root) {
|
|
41
|
-
const stack = [root];
|
|
42
|
-
for (let value = stack.pop(); value !== void 0; value = stack.pop()) {
|
|
43
|
-
if (isNode(value)) yield value;
|
|
44
|
-
const children = Array.isArray(value) ? value : isNode(value) ? Object.values(value) : [];
|
|
45
|
-
require_diagnostic_text.pushAll(stack, children.toReversed());
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
38
|
/** Whether `node` is the callee `import.meta.glob`. */
|
|
49
39
|
function isGlobCallee(node) {
|
|
50
40
|
return node.type === "MemberExpression" && !node.computed && node.property.type === "Identifier" && node.property.name === "glob" && node.object.type === "MetaProperty" && node.object.meta.name === "import" && node.object.property.name === "meta";
|
|
@@ -55,24 +45,62 @@ function stringOf(node) {
|
|
|
55
45
|
if (node.type === "Literal") return typeof node.value === "string" ? node.value : void 0;
|
|
56
46
|
if (node.type === "TemplateLiteral" && node.expressions.length === 0) return node.quasis[0]?.value.raw;
|
|
57
47
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
48
|
+
/** An expression outside the static data subset: never run it or guess the folder it selects. */
|
|
49
|
+
const UNREADABLE = Symbol("unreadable");
|
|
50
|
+
/** Static option data, with JavaScript's cooked strings, computed keys and last-member precedence. */
|
|
51
|
+
function staticValue(node, depth = 0) {
|
|
52
|
+
if (depth > 100) return UNREADABLE;
|
|
53
|
+
switch (node.type) {
|
|
54
|
+
case "Literal": return node.regex === void 0 && node.bigint === void 0 ? node.value : UNREADABLE;
|
|
55
|
+
case "TemplateLiteral": return node.expressions.length === 0 ? node.quasis[0]?.value.cooked ?? UNREADABLE : UNREADABLE;
|
|
56
|
+
case "UnaryExpression": {
|
|
57
|
+
const value = staticValue(node.argument, depth + 1);
|
|
58
|
+
if (value === UNREADABLE) return UNREADABLE;
|
|
59
|
+
if (node.operator === "!") return !value;
|
|
60
|
+
if (typeof value === "number") {
|
|
61
|
+
if (node.operator === "-") return -value;
|
|
62
|
+
if (node.operator === "+") return value;
|
|
63
|
+
}
|
|
64
|
+
return UNREADABLE;
|
|
65
|
+
}
|
|
66
|
+
case "ArrayExpression": {
|
|
67
|
+
const values = [];
|
|
68
|
+
for (const element of node.elements) {
|
|
69
|
+
if (element === null || element.type === "SpreadElement") return UNREADABLE;
|
|
70
|
+
const value = staticValue(element, depth + 1);
|
|
71
|
+
if (value === UNREADABLE) return UNREADABLE;
|
|
72
|
+
values.push(value);
|
|
73
|
+
}
|
|
74
|
+
return values;
|
|
75
|
+
}
|
|
76
|
+
case "ObjectExpression": {
|
|
77
|
+
const entries = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const property of node.properties) {
|
|
79
|
+
if (property.type === "SpreadElement") return UNREADABLE;
|
|
80
|
+
if (property.kind !== "init" || property.method || property.shorthand) return UNREADABLE;
|
|
81
|
+
if (property.computed && property.key.type !== "Literal") return UNREADABLE;
|
|
82
|
+
const key = !property.computed && property.key.type === "Identifier" ? property.key.name : staticValue(property.key, depth + 1);
|
|
83
|
+
const value = staticValue(property.value, depth + 1);
|
|
84
|
+
if (depth === 0 && key === "exhaustive" && property.value.type !== "Literal") return UNREADABLE;
|
|
85
|
+
if (key !== null && typeof key !== "string" && typeof key !== "number" && typeof key !== "boolean" || value === UNREADABLE || !property.computed && key === "__proto__") return UNREADABLE;
|
|
86
|
+
entries.set(String(key), value);
|
|
87
|
+
}
|
|
88
|
+
return Object.fromEntries(entries);
|
|
89
|
+
}
|
|
90
|
+
default: return UNREADABLE;
|
|
64
91
|
}
|
|
65
92
|
}
|
|
66
93
|
/** The call a glob call's arguments make. */
|
|
67
94
|
function callOf(args) {
|
|
68
95
|
const [first, second] = args;
|
|
69
96
|
const patterns = (first === void 0 ? [] : first.type === "ArrayExpression" ? first.elements : [first]).map(stringOf).filter((pattern) => pattern !== void 0);
|
|
70
|
-
const options = second
|
|
71
|
-
|
|
97
|
+
const options = second === void 0 ? {} : second.type === "SpreadElement" ? UNREADABLE : staticValue(second);
|
|
98
|
+
if (options === UNREADABLE) return void 0;
|
|
99
|
+
const base = require_diagnostic_text.isRecord(options) ? options["base"] : void 0;
|
|
72
100
|
return {
|
|
73
101
|
patterns,
|
|
74
102
|
base: typeof base === "string" ? base : void 0,
|
|
75
|
-
exhaustive:
|
|
103
|
+
exhaustive: require_diagnostic_text.isRecord(options) && options["exhaustive"] === true
|
|
76
104
|
};
|
|
77
105
|
}
|
|
78
106
|
/** Where Vite's import-glob finds a call in a module's text: the callee, any TypeScript type arguments, `(`. */
|
|
@@ -82,13 +110,26 @@ const GLOB_CALL_START = /\bimport\.meta\.glob(?:<\w+>)?\s*\(/g;
|
|
|
82
110
|
* there: past strings, template literals, regular expressions and comments that hold parentheses. Undefined when the
|
|
83
111
|
* list does not close, or the text cannot be tokenized.
|
|
84
112
|
*/
|
|
85
|
-
function argumentsEnd(code, paren) {
|
|
113
|
+
function argumentsEnd(code, paren, budget) {
|
|
114
|
+
const tokenizer = Object.assign(require_diagnostic_text.AcornParser.tokenizer("", MODULE_OPTIONS), {
|
|
115
|
+
input: code,
|
|
116
|
+
pos: paren
|
|
117
|
+
});
|
|
86
118
|
const read = require_diagnostic_text.trySyntax(() => {
|
|
87
119
|
let depth = 0;
|
|
88
|
-
for (
|
|
120
|
+
for (;;) {
|
|
121
|
+
const from = tokenizer.pos;
|
|
122
|
+
let token;
|
|
123
|
+
try {
|
|
124
|
+
token = tokenizer.getToken();
|
|
125
|
+
} finally {
|
|
126
|
+
const searched = token === void 0 || token.type === require_diagnostic_text.types$1.invalidTemplate ? code.length : tokenizer.pos;
|
|
127
|
+
budget.remaining -= Math.max(1, searched - from);
|
|
128
|
+
}
|
|
129
|
+
if (budget.remaining < 0 || token.type === require_diagnostic_text.types$1.eof) return void 0;
|
|
89
130
|
if (token.type === require_diagnostic_text.types$1.parenL) depth += 1;
|
|
90
131
|
else if (token.type === require_diagnostic_text.types$1.parenR) depth -= 1;
|
|
91
|
-
if (depth === 0) return
|
|
132
|
+
if (depth === 0) return token.end;
|
|
92
133
|
}
|
|
93
134
|
});
|
|
94
135
|
return read.ok ? read.value : void 0;
|
|
@@ -103,9 +144,11 @@ function wholeExpression(text, options) {
|
|
|
103
144
|
* of its argument list: as a call expression, or, with type arguments between the two (which JavaScript reads as
|
|
104
145
|
* comparisons), as its argument list in parentheses. Undefined when acorn reads neither.
|
|
105
146
|
*/
|
|
106
|
-
function callAt(code, start, paren) {
|
|
107
|
-
const end = argumentsEnd(code, paren);
|
|
147
|
+
function callAt(code, start, paren, budget) {
|
|
148
|
+
const end = argumentsEnd(code, paren, budget);
|
|
108
149
|
if (end === void 0) return void 0;
|
|
150
|
+
budget.remaining -= end - start + end - paren;
|
|
151
|
+
if (budget.remaining < 0) return void 0;
|
|
109
152
|
const call = wholeExpression(code.slice(start, end), MODULE_OPTIONS);
|
|
110
153
|
if (call?.type === "CallExpression" && isGlobCallee(call.callee)) return callOf(call.arguments);
|
|
111
154
|
const list = wholeExpression(code.slice(paren, end), {
|
|
@@ -119,31 +162,46 @@ function callAt(code, start, paren) {
|
|
|
119
162
|
/** The glob calls of a module's code: read whole when it is a module, else each call on its own. */
|
|
120
163
|
function globCalls(code) {
|
|
121
164
|
const parsed = require_diagnostic_text.trySyntax(() => require_diagnostic_text.AcornParser.parse(code, MODULE_OPTIONS));
|
|
122
|
-
if (parsed.ok)
|
|
123
|
-
calls
|
|
124
|
-
unreadable
|
|
125
|
-
|
|
165
|
+
if (parsed.ok) {
|
|
166
|
+
const calls = [];
|
|
167
|
+
const unreadable = [];
|
|
168
|
+
for (const node of require_diagnostic_text.javaScriptNodes(parsed.value)) {
|
|
169
|
+
if (node.type !== "CallExpression" || !isGlobCallee(node.callee)) continue;
|
|
170
|
+
const call = callOf(node.arguments);
|
|
171
|
+
if (call === void 0) unreadable.push(node.start);
|
|
172
|
+
else calls.push(call);
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
calls,
|
|
176
|
+
unreadable
|
|
177
|
+
};
|
|
178
|
+
}
|
|
126
179
|
const calls = [];
|
|
127
180
|
const unreadable = [];
|
|
181
|
+
const budget = { remaining: code.length * 16 };
|
|
128
182
|
for (const match of code.matchAll(GLOB_CALL_START)) {
|
|
129
|
-
const call = callAt(code, match.index, match.index + match[0].length - 1);
|
|
183
|
+
const call = callAt(code, match.index, match.index + match[0].length - 1, budget);
|
|
130
184
|
if (call === void 0) unreadable.push(match.index);
|
|
131
185
|
else calls.push(call);
|
|
186
|
+
if (budget.remaining < 0) return {
|
|
187
|
+
calls,
|
|
188
|
+
unreadable,
|
|
189
|
+
recoveryLimited: true
|
|
190
|
+
};
|
|
132
191
|
}
|
|
133
192
|
return {
|
|
134
193
|
calls,
|
|
135
194
|
unreadable
|
|
136
195
|
};
|
|
137
196
|
}
|
|
138
|
-
/** Where `offset` is in `code`, as `line:column`, both from 1. */
|
|
139
|
-
function lineColumn(code, offset) {
|
|
140
|
-
const lines = code.slice(0, offset).split("\n");
|
|
141
|
-
return `${String(lines.length)}:${String((lines.at(-1)?.length ?? 0) + 1)}`;
|
|
142
|
-
}
|
|
143
197
|
/** Characters that make a segment of a pattern match more than its own name (picomatch's, and its escape). */
|
|
144
198
|
const MAGIC = /[*?[\]{}()!+@\\]/;
|
|
145
|
-
/** The characters
|
|
146
|
-
|
|
199
|
+
/** The characters after the last MAGIC one, found without retrying each literal prefix as a regex start. */
|
|
200
|
+
function literalEnd(segment) {
|
|
201
|
+
let start = segment.length;
|
|
202
|
+
while (start > 0 && !MAGIC.test(segment.charAt(start - 1))) start -= 1;
|
|
203
|
+
return segment.slice(start).toLowerCase();
|
|
204
|
+
}
|
|
147
205
|
/** Whether a pattern's segments may match a name starting with a dot, which a wildcard alone never does. */
|
|
148
206
|
function namesDot(segments) {
|
|
149
207
|
return segments.some((segment) => segment !== ".." && /(?:^|[{,])\./.test(segment));
|
|
@@ -163,7 +221,7 @@ function scopeOf(dir, rest, exhaustive) {
|
|
|
163
221
|
deep: below.length > 1 || below.some((segment) => segment.includes("**")),
|
|
164
222
|
dot: exhaustive || namesDot(below),
|
|
165
223
|
exhaustive,
|
|
166
|
-
suffix: (
|
|
224
|
+
suffix: literalEnd(below.at(-1) ?? "")
|
|
167
225
|
};
|
|
168
226
|
}
|
|
169
227
|
/**
|
|
@@ -286,7 +344,7 @@ function scopeWatchTargets(scopes) {
|
|
|
286
344
|
async function resolveGlob(context, pattern, importer) {
|
|
287
345
|
const isSubImportsPattern = pattern.startsWith("#") && pattern.includes("*");
|
|
288
346
|
try {
|
|
289
|
-
return (await context.resolve(pattern, importer, { custom: { "vite:import-glob": { isSubImportsPattern } } }))?.id
|
|
347
|
+
return (await context.resolve(pattern, importer, { custom: { "vite:import-glob": { isSubImportsPattern } } }))?.id;
|
|
290
348
|
} catch {
|
|
291
349
|
return;
|
|
292
350
|
}
|
|
@@ -298,10 +356,14 @@ async function resolveGlob(context, pattern, importer) {
|
|
|
298
356
|
*/
|
|
299
357
|
async function moduleGlobScopes(context, code, id, root) {
|
|
300
358
|
if (!mayHoldGlob(code)) return [];
|
|
301
|
-
const { calls, unreadable } = globCalls(code);
|
|
359
|
+
const { calls, unreadable, recoveryLimited } = globCalls(code);
|
|
302
360
|
if (unreadable.length > 0) {
|
|
303
|
-
const
|
|
304
|
-
|
|
361
|
+
const locate = require_diagnostic_text.lineColumnFinder(code);
|
|
362
|
+
const where = unreadable.map((offset) => {
|
|
363
|
+
const { line, column } = locate(offset);
|
|
364
|
+
return `${String(line)}:${String(column)}`;
|
|
365
|
+
}).join(", ");
|
|
366
|
+
context.warn(`twee-ts could not read the import.meta.glob() call at ${where} of ${id}; ` + (recoveryLimited === true ? "recovery work limit reached; remaining calls were not read; " : "") + "files added to its folders are bundled the next time something else changes.");
|
|
305
367
|
}
|
|
306
368
|
const file = id.replace(/[?#].*$/s, "");
|
|
307
369
|
const importer = (0, node_path.isAbsolute)(file) && !id.startsWith("\0") ? file : void 0;
|
|
@@ -423,8 +485,24 @@ function entryInputSettings(inputName, entryPath, userOutput, outputFilename) {
|
|
|
423
485
|
};
|
|
424
486
|
}
|
|
425
487
|
/** Removes a trailing source-map comment that points at a file (a data: URL map stays). */
|
|
426
|
-
function dropFileSourceMapComment(code) {
|
|
427
|
-
|
|
488
|
+
function dropFileSourceMapComment(code, language) {
|
|
489
|
+
const end = code.trimEnd().length;
|
|
490
|
+
const start = Math.max(language === "js" ? code.lastIndexOf("//# sourceMappingURL=", end) : -1, code.lastIndexOf("/*# sourceMappingURL=", end));
|
|
491
|
+
if (start === -1) return code;
|
|
492
|
+
const candidate = code.slice(start, end);
|
|
493
|
+
if (!/^(?:\/\/# sourceMappingURL=(?!data:)\S*|\/\*# sourceMappingURL=(?!data:)[^*]*\*\/)$/u.test(candidate)) return code;
|
|
494
|
+
const ranges = [{
|
|
495
|
+
start,
|
|
496
|
+
end
|
|
497
|
+
}, {
|
|
498
|
+
start: Math.max(0, start - 1),
|
|
499
|
+
end
|
|
500
|
+
}];
|
|
501
|
+
const [at, before] = language === "js" ? require_diagnostic_text.javaScriptContexts(code, ranges) : require_diagnostic_text.cssContexts(code, ranges);
|
|
502
|
+
const kind = at?.context.kind;
|
|
503
|
+
if (kind !== "line-comment" && kind !== "block-comment" && kind !== "comment") return code;
|
|
504
|
+
if (start > 0 && before?.context.kind === kind) return code;
|
|
505
|
+
return code.slice(0, code[start - 1] === "\n" ? start - 1 : start);
|
|
428
506
|
}
|
|
429
507
|
/** A module id or watched file as a forward-slash file path, without a query or hash (like Vite's cleanUrl). */
|
|
430
508
|
function fileOfId(id) {
|
|
@@ -459,14 +537,14 @@ function takeEntryFromBundle(bundle, inputName) {
|
|
|
459
537
|
const styles = [];
|
|
460
538
|
for (const [fileName, item] of Object.entries(bundle)) if (item.type === "chunk") {
|
|
461
539
|
if (!item.isEntry || inputName !== void 0 && item.name !== inputName) continue;
|
|
462
|
-
script = dropFileSourceMapComment(item.code);
|
|
540
|
+
script = dropFileSourceMapComment(item.code, "js");
|
|
463
541
|
for (const id of item.moduleIds) if (!id.startsWith("\0")) files.add(fileOfId(id));
|
|
464
542
|
removeFromBundle(bundle, fileName);
|
|
465
543
|
} else if (fileName.endsWith(".css") && !isImportedFile(item)) {
|
|
466
544
|
const css = typeof item.source === "string" ? item.source : new TextDecoder().decode(item.source);
|
|
467
|
-
styles.push(dropFileSourceMapComment(css));
|
|
545
|
+
styles.push(dropFileSourceMapComment(css, "css"));
|
|
468
546
|
removeFromBundle(bundle, fileName);
|
|
469
|
-
} else if (fileName.endsWith(".map")) removeFromBundle(bundle, fileName);
|
|
547
|
+
} else if (fileName.endsWith(".map") && (item.originalFileNames?.length ?? 0) === 0) removeFromBundle(bundle, fileName);
|
|
470
548
|
else assets.set(fileName, item.source);
|
|
471
549
|
return {
|
|
472
550
|
script,
|
|
@@ -568,31 +646,69 @@ function appliesTo(plugin, command, config, env) {
|
|
|
568
646
|
/**
|
|
569
647
|
* `plugin` as the entry build runs it: without `apply` (already decided by
|
|
570
648
|
* appliesTo), and, for the dev command, with its `config`, `configEnvironment`
|
|
571
|
-
* and `configResolved` hooks
|
|
572
|
-
*
|
|
649
|
+
* and `configResolved` hooks, environment selection and hook contexts seeing
|
|
650
|
+
* the dev command. Vite's own build plugins still see build. The plugin object itself is left untouched.
|
|
573
651
|
*/
|
|
574
|
-
function asEntryBuildPlugin(plugin, command) {
|
|
652
|
+
function asEntryBuildPlugin(plugin, command, views) {
|
|
575
653
|
const overrides = /* @__PURE__ */ new Map([["apply", void 0]]);
|
|
576
654
|
if (command === "serve") {
|
|
577
655
|
const devEnv = (env) => Object.assign({}, env, {
|
|
578
656
|
command,
|
|
579
657
|
isSsrBuild: false
|
|
580
658
|
});
|
|
581
|
-
const
|
|
582
|
-
|
|
659
|
+
const devConfig = (config) => {
|
|
660
|
+
if (!require_diagnostic_text.isRecord(config)) return config;
|
|
661
|
+
let view = views.configs.get(config);
|
|
662
|
+
if (view === void 0) {
|
|
663
|
+
view = withOverrides(config, /* @__PURE__ */ new Map([["command", command]]));
|
|
664
|
+
views.configs.set(config, view);
|
|
665
|
+
}
|
|
666
|
+
return view;
|
|
667
|
+
};
|
|
668
|
+
const devEnvironment = (environment) => {
|
|
669
|
+
if (!require_diagnostic_text.isRecord(environment)) return environment;
|
|
670
|
+
const known = views.environments.get(environment);
|
|
671
|
+
if (known !== void 0) return known;
|
|
672
|
+
const overrides = /* @__PURE__ */ new Map([["config", devConfig(environment["config"])]]);
|
|
673
|
+
const topLevel = environment["getTopLevelConfig"];
|
|
674
|
+
if (typeof topLevel === "function") overrides.set("getTopLevelConfig", () => devConfig(Reflect.apply(topLevel, environment, [])));
|
|
675
|
+
const view = withOverrides(environment, overrides);
|
|
676
|
+
views.environments.set(environment, view);
|
|
677
|
+
return view;
|
|
678
|
+
};
|
|
679
|
+
const devContext = (context) => {
|
|
680
|
+
if (!require_diagnostic_text.isRecord(context) || context["environment"] === void 0) return context;
|
|
681
|
+
const environment = devEnvironment(context["environment"]);
|
|
682
|
+
return new Proxy(context, { get(target, key) {
|
|
683
|
+
if (key === "environment") return environment;
|
|
684
|
+
const value = Reflect.get(target, key, target);
|
|
685
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
686
|
+
} });
|
|
687
|
+
};
|
|
688
|
+
const wrap = (name, patch = (args) => args) => {
|
|
689
|
+
const hook = Reflect.get(plugin, name);
|
|
583
690
|
const handler = hookHandler(hook);
|
|
584
691
|
if (typeof handler !== "function") return;
|
|
585
692
|
overrides.set(name, withHandler(hook, function(...args) {
|
|
586
|
-
return Reflect.apply(handler, this, patch(args));
|
|
693
|
+
return Reflect.apply(handler, devContext(this), patch(args));
|
|
587
694
|
}));
|
|
588
695
|
};
|
|
696
|
+
const keys = /* @__PURE__ */ new Set();
|
|
697
|
+
for (let object = plugin; object !== null && object !== Object.prototype; object = Reflect.getPrototypeOf(object)) for (const key of Reflect.ownKeys(object)) keys.add(key);
|
|
698
|
+
for (const key of keys) if (key !== "constructor" && key !== "apply" && key !== "applyToEnvironment") wrap(key);
|
|
589
699
|
wrap("config", ([config, env]) => [config, devEnv(env)]);
|
|
590
700
|
wrap("configEnvironment", ([name, config, env]) => [
|
|
591
701
|
name,
|
|
592
702
|
config,
|
|
593
703
|
devEnv(env)
|
|
594
704
|
]);
|
|
595
|
-
wrap("configResolved", ([config]) => [
|
|
705
|
+
wrap("configResolved", ([config]) => [devConfig(config)]);
|
|
706
|
+
const select = plugin.applyToEnvironment;
|
|
707
|
+
if (select !== void 0) overrides.set("applyToEnvironment", async function(environment) {
|
|
708
|
+
const result = await Reflect.apply(select, this, [devEnvironment(environment)]);
|
|
709
|
+
if (result === true || !result) return result;
|
|
710
|
+
return (await flattenPlugins(result)).filter(isPlugin).map((selected) => asEntryBuildPlugin(selected, command, views));
|
|
711
|
+
});
|
|
596
712
|
}
|
|
597
713
|
return pluginWith(plugin, overrides);
|
|
598
714
|
}
|
|
@@ -697,7 +813,7 @@ function entryBuildEnforcer(entryPath, command, outputFilename) {
|
|
|
697
813
|
}
|
|
698
814
|
};
|
|
699
815
|
}
|
|
700
|
-
/**
|
|
816
|
+
/** Plugin hooks that may read an entry input and register it with `this.addWatchFile` before the story is emitted. */
|
|
701
817
|
const WATCH_FILE_HOOKS = [
|
|
702
818
|
"buildStart",
|
|
703
819
|
"resolveId",
|
|
@@ -705,7 +821,11 @@ const WATCH_FILE_HOOKS = [
|
|
|
705
821
|
"load",
|
|
706
822
|
"transform",
|
|
707
823
|
"moduleParsed",
|
|
708
|
-
"buildEnd"
|
|
824
|
+
"buildEnd",
|
|
825
|
+
"renderStart",
|
|
826
|
+
"renderChunk",
|
|
827
|
+
"augmentChunkHash",
|
|
828
|
+
"generateBundle"
|
|
709
829
|
];
|
|
710
830
|
/** A plugin context whose `addWatchFile` also passes the file to `record`. */
|
|
711
831
|
function recordingContext(context, record) {
|
|
@@ -714,7 +834,7 @@ function recordingContext(context, record) {
|
|
|
714
834
|
if (typeof value !== "function") return value;
|
|
715
835
|
if (key !== "addWatchFile") return value.bind(target);
|
|
716
836
|
return (id) => {
|
|
717
|
-
if (typeof id === "string" && !id.startsWith("\0")) record(
|
|
837
|
+
if (typeof id === "string" && !id.startsWith("\0")) record((0, node_path.resolve)(id));
|
|
718
838
|
return Reflect.apply(value, target, [id]);
|
|
719
839
|
};
|
|
720
840
|
} });
|
|
@@ -725,13 +845,14 @@ function recordingContext(context, record) {
|
|
|
725
845
|
* never collects wrappers. A plugin without such hooks (a built-in one, for
|
|
726
846
|
* instance) is returned as it is.
|
|
727
847
|
*/
|
|
728
|
-
function recordingPlugin(plugin,
|
|
848
|
+
function recordingPlugin(plugin, recordFor) {
|
|
729
849
|
const overrides = /* @__PURE__ */ new Map();
|
|
730
850
|
for (const name of WATCH_FILE_HOOKS) {
|
|
731
851
|
const hook = plugin[name];
|
|
732
852
|
const handler = hookHandler(hook);
|
|
733
853
|
if (typeof handler !== "function") continue;
|
|
734
854
|
overrides.set(name, withHandler(hook, function(...args) {
|
|
855
|
+
const record = recordFor(name, args);
|
|
735
856
|
const context = typeof this === "object" && this !== null ? recordingContext(this, record) : this;
|
|
736
857
|
return Reflect.apply(handler, context, args);
|
|
737
858
|
}));
|
|
@@ -785,6 +906,45 @@ function writtenPaths(source, importer, root) {
|
|
|
785
906
|
return from !== void 0 && (0, node_path.isAbsolute)(from) && /^\.\.?(?:[/\\]|$)/.test(source) ? [fileOfId((0, node_path.resolve)((0, node_path.dirname)(from), source))] : [];
|
|
786
907
|
}
|
|
787
908
|
/**
|
|
909
|
+
* Package locations Node's upward node_modules search can use for an unresolved bare import. These are recovery
|
|
910
|
+
* inputs only: Vite still decides aliases, exports and the actual module. Watching the package itself sees a
|
|
911
|
+
* restored manifest, export target or nested subpath without watching every installed package recursively.
|
|
912
|
+
*/
|
|
913
|
+
function missingPackagePaths(source, importer) {
|
|
914
|
+
if (importer === void 0 || !(0, node_path.isAbsolute)(fileOfId(importer)) || source === "" || /^[./\\#\0]/.test(source) || source.includes(":")) return [];
|
|
915
|
+
const name = source.split("/").slice(0, source.startsWith("@") ? 2 : 1).join("/");
|
|
916
|
+
const paths = [];
|
|
917
|
+
for (let folder = (0, node_path.dirname)(fileOfId(importer));; folder = (0, node_path.dirname)(folder)) {
|
|
918
|
+
if (require_watch_targets.toPosix(folder).split("/").at(-1) !== "node_modules") paths.push(require_watch_targets.toPosix((0, node_path.join)(folder, "node_modules", name)));
|
|
919
|
+
if ((0, node_path.dirname)(folder) === folder) break;
|
|
920
|
+
}
|
|
921
|
+
return paths;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* A package can import itself through its exports without living in node_modules. Node can locate its manifest
|
|
925
|
+
* even when the export target is missing. Track the package's own file listing as a recovery scope, excluding
|
|
926
|
+
* node_modules; recording the whole folder as a watch file would scan all of its installed dependencies too.
|
|
927
|
+
* The node_modules candidates above remain necessary for packages that have no manifest yet.
|
|
928
|
+
*/
|
|
929
|
+
function missingPackageScope(source, importer, candidates) {
|
|
930
|
+
if (importer === void 0 || candidates.length === 0) return void 0;
|
|
931
|
+
let manifest;
|
|
932
|
+
try {
|
|
933
|
+
manifest = (0, node_module.findPackageJSON)(source, (0, node_url.pathToFileURL)(fileOfId(importer)));
|
|
934
|
+
} catch {
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (manifest === void 0) return void 0;
|
|
938
|
+
const dir = require_watch_targets.toPosix((0, node_path.dirname)(manifest));
|
|
939
|
+
return candidates.includes(dir) ? void 0 : {
|
|
940
|
+
dir,
|
|
941
|
+
deep: true,
|
|
942
|
+
dot: true,
|
|
943
|
+
exhaustive: false,
|
|
944
|
+
suffix: ""
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
788
948
|
* Every path an import of `source` by `importer` is spelled as (see writtenPaths), and the path Vite's resolver
|
|
789
949
|
* reaches the file by, links kept (`kept`, see keptPath). A caller then sees a link on the way that is retargeted,
|
|
790
950
|
* which the file's own path never shows. Nothing for an import from a virtual module, or of one.
|
|
@@ -810,55 +970,100 @@ async function importSpellings(context, source, importer, root) {
|
|
|
810
970
|
* which sees the final plugin list, including the plugins Vite resolves per
|
|
811
971
|
* environment (`applyToEnvironment`) after `configResolved`.
|
|
812
972
|
*/
|
|
813
|
-
function recordWatchFiles(files, root, observer) {
|
|
973
|
+
function recordWatchFiles(files, root, observer = {}) {
|
|
814
974
|
const { onLoad, onResolve, onGlob, onWatchFile } = observer;
|
|
975
|
+
const watches = /* @__PURE__ */ new Map();
|
|
976
|
+
const touched = /* @__PURE__ */ new Set();
|
|
977
|
+
let modules = /* @__PURE__ */ new Set();
|
|
978
|
+
let started = false;
|
|
815
979
|
const record = (file) => {
|
|
816
|
-
files
|
|
980
|
+
files?.add(file);
|
|
817
981
|
onWatchFile?.(file);
|
|
818
982
|
};
|
|
983
|
+
const recordFor = (hook, args) => {
|
|
984
|
+
if (hook === "buildStart" && !started) {
|
|
985
|
+
started = true;
|
|
986
|
+
touched.clear();
|
|
987
|
+
watches.delete(void 0);
|
|
988
|
+
}
|
|
989
|
+
const owner = hook === "transform" || hook === "resolveId" || hook === "resolveDynamicImport" ? args[1] : hook === "load" ? args[0] : hook === "moduleParsed" && require_diagnostic_text.isRecord(args[0]) ? args[0]["id"] : void 0;
|
|
990
|
+
const id = typeof owner === "string" ? owner : void 0;
|
|
991
|
+
if (id !== void 0 && (hook === "load" || hook === "transform") && !touched.has(id)) {
|
|
992
|
+
touched.add(id);
|
|
993
|
+
watches.delete(id);
|
|
994
|
+
}
|
|
995
|
+
return (file) => {
|
|
996
|
+
record(file);
|
|
997
|
+
const owned = watches.get(id) ?? /* @__PURE__ */ new Set();
|
|
998
|
+
watches.set(id, owned.add(file));
|
|
999
|
+
};
|
|
1000
|
+
};
|
|
819
1001
|
return {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1002
|
+
plugin: {
|
|
1003
|
+
name: `${PLUGIN_NAME}:record-watch-files`,
|
|
1004
|
+
buildStart() {
|
|
1005
|
+
recordFor("buildStart", []);
|
|
1006
|
+
},
|
|
1007
|
+
load: {
|
|
1008
|
+
order: "pre",
|
|
1009
|
+
handler(id) {
|
|
1010
|
+
const file = fileOfId(id);
|
|
1011
|
+
if (!(0, node_path.isAbsolute)(file) || id.startsWith("\0")) return null;
|
|
1012
|
+
onLoad?.(file);
|
|
1013
|
+
onResolve?.(file);
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
resolveId: {
|
|
1018
|
+
order: "pre",
|
|
1019
|
+
async handler(source, importer) {
|
|
1020
|
+
if (onResolve === void 0) return null;
|
|
1021
|
+
const { spellings, kept } = await importSpellings(this, source, importer, root);
|
|
1022
|
+
for (const spelled of spellings) onResolve(spelled);
|
|
1023
|
+
if (kept === void 0 && spellings.length === 0) {
|
|
1024
|
+
const candidates = missingPackagePaths(source, importer);
|
|
1025
|
+
for (const path of candidates) record(path);
|
|
1026
|
+
const scope = missingPackageScope(source, importer, candidates);
|
|
1027
|
+
if (scope !== void 0) {
|
|
1028
|
+
record((0, node_path.join)(scope.dir, "package.json"));
|
|
1029
|
+
onGlob?.(scope);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
1034
|
+
},
|
|
1035
|
+
transform: {
|
|
1036
|
+
filter: { code: "import.meta.glob" },
|
|
1037
|
+
async handler(code, id) {
|
|
1038
|
+
if (onGlob === void 0) return null;
|
|
1039
|
+
for (const scope of await moduleGlobScopes(this, code, id, root)) onGlob(scope);
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
1042
|
+
},
|
|
1043
|
+
buildEnd() {
|
|
1044
|
+
modules = new Set(this.getModuleIds());
|
|
1045
|
+
started = false;
|
|
1046
|
+
for (const owner of watches.keys()) if (owner !== void 0 && !modules.has(owner)) watches.delete(owner);
|
|
1047
|
+
for (const id of modules) {
|
|
1048
|
+
const file = fileOfId(id);
|
|
1049
|
+
if ((0, node_path.isAbsolute)(file)) files?.add(file);
|
|
1050
|
+
}
|
|
1051
|
+
},
|
|
1052
|
+
options: {
|
|
1053
|
+
order: "post",
|
|
1054
|
+
async handler(inputOptions) {
|
|
1055
|
+
const plugins = (await flattenPlugins(inputOptions.plugins)).filter(isPlugin).map((p) => recordingPlugin(p, recordFor));
|
|
1056
|
+
return {
|
|
1057
|
+
...inputOptions,
|
|
1058
|
+
plugins
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
851
1061
|
}
|
|
852
1062
|
},
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
return {
|
|
858
|
-
...inputOptions,
|
|
859
|
-
plugins
|
|
860
|
-
};
|
|
861
|
-
}
|
|
1063
|
+
inputs: () => {
|
|
1064
|
+
const current = new Set([...modules].filter((id) => !id.startsWith("\0")).map(fileOfId).filter(node_path.isAbsolute));
|
|
1065
|
+
for (const [owner, watched] of watches) if (owner === void 0 || modules.has(owner)) for (const file of watched) current.add(file);
|
|
1066
|
+
return current;
|
|
862
1067
|
}
|
|
863
1068
|
};
|
|
864
1069
|
}
|
|
@@ -903,7 +1108,13 @@ async function bundleEntry(config, entryPath, command, outputFilename, observer
|
|
|
903
1108
|
isPreview: false
|
|
904
1109
|
};
|
|
905
1110
|
const user = await userConfigFor(config, env);
|
|
906
|
-
const
|
|
1111
|
+
const views = {
|
|
1112
|
+
configs: /* @__PURE__ */ new WeakMap(),
|
|
1113
|
+
environments: /* @__PURE__ */ new WeakMap()
|
|
1114
|
+
};
|
|
1115
|
+
const entryPlugins = async (option) => (await flattenPlugins(option)).filter(isPlugin).filter((plugin) => plugin.name !== "twee-ts" && appliesTo(plugin, command, user, env)).map((plugin) => asEntryBuildPlugin(plugin, command, views));
|
|
1116
|
+
const plugins = await entryPlugins(user.plugins);
|
|
1117
|
+
const workerPlugins = user.worker?.plugins;
|
|
907
1118
|
const inline = {
|
|
908
1119
|
...withoutExcludedKeys(user),
|
|
909
1120
|
configFile: false,
|
|
@@ -916,9 +1127,12 @@ async function bundleEntry(config, entryPath, command, outputFilename, observer
|
|
|
916
1127
|
plugins: [
|
|
917
1128
|
...plugins,
|
|
918
1129
|
entryBuildEnforcer(entryPath, command, outputFilename),
|
|
919
|
-
recordWatchFiles(watchFiles, config.root, observer)
|
|
1130
|
+
recordWatchFiles(watchFiles, config.root, observer).plugin
|
|
920
1131
|
],
|
|
921
|
-
worker: withWorkerPlugin(
|
|
1132
|
+
worker: withWorkerPlugin({
|
|
1133
|
+
...user.worker,
|
|
1134
|
+
plugins: () => [entryPlugins(typeof workerPlugins === "function" ? workerPlugins() : workerPlugins)]
|
|
1135
|
+
}, () => recordWatchFiles(watchFiles, config.root, observer).plugin)
|
|
922
1136
|
};
|
|
923
1137
|
const [result] = [await (0, vite.build)(inline)].flat();
|
|
924
1138
|
if (result === void 0 || !("output" in result)) throw new Error("twee-ts: the entry build returned no bundle.");
|
|
@@ -1059,9 +1273,9 @@ function fileState(file) {
|
|
|
1059
1273
|
* `folder` is not a folder.
|
|
1060
1274
|
*/
|
|
1061
1275
|
function folderState(folder) {
|
|
1062
|
-
if ((0, node_fs.statSync)(folder, { throwIfNoEntry: false })?.isDirectory() !== true) return void 0;
|
|
1063
1276
|
let names;
|
|
1064
1277
|
try {
|
|
1278
|
+
if ((0, node_fs.statSync)(folder, { throwIfNoEntry: false })?.isDirectory() !== true) return void 0;
|
|
1065
1279
|
names = (0, node_fs.readdirSync)(folder, {
|
|
1066
1280
|
recursive: true,
|
|
1067
1281
|
encoding: "utf8"
|
|
@@ -1088,6 +1302,15 @@ function fileRead(file) {
|
|
|
1088
1302
|
function tracked(paths) {
|
|
1089
1303
|
return new Map([...paths].map((path) => [require_watch_targets.fileKey(path), require_watch_targets.canonicalPath(path)]));
|
|
1090
1304
|
}
|
|
1305
|
+
/** A native identity key and every parent above it, without identifying any path again. */
|
|
1306
|
+
function* keyParents(key) {
|
|
1307
|
+
for (let current = key;;) {
|
|
1308
|
+
yield current;
|
|
1309
|
+
const parent = (0, node_path.dirname)(current);
|
|
1310
|
+
if (parent === current) return;
|
|
1311
|
+
current = parent;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1091
1314
|
/**
|
|
1092
1315
|
* The key of the file `authored` reaches, when it reaches it through a link (somewhere along the path, or
|
|
1093
1316
|
* at the end of it): the one case where the file's own path says nothing of a change of target.
|
|
@@ -1156,8 +1379,8 @@ function installStoryRoute(middlewares, route) {
|
|
|
1156
1379
|
handle: route
|
|
1157
1380
|
});
|
|
1158
1381
|
}
|
|
1159
|
-
/** The
|
|
1160
|
-
const
|
|
1382
|
+
/** The instances and entry watches of each server; the watcher is shared by every story (#517). */
|
|
1383
|
+
const devServers = /* @__PURE__ */ new WeakMap();
|
|
1161
1384
|
/** The error for a story page whose URL another story or an entry asset of the same dev server also claims. */
|
|
1162
1385
|
function storyCollisionMessage(path) {
|
|
1163
1386
|
return `twee-ts: more than one generated file is served at ${path || "/"} (another story or an entry asset); set a distinct outputFilename.`;
|
|
@@ -1189,11 +1412,20 @@ async function setUpDevStory(server, dev) {
|
|
|
1189
1412
|
let lastError;
|
|
1190
1413
|
let entry;
|
|
1191
1414
|
let servedAssets;
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1415
|
+
const state = devServers.get(server) ?? {
|
|
1416
|
+
instances: /* @__PURE__ */ new Set(),
|
|
1417
|
+
watched: /* @__PURE__ */ new Map(),
|
|
1418
|
+
released: /* @__PURE__ */ new Map()
|
|
1419
|
+
};
|
|
1420
|
+
devServers.set(server, state);
|
|
1421
|
+
const { instances, watched, released } = state;
|
|
1422
|
+
const watchedForEntry = /* @__PURE__ */ new Map();
|
|
1194
1423
|
const self = {
|
|
1195
1424
|
paths,
|
|
1196
|
-
assets: () => servedAssets
|
|
1425
|
+
assets: () => servedAssets,
|
|
1426
|
+
catchUp: () => catchUp(),
|
|
1427
|
+
inputKeys,
|
|
1428
|
+
entryWatches: watchedForEntry
|
|
1197
1429
|
};
|
|
1198
1430
|
instances.add(self);
|
|
1199
1431
|
const fail = (res, message) => {
|
|
@@ -1212,12 +1444,12 @@ async function setUpDevStory(server, dev) {
|
|
|
1212
1444
|
let entryFolders = /* @__PURE__ */ new Map();
|
|
1213
1445
|
let entryReads = /* @__PURE__ */ new Map();
|
|
1214
1446
|
const readsModules = config.server.watch !== null;
|
|
1215
|
-
const watchedForEntry = /* @__PURE__ */ new Map();
|
|
1216
1447
|
let queue = Promise.resolve();
|
|
1217
1448
|
let pending = /* @__PURE__ */ new Set();
|
|
1218
1449
|
let timer;
|
|
1219
1450
|
let closed = false;
|
|
1220
1451
|
let compiledInputs = /* @__PURE__ */ new Map();
|
|
1452
|
+
let compiledInputNames;
|
|
1221
1453
|
let catchingUp;
|
|
1222
1454
|
const closeWatcher = server.watcher.close.bind(server.watcher);
|
|
1223
1455
|
server.watcher.close = async () => {
|
|
@@ -1227,8 +1459,13 @@ async function setUpDevStory(server, dev) {
|
|
|
1227
1459
|
return closeWatcher();
|
|
1228
1460
|
};
|
|
1229
1461
|
const namedInputs = () => inputs.map((input) => {
|
|
1230
|
-
|
|
1231
|
-
|
|
1462
|
+
let kind;
|
|
1463
|
+
try {
|
|
1464
|
+
const stat = (0, node_fs.statSync)(input, { throwIfNoEntry: false });
|
|
1465
|
+
kind = stat === void 0 ? "none" : stat.isFile() ? "file" : stat.isDirectory() ? "folder" : "other";
|
|
1466
|
+
} catch (error) {
|
|
1467
|
+
kind = `failed:${String(error)}`;
|
|
1468
|
+
}
|
|
1232
1469
|
return `${require_watch_targets.fileKey(input)}\0${kind}`;
|
|
1233
1470
|
}).join("\0");
|
|
1234
1471
|
let inputWalk;
|
|
@@ -1237,7 +1474,7 @@ async function setUpDevStory(server, dev) {
|
|
|
1237
1474
|
const folders = /* @__PURE__ */ new Map();
|
|
1238
1475
|
const files = require_diagnostic_text.getFilenames(inputs, outputs, [], "source", (folder) => folders.set(folder, fileState(folder))).files.filter((file) => !excludedGlob(file.path)).map((file) => ({
|
|
1239
1476
|
key: file.key,
|
|
1240
|
-
path:
|
|
1477
|
+
path: require_diagnostic_text.identify(file.path).absolute,
|
|
1241
1478
|
link: file.link === true
|
|
1242
1479
|
}));
|
|
1243
1480
|
return {
|
|
@@ -1271,14 +1508,28 @@ async function setUpDevStory(server, dev) {
|
|
|
1271
1508
|
const entryWatchTargets = () => new Map([...entryFiles, ...tracked(scopeWatchTargets(entryGlobs.values()))]);
|
|
1272
1509
|
const watchEntryFiles = (files) => {
|
|
1273
1510
|
const added = [...files].filter(([key]) => !require_watch_targets.keyWithin(key, [root]) && !require_watch_targets.keyWithin(key, inputKeys()) && !watchedForEntry.has(key));
|
|
1274
|
-
const
|
|
1275
|
-
for (const [key] of
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1511
|
+
for (const key of watchedForEntry.keys()) if (!files.has(key)) watchedForEntry.delete(key);
|
|
1512
|
+
for (const [key, path] of added) {
|
|
1513
|
+
watchedForEntry.set(key, path);
|
|
1514
|
+
watched.set(key, path);
|
|
1515
|
+
}
|
|
1516
|
+
const owners = /* @__PURE__ */ new Set([root, ...[...instances].flatMap((instance) => [...instance.inputKeys(), ...instance.entryWatches.keys()])]);
|
|
1517
|
+
const aboveOwners = new Set([...owners].flatMap((key) => [...keyParents(key)]));
|
|
1518
|
+
const needed = (key) => aboveOwners.has(key) || [...keyParents(key)].some((parent) => owners.has(parent));
|
|
1519
|
+
const dropped = [...watched].filter(([key]) => !needed(key));
|
|
1520
|
+
for (const [key, path] of dropped) {
|
|
1521
|
+
watched.delete(key);
|
|
1522
|
+
released.set(key, path);
|
|
1523
|
+
}
|
|
1524
|
+
const restored = [...released].filter(([key]) => needed(key));
|
|
1525
|
+
for (const [key, path] of restored) {
|
|
1526
|
+
released.delete(key);
|
|
1527
|
+
watched.set(key, path);
|
|
1281
1528
|
}
|
|
1529
|
+
if (dropped.length > 0) server.watcher.unwatch(dropped.map(([, path]) => path));
|
|
1530
|
+
const registrations = new Map([...restored, ...added]);
|
|
1531
|
+
if (registrations.size > 0) server.watcher.add([...registrations.values()]);
|
|
1532
|
+
if (added.length > 0) recheckOnceWatched(new Map(added)).catch(keepQueueAlive);
|
|
1282
1533
|
};
|
|
1283
1534
|
const isListed = (path) => {
|
|
1284
1535
|
return server.watcher.getWatched()[(0, node_path.dirname)(path)]?.includes((0, node_path.basename)(path)) ?? false;
|
|
@@ -1383,7 +1634,6 @@ async function setUpDevStory(server, dev) {
|
|
|
1383
1634
|
globStates = globsRead;
|
|
1384
1635
|
entryFolders = folders;
|
|
1385
1636
|
entryReads = reads;
|
|
1386
|
-
watchEntryFiles(entryWatchTargets());
|
|
1387
1637
|
};
|
|
1388
1638
|
const alreadyRead = (key) => {
|
|
1389
1639
|
const read = entryReads.get(key);
|
|
@@ -1403,8 +1653,10 @@ async function setUpDevStory(server, dev) {
|
|
|
1403
1653
|
outputs = dev.outputs(config);
|
|
1404
1654
|
output = require_diagnostic_text.outputPaths(outputs);
|
|
1405
1655
|
compiledInputs = storyInputFiles(true);
|
|
1656
|
+
compiledInputNames = inputWalk?.named;
|
|
1406
1657
|
for (const key of [...cache.keys()]) if (changed.has(require_watch_targets.fileKey(key))) cache.delete(key);
|
|
1407
1658
|
if (entryStale || regrouped || unread.some(touchesEntry)) await bundle();
|
|
1659
|
+
watchEntryFiles(entryWatchTargets());
|
|
1408
1660
|
const story = await require_watch_targets.compileStory(options.compile(entrySources(entry)), outputs, cache);
|
|
1409
1661
|
for (const warning of story.warnings) config.logger.warn(`[twee-ts] ${warning}`);
|
|
1410
1662
|
html = outputMode === "html" ? dev.injectClient(story.output, base) : story.output;
|
|
@@ -1452,6 +1704,7 @@ async function setUpDevStory(server, dev) {
|
|
|
1452
1704
|
if (queue === waited) break;
|
|
1453
1705
|
}
|
|
1454
1706
|
const changed = filesChanged(compiledInputs, storyInputFiles(false));
|
|
1707
|
+
if (compiledInputNames !== inputWalk?.named) for (const input of inputs) changed.add(require_watch_targets.fileKey(input));
|
|
1455
1708
|
for (const file of filesChanged(entryStates, fileStates(entryFiles))) changed.add(file);
|
|
1456
1709
|
if (changed.size === 0 && pending.size === 0 && !linkMoved() && !globsChanged() && !foldersChanged()) return;
|
|
1457
1710
|
for (const file of pending) changed.add(file);
|
|
@@ -1494,33 +1747,63 @@ async function setUpDevStory(server, dev) {
|
|
|
1494
1747
|
next();
|
|
1495
1748
|
return;
|
|
1496
1749
|
}
|
|
1497
|
-
const others = [...instances].filter((other) => other !== self);
|
|
1498
1750
|
const mine = paths.includes(path);
|
|
1499
|
-
if (
|
|
1500
|
-
|
|
1751
|
+
if (!mine && servedAssets?.has(path) !== true) {
|
|
1752
|
+
next();
|
|
1501
1753
|
return;
|
|
1502
1754
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1755
|
+
([...instances].some((instance) => instance.paths.includes(path)) ? Promise.all([...instances].map((instance) => instance.catchUp())) : Promise.resolve()).then(() => {
|
|
1756
|
+
const others = [...instances].filter((other) => other !== self);
|
|
1757
|
+
if ((mine || servedAssets?.has(path) === true) && others.some((other) => other.paths.includes(path) || mine && paths.some((storyPath) => other.assets()?.has(storyPath) === true))) {
|
|
1758
|
+
fail(res, storyCollisionMessage(path));
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
if (mine) {
|
|
1762
|
+
if (paths.some((storyPath) => servedAssets?.has(storyPath) === true)) {
|
|
1763
|
+
fail(res, storyCollisionMessage(path));
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1505
1766
|
if (html) send(req, res, OUTPUT_MEDIA_TYPES[outputMode], html);
|
|
1506
1767
|
else send(req, res, "text/html; charset=utf-8", waitingPage(base));
|
|
1507
|
-
}, next);
|
|
1508
|
-
return;
|
|
1509
|
-
}
|
|
1510
|
-
const asset = servedAssets?.get(path);
|
|
1511
|
-
if (asset === void 0) {
|
|
1512
|
-
next();
|
|
1513
|
-
return;
|
|
1514
|
-
}
|
|
1515
|
-
for (const other of others) {
|
|
1516
|
-
const theirs = other.assets()?.get(path);
|
|
1517
|
-
if (theirs !== void 0 && !sameBytes(theirs, asset)) {
|
|
1518
|
-
fail(res, entryCollisionMessage(path));
|
|
1519
1768
|
return;
|
|
1520
1769
|
}
|
|
1770
|
+
const asset = servedAssets?.get(path);
|
|
1771
|
+
if (asset === void 0) {
|
|
1772
|
+
next();
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
for (const other of others) {
|
|
1776
|
+
const theirs = other.assets()?.get(path);
|
|
1777
|
+
if (theirs !== void 0 && !sameBytes(theirs, asset)) {
|
|
1778
|
+
fail(res, entryCollisionMessage(path));
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
send(req, res, assetMediaType(path), asset);
|
|
1783
|
+
}, next);
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
//#endregion
|
|
1787
|
+
//#region src/plugins/vite-public.ts
|
|
1788
|
+
/** Inventory public copies by their destination names, following directory links as Vite's copyDir does. */
|
|
1789
|
+
function publicFiles(publicDir) {
|
|
1790
|
+
if (!(0, node_fs.existsSync)(publicDir)) return [];
|
|
1791
|
+
const files = [];
|
|
1792
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
1793
|
+
const walk = (folder) => {
|
|
1794
|
+
const key = require_watch_targets.fileKey(folder);
|
|
1795
|
+
if (ancestors.has(key)) return;
|
|
1796
|
+
ancestors.add(key);
|
|
1797
|
+
for (const name of (0, node_fs.readdirSync)(folder)) {
|
|
1798
|
+
const path = (0, node_path.resolve)(folder, name);
|
|
1799
|
+
if (!(0, node_fs.existsSync)(path)) continue;
|
|
1800
|
+
if ((0, node_fs.statSync)(path).isDirectory()) walk(path);
|
|
1801
|
+
else files.push((0, node_path.relative)(publicDir, path));
|
|
1521
1802
|
}
|
|
1522
|
-
|
|
1803
|
+
ancestors.delete(key);
|
|
1523
1804
|
};
|
|
1805
|
+
walk(publicDir);
|
|
1806
|
+
return files;
|
|
1524
1807
|
}
|
|
1525
1808
|
//#endregion
|
|
1526
1809
|
//#region src/plugins/vite.ts
|
|
@@ -1589,14 +1872,14 @@ function configOutputLocations(config) {
|
|
|
1589
1872
|
* Every path a build with this config writes, as far as the config tells: each
|
|
1590
1873
|
* output's folder (see configOutputLocations), the story in it, and the copies
|
|
1591
1874
|
* of the public files Vite puts there. The plugin adds the files each bundle
|
|
1592
|
-
* writes as it builds (see createOutputRecord).
|
|
1875
|
+
* writes as it builds (see createOutputRecord). A build passes its persistent
|
|
1876
|
+
* record so public copies remain excluded after a file is removed or a link is retargeted.
|
|
1593
1877
|
*/
|
|
1594
|
-
function configOutputs(config,
|
|
1595
|
-
const
|
|
1596
|
-
const publicFiles = config.build.copyPublicDir && config.publicDir ? require_diagnostic_text.getFilenames([config.publicDir]).filenames.map((file) => (0, node_path.relative)(config.publicDir, (0, node_path.resolve)(file))) : [];
|
|
1878
|
+
function configOutputs(config, record) {
|
|
1879
|
+
const copiedFiles = config.build.copyPublicDir && config.publicDir ? publicFiles(config.publicDir) : [];
|
|
1597
1880
|
for (const location of configOutputLocations(config)) {
|
|
1598
1881
|
record.addLocation(location);
|
|
1599
|
-
record.addFiles(location,
|
|
1882
|
+
record.addFiles(location, copiedFiles);
|
|
1600
1883
|
}
|
|
1601
1884
|
return record.outputs();
|
|
1602
1885
|
}
|
|
@@ -1660,8 +1943,9 @@ function tweeTsPlugin(options) {
|
|
|
1660
1943
|
const entryInput = `${ENTRY_INPUT_NAME}-${instances}`;
|
|
1661
1944
|
const cache = /* @__PURE__ */ new Map();
|
|
1662
1945
|
const ownBuilds = /* @__PURE__ */ new WeakMap();
|
|
1946
|
+
const entryInputs = /* @__PURE__ */ new WeakMap();
|
|
1663
1947
|
const record = require_watch_targets.createOutputRecord(outputFilename);
|
|
1664
|
-
const allOutputs = (config) => mergeOutputs(configOutputs(config, outputFilename), record.outputs());
|
|
1948
|
+
const allOutputs = (config) => mergeOutputs(configOutputs(config, require_watch_targets.createOutputRecord(outputFilename)), record.outputs());
|
|
1665
1949
|
/**
|
|
1666
1950
|
* The build settings this instance adds to a client build: none when the
|
|
1667
1951
|
* user's config names an input (the entry is then bundled by a build of its
|
|
@@ -1785,6 +2069,11 @@ function tweeTsPlugin(options) {
|
|
|
1785
2069
|
},
|
|
1786
2070
|
configResolved(config) {
|
|
1787
2071
|
if (entryPath === void 0) return;
|
|
2072
|
+
if (config.command === "build" && (bundlesEntryInside(config) || bundlesEntryInside({ build: config.environments[CLIENT]?.build }))) {
|
|
2073
|
+
const recorder = recordWatchFiles(void 0, config.root);
|
|
2074
|
+
entryInputs.set(config, recorder.inputs);
|
|
2075
|
+
Reflect.set(config.plugins, config.plugins.length, pluginWith(recorder.plugin, /* @__PURE__ */ new Map([["applyToEnvironment", (environment) => environment.name === CLIENT]])));
|
|
2076
|
+
}
|
|
1788
2077
|
if (config.command === "build" && config.build.watch && bundlesEntryInside(config)) config.plugins.forEach((plugin, at) => {
|
|
1789
2078
|
if (!isOwnPlugin(plugin)) Reflect.set(config.plugins, at, claimingPlugin(plugin, (key) => claimed.add(key)));
|
|
1790
2079
|
});
|
|
@@ -1796,7 +2085,7 @@ function tweeTsPlugin(options) {
|
|
|
1796
2085
|
watchOutputs = /* @__PURE__ */ new WeakMap();
|
|
1797
2086
|
forgetKeptResolver(config);
|
|
1798
2087
|
if (this.meta.watchMode) {
|
|
1799
|
-
const outputs = require_diagnostic_text.outputPaths(allOutputs(config));
|
|
2088
|
+
const outputs = require_diagnostic_text.outputPaths(allOutputs(config), "snapshot");
|
|
1800
2089
|
for (const target of require_watch_targets.watchTargets(resolved.inputs, resolved.excluded, outputs, "real")) this.addWatchFile(target);
|
|
1801
2090
|
}
|
|
1802
2091
|
if (entryPath === void 0 || bundlesEntryInside(config)) return;
|
|
@@ -1806,7 +2095,7 @@ function tweeTsPlugin(options) {
|
|
|
1806
2095
|
const registerEntryInputs = () => {
|
|
1807
2096
|
if (!this.meta.watchMode) return;
|
|
1808
2097
|
for (const file of watched) this.addWatchFile(require_watch_targets.canonicalPath(file));
|
|
1809
|
-
const outputs = require_diagnostic_text.outputPaths(allOutputs(config));
|
|
2098
|
+
const outputs = require_diagnostic_text.outputPaths(allOutputs(config), "snapshot");
|
|
1810
2099
|
for (const target of require_watch_targets.importWatchTargets(authored, outputs)) this.addWatchFile(target);
|
|
1811
2100
|
for (const target of globWatchTargets(globs, outputs)) this.addWatchFile(target);
|
|
1812
2101
|
};
|
|
@@ -1883,7 +2172,7 @@ function tweeTsPlugin(options) {
|
|
|
1883
2172
|
const items = bundle;
|
|
1884
2173
|
entry = bundlesEntryInside(config) ? takeEntryFromBundle(items, entryInput) : ownBuilds.get(this.environment);
|
|
1885
2174
|
if (!bundlesEntryInside(config)) for (const [fileName, source] of entry?.assets ?? []) {
|
|
1886
|
-
if (Object.hasOwn(bundle, fileName)) return this.error(entryCollisionMessage(fileName));
|
|
2175
|
+
if (fileName === outputFilename || Object.hasOwn(bundle, fileName)) return this.error(entryCollisionMessage(fileName));
|
|
1887
2176
|
this.emitFile({
|
|
1888
2177
|
type: "asset",
|
|
1889
2178
|
fileName,
|
|
@@ -1895,7 +2184,12 @@ function tweeTsPlugin(options) {
|
|
|
1895
2184
|
record.addFiles(outputOptions, [...Object.keys(bundle), ...entry?.assets.keys() ?? []]);
|
|
1896
2185
|
let story;
|
|
1897
2186
|
try {
|
|
1898
|
-
|
|
2187
|
+
const entryFiles = entryPath === void 0 ? [] : [
|
|
2188
|
+
entryPath,
|
|
2189
|
+
...entry?.files ?? [],
|
|
2190
|
+
...entryInputs.get(this.environment.getTopLevelConfig())?.() ?? []
|
|
2191
|
+
].filter((id) => !id.startsWith("\0"));
|
|
2192
|
+
story = await require_watch_targets.compileStory(resolved.compile(entrySources(entry)), configOutputs(config, record), cache, true, entryFiles);
|
|
1899
2193
|
} catch (e) {
|
|
1900
2194
|
return this.error(require_watch_targets.fatalError(e));
|
|
1901
2195
|
}
|
|
@@ -1907,6 +2201,11 @@ function tweeTsPlugin(options) {
|
|
|
1907
2201
|
});
|
|
1908
2202
|
}
|
|
1909
2203
|
},
|
|
2204
|
+
writeBundle(outputOptions, bundle) {
|
|
2205
|
+
const story = bundle[outputFilename];
|
|
2206
|
+
const path = require_watch_targets.emittedFilePath(outputOptions, outputFilename);
|
|
2207
|
+
if (story?.type === "asset" && path !== void 0) require_diagnostic_text.recordOwnOutput(path, story.source);
|
|
2208
|
+
},
|
|
1910
2209
|
async configureServer(server) {
|
|
1911
2210
|
const route = await setUpDevStory(server, {
|
|
1912
2211
|
options: resolved,
|