@fuzdev/gro 0.192.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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/args.d.ts +37 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +102 -0
- package/dist/build.task.d.ts +20 -0
- package/dist/build.task.d.ts.map +1 -0
- package/dist/build.task.js +119 -0
- package/dist/build_cache.d.ts +100 -0
- package/dist/build_cache.d.ts.map +1 -0
- package/dist/build_cache.js +299 -0
- package/dist/changelog.d.ts +11 -0
- package/dist/changelog.d.ts.map +1 -0
- package/dist/changelog.js +47 -0
- package/dist/changeset.task.d.ts +35 -0
- package/dist/changeset.task.d.ts.map +1 -0
- package/dist/changeset.task.js +151 -0
- package/dist/changeset_helpers.d.ts +17 -0
- package/dist/changeset_helpers.d.ts.map +1 -0
- package/dist/changeset_helpers.js +7 -0
- package/dist/check.task.d.ts +28 -0
- package/dist/check.task.d.ts.map +1 -0
- package/dist/check.task.js +104 -0
- package/dist/child_process_logging.d.ts +10 -0
- package/dist/child_process_logging.d.ts.map +1 -0
- package/dist/child_process_logging.js +26 -0
- package/dist/clean.task.d.ts +15 -0
- package/dist/clean.task.d.ts.map +1 -0
- package/dist/clean.task.js +40 -0
- package/dist/clean_fs.d.ts +9 -0
- package/dist/clean_fs.d.ts.map +1 -0
- package/dist/clean_fs.js +28 -0
- package/dist/cli.d.ts +34 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +61 -0
- package/dist/commit.task.d.ts +11 -0
- package/dist/commit.task.d.ts.map +1 -0
- package/dist/commit.task.js +24 -0
- package/dist/constants.d.ts +46 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +52 -0
- package/dist/deploy.task.d.ts +29 -0
- package/dist/deploy.task.d.ts.map +1 -0
- package/dist/deploy.task.js +217 -0
- package/dist/dev.task.d.ts +16 -0
- package/dist/dev.task.d.ts.map +1 -0
- package/dist/dev.task.js +44 -0
- package/dist/disknode.d.ts +23 -0
- package/dist/disknode.d.ts.map +1 -0
- package/dist/disknode.js +1 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +49 -0
- package/dist/esbuild_helpers.d.ts +16 -0
- package/dist/esbuild_helpers.d.ts.map +1 -0
- package/dist/esbuild_helpers.js +36 -0
- package/dist/esbuild_plugin_external_worker.d.ts +23 -0
- package/dist/esbuild_plugin_external_worker.d.ts.map +1 -0
- package/dist/esbuild_plugin_external_worker.js +55 -0
- package/dist/esbuild_plugin_svelte.d.ts +15 -0
- package/dist/esbuild_plugin_svelte.d.ts.map +1 -0
- package/dist/esbuild_plugin_svelte.js +83 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.d.ts +8 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.js +30 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.d.ts +7 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.js +18 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.d.ts +9 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.js +22 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.d.ts +11 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.js +18 -0
- package/dist/filer.d.ts +33 -0
- package/dist/filer.d.ts.map +1 -0
- package/dist/filer.js +385 -0
- package/dist/format.task.d.ts +11 -0
- package/dist/format.task.d.ts.map +1 -0
- package/dist/format.task.js +27 -0
- package/dist/format_directory.d.ts +13 -0
- package/dist/format_directory.d.ts.map +1 -0
- package/dist/format_directory.js +40 -0
- package/dist/format_file.d.ts +9 -0
- package/dist/format_file.d.ts.map +1 -0
- package/dist/format_file.js +42 -0
- package/dist/gen.d.ts +142 -0
- package/dist/gen.d.ts.map +1 -0
- package/dist/gen.js +199 -0
- package/dist/gen.task.d.ts +12 -0
- package/dist/gen.task.d.ts.map +1 -0
- package/dist/gen.task.js +149 -0
- package/dist/gen_helpers.d.ts +11 -0
- package/dist/gen_helpers.d.ts.map +1 -0
- package/dist/gen_helpers.js +76 -0
- package/dist/github.d.ts +19 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +33 -0
- package/dist/gro.config.default.d.ts +13 -0
- package/dist/gro.config.default.d.ts.map +1 -0
- package/dist/gro.config.default.js +33 -0
- package/dist/gro.d.ts +3 -0
- package/dist/gro.d.ts.map +1 -0
- package/dist/gro.js +21 -0
- package/dist/gro_config.d.ts +115 -0
- package/dist/gro_config.d.ts.map +1 -0
- package/dist/gro_config.js +114 -0
- package/dist/gro_helpers.d.ts +49 -0
- package/dist/gro_helpers.d.ts.map +1 -0
- package/dist/gro_helpers.js +97 -0
- package/dist/gro_plugin_gen.d.ts +12 -0
- package/dist/gro_plugin_gen.d.ts.map +1 -0
- package/dist/gro_plugin_gen.js +101 -0
- package/dist/gro_plugin_server.d.ts +80 -0
- package/dist/gro_plugin_server.d.ts.map +1 -0
- package/dist/gro_plugin_server.js +167 -0
- package/dist/gro_plugin_sveltekit_app.d.ts +9 -0
- package/dist/gro_plugin_sveltekit_app.d.ts.map +1 -0
- package/dist/gro_plugin_sveltekit_app.js +42 -0
- package/dist/gro_plugin_sveltekit_library.d.ts +16 -0
- package/dist/gro_plugin_sveltekit_library.d.ts.map +1 -0
- package/dist/gro_plugin_sveltekit_library.js +34 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/input_path.d.ts +64 -0
- package/dist/input_path.d.ts.map +1 -0
- package/dist/input_path.js +199 -0
- package/dist/invoke.d.ts +2 -0
- package/dist/invoke.d.ts.map +1 -0
- package/dist/invoke.js +28 -0
- package/dist/invoke_task.d.ts +30 -0
- package/dist/invoke_task.d.ts.map +1 -0
- package/dist/invoke_task.js +104 -0
- package/dist/lint.task.d.ts +11 -0
- package/dist/lint.task.d.ts.map +1 -0
- package/dist/lint.task.js +32 -0
- package/dist/loader.d.ts +6 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +192 -0
- package/dist/module.d.ts +4 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +6 -0
- package/dist/modules.d.ts +36 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +71 -0
- package/dist/package_json.d.ts +32 -0
- package/dist/package_json.d.ts.map +1 -0
- package/dist/package_json.js +178 -0
- package/dist/parse_exports.d.ts +20 -0
- package/dist/parse_exports.d.ts.map +1 -0
- package/dist/parse_exports.js +65 -0
- package/dist/parse_exports_context.d.ts +21 -0
- package/dist/parse_exports_context.d.ts.map +1 -0
- package/dist/parse_exports_context.js +332 -0
- package/dist/parse_imports.d.ts +5 -0
- package/dist/parse_imports.d.ts.map +1 -0
- package/dist/parse_imports.js +140 -0
- package/dist/paths.d.ts +41 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +69 -0
- package/dist/plugin.d.ts +36 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +78 -0
- package/dist/publish.task.d.ts +26 -0
- package/dist/publish.task.d.ts.map +1 -0
- package/dist/publish.task.js +176 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +2 -0
- package/dist/reinstall.task.d.ts +8 -0
- package/dist/reinstall.task.d.ts.map +1 -0
- package/dist/reinstall.task.js +35 -0
- package/dist/release.task.d.ts +8 -0
- package/dist/release.task.d.ts.map +1 -0
- package/dist/release.task.js +20 -0
- package/dist/resolve.task.d.ts +11 -0
- package/dist/resolve.task.d.ts.map +1 -0
- package/dist/resolve.task.js +38 -0
- package/dist/resolve_specifier.d.ts +22 -0
- package/dist/resolve_specifier.d.ts.map +1 -0
- package/dist/resolve_specifier.js +57 -0
- package/dist/run.task.d.ts +16 -0
- package/dist/run.task.d.ts.map +1 -0
- package/dist/run.task.js +52 -0
- package/dist/run_gen.d.ts +10 -0
- package/dist/run_gen.d.ts.map +1 -0
- package/dist/run_gen.js +73 -0
- package/dist/run_task.d.ts +17 -0
- package/dist/run_task.d.ts.map +1 -0
- package/dist/run_task.js +45 -0
- package/dist/source_json.d.ts +7 -0
- package/dist/source_json.d.ts.map +1 -0
- package/dist/source_json.js +145 -0
- package/dist/svelte_config.d.ts +57 -0
- package/dist/svelte_config.d.ts.map +1 -0
- package/dist/svelte_config.js +81 -0
- package/dist/sveltekit_helpers.d.ts +75 -0
- package/dist/sveltekit_helpers.d.ts.map +1 -0
- package/dist/sveltekit_helpers.js +94 -0
- package/dist/sveltekit_shim_app.d.ts +11 -0
- package/dist/sveltekit_shim_app.d.ts.map +1 -0
- package/dist/sveltekit_shim_app.js +31 -0
- package/dist/sveltekit_shim_app_environment.d.ts +13 -0
- package/dist/sveltekit_shim_app_environment.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_environment.js +14 -0
- package/dist/sveltekit_shim_app_forms.d.ts +5 -0
- package/dist/sveltekit_shim_app_forms.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_forms.js +6 -0
- package/dist/sveltekit_shim_app_navigation.d.ts +10 -0
- package/dist/sveltekit_shim_app_navigation.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_navigation.js +11 -0
- package/dist/sveltekit_shim_app_paths.d.ts +17 -0
- package/dist/sveltekit_shim_app_paths.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_paths.js +10 -0
- package/dist/sveltekit_shim_app_state.d.ts +5 -0
- package/dist/sveltekit_shim_app_state.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_state.js +26 -0
- package/dist/sveltekit_shim_env.d.ts +5 -0
- package/dist/sveltekit_shim_env.d.ts.map +1 -0
- package/dist/sveltekit_shim_env.js +23 -0
- package/dist/sync.task.d.ts +16 -0
- package/dist/sync.task.d.ts.map +1 -0
- package/dist/sync.task.js +39 -0
- package/dist/task.d.ts +98 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +109 -0
- package/dist/task_logging.d.ts +6 -0
- package/dist/task_logging.d.ts.map +1 -0
- package/dist/task_logging.js +201 -0
- package/dist/test.task.d.ts +13 -0
- package/dist/test.task.d.ts.map +1 -0
- package/dist/test.task.js +53 -0
- package/dist/typecheck.task.d.ts +13 -0
- package/dist/typecheck.task.d.ts.map +1 -0
- package/dist/typecheck.task.js +68 -0
- package/dist/upgrade.task.d.ts +20 -0
- package/dist/upgrade.task.d.ts.map +1 -0
- package/dist/upgrade.task.js +111 -0
- package/dist/watch_dir.d.ts +36 -0
- package/dist/watch_dir.d.ts.map +1 -0
- package/dist/watch_dir.js +69 -0
- package/package.json +149 -0
- package/src/lib/args.ts +115 -0
- package/src/lib/build.task.ts +151 -0
- package/src/lib/build_cache.ts +378 -0
- package/src/lib/changelog.ts +69 -0
- package/src/lib/changeset.task.ts +228 -0
- package/src/lib/changeset_helpers.ts +14 -0
- package/src/lib/check.task.ts +132 -0
- package/src/lib/child_process_logging.ts +38 -0
- package/src/lib/clean.task.ts +48 -0
- package/src/lib/clean_fs.ts +54 -0
- package/src/lib/cli.ts +98 -0
- package/src/lib/commit.task.ts +34 -0
- package/src/lib/constants.ts +56 -0
- package/src/lib/deploy.task.ts +287 -0
- package/src/lib/dev.task.ts +52 -0
- package/src/lib/disknode.ts +26 -0
- package/src/lib/env.ts +78 -0
- package/src/lib/esbuild_helpers.ts +49 -0
- package/src/lib/esbuild_plugin_external_worker.ts +94 -0
- package/src/lib/esbuild_plugin_svelte.ts +134 -0
- package/src/lib/esbuild_plugin_sveltekit_local_imports.ts +38 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_alias.ts +27 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_app.ts +42 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_env.ts +47 -0
- package/src/lib/filer.ts +458 -0
- package/src/lib/format.task.ts +44 -0
- package/src/lib/format_directory.ts +65 -0
- package/src/lib/format_file.ts +49 -0
- package/src/lib/gen.task.ts +206 -0
- package/src/lib/gen.ts +406 -0
- package/src/lib/gen_helpers.ts +131 -0
- package/src/lib/github.ts +46 -0
- package/src/lib/gro.config.default.ts +42 -0
- package/src/lib/gro.ts +29 -0
- package/src/lib/gro_config.ts +254 -0
- package/src/lib/gro_helpers.ts +108 -0
- package/src/lib/gro_plugin_gen.ts +149 -0
- package/src/lib/gro_plugin_server.ts +288 -0
- package/src/lib/gro_plugin_sveltekit_app.ts +58 -0
- package/src/lib/gro_plugin_sveltekit_library.ts +63 -0
- package/src/lib/index.ts +8 -0
- package/src/lib/input_path.ts +254 -0
- package/src/lib/invoke.ts +34 -0
- package/src/lib/invoke_task.ts +139 -0
- package/src/lib/lint.task.ts +39 -0
- package/src/lib/loader.ts +229 -0
- package/src/lib/module.ts +13 -0
- package/src/lib/modules.ts +117 -0
- package/src/lib/package_json.ts +255 -0
- package/src/lib/parse_exports.ts +100 -0
- package/src/lib/parse_exports_context.ts +395 -0
- package/src/lib/parse_imports.ts +180 -0
- package/src/lib/paths.ts +111 -0
- package/src/lib/plugin.ts +106 -0
- package/src/lib/publish.task.ts +228 -0
- package/src/lib/register.ts +3 -0
- package/src/lib/reinstall.task.ts +45 -0
- package/src/lib/release.task.ts +26 -0
- package/src/lib/resolve.task.ts +43 -0
- package/src/lib/resolve_specifier.ts +81 -0
- package/src/lib/run.task.ts +65 -0
- package/src/lib/run_gen.ts +110 -0
- package/src/lib/run_task.ts +82 -0
- package/src/lib/source_json.ts +183 -0
- package/src/lib/svelte_config.ts +140 -0
- package/src/lib/sveltekit_helpers.ts +193 -0
- package/src/lib/sveltekit_shim_app.ts +41 -0
- package/src/lib/sveltekit_shim_app_environment.ts +16 -0
- package/src/lib/sveltekit_shim_app_forms.ts +13 -0
- package/src/lib/sveltekit_shim_app_navigation.ts +23 -0
- package/src/lib/sveltekit_shim_app_paths.ts +26 -0
- package/src/lib/sveltekit_shim_app_state.ts +35 -0
- package/src/lib/sveltekit_shim_env.ts +45 -0
- package/src/lib/sync.task.ts +47 -0
- package/src/lib/task.ts +245 -0
- package/src/lib/task_logging.ts +255 -0
- package/src/lib/test.task.ts +63 -0
- package/src/lib/typecheck.task.ts +81 -0
- package/src/lib/upgrade.task.ts +148 -0
- package/src/lib/watch_dir.ts +115 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { args_serialize } from '@fuzdev/fuz_util/args.js';
|
|
2
|
+
import { GitOrigin, git_pull } from '@fuzdev/fuz_util/git.js';
|
|
3
|
+
import { spawn } from '@fuzdev/fuz_util/process.js';
|
|
4
|
+
import { rm } from 'node:fs/promises';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { to_forwarded_args } from "./args.js";
|
|
7
|
+
import { spawn_cli } from "./cli.js";
|
|
8
|
+
import { NODE_MODULES_DIRNAME } from "./constants.js";
|
|
9
|
+
import { package_json_extract_dependencies, package_json_load, } from "./package_json.js";
|
|
10
|
+
import { TaskError } from "./task.js";
|
|
11
|
+
/** @nodocs */
|
|
12
|
+
export const Args = z.strictObject({
|
|
13
|
+
_: z
|
|
14
|
+
.array(z.string())
|
|
15
|
+
.meta({ description: 'names of deps to exclude from the upgrade' })
|
|
16
|
+
.default([]),
|
|
17
|
+
only: z
|
|
18
|
+
.union([z.string(), z.array(z.string())])
|
|
19
|
+
.meta({
|
|
20
|
+
description: 'names of deps to include in the upgrade',
|
|
21
|
+
})
|
|
22
|
+
.default([])
|
|
23
|
+
.transform((v) => (Array.isArray(v) ? v : [v])),
|
|
24
|
+
origin: GitOrigin.describe('git origin to deploy to').default('origin'),
|
|
25
|
+
force: z.boolean().meta({ description: 'if true, print out the planned upgrades' }).default(false),
|
|
26
|
+
pull: z.boolean().meta({ description: 'dual of no-pull' }).default(true),
|
|
27
|
+
'no-pull': z.boolean().meta({ description: 'opt out of git pull' }).default(false),
|
|
28
|
+
delete_node_modules: z
|
|
29
|
+
.boolean()
|
|
30
|
+
.meta({ description: 'if true, deletes node_modules before upgrading' })
|
|
31
|
+
.default(false),
|
|
32
|
+
node_modules_path: z // TODO maybe configured globally instead
|
|
33
|
+
.string()
|
|
34
|
+
.meta({ description: 'path to modules directory to delete' })
|
|
35
|
+
.default(NODE_MODULES_DIRNAME),
|
|
36
|
+
delete_lockfile: z
|
|
37
|
+
.boolean()
|
|
38
|
+
.meta({ description: 'if true, deletes the lockfile before upgrading' })
|
|
39
|
+
.default(false),
|
|
40
|
+
lockfile_path: z
|
|
41
|
+
.string()
|
|
42
|
+
.meta({ description: 'path to the lockfile to delete' })
|
|
43
|
+
.default('package-lock.json'),
|
|
44
|
+
dry: z.boolean().meta({ description: 'if true, print out the planned upgrades' }).default(false),
|
|
45
|
+
});
|
|
46
|
+
/** @nodocs */
|
|
47
|
+
export const task = {
|
|
48
|
+
summary: 'upgrade deps',
|
|
49
|
+
Args,
|
|
50
|
+
run: async ({ args, log, config }) => {
|
|
51
|
+
const { _, only, origin, force, pull, delete_node_modules, node_modules_path, delete_lockfile, lockfile_path, dry, } = args;
|
|
52
|
+
if (_.length && only.length) {
|
|
53
|
+
throw new TaskError('Cannot call `gro upgrade` with both rest args and --only.');
|
|
54
|
+
}
|
|
55
|
+
// TODO maybe a different task that pulls and does other things, like `gro ready`
|
|
56
|
+
if (pull) {
|
|
57
|
+
await git_pull(origin);
|
|
58
|
+
}
|
|
59
|
+
if (delete_node_modules) {
|
|
60
|
+
log.info(`deleting node_modules at `, node_modules_path);
|
|
61
|
+
await rm(node_modules_path, { recursive: true, force: true });
|
|
62
|
+
}
|
|
63
|
+
if (delete_lockfile) {
|
|
64
|
+
log.info(`deleting lockfile at`, lockfile_path);
|
|
65
|
+
await rm(lockfile_path, { force: true });
|
|
66
|
+
}
|
|
67
|
+
const package_json = await package_json_load();
|
|
68
|
+
const all_deps = package_json_extract_dependencies(package_json);
|
|
69
|
+
const deps = only.length
|
|
70
|
+
? all_deps.filter((d) => only.includes(d.name))
|
|
71
|
+
: all_deps.filter((d) => !_.includes(d.name));
|
|
72
|
+
if (only.length && only.length !== deps.length) {
|
|
73
|
+
throw new TaskError(`Some deps to upgrade were not found: ${only.filter((o) => !deps.find((d) => d.name === o)).join(', ')}`);
|
|
74
|
+
}
|
|
75
|
+
const upgrade_items = to_upgrade_items(deps);
|
|
76
|
+
log.info(`upgrading:`, upgrade_items.join(' '));
|
|
77
|
+
const install_args = ['install'].concat(upgrade_items);
|
|
78
|
+
if (dry) {
|
|
79
|
+
install_args.push('--dry-run');
|
|
80
|
+
log.info(`deps`, deps);
|
|
81
|
+
}
|
|
82
|
+
if (force) {
|
|
83
|
+
install_args.push('--force');
|
|
84
|
+
}
|
|
85
|
+
install_args.push(...args_serialize(to_forwarded_args(config.pm_cli)));
|
|
86
|
+
await spawn(config.pm_cli, install_args);
|
|
87
|
+
// TODO @many this relies on npm behavior that changed in v11
|
|
88
|
+
// If we deleted the lockfile or node modules, `npm install` again
|
|
89
|
+
// to fix a recurring npm bug getting the lockfile to its final state.
|
|
90
|
+
if (!dry && (delete_node_modules || delete_lockfile)) {
|
|
91
|
+
log.info(`installing again to fix npm lockfile bugs`);
|
|
92
|
+
await spawn(config.pm_cli, ['install']);
|
|
93
|
+
}
|
|
94
|
+
// Sync in a new process to pick up any changes after installing, avoiding some errors.
|
|
95
|
+
await spawn_cli('gro', ['sync']); // don't install because we do above
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const EXACT_VERSION_MATCHER = /^..*@.+/;
|
|
99
|
+
const CUSTOM_TAG_MATCHER = /^[\^~><=]*.+-(.+)/;
|
|
100
|
+
// TODO hacky and limited
|
|
101
|
+
// TODO probably want to pass through exact deps as well, e.g. @foo/bar@1
|
|
102
|
+
const to_upgrade_items = (deps) => deps.map((dep) => {
|
|
103
|
+
if (EXACT_VERSION_MATCHER.test(dep.name)) {
|
|
104
|
+
return dep.name;
|
|
105
|
+
}
|
|
106
|
+
const custom_tag_matches = CUSTOM_TAG_MATCHER.exec(dep.version);
|
|
107
|
+
if (custom_tag_matches) {
|
|
108
|
+
return dep.name + '@' + custom_tag_matches[1].split('.')[0]; // I tried adding `\.?` to the end but doesn't work and I'm being lazy so I'm just splitting
|
|
109
|
+
}
|
|
110
|
+
return dep.name + '@latest';
|
|
111
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ChokidarOptions, type Matcher } from 'chokidar';
|
|
2
|
+
import type { PathFilter } from '@fuzdev/fuz_util/path.js';
|
|
3
|
+
export interface WatchNodeFs {
|
|
4
|
+
init: () => Promise<void>;
|
|
5
|
+
close: () => Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export interface WatcherChange {
|
|
8
|
+
type: WatcherChangeType;
|
|
9
|
+
path: string;
|
|
10
|
+
is_directory: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type WatcherChangeType = 'add' | 'update' | 'delete';
|
|
13
|
+
export type WatcherChangeCallback = (change: WatcherChange) => void;
|
|
14
|
+
export interface WatchDirOptions {
|
|
15
|
+
dir: string;
|
|
16
|
+
on_change: WatcherChangeCallback;
|
|
17
|
+
filter?: PathFilter | null | undefined;
|
|
18
|
+
chokidar?: ChokidarOptions;
|
|
19
|
+
/**
|
|
20
|
+
* When `false`, returns the `path` relative to `dir`.
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
absolute?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Pattern to ignore files, merged into `chokidar.ignored` if also provided.
|
|
26
|
+
* - `undefined` (default) ignores files matching `.tmp.` pattern
|
|
27
|
+
* - `null` sets no default ignore pattern
|
|
28
|
+
* - or some custom pattern
|
|
29
|
+
*/
|
|
30
|
+
ignored?: Matcher | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Watch for changes on the filesystem using chokidar.
|
|
34
|
+
*/
|
|
35
|
+
export declare const watch_dir: ({ dir, on_change, filter, absolute, chokidar, ignored, }: WatchDirOptions) => WatchNodeFs;
|
|
36
|
+
//# sourceMappingURL=watch_dir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch_dir.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/watch_dir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,eAAe,EAAkB,KAAK,OAAO,EAAC,MAAM,UAAU,CAAC;AAInF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAOzD,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,OAAO,CAAC;CACtB;AACD,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC5D,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,qBAAqB,CAAC;IACjC,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,0DAOvB,eAAe,KAAG,WA+CpB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { watch } from 'chokidar';
|
|
2
|
+
import { relative } from 'node:path';
|
|
3
|
+
import { statSync } from 'node:fs';
|
|
4
|
+
import { create_deferred } from '@fuzdev/fuz_util/async.js';
|
|
5
|
+
import { EMPTY_OBJECT } from '@fuzdev/fuz_util/object.js';
|
|
6
|
+
const TMP_FILE_PATTERN = /\.tmp\./;
|
|
7
|
+
/**
|
|
8
|
+
* Watch for changes on the filesystem using chokidar.
|
|
9
|
+
*/
|
|
10
|
+
export const watch_dir = ({ dir, on_change, filter, absolute = true, chokidar, ignored = TMP_FILE_PATTERN, }) => {
|
|
11
|
+
let watcher;
|
|
12
|
+
let initing;
|
|
13
|
+
return {
|
|
14
|
+
init: async () => {
|
|
15
|
+
if (initing)
|
|
16
|
+
return initing.promise;
|
|
17
|
+
initing = create_deferred();
|
|
18
|
+
watcher = watch(dir, resolve_chokidar_options(chokidar, ignored));
|
|
19
|
+
watcher.on('add', (path) => {
|
|
20
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
21
|
+
if (filter && !filter(final_path, false))
|
|
22
|
+
return;
|
|
23
|
+
on_change({ type: 'add', path: final_path, is_directory: false });
|
|
24
|
+
});
|
|
25
|
+
watcher.on('addDir', (path) => {
|
|
26
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
27
|
+
if (filter && !filter(final_path, true))
|
|
28
|
+
return;
|
|
29
|
+
on_change({ type: 'add', path: final_path, is_directory: true });
|
|
30
|
+
});
|
|
31
|
+
watcher.on('change', (path, s) => {
|
|
32
|
+
const stats = s ?? statSync(path);
|
|
33
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
34
|
+
if (filter && !filter(final_path, stats.isDirectory())) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
on_change({ type: 'update', path: final_path, is_directory: stats.isDirectory() });
|
|
38
|
+
});
|
|
39
|
+
watcher.on('unlink', (path) => {
|
|
40
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
41
|
+
if (filter && !filter(final_path, false))
|
|
42
|
+
return;
|
|
43
|
+
on_change({ type: 'delete', path: final_path, is_directory: false });
|
|
44
|
+
});
|
|
45
|
+
watcher.on('unlinkDir', (path) => {
|
|
46
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
47
|
+
if (filter && !filter(final_path, true))
|
|
48
|
+
return;
|
|
49
|
+
on_change({ type: 'delete', path: final_path, is_directory: true });
|
|
50
|
+
});
|
|
51
|
+
// wait until ready
|
|
52
|
+
watcher.once('ready', () => initing?.resolve());
|
|
53
|
+
await initing.promise;
|
|
54
|
+
},
|
|
55
|
+
close: async () => {
|
|
56
|
+
initing = undefined;
|
|
57
|
+
if (!watcher)
|
|
58
|
+
return;
|
|
59
|
+
await watcher.close();
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const resolve_chokidar_options = (options, ignored) => {
|
|
64
|
+
if (ignored === null)
|
|
65
|
+
return options;
|
|
66
|
+
const { ignored: i, ...rest } = options ?? EMPTY_OBJECT;
|
|
67
|
+
const resolved_ignored = i === undefined ? ignored : Array.isArray(i) ? [...i, ignored] : [i, ignored];
|
|
68
|
+
return { ...rest, ignored: resolved_ignored };
|
|
69
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fuzdev/gro",
|
|
3
|
+
"version": "0.192.0",
|
|
4
|
+
"description": "task runner and toolkit extending SvelteKit",
|
|
5
|
+
"motto": "generate, run, optimize",
|
|
6
|
+
"glyph": "🌰",
|
|
7
|
+
"logo": "logo.svg",
|
|
8
|
+
"logo_alt": "a pixelated green oak acorn with a glint of sun",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"homepage": "https://gro.fuzdev.com/",
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "Ryan Atkinson",
|
|
13
|
+
"email": "mail@ryanatkn.com",
|
|
14
|
+
"url": "https://www.ryanatkn.com/"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/fuzdev/gro.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": "https://github.com/fuzdev/gro/issues",
|
|
21
|
+
"funding": "https://www.ryanatkn.com/funding",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"bootstrap": "rm -rf .gro dist && svelte-kit sync && svelte-package && chmod +x ./dist/gro.js && npm link -f",
|
|
24
|
+
"start": "gro dev",
|
|
25
|
+
"dev": "gro dev",
|
|
26
|
+
"build": "gro build",
|
|
27
|
+
"check": "gro check",
|
|
28
|
+
"test": "gro test",
|
|
29
|
+
"preview": "vite preview",
|
|
30
|
+
"deploy": "gro deploy"
|
|
31
|
+
},
|
|
32
|
+
"type": "module",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=22.15"
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"gro": "dist/gro.js"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"web",
|
|
41
|
+
"tools",
|
|
42
|
+
"task runner",
|
|
43
|
+
"tasks",
|
|
44
|
+
"codegen",
|
|
45
|
+
"svelte",
|
|
46
|
+
"sveltekit",
|
|
47
|
+
"vite",
|
|
48
|
+
"typescript"
|
|
49
|
+
],
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"chokidar": "^5.0.0",
|
|
52
|
+
"dotenv": "^17.2.3",
|
|
53
|
+
"esm-env": "^1.2.2",
|
|
54
|
+
"oxc-parser": "^0.99.0",
|
|
55
|
+
"prettier": "^3.7.4",
|
|
56
|
+
"prettier-plugin-svelte": "^3.4.1",
|
|
57
|
+
"ts-blank-space": "^0.6.2",
|
|
58
|
+
"tslib": "^2.8.1",
|
|
59
|
+
"zod": "^4.3.6"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@fuzdev/fuz_util": ">=0.49.2",
|
|
63
|
+
"@sveltejs/kit": "^2",
|
|
64
|
+
"esbuild": "^0.27.0",
|
|
65
|
+
"svelte": "^5",
|
|
66
|
+
"typescript": "^5",
|
|
67
|
+
"vitest": "^3 || ^4"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"@sveltejs/kit": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"vitest": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"optionalDependencies": {
|
|
78
|
+
"vitest": "^3 || ^4"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@changesets/changelog-git": "^0.2.1",
|
|
82
|
+
"@changesets/types": "^6.1.0",
|
|
83
|
+
"@fuzdev/fuz_code": "^0.44.1",
|
|
84
|
+
"@fuzdev/fuz_css": "^0.47.0",
|
|
85
|
+
"@fuzdev/fuz_ui": "^0.182.0",
|
|
86
|
+
"@fuzdev/fuz_util": "^0.50.1",
|
|
87
|
+
"@jridgewell/trace-mapping": "^0.3.31",
|
|
88
|
+
"@ryanatkn/eslint-config": "^0.9.0",
|
|
89
|
+
"@sveltejs/adapter-static": "^3.0.10",
|
|
90
|
+
"@sveltejs/kit": "^2.50.1",
|
|
91
|
+
"@sveltejs/package": "^2.5.7",
|
|
92
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
93
|
+
"@types/estree": "^1.0.8",
|
|
94
|
+
"@types/node": "^24.10.1",
|
|
95
|
+
"@webref/css": "^8.2.0",
|
|
96
|
+
"esbuild": "^0.27.1",
|
|
97
|
+
"eslint": "^9.39.1",
|
|
98
|
+
"eslint-plugin-svelte": "^3.13.1",
|
|
99
|
+
"magic-string": "^0.30.21",
|
|
100
|
+
"svelte": "^5.49.1",
|
|
101
|
+
"svelte-check": "^4.3.6",
|
|
102
|
+
"svelte2tsx": "^0.7.47",
|
|
103
|
+
"typescript": "^5.9.3",
|
|
104
|
+
"typescript-eslint": "^8.48.1",
|
|
105
|
+
"vitest": "^4.0.15",
|
|
106
|
+
"zimmerframe": "^1.1.4"
|
|
107
|
+
},
|
|
108
|
+
"prettier": {
|
|
109
|
+
"plugins": [
|
|
110
|
+
"prettier-plugin-svelte"
|
|
111
|
+
],
|
|
112
|
+
"useTabs": true,
|
|
113
|
+
"printWidth": 100,
|
|
114
|
+
"singleQuote": true,
|
|
115
|
+
"bracketSpacing": false,
|
|
116
|
+
"overrides": [
|
|
117
|
+
{
|
|
118
|
+
"files": "package.json",
|
|
119
|
+
"options": {
|
|
120
|
+
"useTabs": false
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"sideEffects": [
|
|
126
|
+
"**/*.css"
|
|
127
|
+
],
|
|
128
|
+
"files": [
|
|
129
|
+
"dist",
|
|
130
|
+
"src/lib/**/*.ts",
|
|
131
|
+
"!src/lib/**/*.test.*",
|
|
132
|
+
"!dist/**/*.test.*"
|
|
133
|
+
],
|
|
134
|
+
"exports": {
|
|
135
|
+
"./package.json": "./package.json",
|
|
136
|
+
".": {
|
|
137
|
+
"types": "./dist/index.d.ts",
|
|
138
|
+
"default": "./dist/index.js"
|
|
139
|
+
},
|
|
140
|
+
"./*.js": {
|
|
141
|
+
"types": "./dist/*.d.ts",
|
|
142
|
+
"default": "./dist/*.js"
|
|
143
|
+
},
|
|
144
|
+
"./*.ts": {
|
|
145
|
+
"types": "./dist/*.d.ts",
|
|
146
|
+
"default": "./dist/*.js"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
package/src/lib/args.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {styleText as st} from 'node:util';
|
|
2
|
+
import {argv_parse, type Args} from '@fuzdev/fuz_util/args.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parses `task_name` and `args` from `process.argv`,
|
|
6
|
+
* ignoring anything after any `--`.
|
|
7
|
+
*/
|
|
8
|
+
export const to_task_args = (argv = process.argv): {task_name: string; args: Args} => {
|
|
9
|
+
const forwarded_index = argv.indexOf('--');
|
|
10
|
+
const args = argv_parse(forwarded_index === -1 ? argv.slice(2) : argv.slice(2, forwarded_index));
|
|
11
|
+
const task_name = args._.shift() ?? '';
|
|
12
|
+
if (!args._.length) delete (args as Args)._; // enable schema defaults
|
|
13
|
+
return {task_name, args};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Gets the array of raw string args starting with the first `--`, if any.
|
|
18
|
+
*/
|
|
19
|
+
export const to_raw_rest_args = (argv = process.argv): Array<string> => {
|
|
20
|
+
const forwarded_index = argv.indexOf('--');
|
|
21
|
+
return forwarded_index === -1 ? [] : argv.slice(forwarded_index);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parses `process.argv` for the specified `command`, so given
|
|
26
|
+
* `gro taskname arg1 --arg2 -- eslint eslintarg1 --eslintarg2 -- tsc --tscarg1 --tscarg2`
|
|
27
|
+
* the `command` `'eslint'` returns `eslintarg1 --eslintarg2`
|
|
28
|
+
* and `'tsc'` returns `--tscarg1` and `--tscarg2`.
|
|
29
|
+
*/
|
|
30
|
+
export const to_forwarded_args = (
|
|
31
|
+
command: string,
|
|
32
|
+
raw_rest_args?: Array<string>,
|
|
33
|
+
cache = to_forwarded_args_by_command(raw_rest_args),
|
|
34
|
+
): Args => cache[command] ?? {};
|
|
35
|
+
|
|
36
|
+
export const to_forwarded_args_by_command = (
|
|
37
|
+
raw_rest_args = to_raw_rest_args(),
|
|
38
|
+
): Record<string, Args | undefined> => {
|
|
39
|
+
// Parse each segment of `argv` separated by `--`.
|
|
40
|
+
const argvs: Array<Array<string>> = [];
|
|
41
|
+
let arr: Array<string> | undefined;
|
|
42
|
+
for (const arg of raw_rest_args) {
|
|
43
|
+
if (arg === '--') {
|
|
44
|
+
if (arr?.length) argvs.push(arr);
|
|
45
|
+
arr = [];
|
|
46
|
+
} else if (!arr) {
|
|
47
|
+
continue;
|
|
48
|
+
} else if (arg) {
|
|
49
|
+
arr.push(arg);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (arr?.length) argvs.push(arr);
|
|
53
|
+
// Add each segment of parsed `argv` keyed by the first rest arg,
|
|
54
|
+
// which is assumed to be the CLI command that gets forwarded the args.
|
|
55
|
+
const forwarded_args_by_command: Record<string, Args> = {};
|
|
56
|
+
for (const argv of argvs) {
|
|
57
|
+
const args = argv_parse(argv);
|
|
58
|
+
let command = args._.shift();
|
|
59
|
+
if (!command) {
|
|
60
|
+
// Skip sections without a command name - these are handled by `to_implicit_forwarded_args`.
|
|
61
|
+
// This allows `gro run script.ts -- --help` to pass `--help` to the script.
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// Gro commands get combined with their task name.
|
|
65
|
+
if (command === 'gro') {
|
|
66
|
+
if (!args._.length) {
|
|
67
|
+
throw Error(
|
|
68
|
+
`Malformed args following a \`--\`. Expected gro taskname: \`${argv.join(' ')}\``,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
command += ' ' + args._.shift();
|
|
72
|
+
}
|
|
73
|
+
if (!args._.length) delete (args as Args)._;
|
|
74
|
+
forwarded_args_by_command[command] = args;
|
|
75
|
+
}
|
|
76
|
+
return forwarded_args_by_command;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Gets all args after the first `--` without assuming a command name.
|
|
81
|
+
* This is useful for tasks that want to forward args directly to a tool
|
|
82
|
+
* without requiring users to specify the tool name explicitly.
|
|
83
|
+
* Optionally strips a specific command name if present for backward compatibility.
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* // `gro test -- --watch` → {watch: true}
|
|
87
|
+
* // `gro test -- foo.test.ts` → {_: ['foo.test.ts']}
|
|
88
|
+
* // `gro test -- vitest --watch` with command_to_strip='vitest' → {watch: true}
|
|
89
|
+
* to_implicit_forwarded_args('vitest')
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export const to_implicit_forwarded_args = (
|
|
93
|
+
command_to_strip?: string,
|
|
94
|
+
raw_rest_args = to_raw_rest_args(),
|
|
95
|
+
): Args => {
|
|
96
|
+
const start = raw_rest_args.indexOf('--');
|
|
97
|
+
if (start === -1) return {};
|
|
98
|
+
|
|
99
|
+
let argv = raw_rest_args.slice(start + 1);
|
|
100
|
+
|
|
101
|
+
if (command_to_strip && argv[0] === command_to_strip) {
|
|
102
|
+
argv = argv.slice(1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const args = argv_parse(argv);
|
|
106
|
+
if (!args._.length) delete (args as Args)._;
|
|
107
|
+
return args;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const print_command_args = (serialized_args: Array<string>): string =>
|
|
111
|
+
st('gray', '[') +
|
|
112
|
+
st('magenta', 'running command') +
|
|
113
|
+
st('gray', ']') +
|
|
114
|
+
' ' +
|
|
115
|
+
serialized_args.join(' ');
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {z} from 'zod';
|
|
2
|
+
import {styleText as st} from 'node:util';
|
|
3
|
+
import {git_check_clean_workspace, git_current_commit_hash} from '@fuzdev/fuz_util/git.js';
|
|
4
|
+
import {rm} from 'node:fs/promises';
|
|
5
|
+
import {join} from 'node:path';
|
|
6
|
+
import {fs_exists} from '@fuzdev/fuz_util/fs.js';
|
|
7
|
+
|
|
8
|
+
import {TaskError, type Task} from './task.ts';
|
|
9
|
+
import {Plugins} from './plugin.ts';
|
|
10
|
+
import {clean_fs} from './clean_fs.ts';
|
|
11
|
+
import {
|
|
12
|
+
is_build_cache_valid,
|
|
13
|
+
create_build_cache_metadata,
|
|
14
|
+
save_build_cache_metadata,
|
|
15
|
+
discover_build_output_dirs,
|
|
16
|
+
} from './build_cache.ts';
|
|
17
|
+
import {paths} from './paths.ts';
|
|
18
|
+
|
|
19
|
+
/** @nodocs */
|
|
20
|
+
export const Args = z.strictObject({
|
|
21
|
+
sync: z.boolean().meta({description: 'dual of no-sync'}).default(true),
|
|
22
|
+
'no-sync': z.boolean().meta({description: 'opt out of gro sync'}).default(false),
|
|
23
|
+
gen: z.boolean().meta({description: 'dual of no-gen'}).default(true),
|
|
24
|
+
'no-gen': z.boolean().meta({description: 'opt out of gro gen'}).default(false),
|
|
25
|
+
install: z.boolean().meta({description: 'dual of no-install'}).default(true),
|
|
26
|
+
'no-install': z // convenience, same as `gro build -- gro sync --no-install` but the latter takes precedence
|
|
27
|
+
.boolean()
|
|
28
|
+
.meta({description: 'opt out of installing packages before building'})
|
|
29
|
+
.default(false),
|
|
30
|
+
force_build: z
|
|
31
|
+
.boolean()
|
|
32
|
+
.meta({description: 'force a fresh build, ignoring the cache'})
|
|
33
|
+
.default(false),
|
|
34
|
+
});
|
|
35
|
+
export type Args = z.infer<typeof Args>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Length of git commit hash when displayed in logs (standard git convention).
|
|
39
|
+
*/
|
|
40
|
+
export const GIT_SHORT_HASH_LENGTH = 7;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Formats a git commit hash for display in logs.
|
|
44
|
+
* Returns '[none]' if hash is null (e.g., not in a git repo).
|
|
45
|
+
*/
|
|
46
|
+
const format_commit_hash = (hash: string | null): string =>
|
|
47
|
+
hash?.slice(0, GIT_SHORT_HASH_LENGTH) ?? '[none]';
|
|
48
|
+
|
|
49
|
+
/** @nodocs */
|
|
50
|
+
export const task: Task<Args> = {
|
|
51
|
+
summary: 'build the project',
|
|
52
|
+
Args,
|
|
53
|
+
run: async (ctx): Promise<void> => {
|
|
54
|
+
const {args, invoke_task, log, config} = ctx;
|
|
55
|
+
const {sync, gen, install, force_build} = args;
|
|
56
|
+
|
|
57
|
+
if (sync || install) {
|
|
58
|
+
if (!sync) log.warn('sync is false but install is true, so ignoring the sync option');
|
|
59
|
+
await invoke_task('sync', {install, gen: false});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (gen) {
|
|
63
|
+
await invoke_task('gen');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Batch git calls upfront for performance (spawning processes is expensive)
|
|
67
|
+
const [workspace_status, initial_commit] = await Promise.all([
|
|
68
|
+
git_check_clean_workspace(),
|
|
69
|
+
git_current_commit_hash(),
|
|
70
|
+
]);
|
|
71
|
+
const workspace_dirty = !!workspace_status;
|
|
72
|
+
|
|
73
|
+
// Discover build output directories once to avoid redundant filesystem scans
|
|
74
|
+
let build_dirs: Array<string> | undefined;
|
|
75
|
+
|
|
76
|
+
// Check build cache unless force_build is set or workspace is dirty
|
|
77
|
+
if (!workspace_dirty && !force_build) {
|
|
78
|
+
const cache_valid = await is_build_cache_valid(config, log, initial_commit);
|
|
79
|
+
if (cache_valid) {
|
|
80
|
+
log.info(
|
|
81
|
+
st('cyan', 'skipping build, cache is valid'),
|
|
82
|
+
st('dim', '(use --force_build to rebuild)'),
|
|
83
|
+
);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
} else if (workspace_dirty) {
|
|
87
|
+
// IMPORTANT: When workspace is dirty, we delete cache AND all outputs to prevent stale state.
|
|
88
|
+
// Rationale: Uncommitted changes could be reverted, leaving cached outputs from reverted code.
|
|
89
|
+
// This conservative approach prioritizes safety over convenience during development.
|
|
90
|
+
const cache_path = join(paths.build, 'build.json');
|
|
91
|
+
if (await fs_exists(cache_path)) {
|
|
92
|
+
await rm(cache_path, {force: true});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Delete all build output directories
|
|
96
|
+
build_dirs = await discover_build_output_dirs();
|
|
97
|
+
await Promise.all(build_dirs.map((dir) => rm(dir, {recursive: true, force: true})));
|
|
98
|
+
|
|
99
|
+
log.info(st('yellow', 'workspace has uncommitted changes - skipping build cache'));
|
|
100
|
+
// Skip clean_fs - already manually cleaned cache and all build outputs above
|
|
101
|
+
} else {
|
|
102
|
+
log.info(st('yellow', 'forcing fresh build, ignoring cache'));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Clean build outputs (skip if workspace was dirty - already cleaned manually above)
|
|
106
|
+
if (!workspace_dirty) {
|
|
107
|
+
await clean_fs({build_dist: true});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const plugins = await Plugins.create({...ctx, dev: false, watch: false});
|
|
111
|
+
await plugins.setup();
|
|
112
|
+
await plugins.adapt();
|
|
113
|
+
await plugins.teardown();
|
|
114
|
+
|
|
115
|
+
// Verify workspace didn't become dirty during build
|
|
116
|
+
const final_workspace_status = await git_check_clean_workspace();
|
|
117
|
+
if (final_workspace_status !== workspace_status) {
|
|
118
|
+
// Workspace state changed during build - this indicates a problem
|
|
119
|
+
throw new TaskError(
|
|
120
|
+
'Build process modified tracked files or created untracked files.\n\n' +
|
|
121
|
+
'Git status after build:\n' +
|
|
122
|
+
final_workspace_status +
|
|
123
|
+
'\n\n' +
|
|
124
|
+
'Builds should only write to output directories (build/, dist/, etc.).\n' +
|
|
125
|
+
'This usually indicates a plugin or build step is incorrectly modifying source files.',
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Save build cache metadata after successful build (only if workspace is clean)
|
|
130
|
+
if (!workspace_dirty) {
|
|
131
|
+
// Race condition protection: verify git commit didn't change during build
|
|
132
|
+
const current_commit = await git_current_commit_hash();
|
|
133
|
+
|
|
134
|
+
if (current_commit !== initial_commit) {
|
|
135
|
+
log.warn(
|
|
136
|
+
st('yellow', 'git commit changed during build'),
|
|
137
|
+
st(
|
|
138
|
+
'dim',
|
|
139
|
+
`(${format_commit_hash(initial_commit)} → ${format_commit_hash(current_commit)})`,
|
|
140
|
+
),
|
|
141
|
+
'- cache not saved',
|
|
142
|
+
);
|
|
143
|
+
} else {
|
|
144
|
+
// Commit is stable - safe to save cache
|
|
145
|
+
const metadata = await create_build_cache_metadata(config, log, initial_commit, build_dirs);
|
|
146
|
+
await save_build_cache_metadata(metadata, log);
|
|
147
|
+
log.debug('Build cache metadata saved');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
};
|