@ryanatkn/gro 0.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +257 -0
- package/dist/args.d.ts +59 -0
- package/dist/args.js +132 -0
- package/dist/args.test.d.ts +1 -0
- package/dist/args.test.js +43 -0
- package/dist/build.task.d.ts +11 -0
- package/dist/build.task.js +24 -0
- package/dist/changelog.d.ts +8 -0
- package/dist/changelog.js +47 -0
- package/dist/changelog.test.d.ts +1 -0
- package/dist/changelog.test.js +118 -0
- package/dist/changeset.task.d.ts +49 -0
- package/dist/changeset.task.js +141 -0
- package/dist/check.task.d.ts +47 -0
- package/dist/check.task.js +77 -0
- package/dist/clean.task.d.ts +26 -0
- package/dist/clean.task.js +41 -0
- package/dist/clean_fs.d.ts +9 -0
- package/dist/clean_fs.js +27 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +25 -0
- package/dist/commit.task.d.ts +11 -0
- package/dist/commit.task.js +22 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.js +42 -0
- package/dist/config.test.d.ts +1 -0
- package/dist/config.test.js +8 -0
- package/dist/deploy.task.d.ts +47 -0
- package/dist/deploy.task.js +198 -0
- package/dist/dev.task.d.ts +22 -0
- package/dist/dev.task.js +32 -0
- package/dist/docs/README.gen.md.d.ts +5 -0
- package/dist/docs/README.gen.md.js +53 -0
- package/dist/docs/README.md +20 -0
- package/dist/docs/build.md +41 -0
- package/dist/docs/config.md +162 -0
- package/dist/docs/deploy.md +32 -0
- package/dist/docs/dev.md +40 -0
- package/dist/docs/gen.md +241 -0
- package/dist/docs/gro_plugin_sveltekit_frontend.md +97 -0
- package/dist/docs/package_json.md +29 -0
- package/dist/docs/plugin.md +50 -0
- package/dist/docs/publish.md +144 -0
- package/dist/docs/task.md +377 -0
- package/dist/docs/tasks.gen.md.d.ts +2 -0
- package/dist/docs/tasks.gen.md.js +60 -0
- package/dist/docs/tasks.md +35 -0
- package/dist/docs/test.md +52 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.js +47 -0
- package/dist/esbuild_helpers.d.ts +14 -0
- package/dist/esbuild_helpers.js +36 -0
- package/dist/esbuild_plugin_external_worker.d.ts +22 -0
- package/dist/esbuild_plugin_external_worker.js +49 -0
- package/dist/esbuild_plugin_svelte.d.ts +9 -0
- package/dist/esbuild_plugin_svelte.js +49 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.d.ts +7 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.js +30 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.d.ts +6 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.js +16 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.d.ts +8 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.js +23 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.d.ts +10 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.js +18 -0
- package/dist/format.task.d.ts +11 -0
- package/dist/format.task.js +24 -0
- package/dist/format_directory.d.ts +2 -0
- package/dist/format_directory.js +27 -0
- package/dist/format_file.d.ts +8 -0
- package/dist/format_file.js +42 -0
- package/dist/format_file.test.d.ts +1 -0
- package/dist/format_file.test.js +16 -0
- package/dist/fs.d.ts +7 -0
- package/dist/fs.js +19 -0
- package/dist/fs.test.d.ts +1 -0
- package/dist/fs.test.js +16 -0
- package/dist/gen.d.ts +57 -0
- package/dist/gen.js +81 -0
- package/dist/gen.task.d.ts +14 -0
- package/dist/gen.task.js +103 -0
- package/dist/gen.test.d.ts +1 -0
- package/dist/gen.test.js +239 -0
- package/dist/gen_module.d.ts +46 -0
- package/dist/gen_module.js +54 -0
- package/dist/gen_module.test.d.ts +1 -0
- package/dist/gen_module.test.js +30 -0
- package/dist/git.d.ts +76 -0
- package/dist/git.js +200 -0
- package/dist/git.test.d.ts +1 -0
- package/dist/git.test.js +18 -0
- package/dist/github.d.ts +35 -0
- package/dist/github.js +32 -0
- package/dist/gro.config.default.d.ts +12 -0
- package/dist/gro.config.default.js +31 -0
- package/dist/gro.d.ts +2 -0
- package/dist/gro.js +19 -0
- package/dist/gro_helpers.d.ts +43 -0
- package/dist/gro_helpers.js +79 -0
- package/dist/gro_plugin_gen.d.ts +6 -0
- package/dist/gro_plugin_gen.js +80 -0
- package/dist/gro_plugin_server.d.ts +77 -0
- package/dist/gro_plugin_server.js +152 -0
- package/dist/gro_plugin_sveltekit_app.d.ts +27 -0
- package/dist/gro_plugin_sveltekit_app.js +180 -0
- package/dist/gro_plugin_sveltekit_library.d.ts +4 -0
- package/dist/gro_plugin_sveltekit_library.js +42 -0
- package/dist/hash.d.ts +5 -0
- package/dist/hash.js +14 -0
- package/dist/hash.test.d.ts +1 -0
- package/dist/hash.test.js +25 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/input_path.d.ts +48 -0
- package/dist/input_path.js +161 -0
- package/dist/input_path.test.d.ts +1 -0
- package/dist/input_path.test.js +106 -0
- package/dist/invoke.d.ts +1 -0
- package/dist/invoke.js +18 -0
- package/dist/invoke_task.d.ts +20 -0
- package/dist/invoke_task.js +140 -0
- package/dist/lint.task.d.ts +11 -0
- package/dist/lint.task.js +29 -0
- package/dist/loader.d.ts +4 -0
- package/dist/loader.js +153 -0
- package/dist/module.d.ts +3 -0
- package/dist/module.js +6 -0
- package/dist/module.test.d.ts +1 -0
- package/dist/module.test.js +41 -0
- package/dist/modules.d.ts +60 -0
- package/dist/modules.js +103 -0
- package/dist/modules.test.d.ts +1 -0
- package/dist/modules.test.js +182 -0
- package/dist/package.d.ts +939 -0
- package/dist/package.gen.d.ts +7 -0
- package/dist/package.gen.js +26 -0
- package/dist/package.js +887 -0
- package/dist/package_json.d.ts +342 -0
- package/dist/package_json.js +212 -0
- package/dist/package_json.test.d.ts +1 -0
- package/dist/package_json.test.js +77 -0
- package/dist/path.d.ts +12 -0
- package/dist/path.js +8 -0
- package/dist/paths.d.ts +60 -0
- package/dist/paths.js +128 -0
- package/dist/paths.test.d.ts +1 -0
- package/dist/paths.test.js +49 -0
- package/dist/plugin.d.ts +36 -0
- package/dist/plugin.js +80 -0
- package/dist/plugin.test.d.ts +1 -0
- package/dist/plugin.test.js +54 -0
- package/dist/print_task.d.ts +4 -0
- package/dist/print_task.js +124 -0
- package/dist/publish.task.d.ts +32 -0
- package/dist/publish.task.js +125 -0
- package/dist/release.task.d.ts +5 -0
- package/dist/release.task.js +18 -0
- package/dist/resolve_node_specifier.d.ts +8 -0
- package/dist/resolve_node_specifier.js +39 -0
- package/dist/resolve_node_specifier.test.d.ts +1 -0
- package/dist/resolve_node_specifier.test.js +21 -0
- package/dist/resolve_specifier.d.ts +15 -0
- package/dist/resolve_specifier.js +51 -0
- package/dist/resolve_specifier.test.d.ts +1 -0
- package/dist/resolve_specifier.test.js +66 -0
- package/dist/run.task.d.ts +11 -0
- package/dist/run.task.js +31 -0
- package/dist/run_gen.d.ts +6 -0
- package/dist/run_gen.js +74 -0
- package/dist/run_gen.test.d.ts +1 -0
- package/dist/run_gen.test.js +182 -0
- package/dist/run_task.d.ts +13 -0
- package/dist/run_task.js +44 -0
- package/dist/run_task.test.d.ts +1 -0
- package/dist/run_task.test.js +63 -0
- package/dist/search_fs.d.ts +11 -0
- package/dist/search_fs.js +22 -0
- package/dist/search_fs.test.d.ts +1 -0
- package/dist/search_fs.test.js +46 -0
- package/dist/src_json.d.ts +256 -0
- package/dist/src_json.js +110 -0
- package/dist/src_json.test.d.ts +1 -0
- package/dist/src_json.test.js +52 -0
- package/dist/sveltekit_config.d.ts +36 -0
- package/dist/sveltekit_config.js +51 -0
- package/dist/sveltekit_shim_app.d.ts +10 -0
- package/dist/sveltekit_shim_app.js +31 -0
- package/dist/sveltekit_shim_app_environment.d.ts +10 -0
- package/dist/sveltekit_shim_app_environment.js +12 -0
- package/dist/sveltekit_shim_app_forms.d.ts +5 -0
- package/dist/sveltekit_shim_app_forms.js +13 -0
- package/dist/sveltekit_shim_app_navigation.d.ts +10 -0
- package/dist/sveltekit_shim_app_navigation.js +11 -0
- package/dist/sveltekit_shim_app_paths.d.ts +11 -0
- package/dist/sveltekit_shim_app_paths.js +6 -0
- package/dist/sveltekit_shim_app_stores.d.ts +6 -0
- package/dist/sveltekit_shim_app_stores.js +17 -0
- package/dist/sveltekit_shim_env.d.ts +4 -0
- package/dist/sveltekit_shim_env.js +23 -0
- package/dist/sync.task.d.ts +30 -0
- package/dist/sync.task.js +45 -0
- package/dist/task.d.ts +29 -0
- package/dist/task.js +17 -0
- package/dist/task.test.d.ts +1 -0
- package/dist/task.test.js +22 -0
- package/dist/task_module.d.ts +14 -0
- package/dist/task_module.js +19 -0
- package/dist/task_module.test.d.ts +1 -0
- package/dist/task_module.test.js +70 -0
- package/dist/test.task.d.ts +20 -0
- package/dist/test.task.js +43 -0
- package/dist/throttle.d.ts +16 -0
- package/dist/throttle.js +59 -0
- package/dist/throttle.test.d.ts +1 -0
- package/dist/throttle.test.js +49 -0
- package/dist/typecheck.task.d.ts +5 -0
- package/dist/typecheck.task.js +38 -0
- package/dist/upgrade.task.d.ts +14 -0
- package/dist/upgrade.task.js +37 -0
- package/dist/watch_dir.d.ts +30 -0
- package/dist/watch_dir.js +59 -0
- package/package.json +422 -0
package/dist/gen.task.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { red, green, gray } from 'kleur/colors';
|
|
2
|
+
import { print_ms, print_error } from '@ryanatkn/belt/print.js';
|
|
3
|
+
import { plural } from '@ryanatkn/belt/string.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { dirname } from 'node:path';
|
|
6
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
7
|
+
import { Task_Error } from './task.js';
|
|
8
|
+
import { run_gen } from './run_gen.js';
|
|
9
|
+
import { load_gen_module, check_gen_modules, find_gen_modules } from './gen_module.js';
|
|
10
|
+
import { resolve_input_paths } from './input_path.js';
|
|
11
|
+
import { load_modules } from './modules.js';
|
|
12
|
+
import { format_file } from './format_file.js';
|
|
13
|
+
import { print_path } from './paths.js';
|
|
14
|
+
import { log_error_reasons } from './print_task.js';
|
|
15
|
+
export const Args = z
|
|
16
|
+
.object({
|
|
17
|
+
_: z.array(z.string(), { description: 'paths to generate' }).default([]),
|
|
18
|
+
check: z
|
|
19
|
+
.boolean({ description: 'exit with a nonzero code if any files need to be generated' })
|
|
20
|
+
.default(false),
|
|
21
|
+
})
|
|
22
|
+
.strict();
|
|
23
|
+
// TODO test - especially making sure nothing gets genned
|
|
24
|
+
// if there's any validation or import errors
|
|
25
|
+
export const task = {
|
|
26
|
+
summary: 'run code generation scripts',
|
|
27
|
+
Args,
|
|
28
|
+
run: async ({ args, log, timings }) => {
|
|
29
|
+
const { _: raw_input_paths, check } = args;
|
|
30
|
+
// resolve the input paths relative to src/lib/
|
|
31
|
+
const input_paths = resolve_input_paths(raw_input_paths);
|
|
32
|
+
// load all of the gen modules
|
|
33
|
+
const find_modules_result = await find_gen_modules(input_paths);
|
|
34
|
+
if (!find_modules_result.ok) {
|
|
35
|
+
if (find_modules_result.type === 'input_directories_with_no_files') {
|
|
36
|
+
log.info('no gen modules found');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
log_error_reasons(log, find_modules_result.reasons);
|
|
41
|
+
throw new Task_Error('Failed to find gen modules.');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
log.info('gen files', Array.from(find_modules_result.source_ids_by_input_path.values()).flat());
|
|
45
|
+
const load_modules_result = await load_modules(find_modules_result.source_ids_by_input_path, load_gen_module);
|
|
46
|
+
if (!load_modules_result.ok) {
|
|
47
|
+
log_error_reasons(log, load_modules_result.reasons);
|
|
48
|
+
throw new Task_Error('Failed to load gen modules.');
|
|
49
|
+
}
|
|
50
|
+
// run `gen` on each of the modules
|
|
51
|
+
const timing_to_generate_code = timings.start('generate code'); // TODO this ignores `gen_results.elapsed` - should it return `Timings` instead?
|
|
52
|
+
const gen_results = await run_gen(load_modules_result.modules, log, timings, format_file);
|
|
53
|
+
timing_to_generate_code();
|
|
54
|
+
const fail_count = gen_results.failures.length;
|
|
55
|
+
if (check) {
|
|
56
|
+
// check if any files changed, and if so, throw errors,
|
|
57
|
+
// but if there are gen failures, skip the check and defer to their errors
|
|
58
|
+
if (!fail_count) {
|
|
59
|
+
log.info('checking generated files for changes');
|
|
60
|
+
const timing_to_check_results = timings.start('check results for changes');
|
|
61
|
+
const check_gen_modules_results = await check_gen_modules(gen_results);
|
|
62
|
+
timing_to_check_results();
|
|
63
|
+
let has_unexpected_changes = false;
|
|
64
|
+
for (const result of check_gen_modules_results) {
|
|
65
|
+
if (!result.has_changed)
|
|
66
|
+
continue;
|
|
67
|
+
has_unexpected_changes = true;
|
|
68
|
+
log.error(red(`Generated file ${print_path(result.file.id)} via ${print_path(result.file.origin_id)} ${result.is_new ? 'is new' : 'has changed'}.`));
|
|
69
|
+
}
|
|
70
|
+
if (has_unexpected_changes) {
|
|
71
|
+
throw new Task_Error('Failed gen check. Some generated files have unexpectedly changed.' +
|
|
72
|
+
' Run `gro gen` and try again.');
|
|
73
|
+
}
|
|
74
|
+
log.info('check passed, no files have changed');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// write generated files to disk
|
|
79
|
+
log.info('writing generated files to disk');
|
|
80
|
+
const timing_to_output_results = timings.start('output results');
|
|
81
|
+
await Promise.all(gen_results.successes
|
|
82
|
+
.map((result) => result.files.map(async (file) => {
|
|
83
|
+
log.info('writing', print_path(file.id), 'generated from', print_path(file.origin_id));
|
|
84
|
+
await mkdir(dirname(file.id), { recursive: true });
|
|
85
|
+
await writeFile(file.id, file.content);
|
|
86
|
+
}))
|
|
87
|
+
.flat());
|
|
88
|
+
timing_to_output_results();
|
|
89
|
+
}
|
|
90
|
+
let logResult = '';
|
|
91
|
+
for (const result of gen_results.results) {
|
|
92
|
+
logResult += `\n\t${result.ok ? green('✓') : red('🞩')} ${result.ok ? result.files.length : 0} ${gray('in')} ${print_ms(result.elapsed)} ${gray('←')} ${print_path(result.id)}`;
|
|
93
|
+
}
|
|
94
|
+
log.info(logResult);
|
|
95
|
+
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)}`));
|
|
96
|
+
if (fail_count) {
|
|
97
|
+
for (const result of gen_results.failures) {
|
|
98
|
+
log.error(result.reason, '\n', print_error(result.error));
|
|
99
|
+
}
|
|
100
|
+
throw new Task_Error(`Failed to generate ${fail_count} file${plural(fail_count)}.`);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/gen.test.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { suite } from 'uvu';
|
|
2
|
+
import * as assert from 'uvu/assert';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { to_gen_result } from './gen.js';
|
|
5
|
+
const origin_id = resolve('src/foo.gen.ts');
|
|
6
|
+
/* test__to_gen_result */
|
|
7
|
+
const test__to_gen_result = suite('to_gen_result');
|
|
8
|
+
test__to_gen_result('plain string', () => {
|
|
9
|
+
assert.equal(to_gen_result(origin_id, '/**/'), {
|
|
10
|
+
origin_id,
|
|
11
|
+
files: [{ id: resolve('src/foo.ts'), content: '/**/', origin_id, format: true }],
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
test__to_gen_result('object with a content string', () => {
|
|
15
|
+
assert.equal(to_gen_result(origin_id, { content: '/**/' }), {
|
|
16
|
+
origin_id,
|
|
17
|
+
files: [{ id: resolve('src/foo.ts'), content: '/**/', origin_id, format: true }],
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
test__to_gen_result('fail with an unresolved id', () => {
|
|
21
|
+
assert.throws(() => to_gen_result('src/foo.ts', { content: '/**/' }));
|
|
22
|
+
});
|
|
23
|
+
test__to_gen_result('fail with a build id', () => {
|
|
24
|
+
assert.throws(() => to_gen_result(resolve('.gro/foo.js'), { content: '/**/' }));
|
|
25
|
+
});
|
|
26
|
+
test__to_gen_result('fail with an empty id', () => {
|
|
27
|
+
assert.throws(() => to_gen_result('', { content: '/**/' }));
|
|
28
|
+
});
|
|
29
|
+
test__to_gen_result('custom file name', () => {
|
|
30
|
+
assert.equal(to_gen_result(origin_id, {
|
|
31
|
+
filename: 'fooz.ts',
|
|
32
|
+
content: '/**/',
|
|
33
|
+
}), {
|
|
34
|
+
origin_id,
|
|
35
|
+
files: [{ id: resolve('src/fooz.ts'), content: '/**/', origin_id, format: true }],
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
test__to_gen_result('custom file name that matches the default file name', () => {
|
|
39
|
+
assert.equal(to_gen_result(origin_id, {
|
|
40
|
+
filename: 'foo.ts',
|
|
41
|
+
content: '/**/',
|
|
42
|
+
}), {
|
|
43
|
+
origin_id,
|
|
44
|
+
files: [{ id: resolve('src/foo.ts'), content: '/**/', origin_id, format: true }],
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
test__to_gen_result('fail when custom file name explicitly matches the origin', () => {
|
|
48
|
+
assert.throws(() => {
|
|
49
|
+
to_gen_result(origin_id, {
|
|
50
|
+
filename: 'foo.gen.ts',
|
|
51
|
+
content: '/**/',
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
test__to_gen_result('fail when file name implicitly matches the origin', () => {
|
|
56
|
+
assert.throws(() => {
|
|
57
|
+
to_gen_result(resolve('src/foo.ts'), { content: '/**/' });
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
test__to_gen_result('fail with an empty file name', () => {
|
|
61
|
+
assert.throws(() => to_gen_result(origin_id, { filename: '', content: '/**/' }));
|
|
62
|
+
});
|
|
63
|
+
test__to_gen_result('additional file name parts', () => {
|
|
64
|
+
assert.equal(to_gen_result(resolve('src/foo.bar.gen.ts'), { content: '/**/' }), {
|
|
65
|
+
origin_id: resolve('src/foo.bar.gen.ts'),
|
|
66
|
+
files: [
|
|
67
|
+
{
|
|
68
|
+
id: resolve('src/foo.bar.ts'),
|
|
69
|
+
content: '/**/',
|
|
70
|
+
origin_id: resolve('src/foo.bar.gen.ts'),
|
|
71
|
+
format: true,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
test__to_gen_result('js', () => {
|
|
77
|
+
assert.equal(to_gen_result(origin_id, {
|
|
78
|
+
filename: 'foo.js',
|
|
79
|
+
content: '/**/',
|
|
80
|
+
}), {
|
|
81
|
+
origin_id,
|
|
82
|
+
files: [{ id: resolve('src/foo.js'), content: '/**/', origin_id, format: true }],
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
test__to_gen_result('implicit custom file extension', () => {
|
|
86
|
+
assert.equal(to_gen_result(resolve('src/foo.gen.json.ts'), '[/**/]'), {
|
|
87
|
+
origin_id: resolve('src/foo.gen.json.ts'),
|
|
88
|
+
files: [
|
|
89
|
+
{
|
|
90
|
+
id: resolve('src/foo.json'),
|
|
91
|
+
content: '[/**/]',
|
|
92
|
+
origin_id: resolve('src/foo.gen.json.ts'),
|
|
93
|
+
format: true,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
test__to_gen_result('implicit empty file extension', () => {
|
|
99
|
+
assert.equal(to_gen_result(resolve('src/foo.gen..ts'), '[/**/]'), {
|
|
100
|
+
origin_id: resolve('src/foo.gen..ts'),
|
|
101
|
+
files: [
|
|
102
|
+
{
|
|
103
|
+
id: resolve('src/foo'),
|
|
104
|
+
content: '[/**/]',
|
|
105
|
+
origin_id: resolve('src/foo.gen..ts'),
|
|
106
|
+
format: true,
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
test__to_gen_result('implicit custom file extension with additional file name parts', () => {
|
|
112
|
+
assert.equal(to_gen_result(resolve('src/foo.bar.gen.json.ts'), { content: '[/**/]' }), {
|
|
113
|
+
origin_id: resolve('src/foo.bar.gen.json.ts'),
|
|
114
|
+
files: [
|
|
115
|
+
{
|
|
116
|
+
id: resolve('src/foo.bar.json'),
|
|
117
|
+
content: '[/**/]',
|
|
118
|
+
origin_id: resolve('src/foo.bar.gen.json.ts'),
|
|
119
|
+
format: true,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
test__to_gen_result('implicit custom file extension with many dots in between', () => {
|
|
125
|
+
assert.equal(to_gen_result(resolve('src/foo...gen.ts'), '[/**/]'), {
|
|
126
|
+
origin_id: resolve('src/foo...gen.ts'),
|
|
127
|
+
files: [
|
|
128
|
+
{
|
|
129
|
+
id: resolve('src/foo...ts'),
|
|
130
|
+
content: '[/**/]',
|
|
131
|
+
origin_id: resolve('src/foo...gen.ts'),
|
|
132
|
+
format: true,
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
test__to_gen_result('fail with two parts following the .gen. pattern in the file name', () => {
|
|
138
|
+
// This just ensures consistent file names - maybe loosen the restriction?
|
|
139
|
+
// You can still implicitly name files like this,
|
|
140
|
+
// but you have to move ".bar" before ".gen".
|
|
141
|
+
assert.throws(() => to_gen_result(resolve('src/foo.gen.bar.json.ts'), '/**/'));
|
|
142
|
+
});
|
|
143
|
+
test__to_gen_result('fail implicit file extension ending with a dot', () => {
|
|
144
|
+
// This just ensures consistent file names - maybe loosen the restriction?
|
|
145
|
+
// This one is more restrictive than the above,
|
|
146
|
+
// because to have a file ending with a dot
|
|
147
|
+
// you have to use an explicit file name.
|
|
148
|
+
assert.throws(() => to_gen_result(resolve('src/foo.gen...ts'), '[/**/]'));
|
|
149
|
+
});
|
|
150
|
+
test__to_gen_result('fail without a .gen. pattern in the file name', () => {
|
|
151
|
+
assert.throws(() => {
|
|
152
|
+
to_gen_result(resolve('src/foo.ts'), '/**/');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
test__to_gen_result('fail without a .gen. pattern in a file name that has multiple other patterns', () => {
|
|
156
|
+
assert.throws(() => {
|
|
157
|
+
to_gen_result(resolve('src/foo.bar.baz.ts'), '/**/');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
test__to_gen_result('fail with two .gen. patterns in the file name', () => {
|
|
161
|
+
assert.throws(() => to_gen_result(resolve('src/lib/gen.gen.ts'), '/**/'));
|
|
162
|
+
assert.throws(() => to_gen_result(resolve('src/foo.gen.gen.ts'), '/**/'));
|
|
163
|
+
assert.throws(() => to_gen_result(resolve('src/foo.gen.bar.gen.ts'), '/**/'));
|
|
164
|
+
assert.throws(() => to_gen_result(resolve('src/foo.gen.bar.gen.baz.ts'), '/**/'));
|
|
165
|
+
});
|
|
166
|
+
test__to_gen_result('explicit custom file extension', () => {
|
|
167
|
+
assert.equal(to_gen_result(origin_id, {
|
|
168
|
+
filename: 'foo.json',
|
|
169
|
+
content: '[/**/]',
|
|
170
|
+
}), {
|
|
171
|
+
origin_id,
|
|
172
|
+
files: [{ id: resolve('src/foo.json'), content: '[/**/]', origin_id, format: true }],
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
test__to_gen_result('explicit custom empty file extension', () => {
|
|
176
|
+
assert.equal(to_gen_result(origin_id, {
|
|
177
|
+
filename: 'foo',
|
|
178
|
+
content: '[/**/]',
|
|
179
|
+
}), {
|
|
180
|
+
origin_id,
|
|
181
|
+
files: [{ id: resolve('src/foo'), content: '[/**/]', origin_id, format: true }],
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
test__to_gen_result('explicit custom file extension ending with a dot', () => {
|
|
185
|
+
assert.equal(to_gen_result(origin_id, {
|
|
186
|
+
filename: 'foo.',
|
|
187
|
+
content: '[/**/]',
|
|
188
|
+
}), {
|
|
189
|
+
origin_id,
|
|
190
|
+
files: [{ id: resolve('src/foo.'), content: '[/**/]', origin_id, format: true }],
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
test__to_gen_result('simple array of raw files', () => {
|
|
194
|
+
assert.equal(to_gen_result(origin_id, [{ content: '/*1*/' }, { filename: 'foo2.ts', content: '/*2*/' }]), {
|
|
195
|
+
origin_id,
|
|
196
|
+
files: [
|
|
197
|
+
{ id: resolve('src/foo.ts'), content: '/*1*/', origin_id, format: true },
|
|
198
|
+
{ id: resolve('src/foo2.ts'), content: '/*2*/', origin_id, format: true },
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
test__to_gen_result('complex array of raw files', () => {
|
|
203
|
+
assert.equal(to_gen_result(origin_id, [
|
|
204
|
+
{ content: '/*1*/' },
|
|
205
|
+
{ filename: 'foo2.ts', content: '/*2*/' },
|
|
206
|
+
{ filename: 'foo3.ts', content: '/*3*/' },
|
|
207
|
+
{ filename: 'foo4.ts', content: '/*4*/' },
|
|
208
|
+
{ filename: 'foo5.json', content: '[/*5*/]' },
|
|
209
|
+
]), {
|
|
210
|
+
origin_id,
|
|
211
|
+
files: [
|
|
212
|
+
{ id: resolve('src/foo.ts'), content: '/*1*/', origin_id, format: true },
|
|
213
|
+
{ id: resolve('src/foo2.ts'), content: '/*2*/', origin_id, format: true },
|
|
214
|
+
{ id: resolve('src/foo3.ts'), content: '/*3*/', origin_id, format: true },
|
|
215
|
+
{ id: resolve('src/foo4.ts'), content: '/*4*/', origin_id, format: true },
|
|
216
|
+
{ id: resolve('src/foo5.json'), content: '[/*5*/]', origin_id, format: true },
|
|
217
|
+
],
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
test__to_gen_result('fail with duplicate names because of omissions', () => {
|
|
221
|
+
assert.throws(() => {
|
|
222
|
+
to_gen_result(origin_id, [{ content: '/*1*/' }, { content: '/*2*/' }]);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
test__to_gen_result('fail with duplicate explicit names', () => {
|
|
226
|
+
assert.throws(() => {
|
|
227
|
+
to_gen_result(origin_id, [
|
|
228
|
+
{ filename: 'foo.ts', content: '/*1*/' },
|
|
229
|
+
{ filename: 'foo.ts', content: '/*2*/' },
|
|
230
|
+
]);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
test__to_gen_result('fail with duplicate explicit and implicit names', () => {
|
|
234
|
+
assert.throws(() => {
|
|
235
|
+
to_gen_result(origin_id, [{ content: '/*1*/' }, { filename: 'foo.ts', content: '/*2*/' }]);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
test__to_gen_result.run();
|
|
239
|
+
/* test__to_gen_result */
|
|
@@ -0,0 +1,46 @@
|
|
|
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';
|
|
3
|
+
export declare const GEN_FILE_PATTERN_TEXT = "gen";
|
|
4
|
+
export declare const GEN_FILE_PATTERN: string;
|
|
5
|
+
export declare const is_gen_path: (path: string) => boolean;
|
|
6
|
+
export declare const GEN_SCHEMA_FILE_PATTERN_TEXT = "schema";
|
|
7
|
+
export declare const GEN_SCHEMA_FILE_PATTERN: string;
|
|
8
|
+
export declare const GEN_SCHEMA_PATH_SUFFIX: string;
|
|
9
|
+
export declare const GEN_SCHEMA_IDENTIFIER_SUFFIX = "Schema";
|
|
10
|
+
export type Gen_Module_Type = 'basic';
|
|
11
|
+
export type Gen_Module = Basic_Gen_Module | Schema_Gen_Module;
|
|
12
|
+
export interface Basic_Gen_Module {
|
|
13
|
+
gen: Gen;
|
|
14
|
+
}
|
|
15
|
+
export interface Schema_Gen_Module extends Basic_Gen_Module {
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export declare const to_gen_module_type: (_filename: string) => Gen_Module_Type;
|
|
19
|
+
export declare const gen_module_meta: Record<Gen_Module_Type, {
|
|
20
|
+
pattern: string;
|
|
21
|
+
text: string;
|
|
22
|
+
}>;
|
|
23
|
+
export declare const validate_gen_module: {
|
|
24
|
+
basic: (mod: Record<string, any>) => mod is Basic_Gen_Module;
|
|
25
|
+
schema: (mod: Record<string, any>) => mod is Schema_Gen_Module;
|
|
26
|
+
};
|
|
27
|
+
export type Gen_Module_Meta = Basic_Gen_Module_Meta;
|
|
28
|
+
export interface Basic_Gen_Module_Meta extends Module_Meta<Gen_Module> {
|
|
29
|
+
type: 'basic';
|
|
30
|
+
mod: Basic_Gen_Module;
|
|
31
|
+
}
|
|
32
|
+
export declare const load_gen_module: (id: string) => Promise<Load_Module_Result<Gen_Module_Meta>>;
|
|
33
|
+
export type Check_Gen_Module_Result = {
|
|
34
|
+
file: Gen_File;
|
|
35
|
+
existing_content: string;
|
|
36
|
+
is_new: false;
|
|
37
|
+
has_changed: boolean;
|
|
38
|
+
} | {
|
|
39
|
+
file: Gen_File;
|
|
40
|
+
existing_content: null;
|
|
41
|
+
is_new: true;
|
|
42
|
+
has_changed: true;
|
|
43
|
+
};
|
|
44
|
+
export declare const check_gen_modules: (gen_results: Gen_Results) => Promise<Check_Gen_Module_Result[]>;
|
|
45
|
+
export declare const check_gen_module: (file: Gen_File) => Promise<Check_Gen_Module_Result>;
|
|
46
|
+
export declare const find_gen_modules: (input_paths?: string[], extensions?: string[], root_dirs?: string[]) => Promise<Find_Modules_Result>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { load_module, find_modules, } from './modules.js';
|
|
3
|
+
import { get_possible_source_ids } from './input_path.js';
|
|
4
|
+
import { paths } from './paths.js';
|
|
5
|
+
import { search_fs } from './search_fs.js';
|
|
6
|
+
import { exists } from './fs.js';
|
|
7
|
+
export const GEN_FILE_PATTERN_TEXT = 'gen';
|
|
8
|
+
export const GEN_FILE_PATTERN = '.' + GEN_FILE_PATTERN_TEXT + '.';
|
|
9
|
+
export const is_gen_path = (path) => path.includes(GEN_FILE_PATTERN);
|
|
10
|
+
export const GEN_SCHEMA_FILE_PATTERN_TEXT = 'schema';
|
|
11
|
+
export const GEN_SCHEMA_FILE_PATTERN = '.' + GEN_SCHEMA_FILE_PATTERN_TEXT + '.';
|
|
12
|
+
export const GEN_SCHEMA_PATH_SUFFIX = GEN_SCHEMA_FILE_PATTERN + 'ts';
|
|
13
|
+
export const GEN_SCHEMA_IDENTIFIER_SUFFIX = 'Schema';
|
|
14
|
+
// TODO remove if not used, but we may generic stuff from Zod schemas or other things
|
|
15
|
+
export const to_gen_module_type = (_filename) => 'basic';
|
|
16
|
+
export const gen_module_meta = {
|
|
17
|
+
basic: { pattern: GEN_FILE_PATTERN, text: GEN_FILE_PATTERN_TEXT },
|
|
18
|
+
};
|
|
19
|
+
export const validate_gen_module = {
|
|
20
|
+
basic: (mod) => typeof mod?.gen === 'function',
|
|
21
|
+
schema: (mod) => !!mod,
|
|
22
|
+
};
|
|
23
|
+
export const load_gen_module = async (id) => {
|
|
24
|
+
const type = to_gen_module_type(id);
|
|
25
|
+
const result = await load_module(id, validate_gen_module[type]);
|
|
26
|
+
if (result.ok) {
|
|
27
|
+
result.mod.type = type;
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
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
|
+
export const find_gen_modules = (input_paths = [paths.source],
|
|
52
|
+
// TODO improve this API to allow config, maybe just a simple `gen` filter function, so the user could return a Rollup pluginutils filter,
|
|
53
|
+
// gets a little tricky with the `get_possible_source_ids` API usage, which would probably need to change
|
|
54
|
+
extensions = [GEN_FILE_PATTERN, GEN_SCHEMA_FILE_PATTERN], root_dirs = []) => find_modules(input_paths, (id) => search_fs(id, { filter: (path) => extensions.some((e) => path.includes(e)) }), (input_path) => get_possible_source_ids(input_path, extensions, root_dirs));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { test } from 'uvu';
|
|
2
|
+
import * as assert from 'uvu/assert';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { validate_gen_module, find_gen_modules } from './gen_module.js';
|
|
5
|
+
import { paths } from './paths.js';
|
|
6
|
+
test('basic minimal interface', () => {
|
|
7
|
+
assert.ok(validate_gen_module.basic({ gen: Function.prototype }));
|
|
8
|
+
});
|
|
9
|
+
test('basic invalid module', () => {
|
|
10
|
+
assert.ok(!validate_gen_module.basic({ gen: {} }));
|
|
11
|
+
assert.ok(!validate_gen_module.basic({ task: { run: {} } }));
|
|
12
|
+
assert.ok(!validate_gen_module.basic(undefined));
|
|
13
|
+
assert.ok(!validate_gen_module.basic(null));
|
|
14
|
+
assert.ok(!validate_gen_module.basic(false));
|
|
15
|
+
});
|
|
16
|
+
test('schema minimal interface', () => {
|
|
17
|
+
assert.ok(validate_gen_module.schema({}));
|
|
18
|
+
assert.ok(validate_gen_module.schema({ SomeSchema: { $id: '/schemas/SomeSchema' } }));
|
|
19
|
+
});
|
|
20
|
+
test('schema invalid module', () => {
|
|
21
|
+
assert.ok(!validate_gen_module.schema(undefined));
|
|
22
|
+
assert.ok(!validate_gen_module.schema(null));
|
|
23
|
+
assert.ok(!validate_gen_module.schema(false));
|
|
24
|
+
});
|
|
25
|
+
test('finds gen modules in a directory', async () => {
|
|
26
|
+
const find_gen_modules_result = await find_gen_modules([join(paths.lib, 'docs/')]);
|
|
27
|
+
assert.ok(find_gen_modules_result.ok);
|
|
28
|
+
assert.ok(find_gen_modules_result.source_id_path_data_by_input_path.size);
|
|
29
|
+
});
|
|
30
|
+
test.run();
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { Flavored } from '@ryanatkn/belt/types.js';
|
|
3
|
+
import type { SpawnOptions } from 'child_process';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export declare const Git_Origin: z.ZodString;
|
|
6
|
+
export type Git_Origin = Flavored<z.infer<typeof Git_Origin>, 'Git_Origin'>;
|
|
7
|
+
export declare const Git_Branch: z.ZodString;
|
|
8
|
+
export type Git_Branch = Flavored<z.infer<typeof Git_Branch>, 'Git_Branch'>;
|
|
9
|
+
/**
|
|
10
|
+
* Returns the current git branch name or throws if something goes wrong.
|
|
11
|
+
*/
|
|
12
|
+
export declare const git_current_branch_name: (options?: SpawnOptions) => Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* @returns a boolean indicating if the remote git branch exists
|
|
15
|
+
*/
|
|
16
|
+
export declare const git_remote_branch_exists: (origin?: Flavored<string, "Git_Origin">, branch?: any, options?: SpawnOptions) => Promise<boolean>;
|
|
17
|
+
/**
|
|
18
|
+
* @returns a boolean indicating if the local git branch exists
|
|
19
|
+
*/
|
|
20
|
+
export declare const git_local_branch_exists: (branch: Flavored<string, "Git_Branch">, options?: SpawnOptions) => Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* TODO make this return an enum and separate the text into a different function
|
|
23
|
+
* @returns an error message if the git workspace has any unstaged or uncommitted changes, or `null` if it's clean
|
|
24
|
+
*/
|
|
25
|
+
export declare const git_check_clean_workspace: (options?: SpawnOptions) => Promise<string | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Calls `git fetch` and throws if anything goes wrong.
|
|
28
|
+
*/
|
|
29
|
+
export declare const git_fetch: (origin?: Flavored<string, "Git_Origin">, branch?: any, options?: SpawnOptions) => Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Calls `git checkout` and throws if anything goes wrong.
|
|
32
|
+
* @returns the previous branch name, if it changed
|
|
33
|
+
*/
|
|
34
|
+
export declare const git_checkout: (branch: Flavored<string, "Git_Branch">, options?: SpawnOptions) => Promise<Git_Branch | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Calls `git pull` and throws if anything goes wrong.
|
|
37
|
+
*/
|
|
38
|
+
export declare const git_pull: (origin?: Flavored<string, "Git_Origin">, branch?: any, options?: SpawnOptions) => Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Calls `git push` and throws if anything goes wrong.
|
|
41
|
+
*/
|
|
42
|
+
export declare const git_push: (origin: Flavored<string, "Git_Origin">, branch: Flavored<string, "Git_Branch">, options?: SpawnOptions) => Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Calls `git push` and throws if anything goes wrong.
|
|
45
|
+
*/
|
|
46
|
+
export declare const git_push_to_create: (origin?: Flavored<string, "Git_Origin">, branch?: any, options?: SpawnOptions) => Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Deletes a branch locally and throws if anything goes wrong.
|
|
49
|
+
*/
|
|
50
|
+
export declare const git_delete_local_branch: (branch: Flavored<string, "Git_Branch">, options?: SpawnOptions) => Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Deletes a branch remotely and throws if anything goes wrong.
|
|
53
|
+
*/
|
|
54
|
+
export declare const git_delete_remote_branch: (origin: Flavored<string, "Git_Origin">, branch: Flavored<string, "Git_Branch">, options?: SpawnOptions) => Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Resets the `target` branch back to its first commit both locally and remotely.
|
|
57
|
+
*/
|
|
58
|
+
export declare const git_reset_branch_to_first_commit: (origin: Flavored<string, "Git_Origin">, branch: Flavored<string, "Git_Branch">, options?: SpawnOptions) => Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Returns the branch's latest commit hash or throws if something goes wrong.
|
|
61
|
+
*/
|
|
62
|
+
export declare const git_current_commit_hash: (branch?: string, options?: SpawnOptions) => Promise<string | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Returns the hash of the current branch's first commit or throws if something goes wrong.
|
|
65
|
+
*/
|
|
66
|
+
export declare const git_current_branch_first_commit_hash: (options?: SpawnOptions) => Promise<string>;
|
|
67
|
+
/**
|
|
68
|
+
* Returns the global git config setting for `pull.rebase`.
|
|
69
|
+
* Gro is currently written to expect `true`,
|
|
70
|
+
* but the restriction could be loosened with additional work.
|
|
71
|
+
*/
|
|
72
|
+
export declare const git_check_setting_pull_rebase: (options?: SpawnOptions) => Promise<boolean>;
|
|
73
|
+
/**
|
|
74
|
+
* Clones a branch locally to another directory and updates the origin to match the source.
|
|
75
|
+
*/
|
|
76
|
+
export declare const git_clone_locally: (origin: Flavored<string, "Git_Origin">, branch: Flavored<string, "Git_Branch">, source_dir: string, target_dir: string, options?: SpawnOptions) => Promise<void>;
|