modern-cmdk 1.4.0 → 1.5.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.
@@ -0,0 +1,43 @@
1
+ // ../modern-cmdk-codemod/src/print-options.ts
2
+ const TOKEN = /\/\/[^\n]*|\/\*[\s\S]*?\*\/|`(?:[^`\\]|\\[\s\S])*`|(?<s>'(?:[^'\\\n]|\\.)*'|"(?:[^"\\\n]|\\.)*")/g;
3
+ const SPECIFIER_CONTEXT = /(?:\bfrom|\bimport|\brequire\s*\(|\bimport\s*\()\s*$/;
4
+ function quoteOf(raw) {
5
+ if (raw.startsWith("'")) return "single";
6
+ if (raw.startsWith("\"")) return "double";
7
+ }
8
+ /**
9
+ * Print options that reproduce the source file's line terminator and quote style.
10
+ *
11
+ * - lineTerminator: CRLF when the source contains a CRLF, else LF.
12
+ * - quote: the quote of `sampleRaw` when it starts with one; otherwise the quote of the first
13
+ * import, export-from, require or dynamic-import specifier; otherwise the more frequent quote
14
+ * of the file's string literals, a tie giving double.
15
+ */
16
+ function printOptions(source, sampleRaw) {
17
+ const lineTerminator = source.includes("\r\n") ? "\r\n" : "\n";
18
+ const sampled = sampleRaw === void 0 ? void 0 : quoteOf(sampleRaw);
19
+ if (sampled !== void 0) return {
20
+ quote: sampled,
21
+ lineTerminator
22
+ };
23
+ let single = 0;
24
+ let double = 0;
25
+ let specifier;
26
+ for (const match of source.matchAll(TOKEN)) {
27
+ const raw = match.groups?.s;
28
+ if (raw === void 0) continue;
29
+ const quote = raw.startsWith("'") ? "single" : "double";
30
+ if (quote === "single") single++;
31
+ else double++;
32
+ if (specifier === void 0 && SPECIFIER_CONTEXT.test(source.slice(Math.max(0, match.index - 32), match.index))) specifier = quote;
33
+ }
34
+ if (specifier !== void 0) return {
35
+ quote: specifier,
36
+ lineTerminator
37
+ };
38
+ return {
39
+ quote: single > double ? "single" : "double",
40
+ lineTerminator
41
+ };
42
+ }
43
+ export { printOptions as t };
@@ -0,0 +1,476 @@
1
+ import { n as __toESM, t as require_jscodeshift } from "./chunk-jscodeshift.mjs";
2
+ import { access, constants, glob, lstat, readFile, realpath, stat } from "node:fs/promises";
3
+ import { basename, delimiter, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
4
+ import { isMainThread, parentPort, workerData } from "node:worker_threads";
5
+ import { execFile } from "node:child_process";
6
+ // ../modern-cmdk-codemod/src/files.ts
7
+ const PARSERS = /* @__PURE__ */ new Map([
8
+ [".ts", "ts"],
9
+ [".mts", "ts"],
10
+ [".cts", "ts"],
11
+ [".tsx", "tsx"],
12
+ [".js", "babel"],
13
+ [".jsx", "babel"],
14
+ [".mjs", "babel"],
15
+ [".cjs", "babel"]
16
+ ]);
17
+ const STYLESHEETS = /* @__PURE__ */ new Set([".css", ".scss"]);
18
+ function extensionOf(path) {
19
+ const dot = path.lastIndexOf(".");
20
+ return dot > Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")) ? path.slice(dot).toLowerCase() : "";
21
+ }
22
+ /**
23
+ * The jscodeshift parser for a script file: `ts` for .ts/.mts/.cts, `tsx` for .tsx, `babel` (which
24
+ * parses JSX) for .js/.jsx/.mjs/.cjs. `undefined` for anything that is not a script.
25
+ */
26
+ function parserFor(path) {
27
+ return PARSERS.get(extensionOf(path));
28
+ }
29
+ function routeFor(path) {
30
+ if (PARSERS.has(extensionOf(path))) return "script";
31
+ return STYLESHEETS.has(extensionOf(path)) ? "stylesheet" : "skip";
32
+ }
33
+ /** What a directory argument expands to, relative to that directory. */
34
+ const DIRECTORY_GLOB = "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,css,scss}";
35
+ /**
36
+ * On win32 every backslash of a command-line pattern becomes '/' (glob syntax has no other use for
37
+ * it there). Elsewhere a backslash is an escape and stays. Braces are never escaped: the directory
38
+ * form needs them.
39
+ */
40
+ function normalizePattern(arg, platform = process.platform) {
41
+ return platform === "win32" ? arg.replaceAll("\\", "/") : arg;
42
+ }
43
+ const LEGACY_EXCLUDES = /* @__PURE__ */ new Set([
44
+ "node_modules",
45
+ "dist",
46
+ "build",
47
+ ".next"
48
+ ]);
49
+ const CODEMOD_EXCLUDES = /* @__PURE__ */ new Set([
50
+ ...LEGACY_EXCLUDES,
51
+ ".git",
52
+ "coverage",
53
+ ".turbo",
54
+ "out",
55
+ "storybook-static",
56
+ ".vercel"
57
+ ]);
58
+ /**
59
+ * The directory that holds the `.git/modules` a gitdir target lies under, else `undefined`. A
60
+ * submodule's `.git` file reads `gitdir: <super>/.git/modules/<name>`; a linked worktree's reads
61
+ * `gitdir: <main>/.git/worktrees/<name>`. `target` is a realpath.
62
+ */
63
+ function superprojectOf(target) {
64
+ const segments = target.split(sep);
65
+ const at = segments.findLastIndex((segment, index) => segment === ".git" && segments[index + 1] === "modules");
66
+ return at < 1 ? void 0 : segments.slice(0, at).join(sep);
67
+ }
68
+ /**
69
+ * The trust boundary of one operation: the realpath of the nearest directory, from `realpath(cwd)`
70
+ * upward, that holds a `.git` entry (a directory, or the file a worktree or submodule has), else
71
+ * `realpath(cwd)` when no ancestor holds one. It is the work tree `git rev-parse --show-toplevel`
72
+ * reports, computed without spawning git, and realpath'd so that a linked cwd (macOS's `/var` ->
73
+ * `/private/var`) or a short Windows path (`RUNNER~1`) compares equal to what git prints. Not the
74
+ * cwd, which may be a subdirectory of the tree whose other directories a planted git can sit in.
75
+ * Not the outermost work tree either: a dotfiles repository at the home directory would exclude
76
+ * every PATH entry under the home (shims, `~/.local/bin`) and leave the user with no git.
77
+ * Three cases make a `.git` entry reach further. A `.git` directory (an ordinary repository, a
78
+ * nested one included) stops the climb. A `.git` file whose `gitdir:` target lies under a
79
+ * `.git/modules` directory is a submodule: the superproject around it came from the same clone,
80
+ * so the climb goes on from there, and again while that superproject is itself a submodule. A `.git`
81
+ * file for a linked worktree (target under `.git/worktrees`), or one that cannot be read or
82
+ * resolved, stops the climb: the main repository of a worktree is the user's own.
83
+ */
84
+ async function trustBoundary(cwd) {
85
+ const start = await realpath(cwd);
86
+ let at = start;
87
+ for (;;) {
88
+ const entry = await lstat(join(at, ".git")).catch(() => void 0);
89
+ if (entry === void 0) {
90
+ if (dirname(at) === at) return start;
91
+ at = dirname(at);
92
+ continue;
93
+ }
94
+ const superproject = entry.isFile() ? await superprojectAbove(at) : void 0;
95
+ if (superproject === void 0) return at;
96
+ at = superproject;
97
+ }
98
+ }
99
+ /** The superproject of the submodule checked out at `at`, from its `.git` file; `undefined` if it is not one. */
100
+ async function superprojectAbove(at) {
101
+ try {
102
+ const link = /^gitdir:\s*(.+?)\s*$/m.exec(await readFile(join(at, ".git"), "utf8"));
103
+ return link?.[1] === void 0 ? void 0 : superprojectOf(await realpath(resolve(at, link[1])));
104
+ } catch {
105
+ return;
106
+ }
107
+ }
108
+ /** True when `path` is `boundary` or lies under it. Written once, for gitSearchDirs and resolveGit. */
109
+ function inside(boundary, path) {
110
+ const rel = relative(boundary, path);
111
+ return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
112
+ }
113
+ /**
114
+ * The directories of a PATH value that may hold git: absolute entries outside `boundary`, the work
115
+ * tree being migrated. Empty and relative entries are dropped (they name the working directory), and
116
+ * so is any entry equal to or under `boundary`, which may carry a planted executable. Order is kept.
117
+ * This is the syntactic filter; resolveGit also compares real paths.
118
+ */
119
+ function gitSearchDirs(pathValue, boundary) {
120
+ return (pathValue ?? "").split(delimiter).filter((entry) => entry !== "" && isAbsolute(entry) && !inside(boundary, entry));
121
+ }
122
+ /**
123
+ * True when `candidate` is a regular file (a directory named git is not git) that the process may
124
+ * execute (`access` with X_OK is a plain existence check on Windows) and whose own realpath lies
125
+ * outside `boundary`, so a link into the tree is refused.
126
+ */
127
+ async function isGitOutside(candidate, boundary) {
128
+ try {
129
+ if (!(await stat(candidate)).isFile()) return false;
130
+ await access(candidate, constants.X_OK);
131
+ return !inside(boundary, await realpath(candidate));
132
+ } catch {
133
+ return false;
134
+ }
135
+ }
136
+ const resolvedGit = /* @__PURE__ */ new Map();
137
+ /**
138
+ * The absolute path of the first git executable in PATH's `gitSearchDirs`, so the spawn does no
139
+ * search of its own. A kept entry is skipped when its realpath is inside `boundary` (a link or an
140
+ * alias into the tree) or does not resolve. Looks for `git.exe` then `git.com` on win32 (the names
141
+ * libuv tries) and `git` elsewhere; isGitOutside says what a candidate must be. `boundary` comes
142
+ * from trustBoundary and is the same for every spawn of one operation, so a submodule's directory
143
+ * or a subdirectory cwd never narrows it. The answer is kept per boundary and PATH value for the
144
+ * life of the process. Rejects with ENOENT, naming `boundary`, when there is none.
145
+ */
146
+ function resolveGit(boundary) {
147
+ const pathValue = process.env.PATH;
148
+ const cacheKey = JSON.stringify([boundary, pathValue]);
149
+ const cached = resolvedGit.get(cacheKey);
150
+ if (cached !== void 0) return cached;
151
+ const names = process.platform === "win32" ? ["git.exe", "git.com"] : ["git"];
152
+ const found = (async () => {
153
+ for (const searchDir of gitSearchDirs(pathValue, boundary)) {
154
+ const realDir = await realpath(searchDir).catch(() => void 0);
155
+ if (realDir === void 0 || inside(boundary, realDir)) continue;
156
+ for (const name of names) {
157
+ const candidate = join(searchDir, name);
158
+ if (await isGitOutside(candidate, boundary)) return candidate;
159
+ }
160
+ }
161
+ throw Object.assign(/* @__PURE__ */ new Error(`git was not found on PATH outside ${boundary}`), { code: "ENOENT" });
162
+ })();
163
+ resolvedGit.set(cacheKey, found);
164
+ found.catch(() => resolvedGit.delete(cacheKey));
165
+ return found;
166
+ }
167
+ /**
168
+ * Run git in `cwd` with execFile on the absolute path resolveGit finds outside `boundary`. The two
169
+ * differ on purpose: `cwd` is where git runs (the repository root, a submodule's directory or a
170
+ * subdirectory); `boundary` is the operation's trustBoundary, what PATH is filtered against. Resolves
171
+ * on any exit code; rejects on a spawn failure, and with ENOENT when git is missing. Reads
172
+ * process.env.PATH at each call, so tests steer it with vi.stubEnv.
173
+ */
174
+ async function runGit(args, cwd, boundary, input = "") {
175
+ const executable = await resolveGit(boundary);
176
+ const { promise, resolve: done, reject } = Promise.withResolvers();
177
+ const child = execFile(executable, [...args], {
178
+ cwd,
179
+ encoding: "utf8",
180
+ maxBuffer: 1024 ** 3,
181
+ windowsHide: true
182
+ }, (error, stdout, stderr) => {
183
+ if (error === null) return done({
184
+ code: 0,
185
+ stdout,
186
+ stderr
187
+ });
188
+ const code = error.code;
189
+ if (typeof code === "number") return done({
190
+ code,
191
+ stdout,
192
+ stderr
193
+ });
194
+ reject(error);
195
+ });
196
+ child.stdin?.on("error", () => {});
197
+ child.stdin?.end(input);
198
+ return promise;
199
+ }
200
+ async function locateRepo(cwd, boundary) {
201
+ try {
202
+ const { code, stdout } = await runGit(["rev-parse", "--show-toplevel"], cwd, boundary);
203
+ return code === 0 ? {
204
+ kind: "repo",
205
+ root: resolve(stdout.trim())
206
+ } : { kind: "none" };
207
+ } catch (error) {
208
+ if (error.code === "ENOENT") return { kind: "missing" };
209
+ throw error;
210
+ }
211
+ }
212
+ /** Paths of `files` relative to the repo root (forward slashes), `undefined` for those outside it. */
213
+ async function relativeToRoot(files, cwd, root) {
214
+ const prefix = relative(await realpath(root), await realpath(cwd));
215
+ return files.map((file) => {
216
+ const rel = normalize(join(prefix, relative(cwd, file)));
217
+ return rel.startsWith("..") || isAbsolute(rel) ? void 0 : rel.replaceAll("\\", "/");
218
+ });
219
+ }
220
+ const key = (path) => process.platform === "win32" ? path.toLowerCase() : path;
221
+ /**
222
+ * Root-relative paths of the gitlinks (mode 160000: submodules) in the repository at `root`. One
223
+ * level is enough: a submodule nested inside a submodule is not looked for.
224
+ */
225
+ async function gitlinksOf(root, boundary) {
226
+ const { code, stdout, stderr } = await runGit([
227
+ "ls-files",
228
+ "-s",
229
+ "-z"
230
+ ], root, boundary);
231
+ if (code !== 0) throw new Error(`git ls-files failed (exit ${code}): ${stderr.trim()}`);
232
+ return stdout.split("\0").filter((entry) => entry.startsWith("160000 ")).map((entry) => entry.slice(entry.indexOf(" ") + 1));
233
+ }
234
+ /** The paths of `rels` that `git check-ignore` run in `owner` reports as ignored. */
235
+ async function ignoredIn(owner, rels, boundary) {
236
+ const { code, stdout, stderr } = await runGit([
237
+ "check-ignore",
238
+ "-z",
239
+ "--stdin"
240
+ ], owner, boundary, rels.join("\0"));
241
+ if (code !== 0 && code !== 1) throw new Error(`git check-ignore failed (exit ${code}): ${stderr.trim()}`);
242
+ return new Set(stdout.split("\0").filter((p) => p !== ""));
243
+ }
244
+ async function dropGitIgnored(files, cwd, boundary, warn) {
245
+ const repo = await locateRepo(cwd, boundary);
246
+ if (repo.kind === "missing") {
247
+ warn("warning: git not found; .gitignore is not applied");
248
+ return files;
249
+ }
250
+ if (repo.kind === "none") return files;
251
+ const rels = await relativeToRoot(files, cwd, repo.root);
252
+ if (!rels.some((rel) => rel !== void 0)) return files;
253
+ const gitlinks = (await gitlinksOf(repo.root, boundary)).map(key);
254
+ const groups = /* @__PURE__ */ new Map();
255
+ rels.forEach((rel, index) => {
256
+ if (rel === void 0) return;
257
+ const link = gitlinks.filter((g) => key(rel).startsWith(`${g}/`)).reduce((deepest, g) => g.length > deepest.length ? g : deepest, "");
258
+ const group = groups.get(link) ?? {
259
+ root: link === "" ? repo.root : join(repo.root, rel.slice(0, link.length)),
260
+ indexes: [],
261
+ paths: []
262
+ };
263
+ group.indexes.push(index);
264
+ group.paths.push(link === "" ? rel : rel.slice(link.length + 1));
265
+ groups.set(link, group);
266
+ });
267
+ const drop = /* @__PURE__ */ new Set();
268
+ for (const group of groups.values()) {
269
+ const ignored = await ignoredIn(group.root, group.paths, boundary);
270
+ group.paths.forEach((path, i) => {
271
+ if (ignored.has(path)) drop.add(group.indexes[i]);
272
+ });
273
+ }
274
+ return files.filter((_, index) => !drop.has(index));
275
+ }
276
+ /** realpath of a file; for one deleted since discovery, its parent's realpath plus its name. */
277
+ async function realpathOrParent(file) {
278
+ try {
279
+ return await realpath(file);
280
+ } catch (error) {
281
+ if (error.code !== "ENOENT") throw error;
282
+ return join(await realpath(dirname(file)), basename(file));
283
+ }
284
+ }
285
+ /**
286
+ * `git status --porcelain -z` in `cwd`, intersected with `files`. Untracked files count as dirty
287
+ * (a codemod write to one cannot be undone); ignored files were already dropped by discovery. A
288
+ * modified submodule (status runs with `--ignore-submodules=none`, so modified or untracked files in
289
+ * it count) or an untracked directory entry (a nested repository, which git never descends into, or
290
+ * any untracked directory) makes every matched file under it dirty.
291
+ */
292
+ async function findDirtyFiles(files, cwd) {
293
+ const boundary = await trustBoundary(cwd);
294
+ const repo = await locateRepo(cwd, boundary);
295
+ if (repo.kind === "missing") return { kind: "no-git" };
296
+ if (repo.kind === "none") return { kind: "no-repo" };
297
+ const { code, stdout, stderr } = await runGit([
298
+ "--no-optional-locks",
299
+ "status",
300
+ "--porcelain",
301
+ "-z",
302
+ "--untracked-files=all",
303
+ "--ignore-submodules=none"
304
+ ], cwd, boundary);
305
+ if (code !== 0) throw new Error(`git status failed (exit ${code}): ${stderr.trim()}`);
306
+ const dirty = /* @__PURE__ */ new Set();
307
+ const dirtyDirs = [];
308
+ const entries = stdout.split("\0");
309
+ for (let i = 0; i < entries.length; i++) {
310
+ const entry = entries[i];
311
+ if (entry.length < 4) continue;
312
+ const path = entry.slice(3);
313
+ if (path.endsWith("/")) dirtyDirs.push(key(path));
314
+ else {
315
+ dirty.add(key(path));
316
+ if ((await lstat(join(repo.root, path)).catch(() => void 0))?.isDirectory()) dirtyDirs.push(`${key(path)}/`);
317
+ }
318
+ if (/[RC]/.test(entry.slice(0, 2))) {
319
+ const origin = entries[++i];
320
+ if (origin !== void 0) dirty.add(key(origin));
321
+ }
322
+ }
323
+ const realRoot = await realpath(repo.root);
324
+ const outside = [];
325
+ for (const file of files) {
326
+ const r = relative(realRoot, await realpathOrParent(file));
327
+ if (r.startsWith("..") || isAbsolute(r)) outside.push(file);
328
+ }
329
+ if (outside.length > 0) return {
330
+ kind: "outside",
331
+ paths: outside
332
+ };
333
+ const rels = await relativeToRoot(files, cwd, repo.root);
334
+ const paths = files.filter((_, index) => {
335
+ const rel = rels[index];
336
+ return rel !== void 0 && (dirty.has(key(rel)) || dirtyDirs.some((d) => key(rel).startsWith(d)));
337
+ });
338
+ return paths.length === 0 ? { kind: "clean" } : {
339
+ kind: "dirty",
340
+ paths
341
+ };
342
+ }
343
+ /** True when a directory between cwd and `file` is a symbolic link (or junction). */
344
+ async function reachedThroughSymlink(file, cwd) {
345
+ const rel = relative(cwd, file);
346
+ if (rel.startsWith("..") || isAbsolute(rel)) return false;
347
+ let at = cwd;
348
+ for (const part of rel.split(sep).slice(0, -1)) {
349
+ at = join(at, part);
350
+ if ((await lstat(at)).isSymbolicLink()) return true;
351
+ }
352
+ return false;
353
+ }
354
+ async function isDirectory(path) {
355
+ try {
356
+ return (await stat(path)).isDirectory();
357
+ } catch {
358
+ return false;
359
+ }
360
+ }
361
+ /**
362
+ * Resolve command-line patterns to absolute, de-duplicated, sorted file paths. A directory argument
363
+ * expands to its script and stylesheet files. `modern-cmdk-codemod` also skips more build
364
+ * directories and the paths .gitignore covers. `**` descends no symlinked directory in either program;
365
+ * modern-cmdk-codemod also drops every file reached through a symlinked directory below cwd.
366
+ */
367
+ async function discoverFiles(patterns, { program, cwd, warn }) {
368
+ const dirs = [];
369
+ const globs = [];
370
+ for (const arg of patterns) {
371
+ const pattern = normalizePattern(arg);
372
+ const abs = resolve(cwd, pattern);
373
+ if (await isDirectory(abs)) dirs.push(abs);
374
+ else globs.push(pattern);
375
+ }
376
+ const excluded = program === "modern-cmdk-codemod" ? CODEMOD_EXCLUDES : LEGACY_EXCLUDES;
377
+ const exclude = (d) => excluded.has(d.name);
378
+ const entries = [...globs.length > 0 ? await Array.fromAsync(glob(globs, {
379
+ cwd,
380
+ withFileTypes: true,
381
+ exclude
382
+ })) : [], ...(await Promise.all(dirs.map((d) => Array.fromAsync(glob(DIRECTORY_GLOB, {
383
+ cwd: d,
384
+ withFileTypes: true,
385
+ exclude
386
+ }))))).flat()];
387
+ const files = [...new Set(entries.filter((d) => d.isFile()).map((d) => resolve(d.parentPath, d.name)))].filter((file) => !relative(cwd, file).split(sep).some((segment) => excluded.has(segment))).sort();
388
+ if (program !== "modern-cmdk-codemod") return files;
389
+ const through = await Promise.all(files.map((file) => reachedThroughSymlink(file, cwd)));
390
+ return dropGitIgnored(files.filter((_, index) => !through[index]), cwd, await trustBoundary(cwd), warn);
391
+ }
392
+ // ../modern-cmdk-codemod/src/worker.ts
393
+ var import_jscodeshift = /* @__PURE__ */ __toESM(require_jscodeshift(), 1);
394
+ /** One jscodeshift API per parser; the API object itself is per file so reports carry the file. */
395
+ function createApiFactory() {
396
+ const parsers = /* @__PURE__ */ new Map();
397
+ return (parser, report) => {
398
+ let j = parsers.get(parser);
399
+ if (j === void 0) {
400
+ j = import_jscodeshift.default.withParser(parser);
401
+ parsers.set(parser, j);
402
+ }
403
+ return {
404
+ jscodeshift: j,
405
+ j,
406
+ stats: () => {},
407
+ report
408
+ };
409
+ };
410
+ }
411
+ /** Transform one file; a thrown error becomes `error`, with the reports made before it. */
412
+ async function transformFile(path, mod, apiForParser, keepSource) {
413
+ const reports = [];
414
+ const report = (message) => void reports.push(message);
415
+ try {
416
+ const route = routeFor(path);
417
+ if (route === "skip" || route === "stylesheet" && mod.transformStylesheet === void 0) return {
418
+ path,
419
+ changed: false,
420
+ skipped: true,
421
+ reports
422
+ };
423
+ const source = await readFile(path, "utf-8");
424
+ const output = route === "script" ? mod.default({
425
+ path,
426
+ source
427
+ }, apiForParser(parserFor(path), report)) : mod.transformStylesheet(source, report);
428
+ if (output === source) return {
429
+ path,
430
+ changed: false,
431
+ reports
432
+ };
433
+ return {
434
+ path,
435
+ changed: true,
436
+ output,
437
+ ...keepSource ? { source } : {},
438
+ reports
439
+ };
440
+ } catch (err) {
441
+ return {
442
+ path,
443
+ changed: false,
444
+ error: err instanceof Error ? err.message : String(err),
445
+ reports
446
+ };
447
+ }
448
+ }
449
+ function isWorkerInit(value) {
450
+ return typeof value === "object" && value !== null && value.kind === "modern-cmdk-codemod-worker";
451
+ }
452
+ if (!isMainThread && parentPort !== null && isWorkerInit(workerData)) {
453
+ const port = parentPort;
454
+ const { transform, keepSource } = workerData;
455
+ const apiForParser = createApiFactory();
456
+ const loaded = import(
457
+ /* @vite-ignore */
458
+ new URL(`./transforms/${transform}.mjs`, import.meta.url).href
459
+ );
460
+ loaded.catch(() => {});
461
+ port.on("message", async (path) => {
462
+ let outcome;
463
+ try {
464
+ outcome = await transformFile(path, await loaded, apiForParser, keepSource);
465
+ } catch (err) {
466
+ outcome = {
467
+ path,
468
+ changed: false,
469
+ error: `cannot load transform "${transform}": ${err instanceof Error ? err.message : String(err)}`,
470
+ reports: []
471
+ };
472
+ }
473
+ port.postMessage(outcome);
474
+ });
475
+ }
476
+ export { findDirtyFiles as i, transformFile as n, discoverFiles as r, createApiFactory as t };