@ryanatkn/gro 0.119.1 → 0.120.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 (104) hide show
  1. package/README.md +3 -2
  2. package/dist/changelog.d.ts +1 -0
  3. package/dist/changeset.task.js +4 -5
  4. package/dist/clean_fs.d.ts +1 -2
  5. package/dist/clean_fs.js +3 -2
  6. package/dist/cli.d.ts +1 -2
  7. package/dist/cli.js +2 -2
  8. package/dist/config.d.ts +14 -1
  9. package/dist/config.js +17 -5
  10. package/dist/config.test.js +50 -1
  11. package/dist/deploy.task.js +8 -7
  12. package/dist/docs/README.gen.md.js +3 -3
  13. package/dist/docs/config.md +22 -6
  14. package/dist/docs/gen.md +2 -1
  15. package/dist/docs/task.md +4 -3
  16. package/dist/docs/tasks.gen.md.js +17 -10
  17. package/dist/docs/tasks.md +1 -0
  18. package/dist/env.d.ts +2 -3
  19. package/dist/env.js +2 -2
  20. package/dist/esbuild_helpers.d.ts +2 -1
  21. package/dist/esbuild_plugin_external_worker.d.ts +0 -1
  22. package/dist/esbuild_plugin_external_worker.js +7 -7
  23. package/dist/esbuild_plugin_svelte.d.ts +0 -1
  24. package/dist/esbuild_plugin_sveltekit_local_imports.js +2 -2
  25. package/dist/format_directory.d.ts +1 -0
  26. package/dist/fs.d.ts +1 -3
  27. package/dist/fs.js +3 -13
  28. package/dist/fs.test.js +5 -5
  29. package/dist/gen.d.ts +66 -13
  30. package/dist/gen.js +77 -9
  31. package/dist/gen.task.d.ts +3 -0
  32. package/dist/gen.task.js +24 -19
  33. package/dist/gen.test.js +48 -35
  34. package/dist/git.d.ts +0 -1
  35. package/dist/git.js +3 -3
  36. package/dist/gro_helpers.js +4 -4
  37. package/dist/gro_plugin_gen.js +7 -7
  38. package/dist/gro_plugin_server.d.ts +2 -2
  39. package/dist/gro_plugin_server.js +5 -5
  40. package/dist/gro_plugin_sveltekit_app.js +8 -8
  41. package/dist/hash.d.ts +1 -2
  42. package/dist/input_path.d.ts +34 -16
  43. package/dist/input_path.js +119 -67
  44. package/dist/input_path.test.js +150 -46
  45. package/dist/invoke_task.d.ts +2 -1
  46. package/dist/invoke_task.js +33 -79
  47. package/dist/loader.d.ts +0 -1
  48. package/dist/loader.js +4 -4
  49. package/dist/modules.d.ts +17 -36
  50. package/dist/modules.js +29 -68
  51. package/dist/modules.test.js +19 -143
  52. package/dist/package.d.ts +11 -20
  53. package/dist/package.js +61 -64
  54. package/dist/package_json.d.ts +1 -0
  55. package/dist/package_json.js +1 -1
  56. package/dist/package_meta.d.ts +1 -1
  57. package/dist/path.d.ts +12 -8
  58. package/dist/path.js +0 -6
  59. package/dist/paths.d.ts +7 -12
  60. package/dist/paths.js +11 -34
  61. package/dist/paths.test.js +17 -15
  62. package/dist/plugin.d.ts +1 -1
  63. package/dist/publish.task.js +3 -3
  64. package/dist/resolve.task.d.ts +11 -0
  65. package/dist/resolve.task.js +24 -0
  66. package/dist/resolve_node_specifier.d.ts +2 -2
  67. package/dist/resolve_node_specifier.js +3 -3
  68. package/dist/resolve_specifier.d.ts +2 -1
  69. package/dist/resolve_specifier.js +16 -16
  70. package/dist/resolve_specifier.test.js +9 -9
  71. package/dist/run.task.js +2 -2
  72. package/dist/run_gen.d.ts +4 -4
  73. package/dist/run_gen.js +9 -16
  74. package/dist/run_gen.test.js +10 -15
  75. package/dist/run_task.d.ts +2 -1
  76. package/dist/run_task.js +2 -0
  77. package/dist/search_fs.d.ts +20 -7
  78. package/dist/search_fs.js +40 -18
  79. package/dist/search_fs.test.js +9 -11
  80. package/dist/src_json.js +2 -2
  81. package/dist/sveltekit_config.d.ts +0 -1
  82. package/dist/sveltekit_helpers.js +4 -4
  83. package/dist/sveltekit_shim_app.d.ts +1 -1
  84. package/dist/sveltekit_shim_app_forms.d.ts +0 -1
  85. package/dist/sveltekit_shim_app_navigation.d.ts +0 -1
  86. package/dist/sveltekit_shim_app_paths.d.ts +0 -1
  87. package/dist/sveltekit_shim_app_stores.d.ts +0 -1
  88. package/dist/sveltekit_shim_env.d.ts +1 -1
  89. package/dist/task.d.ts +65 -1
  90. package/dist/task.js +85 -13
  91. package/dist/task.test.js +25 -11
  92. package/dist/task_logging.d.ts +3 -6
  93. package/dist/task_logging.js +18 -36
  94. package/dist/watch_dir.d.ts +2 -2
  95. package/dist/watch_dir.js +14 -16
  96. package/package.json +18 -23
  97. package/dist/gen_module.d.ts +0 -34
  98. package/dist/gen_module.js +0 -32
  99. package/dist/gen_module.test.d.ts +0 -1
  100. package/dist/gen_module.test.js +0 -30
  101. package/dist/task_module.d.ts +0 -15
  102. package/dist/task_module.js +0 -18
  103. package/dist/task_module.test.d.ts +0 -1
  104. package/dist/task_module.test.js +0 -67
@@ -1,7 +1,7 @@
1
1
  import { test } from 'uvu';
2
2
  import * as assert from 'uvu/assert';
3
3
  import { resolve } from 'node:path';
4
- import { to_input_path, to_input_paths, load_source_ids_by_input_path, get_possible_source_ids, } from './input_path.js';
4
+ import { to_input_path, to_input_paths, resolve_input_files, get_possible_paths, } from './input_path.js';
5
5
  import { GRO_DIST_DIR, paths } from './paths.js';
6
6
  test('to_input_path', () => {
7
7
  assert.is(to_input_path(resolve('foo.ts')), resolve('foo.ts'));
@@ -20,65 +20,169 @@ test('to_input_paths', () => {
20
20
  'foo',
21
21
  ]);
22
22
  });
23
- test('get_possible_source_ids in the gro directory', () => {
23
+ test('get_possible_paths with an implicit relative path', () => {
24
+ const input_path = 'src/foo/bar';
25
+ assert.equal(get_possible_paths(input_path, [resolve('src/foo'), resolve('src/baz'), resolve('src'), resolve('.')], ['.ext.ts']), [
26
+ {
27
+ id: resolve('src/foo/src/foo/bar'),
28
+ input_path: 'src/foo/bar',
29
+ root_dir: resolve('src/foo'),
30
+ },
31
+ {
32
+ id: resolve('src/foo/src/foo/bar.ext.ts'),
33
+ input_path: 'src/foo/bar',
34
+ root_dir: resolve('src/foo'),
35
+ },
36
+ {
37
+ id: resolve('src/baz/src/foo/bar'),
38
+ input_path: 'src/foo/bar',
39
+ root_dir: resolve('src/baz'),
40
+ },
41
+ {
42
+ id: resolve('src/baz/src/foo/bar.ext.ts'),
43
+ input_path: 'src/foo/bar',
44
+ root_dir: resolve('src/baz'),
45
+ },
46
+ {
47
+ id: resolve('src/src/foo/bar'),
48
+ input_path: 'src/foo/bar',
49
+ root_dir: resolve('src'),
50
+ },
51
+ {
52
+ id: resolve('src/src/foo/bar.ext.ts'),
53
+ input_path: 'src/foo/bar',
54
+ root_dir: resolve('src'),
55
+ },
56
+ {
57
+ id: resolve('src/foo/bar'),
58
+ input_path: 'src/foo/bar',
59
+ root_dir: resolve('.'),
60
+ },
61
+ {
62
+ id: resolve('src/foo/bar.ext.ts'),
63
+ input_path: 'src/foo/bar',
64
+ root_dir: resolve('.'),
65
+ },
66
+ ]);
67
+ });
68
+ test('get_possible_paths in the gro directory', () => {
24
69
  const input_path = resolve('src/foo/bar');
25
- assert.equal(get_possible_source_ids(input_path, ['.baz.ts'], []), [
26
- input_path,
27
- input_path + '.baz.ts',
70
+ assert.equal(get_possible_paths(input_path, [], ['.ext.ts']), [
71
+ { id: input_path, input_path: resolve('src/foo/bar'), root_dir: resolve('src/foo') },
72
+ { id: input_path + '.ext.ts', input_path: resolve('src/foo/bar'), root_dir: resolve('src/foo') },
28
73
  ]);
29
74
  });
30
- test('get_possible_source_ids does not repeat the extension', () => {
31
- const input_path = resolve('src/foo/bar.baz.ts');
32
- assert.equal(get_possible_source_ids(input_path, ['.baz.ts'], []), [input_path]);
75
+ test('get_possible_paths does not repeat the extension', () => {
76
+ const input_path = resolve('src/foo/bar.ext.ts');
77
+ assert.equal(get_possible_paths(input_path, [], ['.ext.ts']), [
78
+ { id: input_path, input_path: resolve('src/foo/bar.ext.ts'), root_dir: resolve('src/foo') },
79
+ ]);
33
80
  });
34
- test('get_possible_source_ids does not repeat with the same root directory', () => {
35
- const input_path = resolve('src/foo/bar.baz.ts');
36
- assert.equal(get_possible_source_ids(input_path, ['.baz.ts'], [paths.root, paths.root]), [
37
- input_path,
81
+ test('get_possible_paths does not repeat with the same root directory', () => {
82
+ const input_path = resolve('src/foo/bar.ext.ts');
83
+ assert.equal(get_possible_paths(input_path, [paths.root, paths.root], ['.ext.ts']), [
84
+ { id: input_path, input_path: resolve('src/foo/bar.ext.ts'), root_dir: resolve('src/foo') },
38
85
  ]);
39
86
  });
40
- test('get_possible_source_ids implied to be a directory by trailing slash', () => {
87
+ test('get_possible_paths implied to be a directory by trailing slash', () => {
41
88
  const input_path = resolve('src/foo/bar') + '/';
42
- assert.equal(get_possible_source_ids(input_path, ['.baz.ts'], []), [input_path]);
89
+ assert.equal(get_possible_paths(input_path, [], ['.ext.ts']), [
90
+ { id: input_path, input_path: resolve('src/foo/bar') + '/', root_dir: resolve('src/foo') },
91
+ ]);
43
92
  });
44
- test('load_source_ids_by_input_path', async () => {
93
+ test('resolve_input_files', async () => {
45
94
  const test_files = {
46
- 'fake/test1.bar.ts': new Map([['fake/test1.bar.ts', { isDirectory: () => false }]]),
47
- 'fake/test2.bar.ts': new Map([['fake/test2.bar.ts', { isDirectory: () => false }]]),
48
- 'fake/test3': new Map([
49
- ['fake/test3', { isDirectory: () => true }],
50
- ['a.ts', { isDirectory: () => false }],
51
- ['b.ts', { isDirectory: () => false }],
52
- ]),
95
+ 'fake/test1.ext.ts': [{ id: '', path: 'fake/test1.ext.ts', is_directory: false }],
96
+ 'fake/test2.ext.ts': [{ id: '', path: 'fake/test2.ext.ts', is_directory: false }],
97
+ 'fake/test3': [
98
+ { id: '', path: 'fake/test3', is_directory: true },
99
+ { id: '', path: 'a.ts', is_directory: false },
100
+ { id: '', path: 'b.ts', is_directory: false },
101
+ ],
53
102
  // duplicate
54
- 'fake/': new Map([
55
- ['fake/test3', { isDirectory: () => true }],
56
- ['test3/a.ts', { isDirectory: () => false }],
57
- ]),
103
+ 'fake/': [
104
+ { id: '', path: 'fake/test3', is_directory: true },
105
+ { id: '', path: 'test3/a.ts', is_directory: false },
106
+ ],
58
107
  // duplicate and not
59
- fake: new Map([
60
- ['fake/test3', { isDirectory: () => true }],
61
- ['test3/a.ts', { isDirectory: () => false }],
62
- ['test3/c.ts', { isDirectory: () => false }],
63
- ]),
64
- 'fake/nomatches': new Map([['fake/nomatches', { isDirectory: () => true }]]),
108
+ fake: [
109
+ { id: '', path: 'fake/test3', is_directory: true },
110
+ { id: '', path: 'test3/a.ts', is_directory: false },
111
+ { id: '', path: 'test3/c.ts', is_directory: false },
112
+ ],
113
+ 'fake/nomatches': [{ id: '', path: 'fake/nomatches', is_directory: true }],
65
114
  };
66
- const result = await load_source_ids_by_input_path(new Map([
67
- ['fake/test1.bar.ts', { id: 'fake/test1.bar.ts', isDirectory: false }],
68
- ['fake/test2', { id: 'fake/test2.bar.ts', isDirectory: false }],
69
- ['fake/test3', { id: 'fake/test3', isDirectory: true }],
70
- ['fake/', { id: 'fake/', isDirectory: true }],
71
- ['fake', { id: 'fake', isDirectory: true }],
72
- ['fake/nomatches', { id: 'fake/nomatches', isDirectory: true }],
73
- ]), async (id) => test_files[id]);
115
+ const a = {
116
+ id: 'fake/test1.ext.ts',
117
+ is_directory: false,
118
+ input_path: 'fake/test1.ext.ts',
119
+ root_dir: process.cwd(),
120
+ };
121
+ const b = {
122
+ id: 'fake/test2.ext.ts',
123
+ is_directory: false,
124
+ input_path: 'fake/test2',
125
+ root_dir: process.cwd(),
126
+ };
127
+ const c = {
128
+ id: 'fake/test3',
129
+ is_directory: true,
130
+ input_path: 'fake/test3',
131
+ root_dir: process.cwd(),
132
+ };
133
+ const d = {
134
+ id: 'fake/',
135
+ is_directory: true,
136
+ input_path: 'fake/',
137
+ root_dir: process.cwd(),
138
+ };
139
+ const e = {
140
+ id: 'fake',
141
+ is_directory: true,
142
+ input_path: 'fake',
143
+ root_dir: process.cwd(),
144
+ };
145
+ const f = {
146
+ id: 'fake/nomatches',
147
+ is_directory: true,
148
+ input_path: 'fake/nomatches',
149
+ root_dir: process.cwd(),
150
+ };
151
+ const result = await resolve_input_files([a, b, c, d, e, f], async (id) => test_files[id]);
152
+ const resolved_input_files = [
153
+ { id: a.id, input_path: a.input_path, resolved_input_path: a },
154
+ { id: b.id, input_path: b.input_path, resolved_input_path: b },
155
+ { id: 'fake/test3/a.ts', input_path: c.input_path, resolved_input_path: c },
156
+ { id: 'fake/test3/b.ts', input_path: c.input_path, resolved_input_path: c },
157
+ { id: 'fake/test3/c.ts', input_path: e.input_path, resolved_input_path: e },
158
+ ];
74
159
  assert.equal(result, {
75
- source_ids_by_input_path: new Map([
76
- ['fake/test1.bar.ts', ['fake/test1.bar.ts']],
77
- ['fake/test2', ['fake/test2.bar.ts']],
78
- ['fake/test3', ['fake/test3/a.ts', 'fake/test3/b.ts']],
79
- ['fake', ['fake/test3/c.ts']],
160
+ resolved_input_files,
161
+ resolved_input_files_by_input_path: new Map([
162
+ ['fake/test1.ext.ts', [{ id: a.id, input_path: a.input_path, resolved_input_path: a }]],
163
+ ['fake/test2', [{ id: b.id, input_path: b.input_path, resolved_input_path: b }]],
164
+ [
165
+ 'fake/test3',
166
+ [
167
+ { id: 'fake/test3/a.ts', input_path: c.input_path, resolved_input_path: c },
168
+ { id: 'fake/test3/b.ts', input_path: c.input_path, resolved_input_path: c },
169
+ ],
170
+ ],
171
+ ['fake', [{ id: 'fake/test3/c.ts', input_path: e.input_path, resolved_input_path: e }]],
172
+ ]),
173
+ resolved_input_files_by_root_dir: new Map([
174
+ [
175
+ process.cwd(),
176
+ [
177
+ { id: 'fake/test1.ext.ts', input_path: 'fake/test1.ext.ts', resolved_input_path: a },
178
+ { id: 'fake/test2.ext.ts', input_path: 'fake/test2', resolved_input_path: b },
179
+ { id: 'fake/test3/a.ts', input_path: 'fake/test3', resolved_input_path: c },
180
+ { id: 'fake/test3/b.ts', input_path: 'fake/test3', resolved_input_path: c },
181
+ { id: 'fake/test3/c.ts', input_path: 'fake', resolved_input_path: e },
182
+ ],
183
+ ],
80
184
  ]),
81
- input_directories_with_no_files: ['fake/nomatches'],
185
+ input_directories_with_no_files: [f],
82
186
  });
83
187
  });
84
188
  test.run();
@@ -1,4 +1,5 @@
1
1
  import { type Args } from './args.js';
2
+ import { Raw_Input_Path } from './input_path.js';
2
3
  import type { Gro_Config } from './config.js';
3
4
  /**
4
5
  * Invokes Gro tasks by name using the filesystem as the source.
@@ -17,4 +18,4 @@ import type { Gro_Config } from './config.js';
17
18
  * there are some subtle differences in the complex logical branches.
18
19
  * The comments describe each condition.
19
20
  */
20
- export declare const invoke_task: (task_name: Flavored<string, "Raw_Input_Path">, args: Args | undefined, config: Gro_Config, timings?: any) => Promise<void>;
21
+ export declare const invoke_task: (task_name: Raw_Input_Path, args: Args | undefined, config: Gro_Config, timings?: any) => Promise<void>;
@@ -5,11 +5,9 @@ import { print_ms, print_timings } from '@ryanatkn/belt/print.js';
5
5
  import { to_forwarded_args } from './args.js';
6
6
  import { run_task } from './run_task.js';
7
7
  import { to_input_path, Raw_Input_Path } from './input_path.js';
8
- import { is_gro_id, IS_THIS_GRO, print_path, print_path_or_gro_path } from './paths.js';
9
- import { load_modules } from './modules.js';
10
- import { find_task_modules, load_task_module } from './task_module.js';
8
+ import { find_tasks, load_tasks } from './task.js';
11
9
  import { load_gro_package_json } from './package_json.js';
12
- import { log_tasks, log_error_reasons, log_gro_package_tasks } from './task_logging.js';
10
+ import { log_tasks, log_error_reasons } from './task_logging.js';
13
11
  /**
14
12
  * Invokes Gro tasks by name using the filesystem as the source.
15
13
  *
@@ -44,87 +42,43 @@ export const invoke_task = async (task_name, args, config, timings = new Timings
44
42
  }
45
43
  // Resolve the input path for the provided task name.
46
44
  const input_path = to_input_path(task_name);
47
- const { task_root_paths } = config;
45
+ const { task_root_dirs } = config;
48
46
  // Find the task or directory specified by the `input_path`.
49
47
  // Fall back to searching the Gro directory as well.
50
- const find_modules_result = await find_task_modules([input_path], task_root_paths);
51
- if (!find_modules_result.ok) {
52
- if (find_modules_result.type === 'input_directories_with_no_files') {
53
- // The input path matched a directory, but it contains no matching files.
54
- if (IS_THIS_GRO ||
55
- // this is null safe because of the failure type
56
- is_gro_id(find_modules_result.source_id_path_data_by_input_path.get(input_path).id)) {
57
- // If the directory is inside Gro, just log the errors.
58
- log_error_reasons(log, find_modules_result.reasons);
59
- process.exit(1);
60
- }
61
- else {
62
- // If there's a matching directory in the current working directory,
63
- // but it has no matching files, we still want to search Gro's directory.
64
- const gro_dir_find_modules_result = await log_gro_package_tasks(input_path, task_root_paths, log);
65
- if (!gro_dir_find_modules_result.ok) {
66
- // Log the original errors, not the Gro-specific ones.
67
- log_error_reasons(log, find_modules_result.reasons);
68
- process.exit(1);
69
- }
70
- finish();
71
- return;
72
- }
73
- }
74
- else {
75
- // Some unknown find modules result failure happened, so log it out.
76
- // (currently, just "unmapped_input_paths")
77
- log_error_reasons(log, find_modules_result.reasons);
78
- process.exit(1);
79
- }
48
+ const found = await find_tasks([input_path], task_root_dirs, config);
49
+ if (!found.ok) {
50
+ log_error_reasons(log, found.reasons);
51
+ process.exit(1);
80
52
  }
81
53
  // Found a match either in the current working directory or Gro's directory.
82
- const path_data = find_modules_result.source_id_path_data_by_input_path.get(input_path); // this is null safe because result is ok
83
- if (!path_data.isDirectory) {
84
- // The input path matches a file, so load and run it.
85
- // Try to load the task module.
86
- const load_modules_result = await load_modules(find_modules_result.source_ids_by_input_path, (id) => load_task_module(id, task_root_paths));
87
- if (load_modules_result.ok) {
88
- // We found a task module. Run it!
89
- // `path_data` is not a directory, so there's a single task module here.
90
- const task = load_modules_result.modules[0];
91
- log.info(`→ ${cyan(task.name)} ${(task.mod.task.summary && gray(task.mod.task.summary)) || ''}`);
92
- const timing_to_run_task = timings.start('run task ' + task_name);
93
- const result = await run_task(task, { ...args, ...to_forwarded_args(`gro ${task.name}`) }, invoke_task, config, timings);
94
- timing_to_run_task();
95
- if (result.ok) {
96
- log.info(`✓ ${cyan(task.name)}`);
97
- }
98
- else {
99
- log.info(`${red('🞩')} ${cyan(task.name)}`);
100
- log_error_reasons(log, [result.reason]);
101
- throw result.error;
102
- }
103
- }
104
- else {
105
- log_error_reasons(log, load_modules_result.reasons);
106
- process.exit(1);
107
- }
54
+ const found_tasks = found.value;
55
+ const { resolved_input_files } = found_tasks;
56
+ // Load the task module.
57
+ const loaded = await load_tasks(found_tasks);
58
+ if (!loaded.ok) {
59
+ log_error_reasons(log, loaded.reasons);
60
+ process.exit(1);
108
61
  }
109
- else {
62
+ const loaded_tasks = loaded.value;
63
+ if (resolved_input_files.length > 1 || resolved_input_files[0].resolved_input_path.is_directory) {
110
64
  // The input path matches a directory. Log the tasks but don't run them.
111
- if (IS_THIS_GRO) {
112
- // Is the Gro directory the same as the cwd? Log the matching files.
113
- await log_tasks(log, print_path(path_data.id), find_modules_result.source_ids_by_input_path, task_root_paths);
114
- }
115
- else if (is_gro_id(path_data.id)) {
116
- // Does the Gro directory contain the matching files? Log them.
117
- await log_tasks(log, print_path_or_gro_path(path_data.id), find_modules_result.source_ids_by_input_path, task_root_paths);
118
- }
119
- else {
120
- // The Gro directory is not the same as the cwd and it doesn't contain the matching files.
121
- // Find all of the possible matches in both the current project and the Gro directory,
122
- // and log everything out.
123
- // Ignore any errors - the directory may not exist or have any files!
124
- const gro_dir_find_modules_result = await log_gro_package_tasks(input_path, task_root_paths, log);
125
- // Then log the current working directory matches.
126
- await log_tasks(log, print_path(path_data.id), find_modules_result.source_ids_by_input_path, task_root_paths, !gro_dir_find_modules_result.ok);
127
- }
65
+ await log_tasks(log, loaded_tasks);
66
+ finish();
67
+ return;
68
+ }
69
+ // The input path matches a file that's presumable a task, so load and run it.
70
+ if (loaded_tasks.modules.length !== 1)
71
+ throw Error('expected one loaded task'); // run only one task at a time
72
+ const task = loaded_tasks.modules[0];
73
+ log.info(`→ ${cyan(task.name)} ${(task.mod.task.summary && gray(task.mod.task.summary)) || ''}`);
74
+ const timing_to_run_task = timings.start('run task ' + task_name);
75
+ const result = await run_task(task, { ...args, ...to_forwarded_args(`gro ${task.name}`) }, invoke_task, config, timings);
76
+ timing_to_run_task();
77
+ if (!result.ok) {
78
+ log.info(`${red('🞩')} ${cyan(task.name)}`);
79
+ log_error_reasons(log, [result.reason]);
80
+ throw result.error;
128
81
  }
82
+ log.info(`✓ ${cyan(task.name)}`);
129
83
  finish();
130
84
  };
package/dist/loader.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { LoadHook, ResolveHook } from 'node:module';
3
2
  export declare const load: LoadHook;
4
3
  export declare const resolve: ResolveHook;
package/dist/loader.js CHANGED
@@ -164,13 +164,13 @@ export const resolve = async (specifier, context, nextResolve) => {
164
164
  if (SVELTE_MATCHER.test(path) || json_matcher.test(path)) {
165
165
  // Match the behavior of Vite and esbuild for Svelte and JSON imports.
166
166
  // TODO maybe `.ts` too
167
- const source_id = await resolve_node_specifier(path, dir, parent_url, package_json_cache);
168
- return { url: pathToFileURL(source_id).href, format: 'module', shortCircuit: true };
167
+ const path_id = await resolve_node_specifier(path, dir, parent_url, package_json_cache);
168
+ return { url: pathToFileURL(path_id).href, format: 'module', shortCircuit: true };
169
169
  }
170
170
  else {
171
171
  return nextResolve(path, context);
172
172
  }
173
173
  }
174
- const { source_id } = await resolve_specifier(path, dirname(fileURLToPath(parent_url)));
175
- return { url: pathToFileURL(source_id).href, format: 'module', shortCircuit: true };
174
+ const { path_id } = await resolve_specifier(path, dirname(fileURLToPath(parent_url)));
175
+ return { url: pathToFileURL(path_id).href, format: 'module', shortCircuit: true };
176
176
  };
package/dist/modules.d.ts CHANGED
@@ -1,53 +1,34 @@
1
1
  import type { Result } from '@ryanatkn/belt/result.js';
2
- import { Input_Path } from './input_path.js';
3
- import type { Path_Data } from './path.js';
4
- import { type Source_Id } from './paths.js';
2
+ import type { Resolved_Input_File } from './input_path.js';
3
+ import type { Path_Id } from './path.js';
5
4
  export interface Module_Meta<T_Module extends Record<string, any> = Record<string, any>> {
6
- id: string;
5
+ id: Path_Id;
7
6
  mod: T_Module;
8
7
  }
9
- export type Load_Module_Result<T> = Result<{
10
- mod: T;
8
+ export type Load_Module_Result<T_Module> = Result<{
9
+ id: Path_Id;
10
+ mod: T_Module;
11
11
  }, Load_Module_Failure>;
12
12
  export type Load_Module_Failure = {
13
13
  ok: false;
14
- type: 'importFailed';
15
- id: string;
14
+ type: 'failed_import';
15
+ id: Path_Id;
16
16
  error: Error;
17
17
  } | {
18
18
  ok: false;
19
- type: 'invalid';
20
- id: string;
19
+ type: 'failed_validation';
20
+ id: Path_Id;
21
21
  mod: Record<string, any>;
22
22
  validation: string;
23
23
  };
24
- export declare const load_module: <T extends Record<string, any>>(id: string, validate?: (mod: Record<string, any>) => mod is T) => Promise<Load_Module_Result<Module_Meta<T>>>;
25
- export type Find_Modules_Result = Result<{
26
- source_ids_by_input_path: Map<Input_Path, Source_Id[]>;
27
- source_id_path_data_by_input_path: Map<Input_Path, Path_Data>;
28
- }, Find_Modules_Failure>;
29
- export type Find_Modules_Failure = {
30
- type: 'unmapped_input_paths';
31
- source_id_path_data_by_input_path: Map<Input_Path, Path_Data>;
32
- unmapped_input_paths: Input_Path[];
33
- reasons: string[];
34
- } | {
35
- type: 'input_directories_with_no_files';
36
- source_ids_by_input_path: Map<Input_Path, Source_Id[]>;
37
- source_id_path_data_by_input_path: Map<Input_Path, Path_Data>;
38
- input_directories_with_no_files: Input_Path[];
39
- reasons: string[];
40
- };
41
- export type Load_Modules_Result<T_Module_Meta extends Module_Meta> = Result<{
42
- modules: T_Module_Meta[];
43
- }, {
24
+ export declare const load_module: <T_Module extends Record<string, any>>(id: Path_Id, validate?: (mod: Record<string, any>) => mod is T_Module) => Promise<Load_Module_Result<T_Module>>;
25
+ export interface Load_Modules_Failure<T_Module_Meta extends Module_Meta> {
44
26
  type: 'load_module_failures';
45
27
  load_module_failures: Load_Module_Failure[];
46
28
  reasons: string[];
47
29
  modules: T_Module_Meta[];
48
- }>;
49
- /**
50
- * Finds modules from input paths. (see `src/lib/input_path.ts` for more)
51
- */
52
- export declare const find_modules: (input_paths: Input_Path[], custom_search_fs?: (dir: string, options?: import("./search_fs.js").Search_Fs_Options) => Promise<Map<string, import("./path.js").Path_Stats>>, get_possible_source_ids?: (input_path: Input_Path) => Source_Id[], timings?: any) => Promise<Find_Modules_Result>;
53
- export declare const load_modules: <Module_Type extends Record<string, any>, T_Module_Meta extends Module_Meta<Module_Type>>(source_ids_by_input_path: Map<Input_Path, Source_Id[]>, load_module_by_id: (source_id: Source_Id) => Promise<Load_Module_Result<T_Module_Meta>>, timings?: any) => Promise<Load_Modules_Result<T_Module_Meta>>;
30
+ }
31
+ export type Load_Modules_Result<T_Module_Meta extends Module_Meta> = Result<{
32
+ modules: T_Module_Meta[];
33
+ }, Load_Modules_Failure<T_Module_Meta>>;
34
+ export declare const load_modules: <T_Module extends Record<string, any>, T_Module_Meta extends Module_Meta<T_Module>>(resolved_input_files: Resolved_Input_File[], validate: (mod: any) => mod is T_Module, map_module_meta: (resolved_input_file: Resolved_Input_File, mod: T_Module) => T_Module_Meta, timings?: any) => Promise<Load_Modules_Result<T_Module_Meta>>;
package/dist/modules.js CHANGED
@@ -1,95 +1,56 @@
1
- import { red } from 'kleur/colors';
2
1
  import { Unreachable_Error } from '@ryanatkn/belt/error.js';
3
2
  import { print_error } from '@ryanatkn/belt/print.js';
4
- import { load_source_path_data_by_input_path, load_source_ids_by_input_path, Input_Path, } from './input_path.js';
5
- import { paths_from_id, print_path, print_path_or_gro_path } from './paths.js';
6
- import { search_fs } from './search_fs.js';
3
+ import { print_path } from './paths.js';
7
4
  export const load_module = async (id, validate) => {
8
5
  let mod;
9
6
  try {
10
7
  mod = await import(id);
11
8
  }
12
9
  catch (err) {
13
- return { ok: false, type: 'importFailed', id, error: err };
10
+ return { ok: false, type: 'failed_import', id, error: err };
14
11
  }
15
12
  if (validate && !validate(mod)) {
16
- return { ok: false, type: 'invalid', id, mod, validation: validate.name };
13
+ return { ok: false, type: 'failed_validation', id, mod, validation: validate.name };
17
14
  }
18
- return { ok: true, mod: { id, mod } };
15
+ return { ok: true, id, mod };
19
16
  };
20
- /**
21
- * Finds modules from input paths. (see `src/lib/input_path.ts` for more)
22
- */
23
- export const find_modules = async (input_paths, custom_search_fs = search_fs, get_possible_source_ids, timings) => {
24
- // Check which extension variation works - if it's a directory, prefer others first!
25
- const timing_to_map_input_paths = timings?.start('map input paths');
26
- const { source_id_path_data_by_input_path, unmapped_input_paths } = await load_source_path_data_by_input_path(input_paths, get_possible_source_ids);
27
- timing_to_map_input_paths?.();
28
- // Error if any input path could not be mapped.
29
- if (unmapped_input_paths.length) {
30
- return {
31
- ok: false,
32
- type: 'unmapped_input_paths',
33
- source_id_path_data_by_input_path,
34
- unmapped_input_paths,
35
- reasons: unmapped_input_paths.map((input_path) => red(`Input path ${print_path_or_gro_path(input_path, paths_from_id(input_path))} cannot be mapped to a file or directory.`)),
36
- };
37
- }
38
- // Find all of the files for any directories.
39
- const timing_to_search_fs = timings?.start('find files');
40
- const { source_ids_by_input_path, input_directories_with_no_files } = await load_source_ids_by_input_path(source_id_path_data_by_input_path, custom_search_fs);
41
- timing_to_search_fs?.();
42
- // Error if any input path has no files. (means we have an empty directory)
43
- return input_directories_with_no_files.length
44
- ? {
45
- ok: false,
46
- type: 'input_directories_with_no_files',
47
- source_id_path_data_by_input_path,
48
- source_ids_by_input_path,
49
- input_directories_with_no_files,
50
- reasons: input_directories_with_no_files.map((input_path) => red(`Input directory ${print_path_or_gro_path(source_id_path_data_by_input_path.get(input_path).id, paths_from_id(input_path))} contains no matching files.`)),
51
- }
52
- : { ok: true, source_ids_by_input_path, source_id_path_data_by_input_path };
53
- };
54
- // TODO parallelize, originally it needed to be serial for a specific usecase we no longer have
55
- export const load_modules = async (source_ids_by_input_path, // TODO maybe make this a flat array and remove `input_path`?
56
- load_module_by_id, timings) => {
17
+ // TODO parallelize and sort afterwards
18
+ export const load_modules = async (resolved_input_files, validate, map_module_meta, timings) => {
57
19
  const timing_to_load_modules = timings?.start('load modules');
58
20
  const modules = [];
59
21
  const load_module_failures = [];
60
22
  const reasons = [];
61
- for (const [input_path, source_ids] of source_ids_by_input_path) {
62
- for (const id of source_ids) {
63
- const result = await load_module_by_id(id); // eslint-disable-line no-await-in-loop
64
- if (result.ok) {
65
- modules.push(result.mod);
66
- }
67
- else {
68
- load_module_failures.push(result);
69
- switch (result.type) {
70
- case 'importFailed': {
71
- reasons.push(`Module import ${print_path(id, paths_from_id(id))} failed from input ${print_path(input_path, paths_from_id(input_path))}: ${print_error(result.error)}`);
72
- break;
73
- }
74
- case 'invalid': {
75
- // TODO try to make this a good error message for the task case
76
- reasons.push(`Module ${print_path(id, paths_from_id(id))} failed validation '${result.validation}'.`);
77
- break;
78
- }
79
- default:
80
- throw new Unreachable_Error(result);
23
+ for (const resolved_input_file of resolved_input_files.values()) {
24
+ const { id, input_path } = resolved_input_file;
25
+ const result = await load_module(id, validate); // eslint-disable-line no-await-in-loop
26
+ if (result.ok) {
27
+ modules.push(map_module_meta(resolved_input_file, result.mod));
28
+ }
29
+ else {
30
+ load_module_failures.push(result);
31
+ switch (result.type) {
32
+ case 'failed_import': {
33
+ reasons.push(`Module import ${print_path(id)} failed from input ${print_path(input_path)}: ${print_error(result.error)}`);
34
+ break;
81
35
  }
36
+ case 'failed_validation': {
37
+ reasons.push(`Module ${print_path(id)} failed validation '${result.validation}'.`);
38
+ break;
39
+ }
40
+ default:
41
+ throw new Unreachable_Error(result);
82
42
  }
83
43
  }
84
44
  }
85
45
  timing_to_load_modules?.();
86
- return load_module_failures.length
87
- ? {
46
+ if (load_module_failures.length) {
47
+ return {
88
48
  ok: false,
89
49
  type: 'load_module_failures',
90
50
  load_module_failures,
91
51
  reasons,
92
52
  modules,
93
- }
94
- : { ok: true, modules };
53
+ };
54
+ }
55
+ return { ok: true, modules };
95
56
  };