@rohal12/twee-ts 1.18.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -3
- package/THIRD_PARTY_NOTICES +111 -0
- package/UNLICENSE +24 -0
- package/dist/bin/twee-ts.js +689 -9335
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/diagnostic-text-BRddVulf.cjs +26463 -0
- package/dist/diagnostic-text-BRddVulf.cjs.map +1 -0
- package/dist/diagnostic-text-CebYCTPQ.js +26040 -0
- package/dist/diagnostic-text-CebYCTPQ.js.map +1 -0
- package/dist/index.cjs +86 -9026
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +192 -415
- package/dist/index.d.ts +192 -415
- package/dist/index.js +4 -9206
- package/dist/lint-VayZI_jp.js +288 -0
- package/dist/lint-VayZI_jp.js.map +1 -0
- package/dist/options-DuBkFyqi.d.cts +28 -0
- package/dist/options-nc5NpnSc.d.ts +28 -0
- package/dist/plugins/rollup.cjs +172 -0
- package/dist/plugins/rollup.cjs.map +1 -0
- package/dist/plugins/rollup.d.cts +46 -0
- package/dist/plugins/rollup.d.ts +7 -12
- package/dist/plugins/rollup.js +130 -65
- package/dist/plugins/rollup.js.map +1 -1
- package/dist/plugins/vite.cjs +1926 -0
- package/dist/plugins/vite.cjs.map +1 -0
- package/dist/plugins/vite.d.cts +15 -0
- package/dist/plugins/vite.d.ts +5 -12
- package/dist/plugins/vite.js +1771 -448
- package/dist/plugins/vite.js.map +1 -1
- package/dist/types-BvI6pg2y.d.cts +389 -0
- package/dist/types-BvI6pg2y.d.ts +389 -0
- package/dist/watch-targets-BI7jYrwa.js +486 -0
- package/dist/watch-targets-BI7jYrwa.js.map +1 -0
- package/dist/watch-targets-C0Anuw17.cjs +575 -0
- package/dist/watch-targets-C0Anuw17.cjs.map +1 -0
- package/package.json +80 -27
- package/schemas/twee-ts.config.schema.json +55 -17
- package/dist/index.js.map +0 -1
- package/dist/paths-CUv1qfz-.js +0 -6926
- package/dist/paths-CUv1qfz-.js.map +0 -1
- package/dist/types-D8Xfe0l8.d.ts +0 -71
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
/*! @rohal12/twee-ts (Unlicense). Bundles third-party code under its own licence: see THIRD_PARTY_NOTICES. */
|
|
2
|
+
const require_diagnostic_text = require("./diagnostic-text-BRddVulf.cjs");
|
|
3
|
+
let node_path = require("node:path");
|
|
4
|
+
let node_fs = require("node:fs");
|
|
5
|
+
//#region src/plugins/diagnostics.ts
|
|
6
|
+
/** Returns the warnings; throws a LocatedError when the compile reported errors. */
|
|
7
|
+
function splitDiagnostics(result) {
|
|
8
|
+
const errors = result.diagnostics.filter((d) => d.level === "error");
|
|
9
|
+
if (errors.length === 0) return result.diagnostics.filter((d) => d.level === "warning");
|
|
10
|
+
const error = new Error(errors.map(require_diagnostic_text.formatDiagnostic).join("\n"));
|
|
11
|
+
const [first] = errors;
|
|
12
|
+
if (first?.file) {
|
|
13
|
+
error.id = first.file;
|
|
14
|
+
error.loc = {
|
|
15
|
+
file: first.file,
|
|
16
|
+
line: first.line ?? 1,
|
|
17
|
+
column: 1
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
/** An error thrown by the compiler or bundler, with a TweeTsError's error diagnostics folded into its message. */
|
|
23
|
+
function fatalError(e) {
|
|
24
|
+
if (e instanceof require_diagnostic_text.TweeTsError) {
|
|
25
|
+
const errors = e.diagnostics.filter((d) => d.level === "error").map(require_diagnostic_text.formatDiagnostic);
|
|
26
|
+
return new Error([...errors, e.message].join("\n"));
|
|
27
|
+
}
|
|
28
|
+
return e instanceof Error ? e : new Error(String(e));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compiles the story for a plugin, leaving out what a build writes (`outputs`).
|
|
32
|
+
* `writesStory` is whether the story goes to a file (a build, not the dev server): a story path in `outputs`
|
|
33
|
+
* that holds an authored file of a source folder then fails the compile (`OUTPUT_IS_INPUT`), as a named output
|
|
34
|
+
* does. Throws a LocatedError when the compile fails or reports errors.
|
|
35
|
+
*/
|
|
36
|
+
async function compileStory(options, outputs, cache, writesStory = false) {
|
|
37
|
+
let result;
|
|
38
|
+
try {
|
|
39
|
+
result = await require_diagnostic_text.compileForOutputFile(options, writesStory ? outputs : {
|
|
40
|
+
files: outputs.files,
|
|
41
|
+
dirs: outputs.dirs
|
|
42
|
+
}, cache);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
throw fatalError(e);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
output: result.output,
|
|
48
|
+
warnings: splitDiagnostics(result).map(require_diagnostic_text.formatDiagnostic)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/plugins/paths.ts
|
|
53
|
+
/**
|
|
54
|
+
* Path helpers for the bundler plugins. Watchers and bundlers spell one file
|
|
55
|
+
* differently: macOS FSEvents reports /private/var/… for a file under /var/…,
|
|
56
|
+
* Vite resolves module ids through symbolic links, Windows keeps a short 8.3
|
|
57
|
+
* folder name (C:\Users\RUNNER~1) where another tool gives the long one, and
|
|
58
|
+
* a case-insensitive volume takes any letter case. So the plugins compare
|
|
59
|
+
* files by their identity key (see path-identity.ts), and spell a path they
|
|
60
|
+
* hand a watcher by its canonical (real) path.
|
|
61
|
+
*/
|
|
62
|
+
/** The real path of `path`, with forward slashes: how the Vite plugin spells a path it hands a watcher. */
|
|
63
|
+
function canonicalPath(path) {
|
|
64
|
+
return toPosix(require_diagnostic_text.identify(path).canonical);
|
|
65
|
+
}
|
|
66
|
+
/** The key a file is compared by: two paths name the same file exactly when their keys are equal. */
|
|
67
|
+
function fileKey(path) {
|
|
68
|
+
return require_diagnostic_text.identify(path).key;
|
|
69
|
+
}
|
|
70
|
+
/** Whether the file with key `key` is one of the folders (or files) with keys `within`, or inside one. */
|
|
71
|
+
function keyWithin(key, within) {
|
|
72
|
+
return within.some((outer) => require_diagnostic_text.isKeyInside(key, outer, node_path.sep));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The absolute path a bundle writes the file it emits as `fileName` to: inside
|
|
76
|
+
* `output.dir`, or next to `output.file`, either resolved against the working
|
|
77
|
+
* directory, as the bundler resolves them. Undefined when the output names
|
|
78
|
+
* neither, as for a bundle only generated in memory.
|
|
79
|
+
*/
|
|
80
|
+
function emittedFilePath(output, fileName) {
|
|
81
|
+
const dir = output.dir ?? (output.file === void 0 ? void 0 : (0, node_path.dirname)(output.file));
|
|
82
|
+
return dir === void 0 ? void 0 : (0, node_path.resolve)(dir, fileName);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The locations a bundler's `output` option names: one output's settings or an
|
|
86
|
+
* array of them, as a config gives them. Outputs that name neither `dir` nor
|
|
87
|
+
* `file`, and anything that isn't an output's settings, are left out.
|
|
88
|
+
*/
|
|
89
|
+
function outputLocations(option) {
|
|
90
|
+
return (Array.isArray(option) ? option : [option]).flatMap((output) => {
|
|
91
|
+
if (typeof output !== "object" || output === null) return [];
|
|
92
|
+
const dir = "dir" in output ? output.dir : void 0;
|
|
93
|
+
const file = "file" in output ? output.file : void 0;
|
|
94
|
+
const location = {
|
|
95
|
+
...typeof dir === "string" ? { dir } : {},
|
|
96
|
+
...typeof file === "string" ? { file } : {}
|
|
97
|
+
};
|
|
98
|
+
return location.dir === void 0 && location.file === void 0 ? [] : [location];
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/** An empty OutputRecord for a plugin that writes its story as `storyFileName`. */
|
|
102
|
+
function createOutputRecord(storyFileName) {
|
|
103
|
+
const files = /* @__PURE__ */ new Set();
|
|
104
|
+
const stories = /* @__PURE__ */ new Set();
|
|
105
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
106
|
+
const addFiles = (output, fileNames) => {
|
|
107
|
+
for (const fileName of fileNames) {
|
|
108
|
+
const path = emittedFilePath(output, fileName);
|
|
109
|
+
if (path !== void 0) files.add(path);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
addLocation(output) {
|
|
114
|
+
if (output.dir !== void 0) dirs.add((0, node_path.resolve)(output.dir));
|
|
115
|
+
if (output.file !== void 0) files.add((0, node_path.resolve)(output.file));
|
|
116
|
+
addFiles(output, [storyFileName]);
|
|
117
|
+
const story = emittedFilePath(output, storyFileName);
|
|
118
|
+
if (story !== void 0) stories.add(story);
|
|
119
|
+
},
|
|
120
|
+
addFiles,
|
|
121
|
+
outputs: () => ({
|
|
122
|
+
files: [...files],
|
|
123
|
+
stories: [...stories],
|
|
124
|
+
dirs: [...dirs]
|
|
125
|
+
})
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The path with the platform's separators turned into forward slashes. Only Windows has a backslash separator;
|
|
130
|
+
* on POSIX a backslash is an ordinary filename character and stays one.
|
|
131
|
+
*/
|
|
132
|
+
function toPosix(path) {
|
|
133
|
+
return node_path.sep === "\\" ? path.replaceAll("\\", "/") : path;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Whether `file` is a temporary copy of a Vite config file. Vite writes one next
|
|
137
|
+
* to the config file each time it loads it (when no node_modules folder is
|
|
138
|
+
* above the config, and always under Deno), then deletes it.
|
|
139
|
+
*/
|
|
140
|
+
function isViteConfigTemp(file) {
|
|
141
|
+
return /\.timestamp-\d+-[0-9a-f]*\.mjs$/.test(file);
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/plugins/options.ts
|
|
145
|
+
/**
|
|
146
|
+
* The options both bundler plugins take, checked once where the plugin is
|
|
147
|
+
* created and turned into what the plugin works with: the compile options of a
|
|
148
|
+
* build, the files whose changes rebuild the story, and which of them
|
|
149
|
+
* `compileOptions.exclude` leaves out. The Vite and the Rollup plugin share this,
|
|
150
|
+
* so the same options mean the same thing in both.
|
|
151
|
+
*/
|
|
152
|
+
/** The option names each plugin accepts. */
|
|
153
|
+
const OPTION_NAMES = {
|
|
154
|
+
rollup: [
|
|
155
|
+
"sources",
|
|
156
|
+
"format",
|
|
157
|
+
"outputFilename",
|
|
158
|
+
"compileOptions"
|
|
159
|
+
],
|
|
160
|
+
vite: [
|
|
161
|
+
"sources",
|
|
162
|
+
"format",
|
|
163
|
+
"outputFilename",
|
|
164
|
+
"compileOptions",
|
|
165
|
+
"entry"
|
|
166
|
+
]
|
|
167
|
+
};
|
|
168
|
+
/** The compile options each plugin sets from an option of its own, by that option's name. */
|
|
169
|
+
const PLUGIN_SET_COMPILE_OPTIONS = [["sources", "sources"], ["formatId", "format"]];
|
|
170
|
+
function fail(kind, message) {
|
|
171
|
+
throw new require_diagnostic_text.TweeTsError(`twee-ts ${kind} plugin: ${message}`, [], { code: "INVALID_OPTIONS" });
|
|
172
|
+
}
|
|
173
|
+
/** The oldest Vite the plugin works with (the `vite` peer dependency). */
|
|
174
|
+
const MINIMUM_VITE_MAJOR = 8;
|
|
175
|
+
/**
|
|
176
|
+
* Throws a TweeTsError (`INVALID_OPTIONS`) that names twee-ts and the Vite version when Vite is older than the
|
|
177
|
+
* plugin supports, instead of the obscure failure an older Vite gives (a missing `index.html`, say). A version
|
|
178
|
+
* that is not a SemVer version (a custom build) is accepted.
|
|
179
|
+
*/
|
|
180
|
+
function checkViteVersion(viteVersion) {
|
|
181
|
+
const parsed = require_diagnostic_text.parseVersion(viteVersion);
|
|
182
|
+
if (parsed === null) return;
|
|
183
|
+
if (parsed.major < MINIMUM_VITE_MAJOR) fail("vite", `Vite ${viteVersion} is not supported; the plugin needs Vite ${MINIMUM_VITE_MAJOR} or newer. Upgrade Vite, or use an older twee-ts release for this Vite.`);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Characters a file name can't hold on every file system (Windows rejects
|
|
187
|
+
* `<>:"|?*`, the control characters and `\`), and those a URL path reads
|
|
188
|
+
* differently from the file name (`#`, `?`, `%`).
|
|
189
|
+
*/
|
|
190
|
+
const UNPORTABLE = /[\u0000-\u001f\u007f<>:"|?*#%\\]/;
|
|
191
|
+
/** Names Windows reserves for devices, with or without an extension. */
|
|
192
|
+
const WINDOWS_DEVICE = /^(con|prn|aux|nul|com[0-9¹²³]|lpt[0-9¹²³])(\..*)?$/i;
|
|
193
|
+
/**
|
|
194
|
+
* Why `name` can't be an output file name, or undefined when it can. It must be
|
|
195
|
+
* a relative path: names separated by forward slashes, none of them empty, `.`
|
|
196
|
+
* or `..`, nor one a file system or a URL would read differently. The bundler
|
|
197
|
+
* writes it inside the output folder, and the dev server serves it at the same
|
|
198
|
+
* path under the base URL.
|
|
199
|
+
*/
|
|
200
|
+
function outputFilenameProblem(name) {
|
|
201
|
+
if (name === "") return "it is empty";
|
|
202
|
+
if (UNPORTABLE.test(name)) return "it holds a character that is not portable in a file name or URL path";
|
|
203
|
+
if (name.startsWith("/")) return "it is an absolute path";
|
|
204
|
+
const segments = name.split("/");
|
|
205
|
+
if (segments.includes("")) return "it has an empty name between slashes, or ends with a slash";
|
|
206
|
+
if (segments.some((segment) => segment === "." || segment === "..")) return "it has a \".\" or \"..\" segment";
|
|
207
|
+
if (segments.some((segment) => segment.endsWith(".") || segment.endsWith(" "))) return "a name in it ends with \".\" or a space, which Windows drops";
|
|
208
|
+
if (segments.some((segment) => WINDOWS_DEVICE.test(segment))) return "a name in it is reserved on Windows";
|
|
209
|
+
}
|
|
210
|
+
function checkString(kind, value, name) {
|
|
211
|
+
if (value !== void 0 && (typeof value !== "string" || value === "")) fail(kind, `\`${name}\` must be a non-empty string.`);
|
|
212
|
+
}
|
|
213
|
+
function checkStringList(kind, value, name) {
|
|
214
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item === "")) fail(kind, `\`${name}\` must be an array of non-empty strings.`);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Checks the options as a JavaScript caller may pass them, whatever their type
|
|
218
|
+
* says: an object with only the accepted option names, each of the right type.
|
|
219
|
+
*/
|
|
220
|
+
function checkOptions(kind, options) {
|
|
221
|
+
if (!require_diagnostic_text.isRecord(options)) fail(kind, "the options must be an object.");
|
|
222
|
+
const accepted = OPTION_NAMES[kind];
|
|
223
|
+
const unknown = Object.keys(options).filter((key) => !accepted.includes(key));
|
|
224
|
+
if (unknown.length > 0) fail(kind, `unknown option ${unknown.map((key) => `\`${key}\``).join(", ")}; the options are ${accepted.join(", ")}.`);
|
|
225
|
+
checkStringList(kind, options["sources"], "sources");
|
|
226
|
+
for (const name of [
|
|
227
|
+
"format",
|
|
228
|
+
"outputFilename",
|
|
229
|
+
"entry"
|
|
230
|
+
]) checkString(kind, options[name], name);
|
|
231
|
+
const outputFilename = options["outputFilename"];
|
|
232
|
+
const problem = typeof outputFilename === "string" ? outputFilenameProblem(outputFilename) : void 0;
|
|
233
|
+
if (problem !== void 0) fail(kind, `\`outputFilename\` ${JSON.stringify(outputFilename)} can't be used: ${problem}.`);
|
|
234
|
+
const compileOptions = options["compileOptions"];
|
|
235
|
+
if (compileOptions === void 0) return;
|
|
236
|
+
if (!require_diagnostic_text.isRecord(compileOptions)) fail(kind, "`compileOptions` must be an object.");
|
|
237
|
+
for (const [key, own] of PLUGIN_SET_COMPILE_OPTIONS) if (Object.hasOwn(compileOptions, key)) fail(kind, `\`compileOptions.${key}\` is not accepted; set the plugin's \`${own}\` option instead.`);
|
|
238
|
+
const errors = require_diagnostic_text.compileOptionErrors(compileOptions, [], "compileOptions.");
|
|
239
|
+
if (errors.length > 0) fail(kind, errors.join(" "));
|
|
240
|
+
}
|
|
241
|
+
/** Absolute forward-slash path of a path given relative to the working directory. */
|
|
242
|
+
function absolute(path) {
|
|
243
|
+
return toPosix((0, node_path.resolve)(path));
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* How the compiler spells `file` when it finds it by walking each source it is inside: the source
|
|
247
|
+
* as given, then the file's path below it. A watcher may report the real path of a file the sources
|
|
248
|
+
* (and so the exclude globs) reach through a link, which the globs would otherwise not match.
|
|
249
|
+
*/
|
|
250
|
+
function spellingsUnderSources(file, sources) {
|
|
251
|
+
const real = require_diagnostic_text.identify(file).canonical;
|
|
252
|
+
return sources.flatMap((source) => {
|
|
253
|
+
const below = (0, node_path.relative)(require_diagnostic_text.identify(source).canonical, real);
|
|
254
|
+
return below === ".." || below.startsWith(`..${node_path.sep}`) || (0, node_path.isAbsolute)(below) ? [] : [(0, node_path.join)((0, node_path.resolve)(source), below)];
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Checks a plugin's options and resolves them. Throws a TweeTsError naming the
|
|
259
|
+
* option for anything outside what the plugin supports: an unknown option, a
|
|
260
|
+
* value of the wrong type, `compileOptions.sources` or `compileOptions.formatId`
|
|
261
|
+
* (the plugin's `sources` and `format` set them), or an output file name that
|
|
262
|
+
* is not a plain relative path.
|
|
263
|
+
*/
|
|
264
|
+
function resolvePluginOptions(kind, options) {
|
|
265
|
+
checkOptions(kind, options);
|
|
266
|
+
const { sources, format, entry } = options;
|
|
267
|
+
const compileOptions = { ...options.compileOptions };
|
|
268
|
+
const { headFile, modules = [], exclude = [] } = compileOptions;
|
|
269
|
+
const notExcludable = [...headFile === void 0 ? [] : [headFile], ...modules].map(absolute);
|
|
270
|
+
return {
|
|
271
|
+
sources: [...sources],
|
|
272
|
+
format,
|
|
273
|
+
outputFilename: options.outputFilename ?? "index.html",
|
|
274
|
+
compileOptions,
|
|
275
|
+
entry: entry === void 0 ? void 0 : (0, node_path.resolve)(entry),
|
|
276
|
+
inputs: [...sources.map(absolute), ...notExcludable],
|
|
277
|
+
excluded: (file) => exclude.length > 0 && [file, ...spellingsUnderSources(file, sources)].some((spelling) => require_diagnostic_text.isExcluded(spelling, exclude)) && !notExcludable.some((path) => require_diagnostic_text.isSameOrInside(file, path)),
|
|
278
|
+
compile: (inline = []) => ({
|
|
279
|
+
...compileOptions,
|
|
280
|
+
sources: [...sources, ...inline],
|
|
281
|
+
formatId: format
|
|
282
|
+
})
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
//#endregion
|
|
286
|
+
//#region src/plugins/watch-targets.ts
|
|
287
|
+
/**
|
|
288
|
+
* What a bundler's watch mode (`rollup --watch`, `vite build --watch`) is told
|
|
289
|
+
* to watch for the story, whose inputs the plugins read outside the module
|
|
290
|
+
* graph. Rollup's watcher and the Rolldown watcher of later Vite 8 releases
|
|
291
|
+
* watch a registered folder recursively; earlier ones see only the folder's own
|
|
292
|
+
* entries. So every path is registered on its own as well.
|
|
293
|
+
*/
|
|
294
|
+
const NOTHING = {
|
|
295
|
+
targets: [],
|
|
296
|
+
whole: false
|
|
297
|
+
};
|
|
298
|
+
/**
|
|
299
|
+
* The paths to register for the inputs (forward-slash paths): every file under
|
|
300
|
+
* them that source discovery reads, but those `skip` returns true for, and no
|
|
301
|
+
* path the build writes (`outputs`). With `real` spelling, each link an input is reached through is registered as
|
|
302
|
+
* authored too, every hop of a chain of links (see linksOnTheWay), but those that lead to a folder holding an output.
|
|
303
|
+
*
|
|
304
|
+
* A folder is registered, with what it holds, only when watching it reports
|
|
305
|
+
* nothing the story leaves out: nothing below it is skipped (an `exclude`
|
|
306
|
+
* match), is an output or holds one, or is a link to a folder (which source
|
|
307
|
+
* discovery doesn't follow, and which may lead to the output). Of any other
|
|
308
|
+
* folder only what it holds is registered, minus those, so writing the outputs
|
|
309
|
+
* or editing an excluded file starts no build. A file added straight to such a folder is read at the next build
|
|
310
|
+
* something else starts. An input that can't be read is registered as it is
|
|
311
|
+
* (unless it is an output folder), so its creation may start a build; below an
|
|
312
|
+
* input, what can't be read is left out, as source discovery leaves it out.
|
|
313
|
+
*/
|
|
314
|
+
function watchTargets(inputs, skip, outputs, spelling) {
|
|
315
|
+
return watchPlan(inputs, skip, outputs, spelling).targets;
|
|
316
|
+
}
|
|
317
|
+
/** What watchTargets registers for the inputs, and the links they are reached through. */
|
|
318
|
+
function watchPlan(inputs, skip, outputs, spelling) {
|
|
319
|
+
const links = /* @__PURE__ */ new Set();
|
|
320
|
+
/** Every link on the way to `path`, noted; those registered by real path are the ones that lead to no output. */
|
|
321
|
+
const hopsOf = (path) => {
|
|
322
|
+
const hops = linksOnTheWay(path);
|
|
323
|
+
for (const hop of hops) links.add(hop);
|
|
324
|
+
return hops.filter((hop) => !outputs.holds(require_diagnostic_text.realPathOf(hop))).map(toPosix);
|
|
325
|
+
};
|
|
326
|
+
const reals = /* @__PURE__ */ new Map();
|
|
327
|
+
const spell = (path, real, isRoot) => {
|
|
328
|
+
if (spelling === "real") return [toPosix(real), ...isRoot || isLink(path) ? hopsOf(path) : []];
|
|
329
|
+
if (!isRoot && isLink(path)) for (const hop of linksOnTheWay(path)) links.add(hop);
|
|
330
|
+
if (isLoop(path)) return [];
|
|
331
|
+
if (!isLoop(real)) reals.set(path, real);
|
|
332
|
+
return [path];
|
|
333
|
+
};
|
|
334
|
+
const walk = (path, real, isRoot) => {
|
|
335
|
+
if (outputs.isFile(real) || !isRoot && outputs.isDir(real)) return NOTHING;
|
|
336
|
+
let entry;
|
|
337
|
+
let names;
|
|
338
|
+
try {
|
|
339
|
+
entry = isRoot ? {
|
|
340
|
+
stat: (0, node_fs.statSync)(path),
|
|
341
|
+
real
|
|
342
|
+
} : require_diagnostic_text.walkedEntry(path, real);
|
|
343
|
+
if (entry === void 0 || outputs.isFile(entry.real)) return NOTHING;
|
|
344
|
+
if (!entry.stat.isDirectory()) return skip(path) ? NOTHING : {
|
|
345
|
+
targets: spell(path, entry.real, isRoot),
|
|
346
|
+
whole: true
|
|
347
|
+
};
|
|
348
|
+
names = (0, node_fs.readdirSync)(path);
|
|
349
|
+
} catch {
|
|
350
|
+
return isRoot && !outputs.isDir(real) ? {
|
|
351
|
+
targets: spell(path, real, isRoot),
|
|
352
|
+
whole: true
|
|
353
|
+
} : NOTHING;
|
|
354
|
+
}
|
|
355
|
+
const folder = entry.real;
|
|
356
|
+
const children = names.map((name) => walk(`${path}/${name}`, (0, node_path.join)(folder, name), false));
|
|
357
|
+
const held = children.flatMap((child) => child.targets);
|
|
358
|
+
const whole = !outputs.holds(folder) && children.every((child) => child.whole);
|
|
359
|
+
return whole ? {
|
|
360
|
+
targets: [...spell(path, folder, isRoot), ...held],
|
|
361
|
+
whole
|
|
362
|
+
} : {
|
|
363
|
+
targets: held,
|
|
364
|
+
whole
|
|
365
|
+
};
|
|
366
|
+
};
|
|
367
|
+
const targets = inputs.flatMap((input) => {
|
|
368
|
+
for (const link of linksOnTheWay(input)) links.add(link);
|
|
369
|
+
return [...spelling === "real" ? ancestorLinks(input, outputs) : [], ...walk(input, require_diagnostic_text.realPathOf(input), true).targets];
|
|
370
|
+
});
|
|
371
|
+
return {
|
|
372
|
+
targets: [...new Set(targets)],
|
|
373
|
+
links: [...links],
|
|
374
|
+
reals
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* The paths to register, besides the real paths of the files a bundle read, so that the build watch sees what
|
|
379
|
+
* changes how the entry's imports resolve: for each spelling (absolute) of an import that reaches a file through
|
|
380
|
+
* links, every link on the way (see linksOnTheWay), the links a link leads through too (replacing any of them changes
|
|
381
|
+
* the file the import reads); and for a spelling
|
|
382
|
+
* that reaches nothing, the nearest folder that exists, where creating the file shows (a bundle that failed for a
|
|
383
|
+
* missing import). A folder that holds a build output is left out, since the watcher would report what the build
|
|
384
|
+
* writes there and rebuild for ever: a file created straight in it is read with the next build something else starts.
|
|
385
|
+
*/
|
|
386
|
+
function importWatchTargets(authored, outputs) {
|
|
387
|
+
const targets = /* @__PURE__ */ new Set();
|
|
388
|
+
const missing = [];
|
|
389
|
+
for (const spelling of authored) {
|
|
390
|
+
if ((0, node_fs.existsSync)(spelling)) {
|
|
391
|
+
if (toPosix(require_diagnostic_text.realPathOf(spelling)) === toPosix(spelling)) continue;
|
|
392
|
+
for (const link of linksOnTheWay(spelling)) if (!outputs.holds(require_diagnostic_text.realPathOf(link))) targets.add(toPosix(link));
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
missing.push(spelling);
|
|
396
|
+
}
|
|
397
|
+
for (const folder of missingImportFolders(missing)) if (!outputs.holds(require_diagnostic_text.realPathOf(folder))) targets.add(toPosix(folder));
|
|
398
|
+
return [...targets];
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* The nearest folder that exists, for each of the paths in `authored` that reaches nothing: where creating that
|
|
402
|
+
* file (or the folders above it) shows. Of a path that exists there is none, and neither is the root of a file
|
|
403
|
+
* system (an absolute import such as `/missing.js`, which Vite reads from the project root first), which no watcher
|
|
404
|
+
* is asked to watch whole.
|
|
405
|
+
*/
|
|
406
|
+
function missingImportFolders(authored) {
|
|
407
|
+
const folders = /* @__PURE__ */ new Set();
|
|
408
|
+
for (const spelling of authored) {
|
|
409
|
+
if ((0, node_fs.existsSync)(spelling)) continue;
|
|
410
|
+
let folder = (0, node_path.dirname)(spelling);
|
|
411
|
+
while (!(0, node_fs.existsSync)(folder) && (0, node_path.dirname)(folder) !== folder) folder = (0, node_path.dirname)(folder);
|
|
412
|
+
if ((0, node_fs.existsSync)(folder) && (0, node_path.dirname)(folder) !== folder) folders.add(folder);
|
|
413
|
+
}
|
|
414
|
+
return [...folders];
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* The links among the folders above `path`, as authored (forward slashes), every hop of a chain, in the order they are
|
|
418
|
+
* followed. Replacing one of them changes what the input is, and only its own location sees that. A link directly in
|
|
419
|
+
* the root of the file system (`/var` on macOS) is the system's own alias and is left out, as is a link to a folder that
|
|
420
|
+
* holds a build output, since watching it whole would rebuild for what the build writes.
|
|
421
|
+
*/
|
|
422
|
+
function ancestorLinks(path, outputs) {
|
|
423
|
+
return linksOnTheWay((0, node_path.dirname)(path)).filter((link) => !outputs.holds(require_diagnostic_text.realPathOf(link))).map(toPosix);
|
|
424
|
+
}
|
|
425
|
+
/** How many links the file system follows for one path before it gives up (ELOOP on Linux). */
|
|
426
|
+
const MAX_LINK_HOPS = 40;
|
|
427
|
+
/**
|
|
428
|
+
* Every link the file system follows to reach `path`, in the order it follows them: each link along the path, and
|
|
429
|
+
* along the target each one leads to, so every hop of a link to a link (a chain) is there. A link directly in the
|
|
430
|
+
* root of the file system (`/var` on macOS) is the system's own alias and is left out. The walk ends where a name
|
|
431
|
+
* reaches nothing, or after as many hops as the file system follows.
|
|
432
|
+
*/
|
|
433
|
+
function linksOnTheWay(path) {
|
|
434
|
+
const links = [];
|
|
435
|
+
/** The names of a path or a link's target below its root; `..` is kept for the walk to take. */
|
|
436
|
+
const names = (text, root) => text.slice(root.length).split(/[/\\]/).filter((name) => name !== "" && name !== ".");
|
|
437
|
+
const start = (0, node_path.resolve)(path);
|
|
438
|
+
let reached = (0, node_path.parse)(start).root;
|
|
439
|
+
let rest = names(start, reached);
|
|
440
|
+
for (let hops = 0; rest.length > 0 && hops <= MAX_LINK_HOPS;) {
|
|
441
|
+
const [name = "", ...more] = rest;
|
|
442
|
+
rest = more;
|
|
443
|
+
if (name === "..") {
|
|
444
|
+
reached = (0, node_path.dirname)(reached);
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const next = (0, node_path.join)(reached, name);
|
|
448
|
+
let target;
|
|
449
|
+
try {
|
|
450
|
+
target = (0, node_fs.lstatSync)(next).isSymbolicLink() ? (0, node_fs.readlinkSync)(next) : void 0;
|
|
451
|
+
} catch {
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
if (target === void 0) {
|
|
455
|
+
reached = next;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
hops += 1;
|
|
459
|
+
if ((0, node_path.dirname)(next) !== (0, node_path.dirname)((0, node_path.dirname)(next))) links.push(next);
|
|
460
|
+
const root = (0, node_path.isAbsolute)(target) ? (0, node_path.parse)(target).root : "";
|
|
461
|
+
if (root !== "") reached = root;
|
|
462
|
+
rest = [...names(target, root), ...rest];
|
|
463
|
+
}
|
|
464
|
+
return links;
|
|
465
|
+
}
|
|
466
|
+
/** Whether `path` is a loop of links, which the file system gives up following (ELOOP). */
|
|
467
|
+
function isLoop(path) {
|
|
468
|
+
try {
|
|
469
|
+
(0, node_fs.statSync)(path);
|
|
470
|
+
return false;
|
|
471
|
+
} catch (error) {
|
|
472
|
+
return error instanceof Error && Reflect.get(error, "code") === "ELOOP";
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
/** Whether `path` is a symbolic link (or a Windows junction); a path that can't be read is none. */
|
|
476
|
+
function isLink(path) {
|
|
477
|
+
try {
|
|
478
|
+
return (0, node_fs.lstatSync)(path).isSymbolicLink();
|
|
479
|
+
} catch {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
//#endregion
|
|
484
|
+
Object.defineProperty(exports, "canonicalPath", {
|
|
485
|
+
enumerable: true,
|
|
486
|
+
get: function() {
|
|
487
|
+
return canonicalPath;
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
Object.defineProperty(exports, "checkViteVersion", {
|
|
491
|
+
enumerable: true,
|
|
492
|
+
get: function() {
|
|
493
|
+
return checkViteVersion;
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
Object.defineProperty(exports, "compileStory", {
|
|
497
|
+
enumerable: true,
|
|
498
|
+
get: function() {
|
|
499
|
+
return compileStory;
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
Object.defineProperty(exports, "createOutputRecord", {
|
|
503
|
+
enumerable: true,
|
|
504
|
+
get: function() {
|
|
505
|
+
return createOutputRecord;
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
Object.defineProperty(exports, "fatalError", {
|
|
509
|
+
enumerable: true,
|
|
510
|
+
get: function() {
|
|
511
|
+
return fatalError;
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
Object.defineProperty(exports, "fileKey", {
|
|
515
|
+
enumerable: true,
|
|
516
|
+
get: function() {
|
|
517
|
+
return fileKey;
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
Object.defineProperty(exports, "importWatchTargets", {
|
|
521
|
+
enumerable: true,
|
|
522
|
+
get: function() {
|
|
523
|
+
return importWatchTargets;
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
Object.defineProperty(exports, "isViteConfigTemp", {
|
|
527
|
+
enumerable: true,
|
|
528
|
+
get: function() {
|
|
529
|
+
return isViteConfigTemp;
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
Object.defineProperty(exports, "keyWithin", {
|
|
533
|
+
enumerable: true,
|
|
534
|
+
get: function() {
|
|
535
|
+
return keyWithin;
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
Object.defineProperty(exports, "missingImportFolders", {
|
|
539
|
+
enumerable: true,
|
|
540
|
+
get: function() {
|
|
541
|
+
return missingImportFolders;
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
Object.defineProperty(exports, "outputLocations", {
|
|
545
|
+
enumerable: true,
|
|
546
|
+
get: function() {
|
|
547
|
+
return outputLocations;
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
Object.defineProperty(exports, "resolvePluginOptions", {
|
|
551
|
+
enumerable: true,
|
|
552
|
+
get: function() {
|
|
553
|
+
return resolvePluginOptions;
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
Object.defineProperty(exports, "toPosix", {
|
|
557
|
+
enumerable: true,
|
|
558
|
+
get: function() {
|
|
559
|
+
return toPosix;
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
Object.defineProperty(exports, "watchPlan", {
|
|
563
|
+
enumerable: true,
|
|
564
|
+
get: function() {
|
|
565
|
+
return watchPlan;
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
Object.defineProperty(exports, "watchTargets", {
|
|
569
|
+
enumerable: true,
|
|
570
|
+
get: function() {
|
|
571
|
+
return watchTargets;
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
//# sourceMappingURL=watch-targets-C0Anuw17.cjs.map
|