@ryanatkn/gro 0.129.4 → 0.129.6
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/dist/package.js +3 -3
- package/package.json +3 -2
- package/src/lib/args.test.ts +59 -0
- package/src/lib/args.ts +169 -0
- package/src/lib/build.task.ts +37 -0
- package/src/lib/changelog.test.ts +138 -0
- package/src/lib/changelog.ts +69 -0
- package/src/lib/changeset.task.ts +206 -0
- package/src/lib/changeset_helpers.ts +13 -0
- package/src/lib/check.task.ts +90 -0
- package/src/lib/clean.task.ts +46 -0
- package/src/lib/clean_fs.ts +54 -0
- package/src/lib/cli.ts +97 -0
- package/src/lib/commit.task.ts +33 -0
- package/src/lib/config.test.ts +71 -0
- package/src/lib/config.ts +161 -0
- package/src/lib/deploy.task.ts +243 -0
- package/src/lib/dev.task.ts +43 -0
- package/src/lib/docs/README.gen.md.ts +63 -0
- package/src/lib/docs/README.md +20 -0
- package/src/lib/docs/build.md +41 -0
- package/src/lib/docs/config.md +213 -0
- package/src/lib/docs/deploy.md +32 -0
- package/src/lib/docs/dev.md +40 -0
- package/src/lib/docs/gen.md +269 -0
- package/src/lib/docs/gro_plugin_sveltekit_app.md +113 -0
- package/src/lib/docs/package_json.md +33 -0
- package/src/lib/docs/plugin.md +50 -0
- package/src/lib/docs/publish.md +137 -0
- package/src/lib/docs/task.md +391 -0
- package/src/lib/docs/tasks.gen.md.ts +90 -0
- package/src/lib/docs/tasks.md +37 -0
- package/src/lib/docs/test.md +52 -0
- package/src/lib/env.ts +75 -0
- package/src/lib/esbuild_helpers.ts +50 -0
- package/src/lib/esbuild_plugin_external_worker.ts +92 -0
- package/src/lib/esbuild_plugin_svelte.test.ts +88 -0
- package/src/lib/esbuild_plugin_svelte.ts +108 -0
- package/src/lib/esbuild_plugin_sveltekit_local_imports.ts +31 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_alias.ts +25 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_app.ts +41 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_env.ts +46 -0
- package/src/lib/format.task.ts +30 -0
- package/src/lib/format_directory.ts +55 -0
- package/src/lib/format_file.test.ts +20 -0
- package/src/lib/format_file.ts +49 -0
- package/src/lib/fs.ts +18 -0
- package/src/lib/gen.task.ts +134 -0
- package/src/lib/gen.test.ts +306 -0
- package/src/lib/gen.ts +360 -0
- package/src/lib/git.test.ts +34 -0
- package/src/lib/git.ts +297 -0
- package/src/lib/github.ts +46 -0
- package/src/lib/gro.config.default.ts +34 -0
- package/src/lib/gro.ts +25 -0
- package/src/lib/gro_helpers.ts +101 -0
- package/src/lib/gro_plugin_gen.ts +95 -0
- package/src/lib/gro_plugin_server.ts +288 -0
- package/src/lib/gro_plugin_sveltekit_app.ts +257 -0
- package/src/lib/gro_plugin_sveltekit_library.ts +74 -0
- package/src/lib/hash.test.ts +33 -0
- package/src/lib/hash.ts +19 -0
- package/src/lib/index.ts +4 -0
- package/src/lib/input_path.test.ts +230 -0
- package/src/lib/input_path.ts +255 -0
- package/src/lib/invoke.ts +27 -0
- package/src/lib/invoke_task.ts +116 -0
- package/src/lib/lint.task.ts +38 -0
- package/src/lib/loader.test.ts +49 -0
- package/src/lib/loader.ts +226 -0
- package/src/lib/module.test.ts +46 -0
- package/src/lib/module.ts +13 -0
- package/src/lib/modules.test.ts +63 -0
- package/src/lib/modules.ts +112 -0
- package/src/lib/package.gen.ts +33 -0
- package/src/lib/package.ts +998 -0
- package/src/lib/package_json.test.ts +101 -0
- package/src/lib/package_json.ts +330 -0
- package/src/lib/package_meta.ts +86 -0
- package/src/lib/path.ts +23 -0
- package/src/lib/path_constants.ts +30 -0
- package/src/lib/paths.test.ts +77 -0
- package/src/lib/paths.ts +101 -0
- package/src/lib/plugin.test.ts +57 -0
- package/src/lib/plugin.ts +113 -0
- package/src/lib/publish.task.ts +194 -0
- package/src/lib/register.ts +3 -0
- package/src/lib/reinstall.task.ts +42 -0
- package/src/lib/release.task.ts +21 -0
- package/src/lib/resolve.task.ts +43 -0
- package/src/lib/resolve_node_specifier.test.ts +31 -0
- package/src/lib/resolve_node_specifier.ts +55 -0
- package/src/lib/resolve_specifier.test.ts +76 -0
- package/src/lib/resolve_specifier.ts +61 -0
- package/src/lib/run.task.ts +41 -0
- package/src/lib/run_gen.test.ts +196 -0
- package/src/lib/run_gen.ts +95 -0
- package/src/lib/run_task.test.ts +86 -0
- package/src/lib/run_task.ts +75 -0
- package/src/lib/search_fs.test.ts +56 -0
- package/src/lib/search_fs.ts +93 -0
- package/src/lib/src_json.test.ts +49 -0
- package/src/lib/src_json.ts +153 -0
- package/src/lib/svelte_helpers.ts +2 -0
- package/src/lib/sveltekit_config.ts +101 -0
- package/src/lib/sveltekit_config_global.ts +6 -0
- package/src/lib/sveltekit_helpers.ts +132 -0
- package/src/lib/sveltekit_shim_app.ts +42 -0
- package/src/lib/sveltekit_shim_app_environment.ts +14 -0
- package/src/lib/sveltekit_shim_app_forms.ts +20 -0
- package/src/lib/sveltekit_shim_app_navigation.ts +23 -0
- package/src/lib/sveltekit_shim_app_paths.ts +16 -0
- package/src/lib/sveltekit_shim_app_stores.ts +25 -0
- package/src/lib/sveltekit_shim_env.ts +45 -0
- package/src/lib/sync.task.ts +47 -0
- package/src/lib/task.test.ts +84 -0
- package/src/lib/task.ts +235 -0
- package/src/lib/task_logging.ts +180 -0
- package/src/lib/test.task.ts +50 -0
- package/src/lib/throttle.test.ts +52 -0
- package/src/lib/throttle.ts +63 -0
- package/src/lib/typecheck.task.ts +57 -0
- package/src/lib/upgrade.task.ts +108 -0
- package/src/lib/watch_dir.ts +88 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {wait} from '@ryanatkn/belt/async.js';
|
|
2
|
+
|
|
3
|
+
// TODO maybe support non-promise return values?
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Throttles calls to a callback that returns a void promise.
|
|
7
|
+
* Immediately invokes the callback on the first call.
|
|
8
|
+
* If the throttled function is called while the promise is already pending,
|
|
9
|
+
* the call is queued to run after the pending promise completes plus `delay`,
|
|
10
|
+
* and only the last call is invoked.
|
|
11
|
+
* In other words, all calls and their args are discarded
|
|
12
|
+
* during the pending window except for the most recent.
|
|
13
|
+
* Unlike debouncing, this calls the throttled callback
|
|
14
|
+
* both on the leading and trailing edges of the delay window.
|
|
15
|
+
* It also differs from a queue where every call to the throttled callback eventually runs.
|
|
16
|
+
* @param cb - any function that returns a void promise
|
|
17
|
+
* @param delay - delay this many milliseconds between the pending call finishing and the next starting
|
|
18
|
+
* @returns same as `cb`
|
|
19
|
+
*/
|
|
20
|
+
export const throttle = <T extends (...args: any[]) => Promise<void>>(cb: T, delay = 0): T => {
|
|
21
|
+
let pending_promise: Promise<void> | null = null;
|
|
22
|
+
let next_args: any[] | null = null;
|
|
23
|
+
let next_promise: Promise<void> | null = null;
|
|
24
|
+
let next_promise_resolve: ((value: any) => void) | null = null;
|
|
25
|
+
|
|
26
|
+
const defer = (args: any[]): Promise<void> => {
|
|
27
|
+
next_args = args;
|
|
28
|
+
if (!next_promise) {
|
|
29
|
+
next_promise = new Promise((resolve) => {
|
|
30
|
+
next_promise_resolve = resolve;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return next_promise;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const flush = async (): Promise<void> => {
|
|
37
|
+
if (!next_promise_resolve) return;
|
|
38
|
+
const result = await call(next_args!);
|
|
39
|
+
next_args = null;
|
|
40
|
+
next_promise = null;
|
|
41
|
+
const resolve = next_promise_resolve;
|
|
42
|
+
next_promise_resolve = null;
|
|
43
|
+
resolve(result); // resolve last to prevent synchronous call issues
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const call = (args: any[]): Promise<any> => {
|
|
47
|
+
pending_promise = cb(...args);
|
|
48
|
+
void pending_promise.then(async () => {
|
|
49
|
+
await wait(delay);
|
|
50
|
+
pending_promise = null;
|
|
51
|
+
await flush();
|
|
52
|
+
});
|
|
53
|
+
return pending_promise;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return ((...args) => {
|
|
57
|
+
if (pending_promise) {
|
|
58
|
+
return defer(args);
|
|
59
|
+
} else {
|
|
60
|
+
return call(args);
|
|
61
|
+
}
|
|
62
|
+
}) as T;
|
|
63
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {print_spawn_result} from '@ryanatkn/belt/process.js';
|
|
2
|
+
import {z} from 'zod';
|
|
3
|
+
|
|
4
|
+
import {Task_Error, type Task} from './task.js';
|
|
5
|
+
import {serialize_args, to_forwarded_args} from './args.js';
|
|
6
|
+
import {find_cli, spawn_cli} from './cli.js';
|
|
7
|
+
import {SVELTE_CHECK_CLI, sveltekit_sync} from './sveltekit_helpers.js';
|
|
8
|
+
|
|
9
|
+
export const Args = z
|
|
10
|
+
.object({
|
|
11
|
+
svelte_check_cli: z
|
|
12
|
+
.string({description: 'the svelte-check CLI to use'})
|
|
13
|
+
.default(SVELTE_CHECK_CLI),
|
|
14
|
+
typescript_cli: z
|
|
15
|
+
.string({description: 'the TypeScript CLI to use as a fallback to svelte-check'})
|
|
16
|
+
.default('tsc'),
|
|
17
|
+
})
|
|
18
|
+
.strict();
|
|
19
|
+
export type Args = z.infer<typeof Args>;
|
|
20
|
+
|
|
21
|
+
export const task: Task<Args> = {
|
|
22
|
+
summary: 'run tsc on the project without emitting any files',
|
|
23
|
+
Args,
|
|
24
|
+
run: async ({args, log}): Promise<void> => {
|
|
25
|
+
const {svelte_check_cli, typescript_cli} = args;
|
|
26
|
+
|
|
27
|
+
await sveltekit_sync();
|
|
28
|
+
|
|
29
|
+
// Prefer svelte-check if available.
|
|
30
|
+
const found_svelte_check_cli = find_cli(svelte_check_cli);
|
|
31
|
+
if (found_svelte_check_cli) {
|
|
32
|
+
const serialized = serialize_args(to_forwarded_args(svelte_check_cli));
|
|
33
|
+
const svelte_check_result = await spawn_cli(found_svelte_check_cli, serialized, log);
|
|
34
|
+
if (!svelte_check_result?.ok) {
|
|
35
|
+
throw new Task_Error(`Failed to typecheck. ${print_spawn_result(svelte_check_result!)}`);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Fall back to tsc.
|
|
41
|
+
const found_typescript_cli = find_cli(typescript_cli);
|
|
42
|
+
if (found_typescript_cli) {
|
|
43
|
+
const forwarded = to_forwarded_args(typescript_cli);
|
|
44
|
+
if (!forwarded.noEmit) forwarded.noEmit = true;
|
|
45
|
+
const serialized = serialize_args(forwarded);
|
|
46
|
+
const svelte_check_result = await spawn_cli(found_typescript_cli, serialized, log);
|
|
47
|
+
if (!svelte_check_result?.ok) {
|
|
48
|
+
throw new Task_Error(`Failed to typecheck. ${print_spawn_result(svelte_check_result!)}`);
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
throw new Task_Error(
|
|
54
|
+
`Failed to typecheck because neither \`${svelte_check_cli}\` nor \`${typescript_cli}\` was found`,
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {spawn} from '@ryanatkn/belt/process.js';
|
|
2
|
+
import {z} from 'zod';
|
|
3
|
+
|
|
4
|
+
import {Task_Error, type Task} from './task.js';
|
|
5
|
+
import {load_package_json, type Package_Json} from './package_json.js';
|
|
6
|
+
import {Git_Origin, git_pull} from './git.js';
|
|
7
|
+
import {spawn_cli} from './cli.js';
|
|
8
|
+
|
|
9
|
+
export const Args = z
|
|
10
|
+
.object({
|
|
11
|
+
_: z.array(z.string(), {description: 'names of deps to exclude from the upgrade'}).default([]),
|
|
12
|
+
only: z
|
|
13
|
+
.union([z.string(), z.array(z.string())], {
|
|
14
|
+
description: 'names of deps to include in the upgrade',
|
|
15
|
+
})
|
|
16
|
+
.default([])
|
|
17
|
+
.transform((v) => (Array.isArray(v) ? v : [v])),
|
|
18
|
+
origin: Git_Origin.describe('git origin to deploy to').default('origin'),
|
|
19
|
+
force: z.boolean({description: 'if true, print out the planned upgrades'}).default(false),
|
|
20
|
+
pull: z.boolean({description: 'dual of no-pull'}).default(true),
|
|
21
|
+
'no-pull': z.boolean({description: 'opt out of git pull'}).default(false),
|
|
22
|
+
dry: z.boolean({description: 'if true, print out the planned upgrades'}).default(false),
|
|
23
|
+
})
|
|
24
|
+
.strict();
|
|
25
|
+
export type Args = z.infer<typeof Args>;
|
|
26
|
+
|
|
27
|
+
export const task: Task<Args> = {
|
|
28
|
+
summary: 'upgrade deps',
|
|
29
|
+
Args,
|
|
30
|
+
run: async ({args, log}): Promise<void> => {
|
|
31
|
+
const {_, only, origin, force, pull, dry} = args;
|
|
32
|
+
|
|
33
|
+
if (_.length && only.length) {
|
|
34
|
+
throw new Task_Error('Cannot call `gro upgrade` with both rest args and --only.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// TODO maybe a different task that pulls and does other things, like `gro ready`
|
|
38
|
+
if (pull) {
|
|
39
|
+
await git_pull(origin);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const package_json = load_package_json();
|
|
43
|
+
|
|
44
|
+
const all_deps = to_deps(package_json);
|
|
45
|
+
|
|
46
|
+
const deps = only.length
|
|
47
|
+
? all_deps.filter((d) => only.includes(d.key))
|
|
48
|
+
: all_deps.filter((d) => !_.includes(d.key));
|
|
49
|
+
|
|
50
|
+
if (only.length && only.length !== deps.length) {
|
|
51
|
+
throw new Task_Error(
|
|
52
|
+
`Some deps to upgrade were not found: ${only.filter((o) => !deps.find((d) => d.key === o)).join(', ')}`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const upgrade_items = to_upgrade_items(deps);
|
|
57
|
+
|
|
58
|
+
log.info(`upgrading:`, upgrade_items.join(' '));
|
|
59
|
+
|
|
60
|
+
const install_args = ['install'].concat(upgrade_items);
|
|
61
|
+
|
|
62
|
+
if (dry) {
|
|
63
|
+
install_args.push('--dry-run');
|
|
64
|
+
log.info(`deps`, deps);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (force) {
|
|
68
|
+
install_args.push('--force');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await spawn('npm', install_args);
|
|
72
|
+
|
|
73
|
+
// Sync in a new process to pick up any changes after installing, avoiding some errors.
|
|
74
|
+
await spawn_cli('gro', ['sync']);
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
interface Dep {
|
|
79
|
+
key: string;
|
|
80
|
+
value: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const to_deps = (package_json: Package_Json): Dep[] => {
|
|
84
|
+
const prod_deps: Dep[] = package_json.dependencies
|
|
85
|
+
? Object.entries(package_json.dependencies).map(([key, value]) => ({key, value}))
|
|
86
|
+
: [];
|
|
87
|
+
const dev_deps: Dep[] = package_json.devDependencies
|
|
88
|
+
? Object.entries(package_json.devDependencies).map(([key, value]) => ({key, value}))
|
|
89
|
+
: [];
|
|
90
|
+
return prod_deps.concat(dev_deps);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const EXACT_VERSION_MATCHER = /^..*@.+/u;
|
|
94
|
+
const CUSTOM_TAG_MATCHER = /^[\^~><=]*.+-(.+)/u;
|
|
95
|
+
|
|
96
|
+
// TODO hacky and limited
|
|
97
|
+
// TODO probably want to pass through exact deps as well, e.g. @foo/bar@1
|
|
98
|
+
const to_upgrade_items = (deps: Dep[]): string[] =>
|
|
99
|
+
deps.map((dep) => {
|
|
100
|
+
if (EXACT_VERSION_MATCHER.test(dep.key)) {
|
|
101
|
+
return dep.key;
|
|
102
|
+
}
|
|
103
|
+
const custom_tag_matches = CUSTOM_TAG_MATCHER.exec(dep.value);
|
|
104
|
+
if (custom_tag_matches) {
|
|
105
|
+
return dep.key + '@' + custom_tag_matches[1].split('.')[0]; // I tried adding `\.?` to the end but doesn't work and I'm being lazy so I'm just splitting
|
|
106
|
+
}
|
|
107
|
+
return dep.key + '@latest';
|
|
108
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import chokidar, {type WatchOptions} from 'chokidar';
|
|
2
|
+
import {relative} from 'node:path';
|
|
3
|
+
|
|
4
|
+
import type {Path_Filter} from './path.js';
|
|
5
|
+
import {statSync} from 'node:fs';
|
|
6
|
+
|
|
7
|
+
// TODO pretty hacky
|
|
8
|
+
|
|
9
|
+
export interface Watch_Node_Fs {
|
|
10
|
+
init: () => Promise<void>;
|
|
11
|
+
close: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Watcher_Change {
|
|
15
|
+
type: Watcher_Change_Type;
|
|
16
|
+
path: string;
|
|
17
|
+
is_directory: boolean;
|
|
18
|
+
}
|
|
19
|
+
export type Watcher_Change_Type = 'create' | 'update' | 'delete';
|
|
20
|
+
export type Watcher_Change_Callback = (change: Watcher_Change) => void;
|
|
21
|
+
|
|
22
|
+
export interface Options {
|
|
23
|
+
dir: string;
|
|
24
|
+
on_change: Watcher_Change_Callback;
|
|
25
|
+
filter?: Path_Filter | null | undefined;
|
|
26
|
+
chokidar?: WatchOptions;
|
|
27
|
+
/**
|
|
28
|
+
* When `false`, returns the `path` relative to `dir`.
|
|
29
|
+
* @default true
|
|
30
|
+
*/
|
|
31
|
+
absolute?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Watch for changes on the filesystem using chokidar.
|
|
36
|
+
*/
|
|
37
|
+
export const watch_dir = ({
|
|
38
|
+
dir,
|
|
39
|
+
on_change,
|
|
40
|
+
filter,
|
|
41
|
+
absolute = true,
|
|
42
|
+
chokidar: chokidar_options,
|
|
43
|
+
}: Options): Watch_Node_Fs => {
|
|
44
|
+
let watcher: chokidar.FSWatcher | undefined;
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
init: async () => {
|
|
48
|
+
watcher = chokidar.watch(dir, chokidar_options);
|
|
49
|
+
watcher.on('add', (path, s) => {
|
|
50
|
+
const stats = s ?? statSync(path);
|
|
51
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
52
|
+
if (filter && !filter(final_path, stats.isDirectory())) return;
|
|
53
|
+
on_change({type: 'create', path: final_path, is_directory: stats.isDirectory()});
|
|
54
|
+
});
|
|
55
|
+
watcher.on('addDir', (path, s) => {
|
|
56
|
+
const stats = s ?? statSync(path);
|
|
57
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
58
|
+
if (filter && !filter(final_path, stats.isDirectory())) return;
|
|
59
|
+
on_change({type: 'create', path: final_path, is_directory: stats.isDirectory()});
|
|
60
|
+
});
|
|
61
|
+
watcher.on('change', (path, s) => {
|
|
62
|
+
const stats = s ?? statSync(path);
|
|
63
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
64
|
+
if (filter && !filter(final_path, stats.isDirectory())) return;
|
|
65
|
+
on_change({type: 'update', path: final_path, is_directory: stats.isDirectory()});
|
|
66
|
+
});
|
|
67
|
+
watcher.on('unlink', (path) => {
|
|
68
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
69
|
+
if (filter && !filter(final_path, false)) return;
|
|
70
|
+
on_change({type: 'delete', path: final_path, is_directory: false});
|
|
71
|
+
});
|
|
72
|
+
watcher.on('unlinkDir', (path) => {
|
|
73
|
+
const final_path = absolute ? path : relative(dir, path);
|
|
74
|
+
if (filter && !filter(final_path, true)) return;
|
|
75
|
+
on_change({type: 'delete', path: final_path, is_directory: true});
|
|
76
|
+
});
|
|
77
|
+
// wait until ready
|
|
78
|
+
let resolve: any;
|
|
79
|
+
const promise = new Promise((r) => (resolve = r));
|
|
80
|
+
watcher.once('ready', () => resolve());
|
|
81
|
+
await promise;
|
|
82
|
+
},
|
|
83
|
+
close: async () => {
|
|
84
|
+
if (!watcher) return;
|
|
85
|
+
await watcher.close();
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
};
|