@ryanatkn/gro 0.118.0 → 0.119.1
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/README.md +6 -4
- package/dist/build.task.d.ts +3 -0
- package/dist/build.task.js +5 -1
- package/dist/changeset.task.d.ts +2 -2
- package/dist/changeset.task.js +9 -5
- package/dist/check.task.js +1 -1
- package/dist/deploy.task.d.ts +0 -6
- package/dist/deploy.task.js +2 -7
- package/dist/dev.task.d.ts +2 -2
- package/dist/docs/gen.md +11 -0
- package/dist/docs/publish.md +1 -8
- package/dist/docs/task.md +7 -0
- package/dist/docs/tasks.md +1 -0
- package/dist/format_directory.d.ts +8 -2
- package/dist/format_directory.js +15 -10
- package/dist/gen.d.ts +14 -0
- package/dist/gen.js +45 -0
- package/dist/gen.task.js +17 -17
- package/dist/gen_module.d.ts +1 -14
- package/dist/gen_module.js +0 -22
- package/dist/git.d.ts +5 -0
- package/dist/git.js +15 -0
- package/dist/git.test.js +4 -1
- package/dist/gro.config.default.js +5 -9
- package/dist/gro_plugin_gen.js +1 -1
- package/dist/gro_plugin_server.d.ts +4 -1
- package/dist/gro_plugin_server.js +6 -1
- package/dist/gro_plugin_sveltekit_library.js +9 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -1
- package/dist/invoke.js +2 -0
- package/dist/invoke_task.d.ts +1 -1
- package/dist/invoke_task.js +1 -1
- package/dist/package.d.ts +11 -0
- package/dist/package.js +26 -8
- package/dist/package_json.js +1 -1
- package/dist/path_constants.d.ts +1 -0
- package/dist/path_constants.js +1 -0
- package/dist/publish.task.d.ts +9 -6
- package/dist/publish.task.js +25 -13
- package/dist/reinstall.task.d.ts +5 -0
- package/dist/reinstall.task.js +32 -0
- package/dist/release.task.js +4 -5
- package/dist/run.task.js +1 -1
- package/dist/run_task.js +1 -1
- package/dist/sveltekit_helpers.d.ts +15 -2
- package/dist/sveltekit_helpers.js +48 -6
- package/dist/sync.task.d.ts +0 -1
- package/dist/sync.task.js +2 -11
- package/dist/task.js +11 -7
- package/dist/task.test.js +6 -0
- package/dist/task_logging.js +25 -11
- package/dist/typecheck.task.js +1 -1
- package/dist/upgrade.task.d.ts +4 -1
- package/dist/upgrade.task.js +30 -5
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
> task runner and toolkit extending SvelteKit 🌰 generate, run, optimize
|
|
6
6
|
|
|
7
|
-
[gro.ryanatkn.com](https://gro.ryanatkn.com/)
|
|
8
|
-
|
|
9
7
|
[`npm i -D @ryanatkn/gro`](https://www.npmjs.com/package/@ryanatkn/gro)
|
|
10
8
|
|
|
11
|
-
[Windows won't be supported](https://github.com/ryanatkn/gro/issues/319), I chose Bash instead
|
|
9
|
+
[Windows won't be supported](https://github.com/ryanatkn/gro/issues/319), I chose Bash instead.
|
|
10
|
+
|
|
11
|
+
Feel free to open issues with anything you'd like to discuss or report.
|
|
12
|
+
I also run [a Discord community](https://discord.gg/YU5tyeK72X) that includes channels for Gro.
|
|
12
13
|
|
|
13
14
|
## about
|
|
14
15
|
|
|
@@ -106,7 +107,7 @@ gro # prints available tasks - defers to any local gro installation
|
|
|
106
107
|
Run a task: gro [name]
|
|
107
108
|
View help: gro [name] --help
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
18 tasks in gro:
|
|
110
111
|
|
|
111
112
|
build build the project
|
|
112
113
|
changeset call changeset with gro patterns
|
|
@@ -119,6 +120,7 @@ format format source files
|
|
|
119
120
|
gen run code generation scripts
|
|
120
121
|
lint run eslint
|
|
121
122
|
publish bump version, publish to npm, and git push
|
|
123
|
+
reinstall refreshes package-lock.json with the latest and cleanest deps
|
|
122
124
|
release publish and deploy
|
|
123
125
|
run execute a file with the loader, like `node` but works for TypeScript
|
|
124
126
|
sync run `gro gen`, update `package.json`, and optionally `npm i` to sync up
|
package/dist/build.task.d.ts
CHANGED
|
@@ -2,10 +2,13 @@ import { z } from 'zod';
|
|
|
2
2
|
import type { Task } from './task.js';
|
|
3
3
|
export declare const Args: z.ZodObject<{
|
|
4
4
|
install: z.ZodDefault<z.ZodBoolean>;
|
|
5
|
+
'no-install': z.ZodDefault<z.ZodBoolean>;
|
|
5
6
|
}, "strict", z.ZodTypeAny, {
|
|
6
7
|
install: boolean;
|
|
8
|
+
'no-install': boolean;
|
|
7
9
|
}, {
|
|
8
10
|
install?: boolean | undefined;
|
|
11
|
+
'no-install'?: boolean | undefined;
|
|
9
12
|
}>;
|
|
10
13
|
export type Args = z.infer<typeof Args>;
|
|
11
14
|
export declare const task: Task<Args>;
|
package/dist/build.task.js
CHANGED
|
@@ -3,7 +3,10 @@ import { Plugins } from './plugin.js';
|
|
|
3
3
|
import { clean_fs } from './clean_fs.js';
|
|
4
4
|
export const Args = z
|
|
5
5
|
.object({
|
|
6
|
-
install: z.boolean({ description: '
|
|
6
|
+
install: z.boolean({ description: 'dual of no-install' }).default(true),
|
|
7
|
+
'no-install': z
|
|
8
|
+
.boolean({ description: 'opt out of npm installing before building' })
|
|
9
|
+
.default(false),
|
|
7
10
|
})
|
|
8
11
|
.strict();
|
|
9
12
|
export const task = {
|
|
@@ -12,6 +15,7 @@ export const task = {
|
|
|
12
15
|
run: async (ctx) => {
|
|
13
16
|
const { args, invoke_task } = ctx;
|
|
14
17
|
const { install } = args;
|
|
18
|
+
// By default `gro build` installs, opposite of `gro sync`, so that arg needs special handling.
|
|
15
19
|
await invoke_task('sync', { install });
|
|
16
20
|
// TODO possibly detect if the git workspace is clean, and ask for confirmation if not,
|
|
17
21
|
// because we're not doing things like `gro gen` here because that's a dev/CI concern
|
package/dist/changeset.task.d.ts
CHANGED
|
@@ -19,22 +19,22 @@ export declare const Args: z.ZodObject<{
|
|
|
19
19
|
_: string[];
|
|
20
20
|
dir: string;
|
|
21
21
|
install: boolean;
|
|
22
|
+
'no-install': boolean;
|
|
22
23
|
origin: string & z.BRAND<"Git_Origin">;
|
|
23
24
|
minor: boolean;
|
|
24
25
|
major: boolean;
|
|
25
26
|
changelog: string;
|
|
26
|
-
'no-install': boolean;
|
|
27
27
|
access?: "public" | "restricted" | undefined;
|
|
28
28
|
}, {
|
|
29
29
|
_?: string[] | undefined;
|
|
30
30
|
dir?: string | undefined;
|
|
31
31
|
install?: boolean | undefined;
|
|
32
|
+
'no-install'?: boolean | undefined;
|
|
32
33
|
origin?: string | undefined;
|
|
33
34
|
minor?: boolean | undefined;
|
|
34
35
|
major?: boolean | undefined;
|
|
35
36
|
access?: "public" | "restricted" | undefined;
|
|
36
37
|
changelog?: string | undefined;
|
|
37
|
-
'no-install'?: boolean | undefined;
|
|
38
38
|
}>;
|
|
39
39
|
export type Args = z.infer<typeof Args>;
|
|
40
40
|
/**
|
package/dist/changeset.task.js
CHANGED
|
@@ -8,7 +8,7 @@ import { Task_Error } from './task.js';
|
|
|
8
8
|
import { exists } from './fs.js';
|
|
9
9
|
import { load_package_json } from './package_json.js';
|
|
10
10
|
import { find_cli, spawn_cli } from './cli.js';
|
|
11
|
-
import { Git_Origin, git_push_to_create } from './git.js';
|
|
11
|
+
import { Git_Origin, git_check_fully_staged_workspace, git_push_to_create } from './git.js';
|
|
12
12
|
import { has_sveltekit_library } from './sveltekit_helpers.js';
|
|
13
13
|
const RESTRICTED_ACCESS = 'restricted';
|
|
14
14
|
const PUBLIC_ACCESS = 'public';
|
|
@@ -62,8 +62,9 @@ export const task = {
|
|
|
62
62
|
throw new Task_Error('changeset command not found: install @changesets/cli locally or globally');
|
|
63
63
|
}
|
|
64
64
|
const package_json = await load_package_json();
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const has_sveltekit_library_result = await has_sveltekit_library(package_json);
|
|
66
|
+
if (!has_sveltekit_library_result.ok) {
|
|
67
|
+
throw new Task_Error('Failed to find SvelteKit library: ' + has_sveltekit_library_result.message);
|
|
67
68
|
}
|
|
68
69
|
const path = join(dir, 'config.json');
|
|
69
70
|
const inited = await exists(path);
|
|
@@ -85,14 +86,17 @@ export const task = {
|
|
|
85
86
|
await spawn('npm', ['i', '-D', changelog]);
|
|
86
87
|
}
|
|
87
88
|
}
|
|
89
|
+
// TODO small problem here where generated files don't get committed
|
|
88
90
|
await invoke_task('sync'); // after the `npm i` above, and in all cases
|
|
89
91
|
if (message) {
|
|
90
92
|
// TODO see the helper below, simplify this to CLI flags when support is added to Changesets
|
|
91
93
|
const changeset_adder = await create_changeset_adder(package_json.name, dir, message, bump);
|
|
92
94
|
await spawn_cli('changeset', ['add', '--empty']);
|
|
93
95
|
await changeset_adder();
|
|
94
|
-
await
|
|
95
|
-
|
|
96
|
+
if (!(await git_check_fully_staged_workspace())) {
|
|
97
|
+
await spawn('git', ['commit', '-m', message]);
|
|
98
|
+
await git_push_to_create(origin);
|
|
99
|
+
}
|
|
96
100
|
}
|
|
97
101
|
else {
|
|
98
102
|
await spawn_cli('changeset');
|
package/dist/check.task.js
CHANGED
|
@@ -68,7 +68,7 @@ export const task = {
|
|
|
68
68
|
if (error_message) {
|
|
69
69
|
log.error(red('git status'));
|
|
70
70
|
await spawn('git', ['status']);
|
|
71
|
-
throw new Task_Error('
|
|
71
|
+
throw new Task_Error('Failed check for git_check_clean_workspace:' +
|
|
72
72
|
error_message +
|
|
73
73
|
' - do you need to run `gro sync` or commit some files?');
|
|
74
74
|
}
|
package/dist/deploy.task.d.ts
CHANGED
|
@@ -10,17 +10,13 @@ export declare const Args: z.ZodObject<{
|
|
|
10
10
|
force: z.ZodDefault<z.ZodBoolean>;
|
|
11
11
|
dangerous: z.ZodDefault<z.ZodBoolean>;
|
|
12
12
|
reset: z.ZodDefault<z.ZodBoolean>;
|
|
13
|
-
install: z.ZodDefault<z.ZodBoolean>;
|
|
14
|
-
'no-install': z.ZodDefault<z.ZodBoolean>;
|
|
15
13
|
build: z.ZodDefault<z.ZodBoolean>;
|
|
16
14
|
'no-build': z.ZodDefault<z.ZodBoolean>;
|
|
17
15
|
}, "strict", z.ZodTypeAny, {
|
|
18
16
|
build: boolean;
|
|
19
17
|
target: string & z.BRAND<"Git_Branch">;
|
|
20
|
-
install: boolean;
|
|
21
18
|
origin: string & z.BRAND<"Git_Origin">;
|
|
22
19
|
reset: boolean;
|
|
23
|
-
'no-install': boolean;
|
|
24
20
|
source: string & z.BRAND<"Git_Branch">;
|
|
25
21
|
deploy_dir: string;
|
|
26
22
|
build_dir: string;
|
|
@@ -31,10 +27,8 @@ export declare const Args: z.ZodObject<{
|
|
|
31
27
|
}, {
|
|
32
28
|
build?: boolean | undefined;
|
|
33
29
|
target?: string | undefined;
|
|
34
|
-
install?: boolean | undefined;
|
|
35
30
|
origin?: string | undefined;
|
|
36
31
|
reset?: boolean | undefined;
|
|
37
|
-
'no-install'?: boolean | undefined;
|
|
38
32
|
source?: string | undefined;
|
|
39
33
|
deploy_dir?: string | undefined;
|
|
40
34
|
build_dir?: string | undefined;
|
package/dist/deploy.task.js
CHANGED
|
@@ -10,7 +10,6 @@ import { GRO_DIRNAME, GIT_DIRNAME, SVELTEKIT_BUILD_DIRNAME } from './path_consta
|
|
|
10
10
|
import { empty_dir, exists } from './fs.js';
|
|
11
11
|
import { git_check_clean_workspace, git_checkout, git_local_branch_exists, git_remote_branch_exists, Git_Origin, Git_Branch, git_delete_local_branch, git_push_to_create, git_reset_branch_to_first_commit, git_pull, git_fetch, git_check_setting_pull_rebase, git_clone_locally, git_current_branch_name, } from './git.js';
|
|
12
12
|
// docs at ./docs/deploy.md
|
|
13
|
-
// TODO use `to_forwarded_args` and the `gro deploy -- gro build --no-install` pattern to remove the `install`/`no-install` args (also needs testing, maybe a custom override for `gro ` prefixes)
|
|
14
13
|
// terminal command for testing:
|
|
15
14
|
// npm run build && rm -rf .gro && clear && gro deploy --source no-git-workspace --no-build --dry
|
|
16
15
|
// TODO customize
|
|
@@ -46,10 +45,6 @@ export const Args = z
|
|
|
46
45
|
description: 'if true, resets the target branch back to the first commit before deploying',
|
|
47
46
|
})
|
|
48
47
|
.default(false),
|
|
49
|
-
install: z.boolean({ description: 'dual of no-install' }).default(true),
|
|
50
|
-
'no-install': z
|
|
51
|
-
.boolean({ description: 'opt out of npm installing before building' })
|
|
52
|
-
.default(false),
|
|
53
48
|
build: z.boolean({ description: 'dual of no-build' }).default(true),
|
|
54
49
|
'no-build': z.boolean({ description: 'opt out of building' }).default(false),
|
|
55
50
|
})
|
|
@@ -58,7 +53,7 @@ export const task = {
|
|
|
58
53
|
summary: 'deploy to a branch',
|
|
59
54
|
Args,
|
|
60
55
|
run: async ({ args, log, invoke_task }) => {
|
|
61
|
-
const { source, target, origin, build_dir, deploy_dir, dry, force, dangerous, reset,
|
|
56
|
+
const { source, target, origin, build_dir, deploy_dir, dry, force, dangerous, reset, build } = args;
|
|
62
57
|
// Checks
|
|
63
58
|
if (!force && target !== TARGET_BRANCH) {
|
|
64
59
|
throw new Task_Error(`Warning! You are deploying to a custom target branch '${target}',` +
|
|
@@ -163,7 +158,7 @@ export const task = {
|
|
|
163
158
|
// Build
|
|
164
159
|
try {
|
|
165
160
|
if (build) {
|
|
166
|
-
await invoke_task('build'
|
|
161
|
+
await invoke_task('build');
|
|
167
162
|
}
|
|
168
163
|
if (!(await exists(build_dir))) {
|
|
169
164
|
log.error(red('directory to deploy does not exist after building:'), build_dir);
|
package/dist/dev.task.d.ts
CHANGED
|
@@ -7,13 +7,13 @@ export declare const Args: z.ZodObject<{
|
|
|
7
7
|
sync: z.ZodDefault<z.ZodBoolean>;
|
|
8
8
|
'no-sync': z.ZodDefault<z.ZodBoolean>;
|
|
9
9
|
}, "strict", z.ZodTypeAny, {
|
|
10
|
-
watch: boolean;
|
|
11
10
|
sync: boolean;
|
|
11
|
+
watch: boolean;
|
|
12
12
|
'no-watch': boolean;
|
|
13
13
|
'no-sync': boolean;
|
|
14
14
|
}, {
|
|
15
|
-
watch?: boolean | undefined;
|
|
16
15
|
sync?: boolean | undefined;
|
|
16
|
+
watch?: boolean | undefined;
|
|
17
17
|
'no-watch'?: boolean | undefined;
|
|
18
18
|
'no-sync'?: boolean | undefined;
|
|
19
19
|
}>;
|
package/dist/docs/gen.md
CHANGED
|
@@ -52,6 +52,17 @@ There's no support for sourcemaps yet, and I have no plans for them.
|
|
|
52
52
|
(I would accept contributions, but I think it's a hard problem to do well,
|
|
53
53
|
and I don't know what the payoffs would be)
|
|
54
54
|
|
|
55
|
+
> ⚠️ Generated files should never be edited directly,
|
|
56
|
+
> because the next time `gro gen` or `gro sync` runs,
|
|
57
|
+
> any uncommitted changes will be lost!
|
|
58
|
+
> I considered making `gen` only write to files that have no uncommitted changes,
|
|
59
|
+
> but that would impede many workflows,
|
|
60
|
+
> and I don't want to nudge users towards a habit of always adding an override flag.
|
|
61
|
+
> I can see one possible improvement that lets the user
|
|
62
|
+
> opt into making gen write only to unchanged files for those workflows that don't mind it,
|
|
63
|
+
> so if you would like to see that or something similar,
|
|
64
|
+
> please open an issue or [share your thoughts on Discord](https://discord.gg/YU5tyeK72X).
|
|
65
|
+
|
|
55
66
|
Inspirations include Lisp macros, the
|
|
56
67
|
[Svelte](https://github.com/sveltejs/svelte) compiler,
|
|
57
68
|
and [Zig](https://github.com/ziglang/zig)'s comptime.
|
package/dist/docs/publish.md
CHANGED
|
@@ -52,14 +52,7 @@ a changeset to an already-inited repo, use `gro changeset`:
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
gro changeset # inits or adds a changeset
|
|
55
|
-
gro changeset --help #
|
|
56
|
-
gro changeset: call changeset with gro patterns
|
|
57
|
-
|
|
58
|
-
[...args] string[] [] the commands to pass to changeset
|
|
59
|
-
path string './.changeset/config.json' changeset config file path
|
|
60
|
-
access 'restricted' | 'public' undefined changeset 'access' config value, the default depends on package.json#private
|
|
61
|
-
changelog string '@changesets/changelog-git' changeset "changelog" config value
|
|
62
|
-
no-install boolean false opt out of npm installing the changelog package
|
|
55
|
+
gro changeset --help # view the args docs
|
|
63
56
|
|
|
64
57
|
# `gro changeset` is equivalent to:
|
|
65
58
|
changeset init # if needed -- prefix with `npx ` if installed only locally
|
package/dist/docs/task.md
CHANGED
|
@@ -310,6 +310,11 @@ then `--a` and `--b` will be forwarded to `taskname2`.
|
|
|
310
310
|
Forwarded args to Gro tasks override direct args, including args to `invoke_task`,
|
|
311
311
|
so `gro taskname --a 1 -- gro taskname --a 2` will invoke `taskname` with `{a: 2}`.
|
|
312
312
|
|
|
313
|
+
The `invoke_task` helper in the task context forwards the CLI args for the specified task.
|
|
314
|
+
CLI args take precedence over args passed directly to `invoke_task`.
|
|
315
|
+
This may not always be the desired behavior, but it gives the user more control,
|
|
316
|
+
because you can't change args in code you don't control.
|
|
317
|
+
|
|
313
318
|
### throwing errors
|
|
314
319
|
|
|
315
320
|
If a task encounters an error, normally it should throw rather than exiting the process.
|
|
@@ -355,6 +360,8 @@ What makes Gro different?
|
|
|
355
360
|
and improved DX with new capabilities.
|
|
356
361
|
- Tasks support CLI args that are validated and typesafe
|
|
357
362
|
via colocated Zod schemas with minimal boilerplate.
|
|
363
|
+
- Tasks are forwarded CLI args when called via `invoke_task` in other tasks,
|
|
364
|
+
so running `gro foo -- gro bar --a b` passes `{a: 'b'}` automatically to the `bar` task.
|
|
358
365
|
- Module resolution differs and leverages discoverability:
|
|
359
366
|
- When a task name is given to Gro,
|
|
360
367
|
it first searches `src/lib/` in the current working directory and
|
package/dist/docs/tasks.md
CHANGED
|
@@ -17,6 +17,7 @@ What is a `Task`? See [`task.md`](./task.md).
|
|
|
17
17
|
- [gen](../gen.task.ts) - run code generation scripts
|
|
18
18
|
- [lint](../lint.task.ts) - run eslint
|
|
19
19
|
- [publish](../publish.task.ts) - bump version, publish to npm, and git push
|
|
20
|
+
- [reinstall](../reinstall.task.ts) - refreshes package-lock.json with the latest and cleanest deps
|
|
20
21
|
- [release](../release.task.ts) - publish and deploy
|
|
21
22
|
- [run](../run.task.ts) - execute a file with the loader, like `node` but works for TypeScript
|
|
22
23
|
- [sync](../sync.task.ts) - run `gro gen`, update `package.json`, and optionally `npm i` to sync up
|
|
@@ -1,2 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { Spawn_Result } from '@ryanatkn/belt/process.js';
|
|
2
|
+
/**
|
|
3
|
+
* Formats a directory on the filesystem.
|
|
4
|
+
* If the source directory is given, it also formats all of the root directory files.
|
|
5
|
+
* This is separated from `./format_file` to avoid importing all of the `prettier` code
|
|
6
|
+
* inside modules that import this one. (which has a nontrivial cost)
|
|
7
|
+
*/
|
|
8
|
+
export declare const format_directory: (log: Logger, dir: string, check?: boolean, extensions?: string, root_paths?: string) => Promise<Spawn_Result>;
|
package/dist/format_directory.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { spawn } from '@ryanatkn/belt/process.js';
|
|
2
1
|
import { paths } from './paths.js';
|
|
3
2
|
import { GITHUB_DIRNAME, README_FILENAME, SVELTEKIT_CONFIG_FILENAME, VITE_CONFIG_FILENAME, TSCONFIG_FILENAME, GRO_CONFIG_PATH, } from './path_constants.js';
|
|
4
3
|
import { print_command_args, serialize_args, to_forwarded_args } from './args.js';
|
|
4
|
+
import { spawn_cli } from './cli.js';
|
|
5
5
|
const DEFAULT_EXTENSIONS = 'ts,js,json,svelte,html,css,md,yml';
|
|
6
6
|
const DEFAULT_ROOT_PATHS = `${[
|
|
7
7
|
README_FILENAME,
|
|
@@ -11,18 +11,23 @@ const DEFAULT_ROOT_PATHS = `${[
|
|
|
11
11
|
TSCONFIG_FILENAME,
|
|
12
12
|
GITHUB_DIRNAME,
|
|
13
13
|
].join(',')}/**/*`;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Formats a directory on the filesystem.
|
|
16
|
+
* If the source directory is given, it also formats all of the root directory files.
|
|
17
|
+
* This is separated from `./format_file` to avoid importing all of the `prettier` code
|
|
18
|
+
* inside modules that import this one. (which has a nontrivial cost)
|
|
19
|
+
*/
|
|
20
|
+
export const format_directory = async (log, dir, check = false, extensions = DEFAULT_EXTENSIONS, root_paths = DEFAULT_ROOT_PATHS) => {
|
|
19
21
|
const forwarded_args = to_forwarded_args('prettier');
|
|
20
22
|
forwarded_args[check ? 'check' : 'write'] = true;
|
|
21
|
-
const serialized_args =
|
|
22
|
-
serialized_args.push(`${
|
|
23
|
-
if (
|
|
23
|
+
const serialized_args = serialize_args(forwarded_args);
|
|
24
|
+
serialized_args.push(`${dir}**/*.{${extensions}}`);
|
|
25
|
+
if (dir === paths.source) {
|
|
24
26
|
serialized_args.push(`${paths.root}{${root_paths}}`);
|
|
25
27
|
}
|
|
26
28
|
log.info(print_command_args(serialized_args));
|
|
27
|
-
|
|
29
|
+
const spawned = await spawn_cli('prettier', serialized_args);
|
|
30
|
+
if (!spawned)
|
|
31
|
+
throw new Error('failed to find `prettier` CLI locally or globally, do you need to run `npm i`?');
|
|
32
|
+
return spawned;
|
|
28
33
|
};
|
package/dist/gen.d.ts
CHANGED
|
@@ -60,3 +60,17 @@ export type Gen_Module_Result_Failure = {
|
|
|
60
60
|
};
|
|
61
61
|
export declare const to_gen_result: (origin_id: Flavored<string, "Source_Id">, raw_result: Raw_Gen_Result) => Gen_Result;
|
|
62
62
|
export declare const to_output_file_name: (filename: string) => string;
|
|
63
|
+
export type Analyzed_Gen_Result = {
|
|
64
|
+
file: Gen_File;
|
|
65
|
+
existing_content: string;
|
|
66
|
+
is_new: false;
|
|
67
|
+
has_changed: boolean;
|
|
68
|
+
} | {
|
|
69
|
+
file: Gen_File;
|
|
70
|
+
existing_content: null;
|
|
71
|
+
is_new: true;
|
|
72
|
+
has_changed: true;
|
|
73
|
+
};
|
|
74
|
+
export declare const analyze_gen_results: (gen_results: Gen_Results) => Promise<Analyzed_Gen_Result[]>;
|
|
75
|
+
export declare const analyze_gen_result: (file: Gen_File) => Promise<Analyzed_Gen_Result>;
|
|
76
|
+
export declare const write_gen_results: (gen_results: Gen_Results, analyzed_gen_results: Analyzed_Gen_Result[], log: Logger) => Promise<void>;
|
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,
|
|
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([]),
|
|
@@ -51,20 +50,20 @@ export const task = {
|
|
|
51
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
|
|
64
|
-
if (!
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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) {
|
package/dist/gen_module.d.ts
CHANGED
|
@@ -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
|
|
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>;
|
package/dist/gen_module.js
CHANGED
|
@@ -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
|
});
|
|
@@ -12,16 +12,12 @@ import { has_sveltekit_app, has_sveltekit_library } from './sveltekit_helpers.js
|
|
|
12
12
|
* - if `src/lib/server/server.ts`, assumes a Node server
|
|
13
13
|
*/
|
|
14
14
|
const config = async (cfg) => {
|
|
15
|
-
const [
|
|
16
|
-
has_sveltekit_library(),
|
|
17
|
-
has_server(),
|
|
18
|
-
has_sveltekit_app(),
|
|
19
|
-
]);
|
|
15
|
+
const [has_sveltekit_library_result, has_server_result, has_sveltekit_app_result] = await Promise.all([has_sveltekit_library(), has_server(), has_sveltekit_app()]);
|
|
20
16
|
cfg.plugins = async () => [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
? gro_plugin_sveltekit_app({ host_target:
|
|
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' })
|
|
25
21
|
: null,
|
|
26
22
|
// TODO replace with an esbuild plugin, see the module for more
|
|
27
23
|
// import {gro_plugin_gen} from './gro_plugin_gen.js';
|