@ryanatkn/gro 0.179.0 → 0.181.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/build.task.d.ts +2 -0
- package/dist/build.task.d.ts.map +1 -1
- package/dist/build.task.js +15 -11
- package/dist/build_cache.d.ts +4 -4
- package/dist/build_cache.d.ts.map +1 -1
- package/dist/build_cache.js +54 -44
- package/dist/changelog.d.ts +2 -2
- package/dist/changelog.d.ts.map +1 -1
- package/dist/changeset.task.js +11 -11
- package/dist/check.task.js +2 -2
- package/dist/child_process_logging.js +1 -1
- package/dist/clean.task.js +2 -2
- package/dist/clean_fs.d.ts +1 -1
- package/dist/clean_fs.d.ts.map +1 -1
- package/dist/clean_fs.js +3 -4
- package/dist/cli.d.ts +7 -7
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +11 -12
- package/dist/commit.task.js +2 -2
- package/dist/deploy.task.d.ts +7 -0
- package/dist/deploy.task.d.ts.map +1 -1
- package/dist/deploy.task.js +30 -17
- package/dist/disknode.d.ts +1 -1
- package/dist/disknode.d.ts.map +1 -1
- package/dist/esbuild_helpers.d.ts +1 -1
- package/dist/esbuild_helpers.d.ts.map +1 -1
- package/dist/esbuild_plugin_external_worker.d.ts +1 -1
- package/dist/esbuild_plugin_external_worker.d.ts.map +1 -1
- package/dist/esbuild_plugin_external_worker.js +1 -1
- package/dist/esbuild_plugin_svelte.js +4 -4
- package/dist/esbuild_plugin_sveltekit_local_imports.js +2 -2
- package/dist/esbuild_plugin_sveltekit_shim_alias.js +1 -1
- package/dist/filer.d.ts +4 -4
- package/dist/filer.d.ts.map +1 -1
- package/dist/filer.js +105 -54
- package/dist/format.task.js +1 -1
- package/dist/format_directory.d.ts +2 -2
- package/dist/format_directory.d.ts.map +1 -1
- package/dist/format_file.js +1 -1
- package/dist/gen.d.ts +5 -5
- package/dist/gen.d.ts.map +1 -1
- package/dist/gen.js +28 -22
- package/dist/gen.task.js +3 -3
- package/dist/gen_helpers.d.ts +3 -3
- package/dist/gen_helpers.d.ts.map +1 -1
- package/dist/github.d.ts +2 -2
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +1 -1
- package/dist/gro.config.default.js +1 -1
- package/dist/gro_config.d.ts +1 -1
- package/dist/gro_config.d.ts.map +1 -1
- package/dist/gro_config.js +4 -4
- package/dist/gro_helpers.d.ts +1 -1
- package/dist/gro_helpers.d.ts.map +1 -1
- package/dist/gro_helpers.js +1 -1
- package/dist/gro_plugin_gen.js +4 -4
- package/dist/gro_plugin_server.d.ts +2 -2
- package/dist/gro_plugin_server.d.ts.map +1 -1
- package/dist/gro_plugin_server.js +7 -7
- package/dist/gro_plugin_sveltekit_app.d.ts.map +1 -1
- package/dist/gro_plugin_sveltekit_app.js +40 -36
- package/dist/gro_plugin_sveltekit_library.js +3 -2
- package/dist/input_path.d.ts +5 -5
- package/dist/input_path.d.ts.map +1 -1
- package/dist/input_path.js +17 -15
- package/dist/invoke.js +2 -2
- package/dist/invoke_task.d.ts +2 -2
- package/dist/invoke_task.d.ts.map +1 -1
- package/dist/invoke_task.js +5 -5
- package/dist/lint.task.js +2 -2
- package/dist/loader.js +2 -2
- package/dist/modules.d.ts +3 -3
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +4 -4
- package/dist/package_json.d.ts +6 -6
- package/dist/package_json.d.ts.map +1 -1
- package/dist/package_json.js +14 -16
- package/dist/parse_exports.d.ts +4 -4
- package/dist/parse_exports.d.ts.map +1 -1
- package/dist/parse_exports_context.d.ts +1 -1
- package/dist/parse_exports_context.d.ts.map +1 -1
- package/dist/parse_imports.d.ts +2 -2
- package/dist/parse_imports.d.ts.map +1 -1
- package/dist/parse_imports.js +1 -1
- package/dist/paths.d.ts +1 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +1 -1
- package/dist/publish.task.js +8 -8
- package/dist/reinstall.task.js +1 -1
- package/dist/release.task.js +1 -1
- package/dist/resolve.task.js +2 -2
- package/dist/resolve_specifier.d.ts +2 -2
- package/dist/resolve_specifier.d.ts.map +1 -1
- package/dist/resolve_specifier.js +5 -4
- package/dist/run.task.js +2 -2
- package/dist/run_gen.d.ts +2 -2
- package/dist/run_gen.d.ts.map +1 -1
- package/dist/run_gen.js +10 -9
- package/dist/run_task.d.ts +2 -2
- package/dist/run_task.d.ts.map +1 -1
- package/dist/run_task.js +4 -4
- package/dist/source_json.d.ts +5 -5
- package/dist/source_json.d.ts.map +1 -1
- package/dist/source_json.js +18 -17
- package/dist/svelte_config.js +1 -1
- package/dist/sveltekit_helpers.d.ts +3 -3
- package/dist/sveltekit_helpers.d.ts.map +1 -1
- package/dist/sveltekit_helpers.js +4 -4
- package/dist/sveltekit_shim_app_forms.js +1 -1
- package/dist/sveltekit_shim_app_navigation.js +1 -1
- package/dist/sveltekit_shim_app_paths.js +1 -1
- package/dist/sveltekit_shim_env.js +1 -1
- package/dist/sync.task.js +1 -1
- package/dist/task.d.ts +5 -5
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +5 -5
- package/dist/task_logging.d.ts +1 -1
- package/dist/task_logging.d.ts.map +1 -1
- package/dist/task_logging.js +2 -2
- package/dist/test.task.d.ts.map +1 -1
- package/dist/test.task.js +5 -4
- package/dist/typecheck.task.js +4 -4
- package/dist/upgrade.task.js +6 -6
- package/dist/watch_dir.d.ts +1 -1
- package/dist/watch_dir.d.ts.map +1 -1
- package/dist/watch_dir.js +2 -2
- package/package.json +8 -8
- package/src/lib/build.task.ts +16 -11
- package/src/lib/build_cache.ts +81 -65
- package/src/lib/changelog.ts +2 -2
- package/src/lib/changeset.task.ts +12 -12
- package/src/lib/check.task.ts +2 -2
- package/src/lib/child_process_logging.ts +1 -1
- package/src/lib/clean.task.ts +2 -2
- package/src/lib/clean_fs.ts +4 -4
- package/src/lib/cli.ts +18 -17
- package/src/lib/commit.task.ts +2 -2
- package/src/lib/deploy.task.ts +33 -16
- package/src/lib/disknode.ts +1 -1
- package/src/lib/esbuild_helpers.ts +1 -1
- package/src/lib/esbuild_plugin_external_worker.ts +3 -3
- package/src/lib/esbuild_plugin_svelte.ts +4 -4
- package/src/lib/esbuild_plugin_sveltekit_local_imports.ts +2 -2
- package/src/lib/esbuild_plugin_sveltekit_shim_alias.ts +1 -1
- package/src/lib/filer.ts +117 -58
- package/src/lib/format.task.ts +1 -1
- package/src/lib/format_directory.ts +2 -2
- package/src/lib/format_file.ts +1 -1
- package/src/lib/gen.task.ts +3 -3
- package/src/lib/gen.ts +56 -50
- package/src/lib/gen_helpers.ts +3 -3
- package/src/lib/github.ts +2 -2
- package/src/lib/gro.config.default.ts +1 -1
- package/src/lib/gro_config.ts +5 -5
- package/src/lib/gro_helpers.ts +1 -1
- package/src/lib/gro_plugin_gen.ts +4 -4
- package/src/lib/gro_plugin_server.ts +9 -9
- package/src/lib/gro_plugin_sveltekit_app.ts +44 -40
- package/src/lib/gro_plugin_sveltekit_library.ts +3 -3
- package/src/lib/input_path.ts +23 -24
- package/src/lib/invoke.ts +2 -2
- package/src/lib/invoke_task.ts +5 -5
- package/src/lib/lint.task.ts +2 -2
- package/src/lib/loader.ts +2 -2
- package/src/lib/modules.ts +7 -7
- package/src/lib/package_json.ts +19 -23
- package/src/lib/parse_exports.ts +4 -4
- package/src/lib/parse_exports_context.ts +2 -2
- package/src/lib/parse_imports.ts +3 -3
- package/src/lib/paths.ts +2 -2
- package/src/lib/publish.task.ts +8 -8
- package/src/lib/reinstall.task.ts +1 -1
- package/src/lib/release.task.ts +1 -1
- package/src/lib/resolve.task.ts +2 -2
- package/src/lib/resolve_specifier.ts +9 -5
- package/src/lib/run.task.ts +2 -2
- package/src/lib/run_gen.ts +18 -13
- package/src/lib/run_task.ts +6 -6
- package/src/lib/source_json.ts +26 -22
- package/src/lib/svelte_config.ts +1 -1
- package/src/lib/sveltekit_helpers.ts +7 -7
- package/src/lib/sveltekit_shim_app_forms.ts +1 -1
- package/src/lib/sveltekit_shim_app_navigation.ts +1 -1
- package/src/lib/sveltekit_shim_app_paths.ts +1 -1
- package/src/lib/sync.task.ts +1 -1
- package/src/lib/task.ts +16 -14
- package/src/lib/task_logging.ts +3 -3
- package/src/lib/test.task.ts +4 -3
- package/src/lib/typecheck.task.ts +4 -4
- package/src/lib/upgrade.task.ts +6 -6
- package/src/lib/watch_dir.ts +3 -3
- package/dist/search_fs.d.ts +0 -26
- package/dist/search_fs.d.ts.map +0 -1
- package/dist/search_fs.js +0 -52
- package/src/lib/search_fs.ts +0 -100
package/src/lib/deploy.task.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {spawn} from '@
|
|
2
|
-
import {print_error} from '@
|
|
1
|
+
import {spawn} from '@fuzdev/fuz_util/process.js';
|
|
2
|
+
import {print_error} from '@fuzdev/fuz_util/print.js';
|
|
3
3
|
import {styleText as st} from 'node:util';
|
|
4
4
|
import {z} from 'zod';
|
|
5
|
-
import {cp, mkdir, rm} from 'node:fs/promises';
|
|
5
|
+
import {cp, mkdir, readdir, rm} from 'node:fs/promises';
|
|
6
6
|
import {join, resolve} from 'node:path';
|
|
7
|
-
import {
|
|
7
|
+
import {fs_exists, fs_empty_dir} from '@fuzdev/fuz_util/fs.js';
|
|
8
8
|
import {
|
|
9
9
|
git_check_clean_workspace,
|
|
10
10
|
git_checkout,
|
|
@@ -20,8 +20,7 @@ import {
|
|
|
20
20
|
git_check_setting_pull_rebase,
|
|
21
21
|
git_clone_locally,
|
|
22
22
|
git_current_branch_name,
|
|
23
|
-
} from '@
|
|
24
|
-
import {fs_empty_dir} from '@ryanatkn/belt/fs.js';
|
|
23
|
+
} from '@fuzdev/fuz_util/git.js';
|
|
25
24
|
|
|
26
25
|
import {TaskError, type Task} from './task.ts';
|
|
27
26
|
import {print_path} from './paths.ts';
|
|
@@ -72,6 +71,19 @@ export const Args = z.strictObject({
|
|
|
72
71
|
.default(false),
|
|
73
72
|
build: z.boolean().meta({description: 'dual of no-build'}).default(true),
|
|
74
73
|
'no-build': z.boolean().meta({description: 'opt out of building'}).default(false),
|
|
74
|
+
sync: z.boolean().meta({description: 'dual of no-sync'}).default(true),
|
|
75
|
+
'no-sync': z.boolean().meta({description: 'opt out of gro sync in build'}).default(false),
|
|
76
|
+
gen: z.boolean().meta({description: 'dual of no-gen'}).default(true),
|
|
77
|
+
'no-gen': z.boolean().meta({description: 'opt out of gro gen in build'}).default(false),
|
|
78
|
+
install: z.boolean().meta({description: 'dual of no-install'}).default(true),
|
|
79
|
+
'no-install': z
|
|
80
|
+
.boolean()
|
|
81
|
+
.meta({description: 'opt out of installing packages before building'})
|
|
82
|
+
.default(false),
|
|
83
|
+
force_build: z
|
|
84
|
+
.boolean()
|
|
85
|
+
.meta({description: 'force a fresh build, ignoring the cache'})
|
|
86
|
+
.default(false),
|
|
75
87
|
pull: z.boolean().meta({description: 'dual of no-pull'}).default(true),
|
|
76
88
|
'no-pull': z.boolean().meta({description: 'opt out of git pull'}).default(false),
|
|
77
89
|
});
|
|
@@ -93,6 +105,10 @@ export const task: Task<Args> = {
|
|
|
93
105
|
dangerous,
|
|
94
106
|
reset,
|
|
95
107
|
build,
|
|
108
|
+
sync,
|
|
109
|
+
gen,
|
|
110
|
+
install,
|
|
111
|
+
force_build,
|
|
96
112
|
pull,
|
|
97
113
|
} = args;
|
|
98
114
|
|
|
@@ -154,7 +170,7 @@ export const task: Task<Args> = {
|
|
|
154
170
|
// First, check if the deploy dir exists, and if so, attempt to sync it.
|
|
155
171
|
// If anything goes wrong, delete the directory and we'll initialize it
|
|
156
172
|
// using the same code path as if it didn't exist in the first place.
|
|
157
|
-
if (
|
|
173
|
+
if (await fs_exists(resolved_deploy_dir)) {
|
|
158
174
|
if (target !== (await git_current_branch_name(target_spawn_options))) {
|
|
159
175
|
// We're in a bad state because the target branch has changed,
|
|
160
176
|
// so delete the directory and continue as if it wasn't there.
|
|
@@ -175,7 +191,7 @@ export const task: Task<Args> = {
|
|
|
175
191
|
|
|
176
192
|
// Second, initialize the deploy dir if needed.
|
|
177
193
|
// It may not exist, or it may have been deleted after failing to sync above.
|
|
178
|
-
if (!
|
|
194
|
+
if (!(await fs_exists(resolved_deploy_dir))) {
|
|
179
195
|
const local_deploy_branch_exists = await git_local_branch_exists(target);
|
|
180
196
|
await git_fetch(origin, ('+' + target + ':' + target) as GitBranch); // fetch+merge and allow non-fastforward updates with the +
|
|
181
197
|
await git_clone_locally(origin, target, dir, resolved_deploy_dir);
|
|
@@ -193,7 +209,7 @@ export const task: Task<Args> = {
|
|
|
193
209
|
// Remote target branch does not exist, so start from scratch
|
|
194
210
|
|
|
195
211
|
// Delete the deploy dir and recreate it
|
|
196
|
-
if (
|
|
212
|
+
if (await fs_exists(resolved_deploy_dir)) {
|
|
197
213
|
await rm(resolved_deploy_dir, {recursive: true});
|
|
198
214
|
await mkdir(resolved_deploy_dir, {recursive: true});
|
|
199
215
|
}
|
|
@@ -222,14 +238,14 @@ export const task: Task<Args> = {
|
|
|
222
238
|
// Build
|
|
223
239
|
try {
|
|
224
240
|
if (build) {
|
|
225
|
-
await invoke_task('build');
|
|
241
|
+
await invoke_task('build', {sync, gen, install, force_build});
|
|
226
242
|
}
|
|
227
|
-
} catch (
|
|
243
|
+
} catch (error) {
|
|
228
244
|
log.error(
|
|
229
245
|
st('red', 'build failed'),
|
|
230
246
|
'but',
|
|
231
247
|
st('green', 'no changes were made to git'),
|
|
232
|
-
print_error(
|
|
248
|
+
print_error(error),
|
|
233
249
|
);
|
|
234
250
|
if (dry) {
|
|
235
251
|
log.info(st('red', 'dry deploy failed'));
|
|
@@ -238,13 +254,14 @@ export const task: Task<Args> = {
|
|
|
238
254
|
}
|
|
239
255
|
|
|
240
256
|
// Verify build output exists
|
|
241
|
-
if (!
|
|
257
|
+
if (!(await fs_exists(build_dir))) {
|
|
242
258
|
throw new TaskError(`Directory to deploy does not exist after building: ${build_dir}`);
|
|
243
259
|
}
|
|
244
260
|
|
|
245
261
|
// Copy the build
|
|
262
|
+
const build_entries = await readdir(build_dir);
|
|
246
263
|
await Promise.all(
|
|
247
|
-
|
|
264
|
+
build_entries.map((path) =>
|
|
248
265
|
cp(join(build_dir, path), join(resolved_deploy_dir, path), {recursive: true}),
|
|
249
266
|
),
|
|
250
267
|
);
|
|
@@ -260,8 +277,8 @@ export const task: Task<Args> = {
|
|
|
260
277
|
await spawn('git', ['add', '.', '-f'], target_spawn_options);
|
|
261
278
|
await spawn('git', ['commit', '-m', 'deployment'], target_spawn_options);
|
|
262
279
|
await spawn('git', ['push', origin, target, '-f'], target_spawn_options); // force push because we may be resetting the branch, see the checks above to make this safer
|
|
263
|
-
} catch (
|
|
264
|
-
log.error(st('red', 'updating git failed:'), print_error(
|
|
280
|
+
} catch (error) {
|
|
281
|
+
log.error(st('red', 'updating git failed:'), print_error(error));
|
|
265
282
|
throw new TaskError(`Deploy failed in a bad state: built but not pushed, see error above.`);
|
|
266
283
|
}
|
|
267
284
|
|
package/src/lib/disknode.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild';
|
|
2
|
-
import type {Logger} from '@
|
|
2
|
+
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
3
3
|
import {basename} from 'node:path';
|
|
4
4
|
import type {CompileOptions, ModuleCompileOptions, PreprocessorGroup} from 'svelte/compiler';
|
|
5
|
-
import type {PathId} from '@
|
|
5
|
+
import type {PathId} from '@fuzdev/fuz_util/path.js';
|
|
6
6
|
|
|
7
7
|
import {print_build_result, to_define_import_meta_env} from './esbuild_helpers.ts';
|
|
8
8
|
import {resolve_specifier} from './resolve_specifier.ts';
|
|
@@ -84,7 +84,7 @@ export const esbuild_plugin_external_worker = ({
|
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
build.onResolve({filter: /\.worker(|\.js|\.ts)$/}, async ({path, resolveDir}) => {
|
|
87
|
-
const parsed = resolve_specifier(path, resolveDir);
|
|
87
|
+
const parsed = await resolve_specifier(path, resolveDir);
|
|
88
88
|
const {specifier, path_id, namespace} = parsed;
|
|
89
89
|
const build_result = await build_worker(path_id);
|
|
90
90
|
if (log) print_build_result(log, build_result);
|
|
@@ -71,8 +71,8 @@ export const esbuild_plugin_svelte = (options: EsbuildPluginSvelteOptions): esbu
|
|
|
71
71
|
contents,
|
|
72
72
|
warnings: warnings.map((w) => convert_svelte_message_to_esbuild(filename, source, w)),
|
|
73
73
|
};
|
|
74
|
-
} catch (
|
|
75
|
-
return {errors: [convert_svelte_message_to_esbuild(path, source,
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return {errors: [convert_svelte_message_to_esbuild(path, source, error)]};
|
|
76
76
|
}
|
|
77
77
|
});
|
|
78
78
|
|
|
@@ -90,8 +90,8 @@ export const esbuild_plugin_svelte = (options: EsbuildPluginSvelteOptions): esbu
|
|
|
90
90
|
contents,
|
|
91
91
|
warnings: warnings.map((w) => convert_svelte_message_to_esbuild(filename, source, w)),
|
|
92
92
|
};
|
|
93
|
-
} catch (
|
|
94
|
-
return {errors: [convert_svelte_message_to_esbuild(path, source,
|
|
93
|
+
} catch (error) {
|
|
94
|
+
return {errors: [convert_svelte_message_to_esbuild(path, source, error)]};
|
|
95
95
|
}
|
|
96
96
|
});
|
|
97
97
|
},
|
|
@@ -13,10 +13,10 @@ import {EVERYTHING_MATCHER} from './constants.ts';
|
|
|
13
13
|
export const esbuild_plugin_sveltekit_local_imports = (): esbuild.Plugin => ({
|
|
14
14
|
name: 'sveltekit_local_imports',
|
|
15
15
|
setup: (build) => {
|
|
16
|
-
build.onResolve({filter: /^(\/|\.)/}, (args) => {
|
|
16
|
+
build.onResolve({filter: /^(\/|\.)/}, async (args) => {
|
|
17
17
|
const {path, importer} = args;
|
|
18
18
|
if (!importer) return {path};
|
|
19
|
-
const {path_id, namespace} = resolve_specifier(path, dirname(importer));
|
|
19
|
+
const {path_id, namespace} = await resolve_specifier(path, dirname(importer));
|
|
20
20
|
return {path: path_id, namespace}; // `namespace` may be `undefined`, but esbuild needs the absolute path for json etc
|
|
21
21
|
});
|
|
22
22
|
build.onLoad(
|
package/src/lib/filer.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {EMPTY_OBJECT} from '@
|
|
2
|
-
import {
|
|
1
|
+
import {EMPTY_OBJECT} from '@fuzdev/fuz_util/object.js';
|
|
2
|
+
import {readFile, stat} from 'node:fs/promises';
|
|
3
3
|
import {dirname, resolve} from 'node:path';
|
|
4
|
-
import type {OmitStrict} from '@
|
|
4
|
+
import type {OmitStrict} from '@fuzdev/fuz_util/types.js';
|
|
5
5
|
import {isBuiltin} from 'node:module';
|
|
6
6
|
import {fileURLToPath, pathToFileURL} from 'node:url';
|
|
7
|
-
import {UnreachableError} from '@
|
|
8
|
-
import type {Logger} from '@
|
|
9
|
-
import type {PackageJson} from '@
|
|
10
|
-
import type {FileFilter, PathId} from '@
|
|
7
|
+
import {UnreachableError} from '@fuzdev/fuz_util/error.js';
|
|
8
|
+
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
9
|
+
import type {PackageJson} from '@fuzdev/fuz_util/package_json.js';
|
|
10
|
+
import type {FileFilter, PathId} from '@fuzdev/fuz_util/path.js';
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
watch_dir,
|
|
@@ -51,6 +51,9 @@ export class Filer {
|
|
|
51
51
|
#initing: Promise<void> | undefined;
|
|
52
52
|
#closing: Promise<void> | undefined;
|
|
53
53
|
|
|
54
|
+
#change_queue: Array<WatcherChange> = [];
|
|
55
|
+
#processing_promise: Promise<void> | null = null;
|
|
56
|
+
|
|
54
57
|
constructor(options: FilerOptions = EMPTY_OBJECT) {
|
|
55
58
|
this.#watch_dir = options.watch_dir ?? watch_dir;
|
|
56
59
|
this.#watch_dir_options = options.watch_dir_options ?? EMPTY_OBJECT;
|
|
@@ -82,9 +85,11 @@ export class Filer {
|
|
|
82
85
|
dependencies: new Map(),
|
|
83
86
|
};
|
|
84
87
|
this.files.set(id, file);
|
|
85
|
-
//
|
|
88
|
+
// Defer external file change notification to avoid reentrancy during queue processing
|
|
86
89
|
if (file.external) {
|
|
87
|
-
|
|
90
|
+
queueMicrotask(() => {
|
|
91
|
+
this.#on_change({type: 'add', path: file.id, is_directory: false});
|
|
92
|
+
});
|
|
88
93
|
}
|
|
89
94
|
return file;
|
|
90
95
|
};
|
|
@@ -117,10 +122,10 @@ export class Filer {
|
|
|
117
122
|
this.#initing = this.#init();
|
|
118
123
|
try {
|
|
119
124
|
await this.#initing;
|
|
120
|
-
} catch (
|
|
125
|
+
} catch (error) {
|
|
121
126
|
// use shared cleanup logic
|
|
122
127
|
this.#cleanup();
|
|
123
|
-
throw
|
|
128
|
+
throw error;
|
|
124
129
|
} finally {
|
|
125
130
|
this.#initing = undefined;
|
|
126
131
|
}
|
|
@@ -136,6 +141,9 @@ export class Filer {
|
|
|
136
141
|
try {
|
|
137
142
|
await watcher.init();
|
|
138
143
|
|
|
144
|
+
// Wait for any queued changes from init to be processed
|
|
145
|
+
await this.#drain_queue();
|
|
146
|
+
|
|
139
147
|
// check if close() was called during init
|
|
140
148
|
if (this.#closing) {
|
|
141
149
|
await watcher.close();
|
|
@@ -144,14 +152,14 @@ export class Filer {
|
|
|
144
152
|
|
|
145
153
|
// only set after successful init and not closing
|
|
146
154
|
this.#watching = watcher;
|
|
147
|
-
} catch (
|
|
155
|
+
} catch (error) {
|
|
148
156
|
// clean up watcher on error, but don't let close error mask init error
|
|
149
157
|
try {
|
|
150
158
|
await watcher.close();
|
|
151
159
|
} catch {
|
|
152
160
|
// ignore close errors - init error is more important
|
|
153
161
|
}
|
|
154
|
-
throw
|
|
162
|
+
throw error;
|
|
155
163
|
}
|
|
156
164
|
}
|
|
157
165
|
|
|
@@ -169,6 +177,8 @@ export class Filer {
|
|
|
169
177
|
this.#listeners.clear();
|
|
170
178
|
this.files.clear();
|
|
171
179
|
this.#watching = undefined;
|
|
180
|
+
this.#change_queue = [];
|
|
181
|
+
this.#processing_promise = null;
|
|
172
182
|
// #initing is handled in finally block of init()
|
|
173
183
|
}
|
|
174
184
|
|
|
@@ -214,20 +224,22 @@ export class Filer {
|
|
|
214
224
|
this.#cleanup();
|
|
215
225
|
}
|
|
216
226
|
|
|
217
|
-
#update(id: PathId): Disknode | null {
|
|
227
|
+
async #update(id: PathId): Promise<Disknode | null> {
|
|
218
228
|
const file = this.get_or_create(id);
|
|
219
229
|
|
|
220
|
-
let stats: ReturnType<typeof
|
|
230
|
+
let stats: Awaited<ReturnType<typeof stat>> | null = null;
|
|
221
231
|
let new_contents: string | null = null; // TODO need to lazily load contents, probably turn `Disknode` into a class
|
|
222
232
|
|
|
223
233
|
try {
|
|
224
|
-
stats =
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
234
|
+
[stats, new_contents] = await Promise.all([stat(id), readFile(id, 'utf8')]);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
237
|
+
// Treat file as deleted/inaccessible for common error codes
|
|
238
|
+
if (code === 'ENOENT' || code === 'EACCES' || code === 'EPERM') {
|
|
239
|
+
// File doesn't exist or is inaccessible, treat as deleted
|
|
240
|
+
} else {
|
|
241
|
+
throw error;
|
|
229
242
|
}
|
|
230
|
-
// ENOENT: file doesn't exist, treat as deleted
|
|
231
243
|
}
|
|
232
244
|
|
|
233
245
|
const old_mtime = file.mtime;
|
|
@@ -245,7 +257,14 @@ export class Filer {
|
|
|
245
257
|
const dependencies_before = new Set(file.dependencies.keys());
|
|
246
258
|
const dependencies_removed = new Set(dependencies_before);
|
|
247
259
|
|
|
248
|
-
|
|
260
|
+
let imported: Array<string> = [];
|
|
261
|
+
if (file.contents) {
|
|
262
|
+
try {
|
|
263
|
+
imported = parse_imports(file.id, file.contents);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
this.#log?.error('[filer] Failed to parse imports', file.id, error);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
249
268
|
for (const specifier of imported) {
|
|
250
269
|
if (SVELTEKIT_GLOBAL_SPECIFIER.test(specifier)) continue;
|
|
251
270
|
const path = map_sveltekit_aliases(specifier, aliases);
|
|
@@ -253,7 +272,7 @@ export class Filer {
|
|
|
253
272
|
let path_id;
|
|
254
273
|
// TODO can we replace `resolve_specifier` with `import.meta.resolve` completely now outside of esbuild plugins?
|
|
255
274
|
if (path[0] === '.' || path[0] === '/') {
|
|
256
|
-
const resolved = resolve_specifier(path, dir);
|
|
275
|
+
const resolved = await resolve_specifier(path, dir); // eslint-disable-line no-await-in-loop
|
|
257
276
|
path_id = resolved.path_id;
|
|
258
277
|
} else {
|
|
259
278
|
if (isBuiltin(path)) continue;
|
|
@@ -304,8 +323,8 @@ export class Filer {
|
|
|
304
323
|
for (const disknode of this.files.values()) {
|
|
305
324
|
try {
|
|
306
325
|
listener({type: 'add', path: disknode.id, is_directory: false}, disknode);
|
|
307
|
-
} catch (
|
|
308
|
-
this.#log?.error('[filer] Listener error during sync:',
|
|
326
|
+
} catch (error) {
|
|
327
|
+
this.#log?.error('[filer] Listener error during sync:', error);
|
|
309
328
|
}
|
|
310
329
|
}
|
|
311
330
|
}
|
|
@@ -314,8 +333,8 @@ export class Filer {
|
|
|
314
333
|
for (const listener of this.#listeners) {
|
|
315
334
|
try {
|
|
316
335
|
listener(change, disknode);
|
|
317
|
-
} catch (
|
|
318
|
-
this.#log?.error('[filer] Listener error during change notification:',
|
|
336
|
+
} catch (error) {
|
|
337
|
+
this.#log?.error('[filer] Listener error during change notification:', error);
|
|
319
338
|
}
|
|
320
339
|
}
|
|
321
340
|
}
|
|
@@ -335,26 +354,61 @@ export class Filer {
|
|
|
335
354
|
// keep watching active even with no listeners, only close() tears down
|
|
336
355
|
}
|
|
337
356
|
|
|
338
|
-
#
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
357
|
+
async #drain_queue(): Promise<void> {
|
|
358
|
+
// Wait for queue to be empty and no active processing
|
|
359
|
+
while (this.#change_queue.length > 0 || this.#processing_promise) {
|
|
360
|
+
await this.#process_queue(); // eslint-disable-line no-await-in-loop
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async #process_queue(): Promise<void> {
|
|
365
|
+
// If already processing, return the existing promise
|
|
366
|
+
if (this.#processing_promise) return this.#processing_promise;
|
|
367
|
+
|
|
368
|
+
// Create and track the processing promise
|
|
369
|
+
this.#processing_promise = this.#do_process_queue();
|
|
370
|
+
|
|
371
|
+
try {
|
|
372
|
+
await this.#processing_promise;
|
|
373
|
+
} finally {
|
|
374
|
+
this.#processing_promise = null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async #do_process_queue(): Promise<void> {
|
|
379
|
+
while (this.#change_queue.length > 0) {
|
|
380
|
+
const change = this.#change_queue.shift()!;
|
|
381
|
+
|
|
382
|
+
if (this.#closing) continue; // ignore changes during close
|
|
383
|
+
if (change.is_directory) continue; // TODO manage directories?
|
|
384
|
+
|
|
385
|
+
let disknode: Disknode | null;
|
|
386
|
+
switch (change.type) {
|
|
387
|
+
case 'add':
|
|
388
|
+
case 'update': {
|
|
389
|
+
disknode = await this.#update(change.path); // eslint-disable-line no-await-in-loop
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
case 'delete': {
|
|
393
|
+
disknode = this.#remove(change.path);
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
default:
|
|
397
|
+
throw new UnreachableError(change.type);
|
|
347
398
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
399
|
+
|
|
400
|
+
if (disknode && this.#listeners.size > 0) {
|
|
401
|
+
this.#notify_change(change, disknode);
|
|
351
402
|
}
|
|
352
|
-
default:
|
|
353
|
-
throw new UnreachableError(change.type);
|
|
354
|
-
}
|
|
355
|
-
if (disknode && this.#listeners.size > 0) {
|
|
356
|
-
this.#notify_change(change, disknode);
|
|
357
403
|
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
#on_change: WatcherChangeCallback = (change) => {
|
|
407
|
+
// Enqueue the change (sync callback from chokidar)
|
|
408
|
+
this.#change_queue.push(change);
|
|
409
|
+
|
|
410
|
+
// Start processing if not already running
|
|
411
|
+
void this.#process_queue();
|
|
358
412
|
};
|
|
359
413
|
|
|
360
414
|
#is_external(id: PathId): boolean {
|
|
@@ -372,21 +426,26 @@ export const filter_dependents = (
|
|
|
372
426
|
searched: Set<PathId> = new Set(),
|
|
373
427
|
log?: Logger,
|
|
374
428
|
): Set<PathId> => {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
);
|
|
387
|
-
|
|
429
|
+
// Use iterative approach to avoid stack overflow on deep dependency trees
|
|
430
|
+
const stack = [disknode];
|
|
431
|
+
|
|
432
|
+
while (stack.length > 0) {
|
|
433
|
+
const current = stack.pop()!;
|
|
434
|
+
for (const dependent_id of current.dependents.keys()) {
|
|
435
|
+
if (searched.has(dependent_id)) continue;
|
|
436
|
+
searched.add(dependent_id);
|
|
437
|
+
if (!filter || filter(dependent_id)) {
|
|
438
|
+
results.add(dependent_id);
|
|
439
|
+
}
|
|
440
|
+
const dependent_disknode = get_by_id(dependent_id);
|
|
441
|
+
if (!dependent_disknode) {
|
|
442
|
+
log?.warn(
|
|
443
|
+
`[filer.filter_dependents] dependent source file ${dependent_id} not found for ${current.id}`,
|
|
444
|
+
);
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
stack.push(dependent_disknode);
|
|
388
448
|
}
|
|
389
|
-
filter_dependents(dependent_disknode, get_by_id, filter, results, searched);
|
|
390
449
|
}
|
|
391
450
|
return results;
|
|
392
451
|
};
|
package/src/lib/format.task.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {SpawnResult} from '@
|
|
2
|
-
import type {Logger} from '@
|
|
1
|
+
import type {SpawnResult} from '@fuzdev/fuz_util/process.js';
|
|
2
|
+
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
3
3
|
|
|
4
4
|
import {paths} from './paths.ts';
|
|
5
5
|
import {
|
package/src/lib/format_file.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const format_file = async (
|
|
|
19
19
|
const final_base_options =
|
|
20
20
|
base_options !== undefined
|
|
21
21
|
? base_options
|
|
22
|
-
: (cached_base_options = load_package_json().prettier as any);
|
|
22
|
+
: (cached_base_options = (await load_package_json()).prettier as any);
|
|
23
23
|
let final_options = options;
|
|
24
24
|
if (options.filepath && !options.parser) {
|
|
25
25
|
const {filepath, ...rest} = options;
|
package/src/lib/gen.task.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {styleText as st} from 'node:util';
|
|
2
|
-
import {print_ms, print_error} from '@
|
|
3
|
-
import {plural} from '@
|
|
2
|
+
import {print_ms, print_error} from '@fuzdev/fuz_util/print.js';
|
|
3
|
+
import {plural} from '@fuzdev/fuz_util/string.js';
|
|
4
4
|
import {z} from 'zod';
|
|
5
5
|
|
|
6
6
|
import {TaskError, type Task} from './task.ts';
|
|
@@ -43,7 +43,7 @@ export const task: Task<Args> = {
|
|
|
43
43
|
const input_paths = to_input_paths(raw_input_paths);
|
|
44
44
|
|
|
45
45
|
// load all of the gen modules
|
|
46
|
-
const found = find_genfiles(input_paths, root_dirs, config, timings);
|
|
46
|
+
const found = await find_genfiles(input_paths, root_dirs, config, timings);
|
|
47
47
|
if (!found.ok) {
|
|
48
48
|
if (found.type === 'input_directories_with_no_files') {
|
|
49
49
|
// TODO maybe let this error like the normal case, but only call `gro gen` if we find gen files? problem is the args would need to be hoisted to callers like `gro sync`
|