@ryanatkn/gro 0.179.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 +5 -5
  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 +43 -39
  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 +22 -18
  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
@@ -1,6 +1,7 @@
1
1
  import type {SpawnedProcess} from '@ryanatkn/belt/process.js';
2
- import {cpSync, mkdirSync, rmSync, writeFileSync, existsSync} from 'node:fs';
2
+ import {cp, mkdir, rm, writeFile} from 'node:fs/promises';
3
3
  import {dirname, join} from 'node:path';
4
+ import {fs_exists} from '@ryanatkn/belt/fs.js';
4
5
 
5
6
  import type {Plugin} from './plugin.ts';
6
7
  import {serialize_args, to_forwarded_args} from './args.ts';
@@ -57,7 +58,7 @@ export const gro_plugin_sveltekit_app = ({
57
58
  return {
58
59
  name: 'gro_plugin_sveltekit_app',
59
60
  setup: async ({dev, watch, log, config}) => {
60
- const found_vite_cli = find_cli(vite_cli);
61
+ const found_vite_cli = await find_cli(vite_cli);
61
62
  if (!found_vite_cli)
62
63
  throw Error(
63
64
  `Failed to find Vite CLI \`${vite_cli}\`, do you need to run \`${config.pm_cli} i\`?`,
@@ -66,7 +67,7 @@ export const gro_plugin_sveltekit_app = ({
66
67
  // `vite dev` in development mode
67
68
  if (watch) {
68
69
  const serialized_args = ['dev', ...serialize_args(to_forwarded_args(vite_cli))];
69
- sveltekit_process = spawn_cli_process(found_vite_cli, serialized_args, log);
70
+ sveltekit_process = await spawn_cli_process(found_vite_cli, serialized_args, log);
70
71
  } else {
71
72
  log.debug(
72
73
  `the SvelteKit app plugin is loaded but will not output anything` +
@@ -77,7 +78,7 @@ export const gro_plugin_sveltekit_app = ({
77
78
  // `vite build` in production mode
78
79
 
79
80
  // `.well-known/package.json`
80
- const package_json = load_package_json(); // TODO put in plugin context? same with sveltekit config?
81
+ const package_json = await load_package_json(); // TODO put in plugin context? same with sveltekit config?
81
82
  if (well_known_package_json === undefined) {
82
83
  well_known_package_json = package_json.public; // eslint-disable-line no-param-reassign
83
84
  }
@@ -91,7 +92,7 @@ export const gro_plugin_sveltekit_app = ({
91
92
 
92
93
  // `.well-known/source.json` and `.well-known/src/`
93
94
  const final_package_json = mapped_package_json ?? package_json;
94
- const source_json = source_json_create(final_package_json, undefined, log);
95
+ const source_json = await source_json_create(final_package_json, undefined, log);
95
96
  if (well_known_source_json === undefined) {
96
97
  well_known_source_json = final_package_json.public; // eslint-disable-line no-param-reassign
97
98
  }
@@ -109,7 +110,7 @@ export const gro_plugin_sveltekit_app = ({
109
110
  // copy files to `static` before building, in such a way
110
111
  // that's non-destructive to existing files and dirs and easy to clean up
111
112
  const {assets_path} = default_svelte_config;
112
- const cleanups: Array<Cleanup> = [
113
+ const cleanup_promises = [
113
114
  serialized_package_json
114
115
  ? create_temporarily(
115
116
  join(assets_path, '.well-known/package.json'),
@@ -141,9 +142,11 @@ export const gro_plugin_sveltekit_app = ({
141
142
  host_target === 'github_pages'
142
143
  ? create_temporarily(join(assets_path, '.nojekyll'), '')
143
144
  : null,
144
- ].filter((v) => v != null);
145
- const cleanup = () => {
146
- for (const c of cleanups) c();
145
+ ].filter((v): v is Promise<AsyncCleanup> => v != null);
146
+ const cleanups = await Promise.all(cleanup_promises);
147
+ const cleanup = async () => {
148
+ // eslint-disable-next-line no-await-in-loop
149
+ for (const c of cleanups) await c();
147
150
  };
148
151
  try {
149
152
  const serialized_args = ['build', ...serialize_args(to_forwarded_args(vite_cli))];
@@ -151,11 +154,11 @@ export const gro_plugin_sveltekit_app = ({
151
154
  if (!spawned?.ok) {
152
155
  throw new TaskError(`${vite_cli} build failed with exit code ${spawned?.code}`);
153
156
  }
154
- } catch (err) {
155
- cleanup();
156
- throw err;
157
+ } catch (error) {
158
+ await cleanup();
159
+ throw error;
157
160
  }
158
- cleanup();
161
+ await cleanup();
159
162
  }
160
163
  },
161
164
  teardown: async () => {
@@ -167,41 +170,41 @@ export const gro_plugin_sveltekit_app = ({
167
170
  };
168
171
  };
169
172
 
170
- type Cleanup = () => void;
173
+ type AsyncCleanup = () => Promise<void>;
171
174
 
172
175
  // TODO probably extract these, and create a common helper or merge them
173
176
 
174
- const copy_temporarily = (
177
+ const copy_temporarily = async (
175
178
  source_path: string,
176
179
  dest_dir: string,
177
180
  dest_base_dir = '',
178
181
  filter?: CopyFileFilter,
179
- ): Cleanup => {
182
+ ): Promise<AsyncCleanup> => {
180
183
  const path = join(dest_dir, dest_base_dir, source_path);
181
184
  const dir = dirname(path);
182
185
 
183
- const dir_already_exists = existsSync(dir);
186
+ const dir_already_exists = await fs_exists(dir);
184
187
  let root_created_dir: string | undefined;
185
188
  if (!dir_already_exists) {
186
- root_created_dir = to_root_dir_that_doesnt_exist(dir);
189
+ root_created_dir = await to_root_dir_that_doesnt_exist(dir);
187
190
  if (!root_created_dir) throw Error();
188
- mkdirSync(dir, {recursive: true});
191
+ await mkdir(dir, {recursive: true});
189
192
  }
190
193
 
191
- const path_already_exists = existsSync(path);
194
+ const path_already_exists = await fs_exists(path);
192
195
  if (!path_already_exists) {
193
- cpSync(source_path, path, {recursive: true, filter});
196
+ await cp(source_path, path, {recursive: true, filter});
194
197
  }
195
198
 
196
- return () => {
199
+ return async () => {
197
200
  if (!dir_already_exists) {
198
201
  if (!root_created_dir) throw Error();
199
- if (existsSync(root_created_dir)) {
200
- rmSync(root_created_dir, {recursive: true});
202
+ if (await fs_exists(root_created_dir)) {
203
+ await rm(root_created_dir, {recursive: true});
201
204
  }
202
205
  } else if (!path_already_exists) {
203
- if (existsSync(path)) {
204
- rmSync(path, {recursive: true});
206
+ if (await fs_exists(path)) {
207
+ await rm(path, {recursive: true});
205
208
  }
206
209
  }
207
210
  };
@@ -214,31 +217,31 @@ const copy_temporarily = (
214
217
  * @param contents
215
218
  * @returns cleanup function that deletes the file and any created dirs
216
219
  */
217
- const create_temporarily = (path: string, contents: string): Cleanup => {
220
+ const create_temporarily = async (path: string, contents: string): Promise<AsyncCleanup> => {
218
221
  const dir = dirname(path);
219
222
 
220
- const dir_already_exists = existsSync(dir);
223
+ const dir_already_exists = await fs_exists(dir);
221
224
  let root_created_dir: string | undefined;
222
225
  if (!dir_already_exists) {
223
- root_created_dir = to_root_dir_that_doesnt_exist(dir);
226
+ root_created_dir = await to_root_dir_that_doesnt_exist(dir);
224
227
  if (!root_created_dir) throw Error();
225
- mkdirSync(dir, {recursive: true});
228
+ await mkdir(dir, {recursive: true});
226
229
  }
227
230
 
228
- const path_already_exists = existsSync(path);
231
+ const path_already_exists = await fs_exists(path);
229
232
  if (!path_already_exists) {
230
- writeFileSync(path, contents, 'utf8');
233
+ await writeFile(path, contents, 'utf8');
231
234
  }
232
235
 
233
- return () => {
236
+ return async () => {
234
237
  if (!dir_already_exists) {
235
238
  if (!root_created_dir) throw Error();
236
- if (existsSync(root_created_dir)) {
237
- rmSync(root_created_dir, {recursive: true});
239
+ if (await fs_exists(root_created_dir)) {
240
+ await rm(root_created_dir, {recursive: true});
238
241
  }
239
242
  } else if (!path_already_exists) {
240
- if (existsSync(path)) {
241
- rmSync(path);
243
+ if (await fs_exists(path)) {
244
+ await rm(path);
242
245
  }
243
246
  }
244
247
  };
@@ -249,11 +252,12 @@ const create_temporarily = (path: string, contents: string): Cleanup => {
249
252
  * for `/a/b/DOESNT_EXIST/NOR_THIS/ETC` returns `/a/b/DOESNT_EXIST`
250
253
  * where `/a/b` does exist on the filesystem and `DOESNT_EXIST` is not one of its subdirectories.
251
254
  */
252
- const to_root_dir_that_doesnt_exist = (dir: string): string | undefined => {
255
+ const to_root_dir_that_doesnt_exist = async (dir: string): Promise<string | undefined> => {
253
256
  let prev: string | undefined;
254
257
  let d = dir;
255
258
  do {
256
- if (existsSync(d)) {
259
+ // eslint-disable-next-line no-await-in-loop
260
+ if (await fs_exists(d)) {
257
261
  return prev;
258
262
  }
259
263
  prev = d;
@@ -23,12 +23,11 @@ export const gro_plugin_sveltekit_library = ({
23
23
  svelte_package_options,
24
24
  svelte_package_cli = SVELTE_PACKAGE_CLI,
25
25
  }: GroPluginSveltekitLibraryOptions = {}): Plugin => {
26
- const package_json = load_package_json();
27
-
28
26
  return {
29
27
  name: 'gro_plugin_sveltekit_library',
30
28
  setup: async ({dev, log, config}) => {
31
29
  if (!dev) {
30
+ const package_json = await load_package_json();
32
31
  await run_svelte_package(
33
32
  package_json,
34
33
  svelte_package_options,
@@ -39,6 +38,7 @@ export const gro_plugin_sveltekit_library = ({
39
38
  }
40
39
  },
41
40
  adapt: async ({log, timings, config}) => {
41
+ const package_json = await load_package_json();
42
42
  // link the CLI binaries if they exist
43
43
  if (package_json.bin) {
44
44
  const timing_to_link = timings.start(`${config.pm_cli} link`);
@@ -1,12 +1,12 @@
1
1
  import {dirname, isAbsolute, join, resolve} from 'node:path';
2
- import {existsSync, statSync} from 'node:fs';
2
+ import {stat} from 'node:fs/promises';
3
+ import {fs_exists, fs_search} from '@ryanatkn/belt/fs.js';
3
4
  import {strip_start} from '@ryanatkn/belt/string.js';
4
5
  import {z} from 'zod';
5
6
  import type {Flavored} from '@ryanatkn/belt/types.js';
6
7
  import type {PathInfo, PathId, ResolvedPath} from '@ryanatkn/belt/path.js';
7
8
 
8
9
  import {GRO_PACKAGE_DIR, GRO_DIST_DIR} from './paths.ts';
9
- import {search_fs} from './search_fs.ts';
10
10
  import {TASK_FILE_SUFFIX_JS} from './task.ts';
11
11
 
12
12
  // TODO Flavored doesn't work when used in schemas, use Zod brand instead? problem is ergonomics
@@ -55,11 +55,11 @@ export interface PossiblePath {
55
55
  * Gets a list of possible source ids for each input path with `extensions`,
56
56
  * duplicating each under `root_dirs`, without checking the filesystem.
57
57
  */
58
- export const get_possible_paths = (
58
+ export const get_possible_paths = async (
59
59
  input_path: InputPath,
60
60
  root_dirs: Array<PathId>,
61
61
  extensions: Array<string>,
62
- ): Array<PossiblePath> => {
62
+ ): Promise<Array<PossiblePath>> => {
63
63
  const possible_paths: Set<PossiblePath> = new Set();
64
64
 
65
65
  const add_possible_paths = (path: string, root_dir: PathId) => {
@@ -83,14 +83,9 @@ export const get_possible_paths = (
83
83
  };
84
84
 
85
85
  if (isAbsolute(input_path)) {
86
- // TODO this is hacky because it's the only place we're using sync fs calls (even if they're faster, it's oddly inconsistent),
87
- // we probably should just change this function to check the filesystem and not return non-existing paths
88
- add_possible_paths(
89
- input_path,
90
- existsSync(input_path) && statSync(input_path).isDirectory()
91
- ? input_path
92
- : dirname(input_path),
93
- );
86
+ const exists = await fs_exists(input_path);
87
+ const is_directory = exists && (await stat(input_path)).isDirectory();
88
+ add_possible_paths(input_path, is_directory ? input_path : dirname(input_path));
94
89
  } else {
95
90
  for (const root_dir of root_dirs) {
96
91
  add_possible_paths(join(root_dir, input_path), root_dir);
@@ -123,24 +118,27 @@ export interface ResolvedInputPaths {
123
118
  * and stopping at the first existing file or falling back to the first existing directory.
124
119
  * If none is found for an input path, it's added to `unmapped_input_paths`.
125
120
  */
126
- export const resolve_input_paths = (
121
+ export const resolve_input_paths = async (
127
122
  input_paths: Array<InputPath>,
128
123
  root_dirs: Array<PathId>,
129
124
  extensions: Array<string>,
130
- ): ResolvedInputPaths => {
125
+ ): Promise<ResolvedInputPaths> => {
131
126
  const resolved_input_paths: Array<ResolvedInputPath> = [];
132
127
  const possible_paths_by_input_path: Map<InputPath, Array<PossiblePath>> = new Map();
133
128
  const unmapped_input_paths: Array<InputPath> = [];
134
129
  for (const input_path of input_paths) {
135
130
  let found_file: [PathInfo, PossiblePath] | null = null;
136
131
  let found_dirs: Array<[PathInfo, PossiblePath]> | null = null;
137
- const possible_paths = get_possible_paths(input_path, root_dirs, extensions);
132
+ // eslint-disable-next-line no-await-in-loop
133
+ const possible_paths = await get_possible_paths(input_path, root_dirs, extensions);
138
134
  possible_paths_by_input_path.set(input_path, possible_paths);
139
135
 
140
136
  // Find the first existing file path or fallback to the first directory path.
141
137
  for (const possible_path of possible_paths) {
142
- if (!existsSync(possible_path.id)) continue;
143
- const stats = statSync(possible_path.id);
138
+ // eslint-disable-next-line no-await-in-loop
139
+ if (!(await fs_exists(possible_path.id))) continue;
140
+ // eslint-disable-next-line no-await-in-loop
141
+ const stats = await stat(possible_path.id);
144
142
  if (stats.isDirectory()) {
145
143
  found_dirs ??= [];
146
144
  found_dirs.push([{id: possible_path.id, is_directory: stats.isDirectory()}, possible_path]);
@@ -186,10 +184,10 @@ export interface ResolvedInputFiles {
186
184
  * Finds all of the matching files for the given input paths.
187
185
  * De-dupes source ids.
188
186
  */
189
- export const resolve_input_files = (
187
+ export const resolve_input_files = async (
190
188
  resolved_input_paths: Array<ResolvedInputPath>,
191
- search: (dir: string) => Array<ResolvedPath> = search_fs,
192
- ): ResolvedInputFiles => {
189
+ search: (dir: string) => Promise<Array<ResolvedPath>> = fs_search,
190
+ ): Promise<ResolvedInputFiles> => {
193
191
  const resolved_input_files: Array<ResolvedInputFile> = [];
194
192
  // Add all input paths initially, and remove each when resolved to a file.
195
193
  const existing_path_ids: Set<PathId> = new Set();
@@ -206,7 +204,8 @@ export const resolve_input_files = (
206
204
  const {input_path, id, is_directory} = resolved_input_path;
207
205
  if (is_directory) {
208
206
  // Handle input paths that resolve to directories.
209
- const files = search(id);
207
+ // eslint-disable-next-line no-await-in-loop
208
+ const files = await search(id);
210
209
  if (!files.length) continue;
211
210
  const path_ids: Array<PathId> = [];
212
211
  for (const {path, is_directory} of files) {
@@ -68,7 +68,7 @@ export const invoke_task = async (
68
68
 
69
69
  // Check if the caller just wants to see the version.
70
70
  if (!task_name && (args?.version || args?.v)) {
71
- const gro_package_json = load_gro_package_json();
71
+ const gro_package_json = await load_gro_package_json();
72
72
  log.info(`${st('gray', 'v')}${st('cyan', gro_package_json.version)}`);
73
73
  await finish();
74
74
  return;
@@ -81,7 +81,7 @@ export const invoke_task = async (
81
81
 
82
82
  // Find the task or directory specified by the `input_path`.
83
83
  // Fall back to searching the Gro directory as well.
84
- const found = find_tasks([input_path], task_root_dirs, config);
84
+ const found = await find_tasks([input_path], task_root_dirs, config);
85
85
  if (!found.ok) {
86
86
  log_error_reasons(log, found.reasons);
87
87
  throw new SilentError();
@@ -21,7 +21,7 @@ export const task: Task<Args> = {
21
21
  run: async ({log, args}): Promise<void> => {
22
22
  const {_, eslint_cli} = args;
23
23
 
24
- const found_eslint_cli = find_cli(eslint_cli);
24
+ const found_eslint_cli = await find_cli(eslint_cli);
25
25
  if (!found_eslint_cli) {
26
26
  // TODO maybe make this an option?
27
27
  log.info('ESLint is not installed; skipping linting');
package/src/lib/loader.ts CHANGED
@@ -233,7 +233,7 @@ export const resolve: ResolveHook = async (specifier, context, nextResolve) => {
233
233
  return nextResolve(s, context);
234
234
  }
235
235
 
236
- const resolved = resolve_specifier(s, dirname(fileURLToPath(parent_url)));
236
+ const resolved = await resolve_specifier(s, dirname(fileURLToPath(parent_url)));
237
237
 
238
238
  return {
239
239
  url: pathToFileURL(resolved.path_id_with_querystring).href,
@@ -38,8 +38,8 @@ export const load_module = async <TModule extends Record<string, any>>(
38
38
  import_path = url.href;
39
39
  }
40
40
  mod = await import(import_path);
41
- } catch (err) {
42
- return {ok: false, type: 'failed_import', id, error: err};
41
+ } catch (error) {
42
+ return {ok: false, type: 'failed_import', id, error};
43
43
  }
44
44
  if (validate && !validate(mod)) {
45
45
  return {ok: false, type: 'failed_validation', id, mod, validation: validate.name};
@@ -1,10 +1,11 @@
1
1
  import {z} from 'zod';
2
2
  import {join} from 'node:path';
3
- import {readFileSync, writeFileSync} from 'node:fs';
3
+ import {readFile, writeFile} from 'node:fs/promises';
4
4
  import {plural, strip_end} from '@ryanatkn/belt/string.js';
5
5
  import type {Logger} from '@ryanatkn/belt/log.js';
6
6
  import {styleText as st} from 'node:util';
7
7
  import {PackageJson, PackageJsonExports} from '@ryanatkn/belt/package_json.js';
8
+ import {fs_search} from '@ryanatkn/belt/fs.js';
8
9
 
9
10
  import {paths, gro_paths, IS_THIS_GRO} from './paths.ts';
10
11
  import {
@@ -16,7 +17,6 @@ import {
16
17
  JSON_MATCHER,
17
18
  CSS_MATCHER,
18
19
  } from './constants.ts';
19
- import {search_fs} from './search_fs.ts';
20
20
  import {has_sveltekit_library} from './sveltekit_helpers.ts';
21
21
  import {GITHUB_REPO_MATCHER} from './github.ts';
22
22
 
@@ -26,20 +26,20 @@ export type PackageJsonMapper = (
26
26
 
27
27
  export const EMPTY_PACKAGE_JSON: PackageJson = {name: '', version: ''};
28
28
 
29
- export const load_package_json = (
29
+ export const load_package_json = async (
30
30
  dir = IS_THIS_GRO ? gro_paths.root : paths.root,
31
31
  cache?: Record<string, PackageJson>,
32
32
  parse = true, // TODO pass `false` here in more places, especially anything perf-sensitive like work on startup
33
33
  log?: Logger,
34
- ): PackageJson => {
34
+ ): Promise<PackageJson> => {
35
35
  let package_json: PackageJson;
36
36
  if (cache && dir in cache) {
37
37
  return cache[dir]!;
38
38
  }
39
39
  try {
40
- package_json = JSON.parse(load_package_json_contents(dir));
41
- } catch (err) {
42
- log?.error(st('yellow', `Failed to load package.json in ${dir}`), err);
40
+ package_json = JSON.parse(await load_package_json_contents(dir));
41
+ } catch (error) {
42
+ log?.error(st('yellow', `Failed to load package.json in ${dir}`), error);
43
43
  return EMPTY_PACKAGE_JSON;
44
44
  }
45
45
  if (parse) {
@@ -58,7 +58,7 @@ export const sync_package_json = async (
58
58
  dir = paths.root,
59
59
  exports_dir = paths.lib,
60
60
  ): Promise<{package_json: PackageJson | null; changed: boolean}> => {
61
- const exported_files = search_fs(exports_dir);
61
+ const exported_files = await fs_search(exports_dir);
62
62
  const exported_paths = exported_files.map((f) => f.path);
63
63
  const updated = await update_package_json(
64
64
  async (package_json) => {
@@ -85,15 +85,14 @@ export const sync_package_json = async (
85
85
  return updated;
86
86
  };
87
87
 
88
- export const load_gro_package_json = (): PackageJson => load_package_json(gro_paths.root);
88
+ export const load_gro_package_json = (): Promise<PackageJson> => load_package_json(gro_paths.root);
89
89
 
90
90
  // TODO probably make this nullable and make callers handle failures
91
- const load_package_json_contents = (dir: string): string =>
92
- readFileSync(join(dir, PACKAGE_JSON_FILENAME), 'utf8');
91
+ const load_package_json_contents = (dir: string): Promise<string> =>
92
+ readFile(join(dir, PACKAGE_JSON_FILENAME), 'utf8');
93
93
 
94
- export const write_package_json = (serialized_package_json: string): void => {
95
- writeFileSync(join(paths.root, PACKAGE_JSON_FILENAME), serialized_package_json);
96
- };
94
+ export const write_package_json = (serialized_package_json: string): Promise<void> =>
95
+ writeFile(join(paths.root, PACKAGE_JSON_FILENAME), serialized_package_json);
97
96
 
98
97
  export const serialize_package_json = (package_json: PackageJson): string =>
99
98
  JSON.stringify(parse_package_json(PackageJson, package_json), null, 2) + '\n';
@@ -106,7 +105,7 @@ export const update_package_json = async (
106
105
  dir = paths.root,
107
106
  write = true,
108
107
  ): Promise<{package_json: PackageJson | null; changed: boolean}> => {
109
- const original_contents = load_package_json_contents(dir);
108
+ const original_contents = await load_package_json_contents(dir);
110
109
  const original = JSON.parse(original_contents);
111
110
  const updated = await update(original);
112
111
  if (updated === null) {
@@ -116,7 +115,7 @@ export const update_package_json = async (
116
115
  if (updated_contents === original_contents) {
117
116
  return {package_json: original, changed: false};
118
117
  }
119
- if (write) write_package_json(updated_contents);
118
+ if (write) await write_package_json(updated_contents);
120
119
  return {package_json: updated, changed: true};
121
120
  };
122
121
 
@@ -225,10 +224,7 @@ const parse_or_throw_formatted_error = <T extends z.ZodType>(
225
224
  return parsed.data;
226
225
  };
227
226
 
228
- export const has_dep = (
229
- dep_name: string,
230
- package_json: PackageJson = load_package_json(),
231
- ): boolean =>
227
+ export const has_dep = (dep_name: string, package_json: PackageJson): boolean =>
232
228
  !!package_json.devDependencies?.[dep_name] ||
233
229
  !!package_json.dependencies?.[dep_name] ||
234
230
  !!package_json.peerDependencies?.[dep_name];
@@ -1,7 +1,7 @@
1
1
  import {spawn} from '@ryanatkn/belt/process.js';
2
2
  import {z} from 'zod';
3
3
  import {styleText as st} from 'node:util';
4
- import {existsSync} from 'node:fs';
4
+ import {fs_exists} from '@ryanatkn/belt/fs.js';
5
5
  import {
6
6
  GitBranch,
7
7
  GitOrigin,
@@ -85,7 +85,7 @@ export const task: Task<Args> = {
85
85
  log.info(st('green', 'dry run!'));
86
86
  }
87
87
 
88
- const package_json = load_package_json();
88
+ const package_json = await load_package_json();
89
89
 
90
90
  const has_sveltekit_library_result = await has_sveltekit_library(package_json);
91
91
  if (!has_sveltekit_library_result.ok) {
@@ -94,9 +94,9 @@ export const task: Task<Args> = {
94
94
  );
95
95
  }
96
96
 
97
- const changelog_exists = existsSync(changelog);
97
+ const changelog_exists = await fs_exists(changelog);
98
98
 
99
- const found_changeset_cli = find_cli(changeset_cli);
99
+ const found_changeset_cli = await find_cli(changeset_cli);
100
100
  if (!found_changeset_cli) {
101
101
  throw new TaskError(
102
102
  'changeset command not found, install @changesets/cli locally or globally',
@@ -178,7 +178,7 @@ export const task: Task<Args> = {
178
178
  // The check above ensures gen is updated.
179
179
  await invoke_task('gen');
180
180
 
181
- const package_json_after_versioning = load_package_json();
181
+ const package_json_after_versioning = await load_package_json();
182
182
  version = package_json_after_versioning.version!;
183
183
  if (package_json.version === version) {
184
184
  // The version didn't change.
@@ -217,7 +217,7 @@ export const task: Task<Args> = {
217
217
  );
218
218
  }
219
219
 
220
- if (!changelog_exists && existsSync(changelog)) {
220
+ if (!changelog_exists && (await fs_exists(changelog))) {
221
221
  await spawn('git', ['add', changelog]);
222
222
  }
223
223
  await spawn('git', ['commit', '-a', '-m', `publish v${version}`]);
@@ -13,7 +13,7 @@ export const task: Task<Args> = {
13
13
  summary: 'publish and deploy',
14
14
  Args,
15
15
  run: async ({invoke_task}) => {
16
- const package_json = load_package_json();
16
+ const package_json = await load_package_json();
17
17
 
18
18
  const publish = (await has_sveltekit_library(package_json)).ok;
19
19
  if (publish) {
@@ -15,7 +15,7 @@ export type Args = z.infer<typeof Args>;
15
15
  export const task: Task<Args> = {
16
16
  summary: 'diagnostic that logs resolved filesystem info for the given input paths',
17
17
  Args,
18
- run: ({args, config, log}): void => {
18
+ run: async ({args, config, log}): Promise<void> => {
19
19
  const {_, verbose} = args;
20
20
 
21
21
  if (verbose) log.info('raw input paths:', _);
@@ -27,7 +27,7 @@ export const task: Task<Args> = {
27
27
  if (verbose) log.info('task root paths:', task_root_dirs);
28
28
 
29
29
  const {resolved_input_paths, possible_paths_by_input_path, unmapped_input_paths} =
30
- resolve_input_paths(input_paths, task_root_dirs, TASK_FILE_SUFFIXES);
30
+ await resolve_input_paths(input_paths, task_root_dirs, TASK_FILE_SUFFIXES);
31
31
  if (verbose) log.info('resolved_input_paths:', resolved_input_paths);
32
32
  if (verbose) log.info('possible_paths_by_input_path:', possible_paths_by_input_path);
33
33
  if (verbose) log.info('unmapped_input_paths:', unmapped_input_paths);
@@ -1,5 +1,5 @@
1
1
  import {extname, isAbsolute, join, relative} from 'node:path';
2
- import {existsSync} from 'node:fs';
2
+ import {fs_exists} from '@ryanatkn/belt/fs.js';
3
3
  import type {PathId} from '@ryanatkn/belt/path.js';
4
4
 
5
5
  import {replace_extension} from './paths.ts';
@@ -26,7 +26,10 @@ export interface ResolvedSpecifier {
26
26
  * and infer the correct extension following Vite conventions.
27
27
  * If no `.js` file is found for the specifier on the filesystem, it assumes `.ts`.
28
28
  */
29
- export const resolve_specifier = (specifier: string, dir: string): ResolvedSpecifier => {
29
+ export const resolve_specifier = async (
30
+ specifier: string,
31
+ dir: string,
32
+ ): Promise<ResolvedSpecifier> => {
30
33
  const raw = specifier.endsWith('?raw'); // TODO more robust detection? other values?
31
34
  const final_specifier = raw ? specifier.substring(0, specifier.length - 4) : specifier;
32
35
  const absolute_path = isAbsolute(final_specifier) ? final_specifier : join(dir, final_specifier);
@@ -39,7 +42,7 @@ export const resolve_specifier = (specifier: string, dir: string): ResolvedSpeci
39
42
  const is_js = ext === '.js';
40
43
  const is_ts = ext === '.ts';
41
44
 
42
- if (!is_js && !is_ts && existsSync(absolute_path)) {
45
+ if (!is_js && !is_ts && (await fs_exists(absolute_path))) {
43
46
  // unrecognized extension and the file exists
44
47
  mapped_path = absolute_path;
45
48
  path_id = absolute_path;
@@ -52,7 +55,8 @@ export const resolve_specifier = (specifier: string, dir: string): ResolvedSpeci
52
55
  // extensionless, or js that points to ts, or just js
53
56
  const js_id = is_js ? absolute_path : absolute_path + '.js';
54
57
  const ts_id = is_js ? replace_extension(absolute_path, '.ts') : absolute_path + '.ts';
55
- if (!existsSync(ts_id) && existsSync(js_id)) {
58
+ const [ts_exists, js_exists] = await Promise.all([fs_exists(ts_id), fs_exists(js_id)]);
59
+ if (!ts_exists && js_exists) {
56
60
  mapped_path = js_id;
57
61
  path_id = js_id;
58
62
  namespace = 'sveltekit_local_imports_js';
@@ -1,6 +1,6 @@
1
1
  import {z} from 'zod';
2
2
  import {styleText as st} from 'node:util';
3
- import {existsSync} from 'node:fs';
3
+ import {fs_exists} from '@ryanatkn/belt/fs.js';
4
4
 
5
5
  import {TaskError, type Task} from './task.ts';
6
6
  import {resolve_gro_module_path, spawn_with_loader} from './gro_helpers.ts';
@@ -39,7 +39,7 @@ export const task: Task<Args> = {
39
39
  return;
40
40
  }
41
41
 
42
- if (!existsSync(path)) {
42
+ if (!(await fs_exists(path))) {
43
43
  throw new TaskError('Cannot find file to run at path: ' + path);
44
44
  }
45
45