@ryanatkn/gro 0.178.0 → 0.180.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.
Files changed (108) hide show
  1. package/dist/build.task.d.ts +2 -0
  2. package/dist/build.task.d.ts.map +1 -1
  3. package/dist/build.task.js +14 -10
  4. package/dist/build_cache.d.ts +3 -3
  5. package/dist/build_cache.d.ts.map +1 -1
  6. package/dist/build_cache.js +53 -43
  7. package/dist/changeset.task.js +9 -9
  8. package/dist/clean_fs.d.ts +1 -1
  9. package/dist/clean_fs.d.ts.map +1 -1
  10. package/dist/clean_fs.js +3 -4
  11. package/dist/cli.d.ts +4 -4
  12. package/dist/cli.d.ts.map +1 -1
  13. package/dist/cli.js +11 -12
  14. package/dist/deploy.task.d.ts +7 -0
  15. package/dist/deploy.task.d.ts.map +1 -1
  16. package/dist/deploy.task.js +27 -14
  17. package/dist/esbuild_plugin_external_worker.js +1 -1
  18. package/dist/esbuild_plugin_svelte.js +4 -4
  19. package/dist/esbuild_plugin_sveltekit_local_imports.js +2 -2
  20. package/dist/filer.d.ts.map +1 -1
  21. package/dist/filer.js +103 -52
  22. package/dist/format_file.js +1 -1
  23. package/dist/gen.d.ts +1 -1
  24. package/dist/gen.d.ts.map +1 -1
  25. package/dist/gen.js +28 -22
  26. package/dist/gen.task.js +1 -1
  27. package/dist/gro.config.default.js +1 -1
  28. package/dist/gro_config.js +2 -2
  29. package/dist/gro_plugin_gen.js +1 -1
  30. package/dist/gro_plugin_server.js +2 -2
  31. package/dist/gro_plugin_sveltekit_app.d.ts.map +1 -1
  32. package/dist/gro_plugin_sveltekit_app.js +40 -36
  33. package/dist/gro_plugin_sveltekit_library.js +2 -1
  34. package/dist/input_path.d.ts +3 -3
  35. package/dist/input_path.d.ts.map +1 -1
  36. package/dist/input_path.js +16 -14
  37. package/dist/invoke_task.js +2 -2
  38. package/dist/lint.task.js +1 -1
  39. package/dist/loader.js +1 -1
  40. package/dist/modules.js +2 -2
  41. package/dist/package_json.d.ts +4 -4
  42. package/dist/package_json.d.ts.map +1 -1
  43. package/dist/package_json.js +12 -14
  44. package/dist/publish.task.js +6 -6
  45. package/dist/release.task.js +1 -1
  46. package/dist/resolve.task.js +2 -2
  47. package/dist/resolve_specifier.d.ts +1 -1
  48. package/dist/resolve_specifier.d.ts.map +1 -1
  49. package/dist/resolve_specifier.js +5 -4
  50. package/dist/run.task.js +2 -2
  51. package/dist/run_gen.d.ts.map +1 -1
  52. package/dist/run_gen.js +9 -8
  53. package/dist/run_task.js +4 -4
  54. package/dist/source_json.d.ts +2 -2
  55. package/dist/source_json.d.ts.map +1 -1
  56. package/dist/source_json.js +16 -15
  57. package/dist/sveltekit_helpers.js +3 -3
  58. package/dist/sveltekit_shim_env.js +1 -1
  59. package/dist/task.d.ts +1 -1
  60. package/dist/task.d.ts.map +1 -1
  61. package/dist/task.js +4 -4
  62. package/dist/test.task.d.ts.map +1 -1
  63. package/dist/test.task.js +5 -4
  64. package/dist/typecheck.task.js +3 -3
  65. package/dist/upgrade.task.js +4 -4
  66. package/package.json +7 -7
  67. package/src/lib/build.task.ts +15 -10
  68. package/src/lib/build_cache.ts +79 -63
  69. package/src/lib/changeset.task.ts +10 -10
  70. package/src/lib/clean_fs.ts +4 -4
  71. package/src/lib/cli.ts +15 -14
  72. package/src/lib/deploy.task.ts +30 -13
  73. package/src/lib/esbuild_plugin_external_worker.ts +1 -1
  74. package/src/lib/esbuild_plugin_svelte.ts +4 -4
  75. package/src/lib/esbuild_plugin_sveltekit_local_imports.ts +2 -2
  76. package/src/lib/filer.ts +111 -52
  77. package/src/lib/format_file.ts +1 -1
  78. package/src/lib/gen.task.ts +1 -1
  79. package/src/lib/gen.ts +52 -46
  80. package/src/lib/gro.config.default.ts +1 -1
  81. package/src/lib/gro_config.ts +2 -2
  82. package/src/lib/gro_plugin_gen.ts +1 -1
  83. package/src/lib/gro_plugin_server.ts +2 -2
  84. package/src/lib/gro_plugin_sveltekit_app.ts +49 -41
  85. package/src/lib/gro_plugin_sveltekit_library.ts +2 -2
  86. package/src/lib/input_path.ts +20 -21
  87. package/src/lib/invoke_task.ts +2 -2
  88. package/src/lib/lint.task.ts +1 -1
  89. package/src/lib/loader.ts +1 -1
  90. package/src/lib/modules.ts +2 -2
  91. package/src/lib/package_json.ts +16 -20
  92. package/src/lib/publish.task.ts +6 -6
  93. package/src/lib/release.task.ts +1 -1
  94. package/src/lib/resolve.task.ts +2 -2
  95. package/src/lib/resolve_specifier.ts +8 -4
  96. package/src/lib/run.task.ts +2 -2
  97. package/src/lib/run_gen.ts +15 -10
  98. package/src/lib/run_task.ts +4 -4
  99. package/src/lib/source_json.ts +25 -19
  100. package/src/lib/sveltekit_helpers.ts +3 -3
  101. package/src/lib/task.ts +11 -9
  102. package/src/lib/test.task.ts +4 -3
  103. package/src/lib/typecheck.task.ts +3 -3
  104. package/src/lib/upgrade.task.ts +4 -4
  105. package/dist/search_fs.d.ts +0 -26
  106. package/dist/search_fs.d.ts.map +0 -1
  107. package/dist/search_fs.js +0 -52
  108. package/src/lib/search_fs.ts +0 -100
package/src/lib/filer.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import {EMPTY_OBJECT} from '@ryanatkn/belt/object.js';
2
- import {readFileSync, statSync} from 'node:fs';
2
+ import {readFile, stat} from 'node:fs/promises';
3
3
  import {dirname, resolve} from 'node:path';
4
4
  import type {OmitStrict} from '@ryanatkn/belt/types.js';
5
5
  import {isBuiltin} from 'node:module';
@@ -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
- // TODO this may need to be batched/deferred
88
+ // Defer external file change notification to avoid reentrancy during queue processing
86
89
  if (file.external) {
87
- this.#on_change({type: 'add', path: file.id, is_directory: false});
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 (err) {
125
+ } catch (error) {
121
126
  // use shared cleanup logic
122
127
  this.#cleanup();
123
- throw err;
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 (err) {
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 err;
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 statSync> | null = null;
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 = statSync(id);
225
- new_contents = readFileSync(id, 'utf8');
226
- } catch (err) {
227
- if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
228
- throw err;
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
- const imported = file.contents ? parse_imports(file.id, file.contents) : [];
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 (err) {
308
- this.#log?.error('[filer] Listener error during sync:', err);
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 (err) {
318
- this.#log?.error('[filer] Listener error during change notification:', err);
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
- #on_change: WatcherChangeCallback = (change) => {
339
- if (this.#closing) return; // ignore changes during close
340
- if (change.is_directory) return; // TODO manage directories?
341
- let disknode: Disknode | null;
342
- switch (change.type) {
343
- case 'add':
344
- case 'update': {
345
- disknode = this.#update(change.path);
346
- break;
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
- case 'delete': {
349
- disknode = this.#remove(change.path);
350
- break;
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
- const {dependents} = disknode;
376
- for (const dependent_id of dependents.keys()) {
377
- if (searched.has(dependent_id)) continue;
378
- searched.add(dependent_id);
379
- if (!filter || filter(dependent_id)) {
380
- results.add(dependent_id);
381
- }
382
- const dependent_disknode = get_by_id(dependent_id);
383
- if (!dependent_disknode) {
384
- log?.warn(
385
- `[filer.filter_dependents] dependent source file ${dependent_id} not found for ${disknode.id}`,
386
- );
387
- continue;
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
  };
@@ -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;
@@ -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`
package/src/lib/gen.ts CHANGED
@@ -4,8 +4,9 @@ import {mkdir, readFile, writeFile} from 'node:fs/promises';
4
4
  import type {Result} from '@ryanatkn/belt/result.js';
5
5
  import type {Timings} from '@ryanatkn/belt/timings.js';
6
6
  import {styleText as st} from 'node:util';
7
- import {existsSync} from 'node:fs';
8
7
  import type {PathId} from '@ryanatkn/belt/path.js';
8
+ import {map_concurrent} from '@ryanatkn/belt/async.js';
9
+ import {fs_search} from '@ryanatkn/belt/fs.js';
9
10
 
10
11
  import {print_path} from './paths.ts';
11
12
  import type {GroConfig} from './gro_config.ts';
@@ -18,7 +19,6 @@ import {
18
19
  type ResolvedInputFile,
19
20
  type ResolvedInputPath,
20
21
  } from './input_path.ts';
21
- import {search_fs} from './search_fs.ts';
22
22
  import type {Filer} from './filer.ts';
23
23
  import type {InvokeTask} from './task.ts';
24
24
 
@@ -210,23 +210,28 @@ export type AnalyzedGenResult =
210
210
  has_changed: true;
211
211
  };
212
212
 
213
- export const analyze_gen_results = (gen_results: GenResults): Promise<Array<AnalyzedGenResult>> =>
214
- Promise.all(
215
- gen_results.successes
216
- .map((result) => result.files.map((file) => analyze_gen_result(file)))
217
- .flat(),
218
- );
213
+ export const analyze_gen_results = async (
214
+ gen_results: GenResults,
215
+ ): Promise<Array<AnalyzedGenResult>> => {
216
+ const files = gen_results.successes.flatMap((result) => result.files);
217
+ return map_concurrent(files, (file) => analyze_gen_result(file), 10);
218
+ };
219
219
 
220
220
  export const analyze_gen_result = async (file: GenFile): Promise<AnalyzedGenResult> => {
221
- if (!existsSync(file.id)) {
222
- return {
223
- file,
224
- existing_content: null,
225
- is_new: true,
226
- has_changed: true,
227
- };
221
+ let existing_content: string;
222
+ try {
223
+ existing_content = await readFile(file.id, 'utf8');
224
+ } catch (error) {
225
+ if (error.code === 'ENOENT') {
226
+ return {
227
+ file,
228
+ existing_content: null,
229
+ is_new: true,
230
+ has_changed: true,
231
+ };
232
+ }
233
+ throw error;
228
234
  }
229
- const existing_content = await readFile(file.id, 'utf8');
230
235
  return {
231
236
  file,
232
237
  existing_content,
@@ -240,26 +245,25 @@ export const write_gen_results = async (
240
245
  analyzed_gen_results: Array<AnalyzedGenResult>,
241
246
  log: Logger,
242
247
  ): Promise<void> => {
243
- await Promise.all(
244
- gen_results.successes
245
- .map((result) =>
246
- result.files.map(async (file) => {
247
- const analyzed = analyzed_gen_results.find((r) => r.file.id === file.id);
248
- if (!analyzed) throw Error('Expected to find analyzed result: ' + file.id);
249
- const log_args = [print_path(file.id), 'generated from', print_path(file.origin_id)];
250
- if (analyzed.is_new) {
251
- log.info('writing new', ...log_args);
252
- await mkdir(dirname(file.id), {recursive: true});
253
- await writeFile(file.id, file.content);
254
- } else if (analyzed.has_changed) {
255
- log.info('writing changed', ...log_args);
256
- await writeFile(file.id, file.content);
257
- } else {
258
- log.info('skipping unchanged', ...log_args);
259
- }
260
- }),
261
- )
262
- .flat(),
248
+ const files = gen_results.successes.flatMap((result) => result.files);
249
+ await map_concurrent(
250
+ files,
251
+ async (file) => {
252
+ const analyzed = analyzed_gen_results.find((r) => r.file.id === file.id);
253
+ if (!analyzed) throw Error('Expected to find analyzed result: ' + file.id);
254
+ const log_args = [print_path(file.id), 'generated from', print_path(file.origin_id)];
255
+ if (analyzed.is_new) {
256
+ log.info('writing new', ...log_args);
257
+ await mkdir(dirname(file.id), {recursive: true});
258
+ await writeFile(file.id, file.content);
259
+ } else if (analyzed.has_changed) {
260
+ log.info('writing changed', ...log_args);
261
+ await writeFile(file.id, file.content);
262
+ } else {
263
+ log.info('skipping unchanged', ...log_args);
264
+ }
265
+ },
266
+ 10,
263
267
  );
264
268
  };
265
269
 
@@ -289,17 +293,17 @@ export type FindGenfilesFailure =
289
293
  /**
290
294
  * Finds modules from input paths. (see `src/lib/input_path.ts` for more)
291
295
  */
292
- export const find_genfiles = (
296
+ export const find_genfiles = async (
293
297
  input_paths: Array<InputPath>,
294
298
  root_dirs: Array<PathId>,
295
299
  config: GroConfig,
296
300
  timings?: Timings,
297
- ): FindGenfilesResult => {
301
+ ): Promise<FindGenfilesResult> => {
298
302
  const extensions: Array<string> = [GEN_FILE_PATTERN];
299
303
 
300
304
  // Check which extension variation works - if it's a directory, prefer others first!
301
305
  const timing_to_resolve_input_paths = timings?.start('resolve input paths');
302
- const {resolved_input_paths, unmapped_input_paths} = resolve_input_paths(
306
+ const {resolved_input_paths, unmapped_input_paths} = await resolve_input_paths(
303
307
  input_paths,
304
308
  root_dirs,
305
309
  extensions,
@@ -320,15 +324,17 @@ export const find_genfiles = (
320
324
  }
321
325
 
322
326
  // Find all of the files for any directories.
323
- const timing_to_search_fs = timings?.start('find files');
327
+ const timing_to_fs_search = timings?.start('find files');
324
328
  const {resolved_input_files, resolved_input_files_by_root_dir, input_directories_with_no_files} =
325
- resolve_input_files(resolved_input_paths, (id) =>
326
- search_fs(id, {
327
- filter: config.search_filters,
328
- file_filter: (p) => extensions.some((e) => p.includes(e)),
329
- }),
329
+ await resolve_input_files(
330
+ resolved_input_paths,
331
+ async (id) =>
332
+ await fs_search(id, {
333
+ filter: config.search_filters,
334
+ file_filter: (p) => extensions.some((e) => p.includes(e)),
335
+ }),
330
336
  );
331
- timing_to_search_fs?.();
337
+ timing_to_fs_search?.();
332
338
 
333
339
  // Error if any input path has no files. (means we have an empty directory)
334
340
  if (input_directories_with_no_files.length) {
@@ -18,7 +18,7 @@ import {load_package_json} from './package_json.ts';
18
18
  * - if `src/lib/server/server.ts`, assumes a Node server - needs config
19
19
  */
20
20
  const config: CreateGroConfig = async (cfg, svelte_config) => {
21
- const package_json = load_package_json(); // TODO gets wastefully loaded by some plugins, maybe put in plugin/task context? how does that interact with `map_package_json`?
21
+ const package_json = await load_package_json(); // TODO gets wastefully loaded by some plugins, maybe put in plugin/task context? how does that interact with `map_package_json`?
22
22
 
23
23
  const [has_server_result, has_sveltekit_library_result, has_sveltekit_app_result] =
24
24
  await Promise.all([
@@ -1,5 +1,5 @@
1
1
  import {join, resolve} from 'node:path';
2
- import {existsSync} from 'node:fs';
2
+ import {fs_exists} from '@ryanatkn/belt/fs.js';
3
3
  import {identity} from '@ryanatkn/belt/function.js';
4
4
  import type {PathFilter, PathId} from '@ryanatkn/belt/path.js';
5
5
  import {json_stringify_deterministic} from '@ryanatkn/belt/json.js';
@@ -208,7 +208,7 @@ export const load_gro_config = async (dir = paths.root): Promise<GroConfig> => {
208
208
  );
209
209
 
210
210
  const config_path = join(dir, GRO_CONFIG_FILENAME);
211
- if (!existsSync(config_path)) {
211
+ if (!(await fs_exists(config_path))) {
212
212
  // No user config file found, so return the default.
213
213
  return default_config;
214
214
  }
@@ -48,7 +48,7 @@ export const gro_plugin_gen = ({
48
48
  // Some parts of the build may have already happened,
49
49
  // making us miss `build` events for gen dependencies,
50
50
  // so we run a full `gen` here even if it's usually wasteful.
51
- const found = find_genfiles(input_paths, root_dirs, config);
51
+ const found = await find_genfiles(input_paths, root_dirs, config);
52
52
  if (found.ok && found.value.resolved_input_files.length > 0) {
53
53
  await gen();
54
54
  }
@@ -217,8 +217,8 @@ export const gro_plugin_server = ({
217
217
  let build_result;
218
218
  try {
219
219
  build_result = await build_ctx!.rebuild();
220
- } catch (err) {
221
- log.error('[gro_plugin_server] build failed', err);
220
+ } catch (error) {
221
+ log.error('[gro_plugin_server] build failed', error);
222
222
  return;
223
223
  }
224
224
  const {metafile} = build_result;