vite-plus 0.2.8 → 0.2.9

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.
Files changed (74) hide show
  1. package/AGENTS.md +7 -0
  2. package/README.md +9 -3
  3. package/binding/index.cjs +54 -54
  4. package/binding/index.d.cts +7 -3
  5. package/dist/{agent-CI79DuSy.js → agent-DQU8uS6P.js} +4 -188
  6. package/dist/bin.js +288 -278
  7. package/dist/config/bin.js +27 -15
  8. package/dist/{constants-BppDcRc1.js → constants-CG513DRa.js} +10 -2
  9. package/dist/create/bin.js +178 -204
  10. package/dist/{define-config-DPnHe1Mx.js → define-config-CV4bQG_8.js} +3 -3
  11. package/dist/{define-config-CEm_MtvJ.cjs → define-config-DyNLA_f0.cjs} +1 -1
  12. package/dist/define-config.cjs +1 -1
  13. package/dist/define-config.js +1 -1
  14. package/dist/{dist-CSQWHI6y.js → dist-BDYZP12R.js} +193 -149
  15. package/dist/dist-Dqv1-Clg.js +3 -0
  16. package/dist/{editor-CGWdbLgD.js → editor-g4PosU99.js} +188 -108
  17. package/dist/hooks/bin.d.ts +1 -0
  18. package/dist/hooks/bin.js +130 -0
  19. package/dist/hooks-pNCBWtFT.js +570 -0
  20. package/dist/index.cjs +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/{json-BU88uu6o.js → json-qlK6UH0r.js} +38 -32
  23. package/dist/migration/bin.js +15 -18
  24. package/dist/{oxlint-plugin-config-BHOzlwMw.js → oxlint-plugin-config-BEZ9IUf7.js} +1 -1
  25. package/dist/oxlint-plugin.js +1 -1
  26. package/dist/pack-bin.js +1 -1
  27. package/dist/{package-hV-77cBb.js → package-B4T8RGMG.js} +2 -2
  28. package/dist/{prompts-DYap08te.js → prompts-CHz_98bJ.js} +142 -50
  29. package/dist/{resolve-vite-config-EWXclqvV.js → resolve-vite-config-Dmeyeyj-.js} +2 -9
  30. package/dist/staged/bin.js +224 -206
  31. package/dist/{terminal-CrqqK8WT.js → terminal-Bz-ps6rJ.js} +33 -3
  32. package/dist/test/browser/providers/playwright/context.d.ts +1 -1
  33. package/dist/test/browser/providers/playwright.d.ts +6 -6
  34. package/dist/test/browser/providers/preview/context.d.ts +1 -1
  35. package/dist/test/browser/providers/preview.d.ts +4 -4
  36. package/dist/test/browser/providers/webdriverio/context.d.ts +1 -1
  37. package/dist/test/browser/providers/webdriverio.d.ts +6 -6
  38. package/dist/test/browser-playwright/context.d.ts +1 -1
  39. package/dist/test/browser-playwright.d.ts +6 -6
  40. package/dist/test/browser-preview/context.d.ts +1 -1
  41. package/dist/test/browser-preview.d.ts +4 -4
  42. package/dist/test/browser-webdriverio/context.d.ts +1 -1
  43. package/dist/test/browser-webdriverio.d.ts +6 -6
  44. package/dist/test/context.d.ts +3 -3
  45. package/dist/test/locators.d.ts +1 -1
  46. package/dist/toolchain.d.ts +25 -0
  47. package/dist/toolchain.js +194 -0
  48. package/dist/toolchain.json +193 -0
  49. package/dist/{tsconfig-CVUKLfL8.js → tsconfig-7v_BHagU.js} +3 -3
  50. package/dist/tsgolint-path.js +1 -1
  51. package/dist/version.js +4 -4
  52. package/dist/versions.d.ts +3 -3
  53. package/dist/versions.js +6 -6
  54. package/docs/guide/ci.md +37 -4
  55. package/docs/guide/commit-hooks.md +87 -14
  56. package/docs/guide/create.md +7 -4
  57. package/docs/guide/fmt.md +2 -2
  58. package/docs/guide/github-actions-cache.md +5 -1
  59. package/docs/guide/ide-integration.md +61 -2
  60. package/docs/guide/index.md +3 -1
  61. package/docs/guide/install.md +25 -0
  62. package/docs/guide/installer-env-vars.md +12 -1
  63. package/docs/guide/lint.md +3 -1
  64. package/docs/guide/migrate.md +39 -2
  65. package/docs/guide/monorepo.md +4 -4
  66. package/docs/guide/troubleshooting.md +12 -4
  67. package/docs/guide/upgrade.md +27 -4
  68. package/docs/package.json +1 -1
  69. package/docs/pnpm-workspace.yaml +7 -0
  70. package/docs/vite.config.ts +3 -0
  71. package/package.json +18 -14
  72. package/rules/vite-tools.yml +0 -7
  73. package/dist/dist-DT25H9pj.js +0 -3
  74. package/dist/{tsgolint-path-eMZT-oea.js → tsgolint-path-CbDReEOx.js} +1 -1
@@ -0,0 +1,570 @@
1
+ import { isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
2
+ import { chmodSync, existsSync, lstatSync, mkdirSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
3
+ import { spawnSync } from "node:child_process";
4
+ //#region src/config/hooks.ts
5
+ const SUPPORTED_GIT_HOOK_NAMES = [
6
+ "pre-commit",
7
+ "pre-merge-commit",
8
+ "prepare-commit-msg",
9
+ "commit-msg",
10
+ "post-commit",
11
+ "applypatch-msg",
12
+ "pre-applypatch",
13
+ "post-applypatch",
14
+ "pre-rebase",
15
+ "post-rewrite",
16
+ "post-checkout",
17
+ "post-merge",
18
+ "pre-push",
19
+ "pre-auto-gc"
20
+ ];
21
+ const DEFAULT_HOOKS_DIR = ".vite-hooks";
22
+ /** Local git config: user chose `vp hooks disable` (survives prepare / vp config). */
23
+ const PREFERENCE_DISABLED_KEY = "vp.hooks.disabled";
24
+ /** Local git config: last hooks directory used by enable (relative to setup cwd). */
25
+ const PREFERENCE_DIR_KEY = "vp.hooks.dir";
26
+ /** Local git config: `git rev-parse --show-prefix` when the dir was stored. `.` = worktree root. */
27
+ const PREFERENCE_PREFIX_KEY = "vp.hooks.prefix";
28
+ const ROOT_PREFIX_TOKEN = ".";
29
+ function nestedDirname(depth) {
30
+ let expr = "\"$0\"";
31
+ for (let i = 0; i < depth; i++) expr = `"$(dirname ${expr})"`;
32
+ return expr;
33
+ }
34
+ function hookScript(dir) {
35
+ const separators = process.platform === "win32" ? /[\\/]/ : /\//;
36
+ return `#!/usr/bin/env sh
37
+ { [ "$HUSKY" = "2" ] || [ "$VP_GIT_HOOKS" = "2" ] || [ "$VITE_GIT_HOOKS" = "2" ]; } && set -x
38
+ n=$(basename "$0")
39
+ s=$(dirname "$(dirname "$0")")/$n
40
+
41
+ [ ! -f "$s" ] && exit 0
42
+
43
+ i="\${XDG_CONFIG_HOME:-$HOME/.config}/vite-plus/hooks-init.sh"
44
+ [ ! -f "$i" ] && i="\${XDG_CONFIG_HOME:-$HOME/.config}/husky/init.sh"
45
+ [ -f "$i" ] && . "$i"
46
+
47
+ { [ "\${HUSKY-}" = "0" ] || [ "\${VP_GIT_HOOKS-}" = "0" ] || [ "\${VITE_GIT_HOOKS-}" = "0" ]; } && exit 0
48
+
49
+ d=${nestedDirname(dir.split(separators).filter((s) => s !== "" && s !== ".").length + 2)}
50
+ __vp_shell=/bin/sh
51
+ [ -x "$__vp_shell" ] || __vp_shell=$(command -v sh)
52
+
53
+ if [ -n "\${VP_HOME-}" ]; then
54
+ __vp_bin="$VP_HOME/bin"
55
+ elif [ -n "\${HOME-}" ]; then
56
+ __vp_bin="$HOME/.vite-plus/bin"
57
+ else
58
+ __vp_bin=""
59
+ fi
60
+ [ -n "$__vp_bin" ] && [ -d "$__vp_bin" ] && export PATH="$PATH:$__vp_bin"
61
+
62
+ export PATH="$d/node_modules/.bin:$PATH"
63
+ "$__vp_shell" -e "$s" "$@"
64
+ c=$?
65
+
66
+ [ $c != 0 ] && echo "VITE+ - $n script failed (code $c)"
67
+ [ $c = 127 ] && echo "VITE+ - command not found in PATH=$PATH"
68
+ exit $c`;
69
+ }
70
+ function normalizeHooksPath(hooksPath) {
71
+ let normalized = normalize(hooksPath);
72
+ while (normalized.endsWith(sep)) normalized = normalized.slice(0, -1);
73
+ return normalized;
74
+ }
75
+ function getGitToplevel() {
76
+ const result = spawnSync("git", ["rev-parse", "--show-toplevel"]);
77
+ if (result.status == null) return {
78
+ message: "git command not found",
79
+ isError: true
80
+ };
81
+ if (result.status !== 0) return {
82
+ message: ".git can't be found",
83
+ isError: false
84
+ };
85
+ const toplevel = result.stdout.toString().trim();
86
+ try {
87
+ return realpathSync(toplevel);
88
+ } catch {
89
+ return toplevel;
90
+ }
91
+ }
92
+ /** Resolve a core.hooksPath value against the worktree root for ownership checks. */
93
+ function resolveHooksPath(hooksPath, gitRoot) {
94
+ const resolved = isAbsolute(hooksPath) ? hooksPath : resolve(gitRoot, hooksPath);
95
+ try {
96
+ return normalizeHooksPath(realpathSync(resolved));
97
+ } catch {
98
+ return normalizeHooksPath(resolved);
99
+ }
100
+ }
101
+ function hooksPathsEqual(a, b, gitRoot) {
102
+ return resolveHooksPath(a, gitRoot) === resolveHooksPath(b, gitRoot);
103
+ }
104
+ function findUnsafeHookInstallPath(root, dir) {
105
+ const projectRoot = resolve(root);
106
+ const internalPath = resolve(projectRoot, dir, "_");
107
+ const relativeInternalPath = relative(projectRoot, internalPath);
108
+ let currentPath = projectRoot;
109
+ for (const component of relativeInternalPath.split(sep).filter(Boolean)) {
110
+ currentPath = join(currentPath, component);
111
+ const stats = lstatSync(currentPath, { throwIfNoEntry: false });
112
+ if (!stats) return null;
113
+ if (stats.isSymbolicLink()) return {
114
+ kind: "symbolic",
115
+ relativePath: relative(projectRoot, currentPath)
116
+ };
117
+ if (!stats.isDirectory()) return {
118
+ kind: "not-directory",
119
+ relativePath: relative(projectRoot, currentPath)
120
+ };
121
+ }
122
+ for (const filename of [
123
+ "husky.sh",
124
+ ".gitignore",
125
+ "h",
126
+ ...SUPPORTED_GIT_HOOK_NAMES
127
+ ]) {
128
+ const filePath = join(internalPath, filename);
129
+ const stats = lstatSync(filePath, { throwIfNoEntry: false });
130
+ if (!stats) continue;
131
+ if (stats.isSymbolicLink()) return {
132
+ kind: "symbolic",
133
+ relativePath: relative(projectRoot, filePath)
134
+ };
135
+ if (!stats.isFile()) return {
136
+ kind: "not-file",
137
+ relativePath: relative(projectRoot, filePath)
138
+ };
139
+ if (stats.nlink > 1) return {
140
+ kind: "linked",
141
+ relativePath: relative(projectRoot, filePath)
142
+ };
143
+ }
144
+ return null;
145
+ }
146
+ function describeUnsafeHookInstallPath(unsafePath) {
147
+ if (unsafePath.kind === "symbolic") return `symbolic hook path "${unsafePath.relativePath}" not allowed`;
148
+ if (unsafePath.kind === "linked") return `multiply linked hook path "${unsafePath.relativePath}" not allowed`;
149
+ if (unsafePath.kind === "not-directory") return `hook path "${unsafePath.relativePath}" is not a directory`;
150
+ return `hook path "${unsafePath.relativePath}" is not a file`;
151
+ }
152
+ function gitConfigGet(key, options) {
153
+ const args = ["config"];
154
+ if (options?.local) args.push("--local");
155
+ if (options?.bool) args.push("--bool");
156
+ args.push("--get", key);
157
+ const result = spawnSync("git", args);
158
+ if (result.status !== 0) return null;
159
+ return result.stdout?.toString().trim() || null;
160
+ }
161
+ function gitConfigSet(key, value) {
162
+ const result = spawnSync("git", [
163
+ "config",
164
+ "--local",
165
+ key,
166
+ value
167
+ ]);
168
+ if (result.status == null) return {
169
+ ok: false,
170
+ error: "git command not found"
171
+ };
172
+ if (result.status !== 0) return {
173
+ ok: false,
174
+ error: result.stderr?.toString().trim() || `failed to set ${key}`
175
+ };
176
+ return { ok: true };
177
+ }
178
+ function gitConfigUnset(key) {
179
+ const result = spawnSync("git", [
180
+ "config",
181
+ "--local",
182
+ "--unset-all",
183
+ key
184
+ ]);
185
+ if (result.status == null) return {
186
+ ok: false,
187
+ error: "git command not found"
188
+ };
189
+ if (result.status !== 0 && result.status !== 5) return {
190
+ ok: false,
191
+ error: result.stderr?.toString().trim() || `failed to unset ${key}`
192
+ };
193
+ return { ok: true };
194
+ }
195
+ /** Whether the user ran `vp hooks disable` in this repo (local git config). */
196
+ function isHooksUserDisabled() {
197
+ return gitConfigGet(PREFERENCE_DISABLED_KEY, {
198
+ local: true,
199
+ bool: true
200
+ }) === "true";
201
+ }
202
+ function setHooksUserDisabled(disabled) {
203
+ if (disabled) return gitConfigSet(PREFERENCE_DISABLED_KEY, "true");
204
+ return gitConfigUnset(PREFERENCE_DISABLED_KEY);
205
+ }
206
+ function getStoredHooksDir() {
207
+ return gitConfigGet(PREFERENCE_DIR_KEY, { local: true });
208
+ }
209
+ function getStoredHooksPrefix() {
210
+ const value = gitConfigGet(PREFERENCE_PREFIX_KEY, { local: true });
211
+ if (value == null) return null;
212
+ if (value === ROOT_PREFIX_TOKEN) return "";
213
+ return value.replace(/\/$/, "");
214
+ }
215
+ function setStoredHooksLocation(dir, prefix) {
216
+ const storedDir = gitConfigSet(PREFERENCE_DIR_KEY, dir);
217
+ if (!storedDir.ok) return storedDir;
218
+ return gitConfigSet(PREFERENCE_PREFIX_KEY, prefix || ROOT_PREFIX_TOKEN);
219
+ }
220
+ function displayHooksDir(location) {
221
+ return location.prefix ? `${location.prefix}/${location.dir}` : location.dir;
222
+ }
223
+ function getGitWorktree() {
224
+ const toplevel = getGitToplevel();
225
+ if (typeof toplevel !== "string") return toplevel;
226
+ const prefixResult = spawnSync("git", ["rev-parse", "--show-prefix"]);
227
+ if (prefixResult.status == null) return {
228
+ message: "git command not found",
229
+ isError: true
230
+ };
231
+ if (prefixResult.status !== 0) return {
232
+ message: ".git can't be found",
233
+ isError: false
234
+ };
235
+ return {
236
+ toplevel,
237
+ prefix: prefixResult.stdout.toString().trim().replace(/\/$/, "")
238
+ };
239
+ }
240
+ function buildHooksLocation(git, hooksDir, prefix) {
241
+ const dirError = validateHooksDir(hooksDir);
242
+ if (dirError) return dirError;
243
+ const baseDir = prefix ? resolve(git.toplevel, prefix) : git.toplevel;
244
+ const target = prefix ? `${prefix}/${hooksDir}/_` : `${hooksDir}/_`;
245
+ return {
246
+ toplevel: git.toplevel,
247
+ baseDir,
248
+ dir: hooksDir,
249
+ prefix,
250
+ target
251
+ };
252
+ }
253
+ function tryAdoptEffectiveDispatcher(git) {
254
+ const existing = getEffectiveHooksPath();
255
+ if (!existing) return null;
256
+ const abs = isAbsolute(existing) ? existing : resolve(git.toplevel, existing);
257
+ let dispatcherDir;
258
+ try {
259
+ dispatcherDir = realpathSync(abs);
260
+ } catch {
261
+ return null;
262
+ }
263
+ if (!existsSync(join(dispatcherDir, "h"))) return null;
264
+ const hooksAbs = resolve(dispatcherDir, "..");
265
+ const relHooks = relative(git.toplevel, hooksAbs);
266
+ if (!relHooks || relHooks === "." || relHooks.startsWith("..")) return null;
267
+ const posixRel = relHooks.split(sep).join("/");
268
+ let prefix = "";
269
+ let dir = posixRel;
270
+ if (posixRel === ".vite-hooks") {
271
+ prefix = "";
272
+ dir = DEFAULT_HOOKS_DIR;
273
+ } else if (posixRel.endsWith(`/.vite-hooks`)) {
274
+ prefix = posixRel.slice(0, -12);
275
+ dir = DEFAULT_HOOKS_DIR;
276
+ }
277
+ const location = buildHooksLocation(git, dir, prefix);
278
+ return "isError" in location ? null : location;
279
+ }
280
+ /**
281
+ * Resolve where hook files live.
282
+ *
283
+ * An explicit `dir` is relative to the current working directory (current
284
+ * git prefix). Omitting it uses the stored dir + the prefix recorded at
285
+ * enable/disable time, so later commands find the same tree from any cwd.
286
+ */
287
+ function resolveHooksLocation(dir, options = {}) {
288
+ const git = getGitWorktree();
289
+ if ("isError" in git) return git;
290
+ let prefix;
291
+ let hooksDir;
292
+ if (dir !== void 0) {
293
+ prefix = git.prefix;
294
+ hooksDir = dir;
295
+ } else {
296
+ const storedDir = getStoredHooksDir();
297
+ if (storedDir) {
298
+ hooksDir = storedDir;
299
+ prefix = getStoredHooksPrefix() ?? git.prefix;
300
+ } else if (options.adoptEffectiveDispatcher) {
301
+ const adopted = tryAdoptEffectiveDispatcher(git);
302
+ if (adopted) return adopted;
303
+ hooksDir = DEFAULT_HOOKS_DIR;
304
+ prefix = options.unstoredPrefix === "root" ? "" : git.prefix;
305
+ } else {
306
+ hooksDir = DEFAULT_HOOKS_DIR;
307
+ prefix = options.unstoredPrefix === "root" ? "" : git.prefix;
308
+ }
309
+ }
310
+ return buildHooksLocation(git, hooksDir, prefix);
311
+ }
312
+ function validateHooksDir(dir) {
313
+ if (dir.includes("..")) return {
314
+ message: ".. not allowed",
315
+ isError: true
316
+ };
317
+ if (isAbsolute(dir)) return {
318
+ message: "absolute hooks directory not allowed",
319
+ isError: true
320
+ };
321
+ if (relative(process.cwd(), resolve(process.cwd(), dir)) === "") return {
322
+ message: "hooks directory must be a project subdirectory",
323
+ isError: true
324
+ };
325
+ return null;
326
+ }
327
+ function getEffectiveHooksPath() {
328
+ const checkResult = spawnSync("git", [
329
+ "config",
330
+ "--get",
331
+ "core.hooksPath"
332
+ ]);
333
+ return checkResult.status === 0 ? checkResult.stdout?.toString().trim() : "";
334
+ }
335
+ function getScopedHooksPath(scope) {
336
+ const result = spawnSync("git", [
337
+ "config",
338
+ `--${scope}`,
339
+ "--get",
340
+ "core.hooksPath"
341
+ ]);
342
+ return result.status === 0 ? result.stdout?.toString().trim() : "";
343
+ }
344
+ function unsetScopedHooksPath(scope) {
345
+ const result = spawnSync("git", [
346
+ "config",
347
+ `--${scope}`,
348
+ "--unset-all",
349
+ "core.hooksPath"
350
+ ]);
351
+ if (result.status == null) return {
352
+ message: "git command not found",
353
+ isError: true
354
+ };
355
+ if (result.status !== 0 && result.status !== 5) return {
356
+ message: result.stderr?.toString().trim() || `failed to unset ${scope} core.hooksPath`,
357
+ isError: true
358
+ };
359
+ return null;
360
+ }
361
+ /**
362
+ * Unset core.hooksPath only at scopes that actually point at our dispatcher.
363
+ *
364
+ * Must not touch a foreign value at another scope (e.g. local still `.husky/_`
365
+ * while worktree holds the Vite+ target).
366
+ */
367
+ function unsetOwnedHooksPath(target) {
368
+ const toplevel = getGitToplevel();
369
+ if (typeof toplevel !== "string") return toplevel;
370
+ for (const scope of ["local", "worktree"]) {
371
+ const scopedPath = getScopedHooksPath(scope);
372
+ if (!scopedPath || !hooksPathsEqual(scopedPath, target, toplevel)) continue;
373
+ const unsetError = unsetScopedHooksPath(scope);
374
+ if (unsetError) return unsetError;
375
+ }
376
+ const finalPath = getEffectiveHooksPath();
377
+ if (finalPath && hooksPathsEqual(finalPath, target, toplevel)) return {
378
+ message: `could not unset core.hooksPath (still "${finalPath}"); remove it with git config --unset core.hooksPath`,
379
+ isError: true
380
+ };
381
+ return null;
382
+ }
383
+ function install(dir, options = {}) {
384
+ if (process.env.HUSKY === "0" || process.env.VP_GIT_HOOKS === "0" || process.env.VITE_GIT_HOOKS === "0") return {
385
+ message: "skip install (git hooks disabled)",
386
+ isError: false
387
+ };
388
+ if (!options.ignoreUserPreference && isHooksUserDisabled()) return {
389
+ message: "skip install (hooks disabled; run `vp hooks enable` to re-enable)",
390
+ isError: false
391
+ };
392
+ const location = resolveHooksLocation(dir);
393
+ if ("isError" in location) return location;
394
+ const unsafeInstallPath = findUnsafeHookInstallPath(location.baseDir, location.dir);
395
+ if (unsafeInstallPath) return {
396
+ message: describeUnsafeHookInstallPath(unsafeInstallPath),
397
+ isError: false
398
+ };
399
+ const internal = (x = "") => join(location.baseDir, location.dir, "_", x);
400
+ const existingHooksPath = getEffectiveHooksPath();
401
+ if (existingHooksPath && !hooksPathsEqual(existingHooksPath, location.target, location.toplevel)) return {
402
+ message: `core.hooksPath is already set to "${existingHooksPath}", skipping`,
403
+ isError: false
404
+ };
405
+ rmSync(internal("husky.sh"), { force: true });
406
+ mkdirSync(internal(), { recursive: true });
407
+ writeFileSync(internal(".gitignore"), "*");
408
+ writeFileSync(internal("h"), hookScript(location.dir), { mode: 493 });
409
+ chmodSync(internal("h"), 493);
410
+ for (const hook of SUPPORTED_GIT_HOOK_NAMES) {
411
+ writeFileSync(internal(hook), `#!/usr/bin/env sh\n. "$(dirname "$0")/h"`, { mode: 493 });
412
+ chmodSync(internal(hook), 493);
413
+ }
414
+ const { status, stderr } = spawnSync("git", [
415
+ "config",
416
+ "core.hooksPath",
417
+ location.target
418
+ ]);
419
+ if (status == null) return {
420
+ message: "git command not found",
421
+ isError: true
422
+ };
423
+ if (status) return {
424
+ message: "" + stderr,
425
+ isError: true
426
+ };
427
+ const clearDisabled = setHooksUserDisabled(false);
428
+ if (!clearDisabled.ok) return {
429
+ message: clearDisabled.error || "failed to clear hooks disabled preference",
430
+ isError: true
431
+ };
432
+ const storeDir = setStoredHooksLocation(location.dir, location.prefix);
433
+ if (!storeDir.ok) return {
434
+ message: storeDir.error || "failed to store hooks directory",
435
+ isError: true
436
+ };
437
+ return {
438
+ message: "",
439
+ isError: false
440
+ };
441
+ }
442
+ /**
443
+ * Install (or refresh) the Vite+ hook dispatcher and mark hooks as enabled.
444
+ * Clears a previous `vp hooks disable` preference.
445
+ */
446
+ function enable(dir) {
447
+ const location = resolveHooksLocation(dir);
448
+ if ("isError" in location) return location;
449
+ const result = install(dir, { ignoreUserPreference: true });
450
+ if (result.isError) return result;
451
+ if (result.message) return result;
452
+ return {
453
+ message: `Git hook dispatcher installed at ${displayHooksDir(location)}/_`,
454
+ isError: false
455
+ };
456
+ }
457
+ /**
458
+ * Disable Vite+ hooks in this repo and tear down the dispatcher.
459
+ *
460
+ * - Persists the decision in local git config so `vp config` / prepare do not reinstall
461
+ * - Unsets `core.hooksPath` only when it points at this project's dispatcher
462
+ * - Removes the generated `<dir>/_` directory
463
+ * - Leaves project-owned hooks, staged config, and package.json scripts alone
464
+ */
465
+ function disable(dir) {
466
+ const location = resolveHooksLocation(dir, {
467
+ unstoredPrefix: "root",
468
+ adoptEffectiveDispatcher: true
469
+ });
470
+ if ("isError" in location) return location;
471
+ const displayedDir = displayHooksDir(location);
472
+ const internalDir = join(location.baseDir, location.dir, "_");
473
+ const hasInternalDir = existsSync(internalDir);
474
+ if (hasInternalDir) {
475
+ const unsafeInstallPath = findUnsafeHookInstallPath(location.baseDir, location.dir);
476
+ if (unsafeInstallPath) return {
477
+ message: describeUnsafeHookInstallPath(unsafeInstallPath),
478
+ isError: false
479
+ };
480
+ }
481
+ const existingHooksPath = getEffectiveHooksPath();
482
+ const ownsHooksPath = !!existingHooksPath && hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
483
+ const foreignHooksPath = !!existingHooksPath && !hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
484
+ const actions = [];
485
+ const notes = [];
486
+ const pref = setHooksUserDisabled(true);
487
+ if (!pref.ok) return {
488
+ message: pref.error || "failed to persist hooks disabled preference",
489
+ isError: true
490
+ };
491
+ const storeDir = setStoredHooksLocation(location.dir, location.prefix);
492
+ if (!storeDir.ok) return {
493
+ message: storeDir.error || "failed to store hooks directory",
494
+ isError: true
495
+ };
496
+ actions.push("recorded disable preference (local git config)");
497
+ const unsetError = unsetOwnedHooksPath(location.target);
498
+ if (unsetError) return {
499
+ message: `${unsetError.message}; disable preference was recorded (local git config). Run \`vp hooks enable\` to clear it, or \`git config --local --unset vp.hooks.disabled\``,
500
+ isError: true
501
+ };
502
+ if (ownsHooksPath) actions.push(`unset core.hooksPath (was "${existingHooksPath}")`);
503
+ else if (foreignHooksPath) notes.push(`core.hooksPath is set to "${existingHooksPath}" (not Vite+ dispatcher "${location.target}"), left unchanged`);
504
+ if (hasInternalDir) {
505
+ rmSync(internalDir, {
506
+ recursive: true,
507
+ force: true
508
+ });
509
+ actions.push(`removed ${displayedDir}/_`);
510
+ }
511
+ const summary = `Git hooks disabled: ${actions.join("; ")}. Project-owned hooks under ${displayedDir}/ and staged config were left unchanged. Run \`vp hooks enable\` to re-enable.`;
512
+ if (notes.length > 0) return {
513
+ message: `${summary} ${notes.join("; ")}.`,
514
+ isError: false
515
+ };
516
+ return {
517
+ message: summary,
518
+ isError: false
519
+ };
520
+ }
521
+ /**
522
+ * Report whether Vite+ hooks are set up, disabled by preference, and active.
523
+ */
524
+ function status(dir) {
525
+ const location = resolveHooksLocation(dir, {
526
+ unstoredPrefix: "root",
527
+ adoptEffectiveDispatcher: true
528
+ });
529
+ if ("isError" in location) return location;
530
+ const hooksDir = displayHooksDir(location);
531
+ const existingHooksPath = getEffectiveHooksPath();
532
+ const userDisabled = isHooksUserDisabled();
533
+ const dispatcherInstalled = existsSync(join(location.baseDir, location.dir, "_", "h"));
534
+ const ownsHooksPath = !!existingHooksPath && hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
535
+ let projectHooks = [];
536
+ const hooksDirPath = join(location.baseDir, location.dir);
537
+ if (existsSync(hooksDirPath)) try {
538
+ projectHooks = readdirSync(hooksDirPath, { withFileTypes: true }).filter((entry) => entry.isFile() && SUPPORTED_GIT_HOOK_NAMES.includes(entry.name)).map((entry) => entry.name).toSorted();
539
+ } catch {
540
+ projectHooks = [];
541
+ }
542
+ const preferenceLabel = userDisabled ? "disabled (local)" : getStoredHooksDir() || dispatcherInstalled || ownsHooksPath ? "enabled" : "not set";
543
+ const hooksPathLabel = existingHooksPath || "(unset)";
544
+ const ownership = !existingHooksPath ? "" : ownsHooksPath ? " (Vite+ dispatcher)" : " (not Vite+ dispatcher)";
545
+ const dispatcherLabel = dispatcherInstalled ? "installed" : "missing";
546
+ const projectHooksLabel = projectHooks.length > 0 ? projectHooks.join(", ") : "(none)";
547
+ const lines = [
548
+ `Preference: ${preferenceLabel}`,
549
+ `Hooks dir: ${hooksDir}`,
550
+ `core.hooksPath: ${hooksPathLabel}${ownership}`,
551
+ `Dispatcher: ${dispatcherLabel} (${hooksDir}/_)`,
552
+ `Project hooks: ${projectHooksLabel}`
553
+ ];
554
+ const hooksStatus = {
555
+ hooksDir,
556
+ userDisabled,
557
+ hooksPath: existingHooksPath || null,
558
+ ownsHooksPath,
559
+ dispatcherInstalled,
560
+ projectHooks,
561
+ lines
562
+ };
563
+ return {
564
+ message: lines.join("\n"),
565
+ isError: false,
566
+ status: hooksStatus
567
+ };
568
+ }
569
+ //#endregion
570
+ export { findUnsafeHookInstallPath as a, resolveHooksLocation as c, enable as i, status as l, SUPPORTED_GIT_HOOK_NAMES as n, install as o, disable as r, isHooksUserDisabled as s, DEFAULT_HOOKS_DIR as t };
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_define_config = require("./define-config-CEm_MtvJ.cjs");
1
+ const require_define_config = require("./define-config-DyNLA_f0.cjs");
2
2
  //#region src/index.cts
3
3
  const vite = require("@voidzero-dev/vite-plus-core");
4
4
  const { configDefaults, coverageConfigDefaults, defaultBrowserPort, defaultExclude, defaultInclude } = require("vitest/config");
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as defineConfig, c as lazyPlugins, o as defineProject } from "./define-config-DPnHe1Mx.js";
1
+ import { a as defineConfig, c as lazyPlugins, o as defineProject } from "./define-config-CV4bQG_8.js";
2
2
  import { configDefaults, coverageConfigDefaults, defaultBrowserPort, defaultExclude, defaultInclude } from "vitest/config";
3
3
  export * from "@voidzero-dev/vite-plus-core";
4
4
  export { configDefaults, coverageConfigDefaults, defaultBrowserPort, defaultExclude, defaultInclude, defineConfig, defineProject, lazyPlugins };
@@ -114,11 +114,13 @@ function createScanner(text, ignoreTrivia = false) {
114
114
  start = pos;
115
115
  continue;
116
116
  }
117
- if (ch >= 0 && ch <= 31) if (isLineBreak(ch)) {
118
- result += text.substring(start, pos);
119
- scanError = 2;
120
- break;
121
- } else scanError = 6;
117
+ if (ch >= 0 && ch <= 31) {
118
+ if (isLineBreak(ch)) {
119
+ result += text.substring(start, pos);
120
+ scanError = 2;
121
+ break;
122
+ } else scanError = 6;
123
+ }
122
124
  pos++;
123
125
  }
124
126
  return result;
@@ -539,8 +541,10 @@ function format(documentText, range, options) {
539
541
  }
540
542
  if (numberLineBreaks > 0 && (secondToken === 12 || secondToken === 13)) replaceContent = newLinesAndIndent();
541
543
  }
542
- if (secondToken === 17) if (options.keepLines && numberLineBreaks > 0) replaceContent = newLinesAndIndent();
543
- else replaceContent = options.insertFinalNewline ? eol : "";
544
+ if (secondToken === 17) {
545
+ if (options.keepLines && numberLineBreaks > 0) replaceContent = newLinesAndIndent();
546
+ else replaceContent = options.insertFinalNewline ? eol : "";
547
+ }
544
548
  const secondTokenStart = scanner.getTokenOffset() + formatTextStart;
545
549
  addEdit(replaceContent, firstTokenEnd, secondTokenStart);
546
550
  firstToken = secondToken;
@@ -964,9 +968,10 @@ function setProperty(text, originalPath, value, options) {
964
968
  while (path.length > 0) {
965
969
  lastSegment = path.pop();
966
970
  parent = findNodeAtLocation(root, path);
967
- if (parent === void 0 && value !== void 0) if (typeof lastSegment === "string") value = { [lastSegment]: value };
968
- else value = [value];
969
- else break;
971
+ if (parent === void 0 && value !== void 0) {
972
+ if (typeof lastSegment === "string") value = { [lastSegment]: value };
973
+ else value = [value];
974
+ } else break;
970
975
  }
971
976
  if (!parent) {
972
977
  if (value === void 0) throw new Error("Can not delete in empty document");
@@ -977,29 +982,30 @@ function setProperty(text, originalPath, value, options) {
977
982
  }, options);
978
983
  } else if (parent.type === "object" && typeof lastSegment === "string" && Array.isArray(parent.children)) {
979
984
  const existing = findNodeAtLocation(parent, [lastSegment]);
980
- if (existing !== void 0) if (value === void 0) {
981
- if (!existing.parent) throw new Error("Malformed AST");
982
- const propertyIndex = parent.children.indexOf(existing.parent);
983
- let removeBegin;
984
- let removeEnd = existing.parent.offset + existing.parent.length;
985
- if (propertyIndex > 0) {
986
- let previous = parent.children[propertyIndex - 1];
987
- removeBegin = previous.offset + previous.length;
988
- } else {
989
- removeBegin = parent.offset + 1;
990
- if (parent.children.length > 1) removeEnd = parent.children[1].offset;
991
- }
992
- return withFormatting(text, {
993
- offset: removeBegin,
994
- length: removeEnd - removeBegin,
995
- content: ""
985
+ if (existing !== void 0) {
986
+ if (value === void 0) {
987
+ if (!existing.parent) throw new Error("Malformed AST");
988
+ const propertyIndex = parent.children.indexOf(existing.parent);
989
+ let removeBegin;
990
+ let removeEnd = existing.parent.offset + existing.parent.length;
991
+ if (propertyIndex > 0) {
992
+ let previous = parent.children[propertyIndex - 1];
993
+ removeBegin = previous.offset + previous.length;
994
+ } else {
995
+ removeBegin = parent.offset + 1;
996
+ if (parent.children.length > 1) removeEnd = parent.children[1].offset;
997
+ }
998
+ return withFormatting(text, {
999
+ offset: removeBegin,
1000
+ length: removeEnd - removeBegin,
1001
+ content: ""
1002
+ }, options);
1003
+ } else return withFormatting(text, {
1004
+ offset: existing.offset,
1005
+ length: existing.length,
1006
+ content: JSON.stringify(value)
996
1007
  }, options);
997
- } else return withFormatting(text, {
998
- offset: existing.offset,
999
- length: existing.length,
1000
- content: JSON.stringify(value)
1001
- }, options);
1002
- else {
1008
+ } else {
1003
1009
  if (value === void 0) return [];
1004
1010
  const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
1005
1011
  const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map((p) => p.children[0].value)) : parent.children.length;