@ryanatkn/gro 0.117.0 → 0.119.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 (94) hide show
  1. package/README.md +37 -19
  2. package/dist/build.task.d.ts +3 -0
  3. package/dist/build.task.js +5 -1
  4. package/dist/changeset.task.d.ts +2 -2
  5. package/dist/changeset.task.js +10 -6
  6. package/dist/check.task.js +1 -1
  7. package/dist/clean_fs.js +2 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/config.js +3 -2
  10. package/dist/deploy.task.d.ts +0 -6
  11. package/dist/deploy.task.js +7 -11
  12. package/dist/dev.task.d.ts +2 -2
  13. package/dist/docs/gen.md +27 -0
  14. package/dist/docs/publish.md +1 -8
  15. package/dist/docs/task.md +7 -0
  16. package/dist/docs/tasks.gen.md.js +2 -3
  17. package/dist/docs/tasks.md +1 -0
  18. package/dist/esbuild_plugin_external_worker.js +1 -2
  19. package/dist/esbuild_plugin_svelte.js +1 -2
  20. package/dist/esbuild_plugin_sveltekit_shim_alias.js +1 -2
  21. package/dist/format_directory.d.ts +8 -2
  22. package/dist/format_directory.js +18 -12
  23. package/dist/gen.d.ts +19 -0
  24. package/dist/gen.js +45 -0
  25. package/dist/gen.task.js +19 -19
  26. package/dist/gen_module.d.ts +1 -14
  27. package/dist/gen_module.js +0 -22
  28. package/dist/git.d.ts +5 -0
  29. package/dist/git.js +15 -0
  30. package/dist/git.test.js +4 -1
  31. package/dist/gro.config.default.js +8 -11
  32. package/dist/gro_helpers.js +18 -17
  33. package/dist/gro_plugin_gen.js +1 -1
  34. package/dist/gro_plugin_server.d.ts +4 -1
  35. package/dist/gro_plugin_server.js +15 -6
  36. package/dist/gro_plugin_sveltekit_app.d.ts +0 -1
  37. package/dist/gro_plugin_sveltekit_app.js +2 -4
  38. package/dist/gro_plugin_sveltekit_library.d.ts +0 -2
  39. package/dist/gro_plugin_sveltekit_library.js +10 -11
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.js +0 -1
  42. package/dist/input_path.d.ts +1 -1
  43. package/dist/input_path.js +1 -1
  44. package/dist/input_path.test.js +3 -3
  45. package/dist/invoke.js +2 -0
  46. package/dist/invoke_task.d.ts +1 -1
  47. package/dist/invoke_task.js +10 -11
  48. package/dist/lint.task.js +1 -1
  49. package/dist/loader.js +11 -4
  50. package/dist/module.d.ts +1 -1
  51. package/dist/module.js +2 -2
  52. package/dist/modules.test.js +2 -2
  53. package/dist/package.d.ts +52 -0
  54. package/dist/package.js +80 -36
  55. package/dist/package_json.d.ts +5 -0
  56. package/dist/package_json.js +8 -3
  57. package/dist/package_meta.d.ts +1 -2
  58. package/dist/path_constants.d.ts +21 -0
  59. package/dist/path_constants.js +28 -0
  60. package/dist/paths.d.ts +2 -26
  61. package/dist/paths.js +10 -33
  62. package/dist/publish.task.d.ts +9 -6
  63. package/dist/publish.task.js +26 -14
  64. package/dist/register.d.ts +1 -0
  65. package/dist/register.js +2 -0
  66. package/dist/reinstall.task.d.ts +5 -0
  67. package/dist/reinstall.task.js +32 -0
  68. package/dist/release.task.js +5 -7
  69. package/dist/resolve_node_specifier.js +2 -1
  70. package/dist/run.task.js +1 -1
  71. package/dist/run_gen.d.ts +2 -1
  72. package/dist/run_gen.js +2 -2
  73. package/dist/run_gen.test.js +3 -2
  74. package/dist/run_task.js +1 -1
  75. package/dist/sveltekit_config.d.ts +1 -1
  76. package/dist/sveltekit_config.js +9 -5
  77. package/dist/sveltekit_config_global.d.ts +4 -0
  78. package/dist/sveltekit_config_global.js +5 -0
  79. package/dist/sveltekit_helpers.d.ts +17 -0
  80. package/dist/sveltekit_helpers.js +54 -0
  81. package/dist/sync.task.d.ts +0 -1
  82. package/dist/sync.task.js +5 -11
  83. package/dist/task.d.ts +1 -1
  84. package/dist/task.js +11 -7
  85. package/dist/task.test.js +9 -13
  86. package/dist/task_logging.d.ts +2 -2
  87. package/dist/task_logging.js +29 -15
  88. package/dist/task_module.d.ts +3 -3
  89. package/dist/task_module.js +6 -6
  90. package/dist/task_module.test.js +4 -7
  91. package/dist/typecheck.task.js +1 -1
  92. package/dist/upgrade.task.d.ts +4 -1
  93. package/dist/upgrade.task.js +30 -5
  94. package/package.json +23 -3
package/dist/gen.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { join, basename, dirname, isAbsolute } from 'node:path';
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
3
  import { z } from 'zod';
3
4
  import { gen_module_meta, to_gen_module_type } from './gen_module.js';
5
+ import { print_path } from './paths.js';
6
+ import { exists } from './fs.js';
4
7
  export const Gen_Config = z.object({
5
8
  imports: z.record(z.string(), z.string()).default({}),
6
9
  });
@@ -79,3 +82,45 @@ const validate_gen_files = (files) => {
79
82
  ids.add(file.id);
80
83
  }
81
84
  };
85
+ export const analyze_gen_results = (gen_results) => Promise.all(gen_results.successes
86
+ .map((result) => result.files.map((file) => analyze_gen_result(file)))
87
+ .flat());
88
+ export const analyze_gen_result = async (file) => {
89
+ if (!(await exists(file.id))) {
90
+ return {
91
+ file,
92
+ existing_content: null,
93
+ is_new: true,
94
+ has_changed: true,
95
+ };
96
+ }
97
+ const existing_content = await readFile(file.id, 'utf8');
98
+ return {
99
+ file,
100
+ existing_content,
101
+ is_new: false,
102
+ has_changed: file.content !== existing_content,
103
+ };
104
+ };
105
+ export const write_gen_results = async (gen_results, analyzed_gen_results, log) => {
106
+ await Promise.all(gen_results.successes
107
+ .map((result) => result.files.map(async (file) => {
108
+ const analyzed = analyzed_gen_results.find((r) => r.file.id === file.id);
109
+ if (!analyzed)
110
+ throw Error('Expected to find analyzed result: ' + file.id);
111
+ const log_args = [print_path(file.id), 'generated from', print_path(file.origin_id)];
112
+ if (analyzed.is_new) {
113
+ log.info('writing new', ...log_args);
114
+ await mkdir(dirname(file.id), { recursive: true });
115
+ await writeFile(file.id, file.content);
116
+ }
117
+ else if (analyzed.has_changed) {
118
+ log.info('writing changed', ...log_args);
119
+ await writeFile(file.id, file.content);
120
+ }
121
+ else {
122
+ log.info('skipping unchanged', ...log_args);
123
+ }
124
+ }))
125
+ .flat());
126
+ };
package/dist/gen.task.js CHANGED
@@ -2,16 +2,15 @@ import { red, green, gray } from 'kleur/colors';
2
2
  import { print_ms, print_error } from '@ryanatkn/belt/print.js';
3
3
  import { plural } from '@ryanatkn/belt/string.js';
4
4
  import { z } from 'zod';
5
- import { dirname } from 'node:path';
6
- import { mkdir, writeFile } from 'node:fs/promises';
7
5
  import { Task_Error } from './task.js';
8
6
  import { run_gen } from './run_gen.js';
9
- import { load_gen_module, check_gen_modules, find_gen_modules } from './gen_module.js';
7
+ import { load_gen_module, find_gen_modules } from './gen_module.js';
10
8
  import { Raw_Input_Path, to_input_paths } from './input_path.js';
11
9
  import { load_modules } from './modules.js';
12
10
  import { format_file } from './format_file.js';
13
11
  import { paths, print_path } from './paths.js';
14
12
  import { log_error_reasons } from './task_logging.js';
13
+ import { write_gen_results, analyze_gen_results } from './gen.js';
15
14
  export const Args = z
16
15
  .object({
17
16
  _: z.array(Raw_Input_Path, { description: 'paths to generate' }).default([]),
@@ -25,7 +24,7 @@ export const Args = z
25
24
  export const task = {
26
25
  summary: 'run code generation scripts',
27
26
  Args,
28
- run: async ({ args, log, timings }) => {
27
+ run: async ({ args, log, timings, config }) => {
29
28
  const { _: raw_input_paths, check } = args;
30
29
  const input_paths = raw_input_paths.length ? to_input_paths(raw_input_paths) : [paths.source];
31
30
  // load all of the gen modules
@@ -48,23 +47,23 @@ export const task = {
48
47
  }
49
48
  // run `gen` on each of the modules
50
49
  const timing_to_generate_code = timings.start('generate code'); // TODO this ignores `gen_results.elapsed` - should it return `Timings` instead?
51
- const gen_results = await run_gen(load_modules_result.modules, log, timings, format_file);
50
+ const gen_results = await run_gen(load_modules_result.modules, config, log, timings, format_file);
52
51
  timing_to_generate_code();
53
52
  const fail_count = gen_results.failures.length;
53
+ const analyzed_gen_results = await analyze_gen_results(gen_results);
54
54
  if (check) {
55
55
  // check if any files changed, and if so, throw errors,
56
56
  // but if there are gen failures, skip the check and defer to their errors
57
57
  if (!fail_count) {
58
58
  log.info('checking generated files for changes');
59
59
  const timing_to_check_results = timings.start('check results for changes');
60
- const check_gen_modules_results = await check_gen_modules(gen_results);
61
60
  timing_to_check_results();
62
61
  let has_unexpected_changes = false;
63
- for (const result of check_gen_modules_results) {
64
- if (!result.has_changed)
62
+ for (const analyzed of analyzed_gen_results) {
63
+ if (!analyzed.has_changed)
65
64
  continue;
66
65
  has_unexpected_changes = true;
67
- log.error(red(`Generated file ${print_path(result.file.id)} via ${print_path(result.file.origin_id)} ${result.is_new ? 'is new' : 'has changed'}.`));
66
+ log.error(red(`Generated file ${print_path(analyzed.file.id)} via ${print_path(analyzed.file.origin_id)} ${analyzed.is_new ? 'is new' : 'has changed'}.`));
68
67
  }
69
68
  if (has_unexpected_changes) {
70
69
  throw new Task_Error('Failed gen check. Some generated files have unexpectedly changed.' +
@@ -77,20 +76,21 @@ export const task = {
77
76
  // write generated files to disk
78
77
  log.info('writing generated files to disk');
79
78
  const timing_to_output_results = timings.start('output results');
80
- await Promise.all(gen_results.successes
81
- .map((result) => result.files.map(async (file) => {
82
- log.info('writing', print_path(file.id), 'generated from', print_path(file.origin_id));
83
- await mkdir(dirname(file.id), { recursive: true });
84
- await writeFile(file.id, file.content);
85
- }))
86
- .flat());
79
+ await write_gen_results(gen_results, analyzed_gen_results, log);
87
80
  timing_to_output_results();
88
81
  }
89
- let logResult = '';
82
+ // TODO these final printed results could be improved showing a breakdown per file id
83
+ const new_count = analyzed_gen_results.filter((r) => r.is_new).length;
84
+ const changed_count = analyzed_gen_results.filter((r) => r.has_changed).length;
85
+ const skipped_count = analyzed_gen_results.filter((r) => !r.is_new && !r.has_changed).length;
86
+ let log_result = green('gen results:');
87
+ log_result += `\n\t${new_count} ` + gray('new');
88
+ log_result += `\n\t${changed_count} ` + gray('changed');
89
+ log_result += `\n\t${skipped_count} ` + gray('skipped');
90
90
  for (const result of gen_results.results) {
91
- logResult += `\n\t${result.ok ? green('✓') : red('🞩')} ${result.ok ? result.files.length : 0} ${gray('in')} ${print_ms(result.elapsed)} ${gray('←')} ${print_path(result.id)}`;
91
+ log_result += `\n\t${result.ok ? green('✓') : red('🞩')} ${result.ok ? result.files.length : 0} ${gray('in')} ${print_ms(result.elapsed)} ${gray('←')} ${print_path(result.id)}`;
92
92
  }
93
- log.info(logResult);
93
+ log.info(log_result);
94
94
  log.info(green(`generated ${gen_results.output_count} file${plural(gen_results.output_count)} from ${gen_results.successes.length} input file${plural(gen_results.successes.length)}`));
95
95
  if (fail_count) {
96
96
  for (const result of gen_results.failures) {
@@ -1,5 +1,5 @@
1
1
  import { type Module_Meta, type Load_Module_Result, type Find_Modules_Result } from './modules.js';
2
- import type { Gen, Gen_Results, Gen_File } from './gen.js';
2
+ import type { Gen } from './gen.js';
3
3
  import { Input_Path } from './input_path.js';
4
4
  export declare const GEN_FILE_PATTERN_TEXT = "gen";
5
5
  export declare const GEN_FILE_PATTERN: string;
@@ -31,17 +31,4 @@ export interface Basic_Gen_Module_Meta extends Module_Meta<Gen_Module> {
31
31
  mod: Basic_Gen_Module;
32
32
  }
33
33
  export declare const load_gen_module: (id: string) => Promise<Load_Module_Result<Gen_Module_Meta>>;
34
- export type Check_Gen_Module_Result = {
35
- file: Gen_File;
36
- existing_content: string;
37
- is_new: false;
38
- has_changed: boolean;
39
- } | {
40
- file: Gen_File;
41
- existing_content: null;
42
- is_new: true;
43
- has_changed: true;
44
- };
45
- export declare const check_gen_modules: (gen_results: Gen_Results) => Promise<Check_Gen_Module_Result[]>;
46
- export declare const check_gen_module: (file: Gen_File) => Promise<Check_Gen_Module_Result>;
47
34
  export declare const find_gen_modules: (input_paths?: Input_Path[], extensions?: string[], root_dirs?: string[]) => Promise<Find_Modules_Result>;
@@ -1,9 +1,7 @@
1
- import { readFile } from 'node:fs/promises';
2
1
  import { load_module, find_modules, } from './modules.js';
3
2
  import { Input_Path, get_possible_source_ids } from './input_path.js';
4
3
  import { paths } from './paths.js';
5
4
  import { search_fs } from './search_fs.js';
6
- import { exists } from './fs.js';
7
5
  export const GEN_FILE_PATTERN_TEXT = 'gen';
8
6
  export const GEN_FILE_PATTERN = '.' + GEN_FILE_PATTERN_TEXT + '.';
9
7
  export const is_gen_path = (path) => path.includes(GEN_FILE_PATTERN);
@@ -28,26 +26,6 @@ export const load_gen_module = async (id) => {
28
26
  }
29
27
  return result;
30
28
  };
31
- export const check_gen_modules = (gen_results) => Promise.all(gen_results.successes
32
- .map((result) => result.files.map((file) => check_gen_module(file)))
33
- .flat());
34
- export const check_gen_module = async (file) => {
35
- if (!(await exists(file.id))) {
36
- return {
37
- file,
38
- existing_content: null,
39
- is_new: true,
40
- has_changed: true,
41
- };
42
- }
43
- const existing_content = await readFile(file.id, 'utf8');
44
- return {
45
- file,
46
- existing_content,
47
- is_new: false,
48
- has_changed: file.content !== existing_content,
49
- };
50
- };
51
29
  export const find_gen_modules = (input_paths = [paths.source],
52
30
  // TODO improve this API to allow config, maybe just a simple `gen` filter function, so the user could return a Rollup pluginutils filter,
53
31
  // gets a little tricky with the `get_possible_source_ids` API usage, which would probably need to change
package/dist/git.d.ts CHANGED
@@ -22,6 +22,11 @@ export declare const git_local_branch_exists: (branch: Git_Branch, options?: Spa
22
22
  * @returns an error message if the git workspace has any unstaged or uncommitted changes, or `null` if it's clean
23
23
  */
24
24
  export declare const git_check_clean_workspace: (options?: SpawnOptions) => Promise<string | null>;
25
+ /**
26
+ * TODO make this return an enum and separate the text into a different function
27
+ * @returns an error message if the git workspace has any unstaged stages, or `null` if it's clean
28
+ */
29
+ export declare const git_check_fully_staged_workspace: (options?: SpawnOptions) => Promise<string | null>;
25
30
  /**
26
31
  * Calls `git fetch` and throws if anything goes wrong.
27
32
  */
package/dist/git.js CHANGED
@@ -63,6 +63,21 @@ export const git_check_clean_workspace = async (options) => {
63
63
  }
64
64
  return null;
65
65
  };
66
+ /**
67
+ * TODO make this return an enum and separate the text into a different function
68
+ * @returns an error message if the git workspace has any unstaged stages, or `null` if it's clean
69
+ */
70
+ export const git_check_fully_staged_workspace = async (options) => {
71
+ const unstaged_result = await spawn('git', ['diff', '--exit-code', '--quiet'], options);
72
+ if (!unstaged_result.ok) {
73
+ return 'git has unstaged changes';
74
+ }
75
+ const status_result = await spawn_out('git', ['status', '--porcelain'], options);
76
+ if (status_result.stdout?.includes('??')) {
77
+ return 'git has untracked files';
78
+ }
79
+ return null;
80
+ };
66
81
  /**
67
82
  * Calls `git fetch` and throws if anything goes wrong.
68
83
  */
package/dist/git.test.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { test } from 'uvu';
2
2
  import * as assert from 'uvu/assert';
3
- import { git_check_clean_workspace, git_current_branch_first_commit_hash, git_current_branch_name, git_current_commit_hash, } from './git.js';
3
+ import { git_check_clean_workspace, git_check_fully_staged_workspace, git_current_branch_first_commit_hash, git_current_branch_name, git_current_commit_hash, } from './git.js';
4
4
  test('git_current_branch_name', async () => {
5
5
  const branch_name = await git_current_branch_name();
6
6
  assert.ok(branch_name);
@@ -8,6 +8,9 @@ test('git_current_branch_name', async () => {
8
8
  test('git_check_clean_workspace', async () => {
9
9
  await git_check_clean_workspace();
10
10
  });
11
+ test('git_check_fully_staged_workspace', async () => {
12
+ await git_check_fully_staged_workspace();
13
+ });
11
14
  test('git_current_commit_hash', async () => {
12
15
  await git_current_commit_hash();
13
16
  });
@@ -1,6 +1,7 @@
1
- import { has_sveltekit_library, gro_plugin_sveltekit_library, } from './gro_plugin_sveltekit_library.js';
1
+ import { gro_plugin_sveltekit_library } from './gro_plugin_sveltekit_library.js';
2
2
  import { has_server, gro_plugin_server } from './gro_plugin_server.js';
3
- import { has_sveltekit_app, gro_plugin_sveltekit_app } from './gro_plugin_sveltekit_app.js';
3
+ import { gro_plugin_sveltekit_app } from './gro_plugin_sveltekit_app.js';
4
+ import { has_sveltekit_app, has_sveltekit_library } from './sveltekit_helpers.js';
4
5
  /**
5
6
  * This is the default config that's passed to `gro.config.ts`
6
7
  * if it exists in the current project, and if not, this is the final config.
@@ -11,16 +12,12 @@ import { has_sveltekit_app, gro_plugin_sveltekit_app } from './gro_plugin_svelte
11
12
  * - if `src/lib/server/server.ts`, assumes a Node server
12
13
  */
13
14
  const config = async (cfg) => {
14
- const [enable_sveltekit_library, enable_server, enable_sveltekit_app] = await Promise.all([
15
- has_sveltekit_library(),
16
- has_server(),
17
- has_sveltekit_app(),
18
- ]);
15
+ const [has_sveltekit_library_result, has_server_result, has_sveltekit_app_result] = await Promise.all([has_sveltekit_library(), has_server(), has_sveltekit_app()]);
19
16
  cfg.plugins = async () => [
20
- enable_sveltekit_library ? gro_plugin_sveltekit_library() : null,
21
- enable_server ? gro_plugin_server() : null,
22
- enable_sveltekit_app
23
- ? gro_plugin_sveltekit_app({ host_target: enable_server ? 'node' : 'github_pages' })
17
+ has_sveltekit_library_result.ok ? gro_plugin_sveltekit_library() : null,
18
+ has_server_result.ok ? gro_plugin_server() : null,
19
+ has_sveltekit_app_result.ok
20
+ ? gro_plugin_sveltekit_app({ host_target: has_server_result.ok ? 'node' : 'github_pages' })
24
21
  : null,
25
22
  // TODO replace with an esbuild plugin, see the module for more
26
23
  // import {gro_plugin_gen} from './gro_plugin_gen.js';
@@ -3,7 +3,12 @@ import { join, resolve } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { spawn } from '@ryanatkn/belt/process.js';
5
5
  import { exists } from './fs.js';
6
- import { NODE_MODULES_DIRNAME } from './paths.js';
6
+ import { NODE_MODULES_DIRNAME, SVELTEKIT_DIST_DIRNAME } from './path_constants.js';
7
+ /*
8
+
9
+ This module is intended to have minimal dependencies to avoid over-imports in the CLI.
10
+
11
+ */
7
12
  /**
8
13
  * Resolves a path to an internal Gro file.
9
14
  * Prefers any local installation of Gro and falls back to the current CLI context.
@@ -40,26 +45,22 @@ import { NODE_MODULES_DIRNAME } from './paths.js';
40
45
  */
41
46
  export const resolve_gro_module_path = async (path = '') => {
42
47
  const gro_bin_path = resolve(NODE_MODULES_DIRNAME, '.bin/gro');
48
+ // case 1
49
+ // Prefer any locally installed version of Gro.
43
50
  if (await exists(gro_bin_path)) {
44
- // case 1
45
- // Prefer any locally installed version of Gro.
46
51
  return join(await realpath(gro_bin_path), '..', path);
47
52
  }
48
- else {
49
- // case 2
50
- // If running Gro inside its own repo, require the local dist.
51
- // If the local dist is not yet built it will fall back to the global.
52
- const file_path = fileURLToPath(import.meta.url);
53
- const base_path = 'dist';
54
- if ((await exists(join(base_path, 'gro.js'))) && (await exists(join(base_path, path)))) {
55
- return join(file_path, '../..', base_path, path);
56
- }
57
- else {
58
- // case 3
59
- // Fall back to the version associated with the running CLI.
60
- return join(file_path, '..', path);
61
- }
53
+ // case 2
54
+ // If running Gro inside its own repo, require the local dist.
55
+ // If the local dist is not yet built it will fall back to the global.
56
+ if ((await exists(join(SVELTEKIT_DIST_DIRNAME, 'gro.js'))) &&
57
+ (await exists(join(SVELTEKIT_DIST_DIRNAME, path)))) {
58
+ return resolve(SVELTEKIT_DIST_DIRNAME, path);
62
59
  }
60
+ // case 3
61
+ // Fall back to the version associated with the running CLI.
62
+ const file_path = fileURLToPath(import.meta.url);
63
+ return join(file_path, '..', path);
63
64
  };
64
65
  /**
65
66
  * Runs a file using the Gro loader.
@@ -32,7 +32,7 @@ export const plugin = () => {
32
32
  void flush_gen_queue();
33
33
  }
34
34
  }, FLUSH_DEBOUNCE_DELAY);
35
- const gen = (files = []) => spawn('npx', ['gro', 'gen', ...files]);
35
+ const gen = (files = []) => spawn_cli('gro', ['gen', ...files]);
36
36
  return {
37
37
  name: 'gro_plugin_gen',
38
38
  setup: async ({ args: { watch }, dev, log }) => {
@@ -1,8 +1,11 @@
1
1
  import * as esbuild from 'esbuild';
2
2
  import type { Config as SvelteKitConfig } from '@sveltejs/kit';
3
+ import type { Result } from '@ryanatkn/belt/result.js';
3
4
  import type { Plugin, Plugin_Context } from './plugin.js';
4
5
  export declare const SERVER_SOURCE_ID: Flavored<string, "Source_Id">;
5
- export declare const has_server: (path?: Flavored<string, "Source_Id">) => Promise<boolean>;
6
+ export declare const has_server: (path?: Flavored<string, "Source_Id">) => Promise<Result<object, {
7
+ message: string;
8
+ }>>;
6
9
  export interface Options {
7
10
  /**
8
11
  * same as esbuild's `entryPoints`
@@ -1,10 +1,10 @@
1
1
  import { spawn_restartable_process } from '@ryanatkn/belt/process.js';
2
2
  import * as esbuild from 'esbuild';
3
- import { cwd } from 'node:process';
4
3
  import { join, resolve } from 'node:path';
5
4
  import { identity } from '@ryanatkn/belt/function.js';
6
- import { strip_before } from '@ryanatkn/belt/string.js';
7
- import { base_path_to_source_id, GRO_DEV_DIRNAME, SERVER_DIST_PATH, LIB_DIRNAME, paths, } from './paths.js';
5
+ import { strip_before, strip_end } from '@ryanatkn/belt/string.js';
6
+ import { base_path_to_source_id, LIB_DIRNAME, paths } from './paths.js';
7
+ import { GRO_DEV_DIRNAME, SERVER_DIST_PATH } from './path_constants.js';
8
8
  import { watch_dir } from './watch_dir.js';
9
9
  import { init_sveltekit_config } from './sveltekit_config.js';
10
10
  import { esbuild_plugin_sveltekit_shim_app } from './esbuild_plugin_sveltekit_shim_app.js';
@@ -16,10 +16,16 @@ import { esbuild_plugin_sveltekit_local_imports } from './esbuild_plugin_sveltek
16
16
  import { exists } from './fs.js';
17
17
  import { esbuild_plugin_svelte } from './esbuild_plugin_svelte.js';
18
18
  import { throttle } from './throttle.js';
19
+ import { sveltekit_config_global } from './sveltekit_config_global.js';
19
20
  // TODO sourcemap as a hoisted option? disable for production by default - or like `outpaths`, passed a `dev` param
20
21
  export const SERVER_SOURCE_ID = base_path_to_source_id(LIB_DIRNAME + '/server/server.ts');
21
- export const has_server = (path = SERVER_SOURCE_ID) => exists(path);
22
- export const gro_plugin_server = ({ entry_points = [SERVER_SOURCE_ID], dir = cwd(), outpaths = (dev) => ({
22
+ export const has_server = async (path = SERVER_SOURCE_ID) => {
23
+ if (!(await exists(path))) {
24
+ return { ok: false, message: `no server file found at ${path}` };
25
+ }
26
+ return { ok: true };
27
+ };
28
+ export const gro_plugin_server = ({ entry_points = [SERVER_SOURCE_ID], dir = process.cwd(), outpaths = (dev) => ({
23
29
  outdir: join(dir, dev ? GRO_DEV_DIRNAME : SERVER_DIST_PATH),
24
30
  outbase: paths.lib,
25
31
  outname: 'server/server.js',
@@ -32,7 +38,10 @@ export const gro_plugin_server = ({ entry_points = [SERVER_SOURCE_ID], dir = cwd
32
38
  return {
33
39
  name: 'gro_plugin_server',
34
40
  setup: async ({ dev, watch, timings, log }) => {
35
- const { alias, base_url, assets_url, env_dir, private_prefix, public_prefix, svelte_compile_options, svelte_compile_module_options, svelte_preprocessors, } = await init_sveltekit_config(sveltekit_config ?? dir);
41
+ const parsed_sveltekit_config = !sveltekit_config && strip_end(dir, '/') === process.cwd()
42
+ ? sveltekit_config_global
43
+ : await init_sveltekit_config(sveltekit_config ?? dir);
44
+ const { alias, base_url, assets_url, env_dir, private_prefix, public_prefix, svelte_compile_options, svelte_compile_module_options, svelte_preprocessors, } = parsed_sveltekit_config;
36
45
  // TODO hacky
37
46
  if (svelte_compile_options.generate === undefined) {
38
47
  svelte_compile_options.generate = 'server';
@@ -1,7 +1,6 @@
1
1
  import type { Plugin, Plugin_Context } from './plugin.js';
2
2
  import { type Map_Package_Json } from './package_json.js';
3
3
  import { type Map_Src_Json } from './src_json.js';
4
- export declare const has_sveltekit_app: () => Promise<boolean>;
5
4
  export interface Options {
6
5
  /**
7
6
  * Used for finalizing a SvelteKit build like adding a `.nojekyll` file for GitHub Pages.
@@ -4,13 +4,11 @@ import { dirname, join } from 'node:path';
4
4
  import { print_command_args, serialize_args, to_forwarded_args } from './args.js';
5
5
  import { exists } from './fs.js';
6
6
  import { serialize_package_json, load_package_json } from './package_json.js';
7
- import { init_sveltekit_config } from './sveltekit_config.js';
8
7
  import { Task_Error } from './task.js';
9
8
  import { spawn_cli } from './cli.js';
10
9
  import { serialize_src_json, create_src_json } from './src_json.js';
11
10
  import { DEFAULT_EXPORTS_EXCLUDER } from './config.js';
12
- import { SVELTEKIT_CONFIG_FILENAME } from './paths.js';
13
- export const has_sveltekit_app = () => exists(SVELTEKIT_CONFIG_FILENAME);
11
+ import { sveltekit_config_global } from './sveltekit_config_global.js';
14
12
  export const gro_plugin_sveltekit_app = ({ host_target = 'github_pages', well_known_package_json, well_known_src_json, well_known_src_files, } = {}) => {
15
13
  let sveltekit_process = null;
16
14
  return {
@@ -57,7 +55,7 @@ export const gro_plugin_sveltekit_app = ({ host_target = 'github_pages', well_kn
57
55
  // maybe a Vite middleware is best? what if this plugin added its plugin to your `vite.config.ts`?
58
56
  // copy files to `static` before building, in such a way
59
57
  // that's non-destructive to existing files and dirs and easy to clean up
60
- const { assets_path } = await init_sveltekit_config(); // TODO probably put in plugin context
58
+ const { assets_path } = sveltekit_config_global;
61
59
  const cleanups = [
62
60
  serialized_package_json
63
61
  ? await create_temporarily(join(assets_path, '.well-known/package.json'), serialized_package_json)
@@ -1,4 +1,2 @@
1
1
  import type { Plugin, Plugin_Context } from './plugin.js';
2
- import { Package_Json } from './package_json.js';
3
- export declare const has_sveltekit_library: (package_json?: Package_Json) => Promise<boolean>;
4
2
  export declare const gro_plugin_sveltekit_library: () => Plugin<Plugin_Context>;
@@ -1,24 +1,23 @@
1
1
  import { print_spawn_result, spawn } from '@ryanatkn/belt/process.js';
2
2
  import { Task_Error } from './task.js';
3
- import { Package_Json, load_package_json } from './package_json.js';
3
+ import { load_package_json } from './package_json.js';
4
4
  import { print_command_args, serialize_args, to_forwarded_args } from './args.js';
5
5
  import { find_cli, spawn_cli } from './cli.js';
6
- export const has_sveltekit_library = async (package_json) => {
7
- const p = package_json ?? (await load_package_json()); // TODO from param, on config?
8
- return !!p.devDependencies?.['@sveltejs/package'] || !!p.dependencies?.['@sveltejs/package'];
9
- // TODO @multiple get from the sveltekit config
10
- // && exists(sveltekit_config.lib_path);
11
- };
6
+ import { SVELTE_PACKAGE_CLI, has_sveltekit_library } from './sveltekit_helpers.js';
12
7
  export const gro_plugin_sveltekit_library = () => {
13
8
  return {
14
9
  name: 'gro_plugin_sveltekit_library',
15
10
  setup: async ({ log }) => {
16
- if ((await find_cli('svelte-package')) !== 'local') {
17
- throw new Task_Error('Failed to find svelte-package, run `npm i -D @sveltejs/package`');
11
+ const has_sveltekit_library_result = await has_sveltekit_library();
12
+ if (!has_sveltekit_library_result.ok) {
13
+ throw new Task_Error('Failed to find SvelteKit library: ' + has_sveltekit_library_result.message);
14
+ }
15
+ if ((await find_cli(SVELTE_PACKAGE_CLI)) !== 'local') {
16
+ throw new Task_Error(`Failed to find ${SVELTE_PACKAGE_CLI}, run \`npm i\``);
18
17
  }
19
- const serialized_args = serialize_args(to_forwarded_args('svelte-package'));
18
+ const serialized_args = serialize_args(to_forwarded_args(SVELTE_PACKAGE_CLI));
20
19
  log.info(print_command_args(serialized_args));
21
- await spawn_cli('svelte-package', serialized_args);
20
+ await spawn_cli(SVELTE_PACKAGE_CLI, serialized_args);
22
21
  },
23
22
  adapt: async ({ log, timings }) => {
24
23
  const package_json = await load_package_json();
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export type { Gro_Config, Create_Gro_Config } from './config.js';
2
2
  export { type Plugin, replace_plugin } from './plugin.js';
3
- export { type Gen, type Gen_Context } from './gen.js';
3
+ export type { Gen, Gen_Context } from './gen.js';
4
4
  export { type Task, type Task_Context, Task_Error } from './task.js';
package/dist/index.js CHANGED
@@ -1,3 +1,2 @@
1
1
  export { replace_plugin } from './plugin.js';
2
- export {} from './gen.js';
3
2
  export { Task_Error } from './task.js';
@@ -26,7 +26,7 @@ export declare const to_input_paths: (raw_input_paths: Raw_Input_Path[], root_pa
26
26
  * This is first used to fall back to the Gro dir to search for tasks.
27
27
  * It's the helper used in implementations of `get_possible_source_ids_for_input_path` below.
28
28
  */
29
- export declare const get_possible_source_ids: (input_path: Flavored<string, "Input_Path">, extensions: string[], root_dirs?: string[]) => Source_Id[];
29
+ export declare const get_possible_source_ids: (input_path: Flavored<string, "Input_Path">, extensions: string[], root_dirs: string[]) => Source_Id[];
30
30
  /**
31
31
  * Gets the path data for each input path, checking the filesystem for the possibilities
32
32
  * and stopping at the first existing file or falling back to the first existing directory.
@@ -59,7 +59,7 @@ export const get_possible_source_ids = (input_path, extensions, root_dirs) => {
59
59
  if (isAbsolute(input_path)) {
60
60
  add_possible_source_ids(input_path);
61
61
  }
62
- else if (root_dirs?.length) {
62
+ else {
63
63
  for (const root_dir of root_dirs) {
64
64
  add_possible_source_ids(join(root_dir, input_path));
65
65
  }
@@ -22,14 +22,14 @@ test('to_input_paths', () => {
22
22
  });
23
23
  test('get_possible_source_ids in the gro directory', () => {
24
24
  const input_path = resolve('src/foo/bar');
25
- assert.equal(get_possible_source_ids(input_path, ['.baz.ts']), [
25
+ assert.equal(get_possible_source_ids(input_path, ['.baz.ts'], []), [
26
26
  input_path,
27
27
  input_path + '.baz.ts',
28
28
  ]);
29
29
  });
30
30
  test('get_possible_source_ids does not repeat the extension', () => {
31
31
  const input_path = resolve('src/foo/bar.baz.ts');
32
- assert.equal(get_possible_source_ids(input_path, ['.baz.ts']), [input_path]);
32
+ assert.equal(get_possible_source_ids(input_path, ['.baz.ts'], []), [input_path]);
33
33
  });
34
34
  test('get_possible_source_ids does not repeat with the same root directory', () => {
35
35
  const input_path = resolve('src/foo/bar.baz.ts');
@@ -39,7 +39,7 @@ test('get_possible_source_ids does not repeat with the same root directory', ()
39
39
  });
40
40
  test('get_possible_source_ids implied to be a directory by trailing slash', () => {
41
41
  const input_path = resolve('src/foo/bar') + '/';
42
- assert.equal(get_possible_source_ids(input_path, ['.baz.ts']), [input_path]);
42
+ assert.equal(get_possible_source_ids(input_path, ['.baz.ts'], []), [input_path]);
43
43
  });
44
44
  test('load_source_ids_by_input_path', async () => {
45
45
  const test_files = {
package/dist/invoke.js CHANGED
@@ -2,6 +2,7 @@ import { attach_process_error_handlers } from '@ryanatkn/belt/process.js';
2
2
  import { invoke_task } from './invoke_task.js';
3
3
  import { to_task_args } from './args.js';
4
4
  import { load_config } from './config.js';
5
+ import { sveltekit_sync_if_obviously_needed } from './sveltekit_helpers.js';
5
6
  /*
6
7
 
7
8
  This module invokes the Gro CLI which in turn invokes tasks.
@@ -14,5 +15,6 @@ and the rest of the args are forwarded to the task's `run` function.
14
15
  */
15
16
  // handle uncaught errors
16
17
  attach_process_error_handlers((err) => err?.constructor?.name === 'Task_Error' ? 'Task_Error' : null);
18
+ await sveltekit_sync_if_obviously_needed();
17
19
  const { task_name, args } = to_task_args();
18
20
  await invoke_task(task_name, args, await load_config());
@@ -17,4 +17,4 @@ import type { Gro_Config } from './config.js';
17
17
  * there are some subtle differences in the complex logical branches.
18
18
  * The comments describe each condition.
19
19
  */
20
- export declare const invoke_task: (task_name: Flavored<string, "Raw_Input_Path">, args: Args, config: Gro_Config, timings?: any) => Promise<void>;
20
+ export declare const invoke_task: (task_name: Flavored<string, "Raw_Input_Path">, args: Args | undefined, config: Gro_Config, timings?: any) => Promise<void>;