@ryanatkn/gro 0.116.2 → 0.118.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/README.md +31 -15
- package/dist/changeset.task.js +1 -1
- package/dist/clean_fs.js +2 -1
- package/dist/cli.js +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.js +11 -3
- package/dist/deploy.task.js +5 -4
- package/dist/docs/config.md +25 -0
- package/dist/docs/gen.md +16 -0
- package/dist/docs/task.md +38 -32
- package/dist/docs/tasks.gen.md.js +3 -4
- package/dist/esbuild_plugin_external_worker.js +1 -2
- package/dist/esbuild_plugin_svelte.js +1 -2
- package/dist/esbuild_plugin_sveltekit_shim_alias.js +1 -2
- package/dist/format_directory.js +3 -2
- package/dist/gen.d.ts +5 -0
- package/dist/gen.task.js +7 -8
- package/dist/gen_module.d.ts +2 -1
- package/dist/gen_module.js +1 -1
- package/dist/gro.config.default.js +3 -2
- package/dist/gro_helpers.js +18 -17
- package/dist/gro_plugin_server.js +9 -5
- package/dist/gro_plugin_sveltekit_app.d.ts +0 -1
- package/dist/gro_plugin_sveltekit_app.js +2 -4
- package/dist/gro_plugin_sveltekit_library.d.ts +0 -2
- package/dist/gro_plugin_sveltekit_library.js +1 -7
- package/dist/input_path.d.ts +27 -28
- package/dist/input_path.js +62 -66
- package/dist/input_path.test.js +26 -48
- package/dist/invoke_task.d.ts +1 -1
- package/dist/invoke_task.js +78 -88
- package/dist/lint.task.js +1 -1
- package/dist/loader.js +11 -4
- package/dist/module.d.ts +1 -1
- package/dist/module.js +2 -2
- package/dist/modules.d.ts +13 -9
- package/dist/modules.js +5 -13
- package/dist/modules.test.js +2 -2
- package/dist/package.d.ts +47 -6
- package/dist/package.gen.js +3 -3
- package/dist/package.js +89 -60
- package/dist/package_json.d.ts +5 -0
- package/dist/package_json.js +9 -4
- package/dist/package_meta.d.ts +1 -2
- package/dist/path_constants.d.ts +20 -0
- package/dist/path_constants.js +27 -0
- package/dist/paths.d.ts +11 -34
- package/dist/paths.js +28 -67
- package/dist/publish.task.js +3 -3
- package/dist/register.d.ts +1 -0
- package/dist/register.js +2 -0
- package/dist/release.task.js +1 -2
- package/dist/resolve_node_specifier.js +2 -1
- package/dist/run_gen.d.ts +2 -1
- package/dist/run_gen.js +2 -2
- package/dist/run_gen.test.js +3 -2
- package/dist/run_task.js +2 -2
- package/dist/sveltekit_config.d.ts +1 -1
- package/dist/sveltekit_config.js +9 -5
- package/dist/sveltekit_config_global.d.ts +4 -0
- package/dist/sveltekit_config_global.js +5 -0
- package/dist/sveltekit_helpers.d.ts +4 -0
- package/dist/sveltekit_helpers.js +12 -0
- package/dist/sync.task.js +4 -1
- package/dist/task.d.ts +1 -1
- package/dist/task.js +11 -6
- package/dist/task.test.js +9 -13
- package/dist/task_logging.d.ts +8 -0
- package/dist/{print_task.js → task_logging.js} +30 -16
- package/dist/task_module.d.ts +4 -3
- package/dist/task_module.js +7 -8
- package/dist/task_module.test.js +4 -7
- package/package.json +36 -20
- package/dist/print_task.d.ts +0 -4
package/README.md
CHANGED
|
@@ -35,8 +35,7 @@ It includes:
|
|
|
35
35
|
[`@sveltejs/package`](https://kit.svelte.dev/docs/packaging) for the library
|
|
36
36
|
- exposes all of its internals in `$lib`
|
|
37
37
|
- uses [Changesets](https://github.com/changesets/changesets) for versioning and changelogs
|
|
38
|
-
- provides a [Node loader](/src/lib/loader.ts)
|
|
39
|
-
[esbuild plugins for the server](/src/lib/gro_plugin_server.ts)
|
|
38
|
+
- provides a [Node loader](/src/lib/loader.ts) with a [register hook](/src/lib/register.ts)
|
|
40
39
|
- supports importing TypeScript, JSON, and SSR'd Svelte files in tests and tasks
|
|
41
40
|
- supports [SvelteKit module imports](https://kit.svelte.dev/docs/modules) for
|
|
42
41
|
`$lib`, `$env`, and `$app` in tasks, tests, Node servers,
|
|
@@ -44,8 +43,10 @@ It includes:
|
|
|
44
43
|
so you can use SvelteKit patterns everywhere
|
|
45
44
|
(these are best-effort shims, not perfect)
|
|
46
45
|
- supports running TypeScript files directly without a task via `gro run a.ts`
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
or `node --import @ryanatkn/gro/register.js a.ts`
|
|
47
|
+
- [configurable plugins](/src/lib/docs/plugin.md) to support SvelteKit,
|
|
48
|
+
[auto-restarting Node servers](/src/lib/gro_plugin_server.ts),
|
|
49
|
+
and other external build processes
|
|
49
50
|
- see the [Gro config docs](/src/lib/docs/config.md) and
|
|
50
51
|
[the default config](https://github.com/ryanatkn/gro/blob/main/src/lib/gro.config.default.ts)
|
|
51
52
|
- see [`fuz_template`](https://github.com/fuz-dev/fuz_template)
|
|
@@ -126,17 +127,34 @@ typecheck run tsc on the project without emitting any files
|
|
|
126
127
|
upgrade upgrade deps
|
|
127
128
|
```
|
|
128
129
|
|
|
129
|
-
Gro matches your CLI input against its filesystem conventions.
|
|
130
|
+
To run tasks, Gro matches your CLI input against its filesystem conventions.
|
|
130
131
|
It tries to do the right thing, where right is helpful but not surprising,
|
|
131
132
|
with some magic but not too much:
|
|
132
133
|
|
|
133
134
|
```bash
|
|
134
|
-
gro #
|
|
135
|
-
gro
|
|
136
|
-
gro
|
|
135
|
+
gro # displays all available tasks matching `src/lib/**/*.task.ts` and Gro's builtins
|
|
136
|
+
gro a # tries to run `src/lib/a.task.ts`, then `./a.task.ts`, then Gro's builtin if one exists
|
|
137
|
+
gro a --help # displays docs for the "a" task and its args, works for every task
|
|
138
|
+
gro some/dir # lists all tasks inside `src/lib/some/dir`
|
|
139
|
+
gro some/file # runs `src/lib/some/file.task.ts`
|
|
137
140
|
gro some/file.task.ts # same as above
|
|
138
|
-
|
|
139
|
-
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Gro can also run non-task TypeScript files directly
|
|
144
|
+
with [the `gro run` task](/src/lib/run.task.ts) or [register hook](/src/lib/register.ts):
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
gro run foo.ts
|
|
148
|
+
node --import @ryanatkn/gro/register.js foo.ts
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Or programmatically:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
// myfile.js
|
|
155
|
+
import {register} from 'node:module';
|
|
156
|
+
register('@ryanatkn/gro/loader.js', import.meta.url);
|
|
157
|
+
await import('./foo.ts');
|
|
140
158
|
```
|
|
141
159
|
|
|
142
160
|
Gro has a number of builtin tasks that you can run with the CLI.
|
|
@@ -200,19 +218,17 @@ To publish: (also see [`src/lib/docs/publish.md`](/src/lib/docs/publish.md))
|
|
|
200
218
|
gro publish # flush changeset to changelog, bump version, publish to npm, and git push
|
|
201
219
|
```
|
|
202
220
|
|
|
203
|
-
|
|
221
|
+
More:
|
|
204
222
|
|
|
205
223
|
```bash
|
|
206
224
|
gro clean # delete all build artifacts from the filesystem
|
|
207
225
|
gro clean --sveltekit --nodemodules --git # also deletes dirs and prunes git branches
|
|
208
226
|
gro upgrade excluded-dep-1 excluded-dep-2 # npm updates to the latest everything
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
```bash
|
|
212
227
|
gro --version # print the Gro version
|
|
213
228
|
```
|
|
214
229
|
|
|
215
|
-
For more see [
|
|
230
|
+
For more see [the tasks index](/src/lib/docs/tasks.md),
|
|
231
|
+
[the task feature docs](/src/lib/docs/task.md), and [the docs index](/src/lib/docs/README.md).
|
|
216
232
|
|
|
217
233
|
## develop
|
|
218
234
|
|
package/dist/changeset.task.js
CHANGED
|
@@ -9,7 +9,7 @@ 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
11
|
import { Git_Origin, git_push_to_create } from './git.js';
|
|
12
|
-
import { has_sveltekit_library } from './
|
|
12
|
+
import { has_sveltekit_library } from './sveltekit_helpers.js';
|
|
13
13
|
const RESTRICTED_ACCESS = 'restricted';
|
|
14
14
|
const PUBLIC_ACCESS = 'public';
|
|
15
15
|
const CHANGESET_DIR = '.changeset';
|
package/dist/clean_fs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { rm, readdir } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import { paths } from './paths.js';
|
|
3
|
+
import { NODE_MODULES_DIRNAME, GRO_DIST_PREFIX, SVELTEKIT_DEV_DIRNAME, SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_VITE_CACHE_PATH, SVELTEKIT_DIST_DIRNAME, } from './path_constants.js';
|
|
3
4
|
export const clean_fs = async ({ build = false, build_dev = false, build_dist = false, sveltekit = false, nodemodules = false, }, rm_options = { force: true, recursive: true }) => {
|
|
4
5
|
const promises = [];
|
|
5
6
|
if (build) {
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn, spawn_out } from '@ryanatkn/belt/process.js';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { exists } from './fs.js';
|
|
4
|
-
import { NODE_MODULES_DIRNAME } from './
|
|
4
|
+
import { NODE_MODULES_DIRNAME } from './path_constants.js';
|
|
5
5
|
/**
|
|
6
6
|
* Looks for the CLI `name`, first local to the cwd and then globally.
|
|
7
7
|
*/
|
package/dist/config.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ export interface Gro_Config {
|
|
|
8
8
|
* Returning `null` is a no-op for the caller.
|
|
9
9
|
*/
|
|
10
10
|
map_package_json: Map_Package_Json | null;
|
|
11
|
+
/**
|
|
12
|
+
* The root directories to search for tasks given implicit relative input paths.
|
|
13
|
+
* Defaults to `./src/lib`, then the cwd, then the Gro package dist.
|
|
14
|
+
*/
|
|
15
|
+
task_root_paths: string[];
|
|
11
16
|
}
|
|
12
17
|
export interface Create_Gro_Config {
|
|
13
18
|
(base_config: Gro_Config): Gro_Config | Promise<Gro_Config>;
|
package/dist/config.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { join } from 'node:path';
|
|
2
|
-
import {
|
|
1
|
+
import { join, resolve } from 'node:path';
|
|
2
|
+
import { GRO_DIST_DIR, IS_THIS_GRO, paths } from './paths.js';
|
|
3
|
+
import { GRO_CONFIG_PATH } from './path_constants.js';
|
|
3
4
|
import create_default_config from './gro.config.default.js';
|
|
4
5
|
import { exists } from './fs.js';
|
|
5
6
|
export const create_empty_config = () => ({
|
|
6
7
|
plugins: () => [],
|
|
7
8
|
// TODO maybe disable if no SvelteKit `lib` directory? or other detection to improve defaults
|
|
8
9
|
map_package_json: default_map_package_json,
|
|
10
|
+
task_root_paths: [paths.lib, paths.root, IS_THIS_GRO ? null : GRO_DIST_DIR].filter(Boolean),
|
|
9
11
|
});
|
|
10
12
|
const default_map_package_json = async (package_json) => {
|
|
11
13
|
if (package_json.exports) {
|
|
@@ -16,7 +18,7 @@ const default_map_package_json = async (package_json) => {
|
|
|
16
18
|
export const DEFAULT_EXPORTS_EXCLUDER = /(\.md|\.(test|ignore)\.|\/(test|fixtures|ignore)\/)/u;
|
|
17
19
|
export const load_config = async (dir = paths.root) => {
|
|
18
20
|
const default_config = await create_default_config(create_empty_config());
|
|
19
|
-
const config_path = join(dir,
|
|
21
|
+
const config_path = join(dir, GRO_CONFIG_PATH);
|
|
20
22
|
let config;
|
|
21
23
|
if (await exists(config_path)) {
|
|
22
24
|
const config_module = await import(config_path);
|
|
@@ -25,12 +27,18 @@ export const load_config = async (dir = paths.root) => {
|
|
|
25
27
|
typeof config_module.default === 'function'
|
|
26
28
|
? await config_module.default(default_config)
|
|
27
29
|
: config_module.default;
|
|
30
|
+
normalize_config(config);
|
|
28
31
|
}
|
|
29
32
|
else {
|
|
30
33
|
config = default_config;
|
|
31
34
|
}
|
|
32
35
|
return config;
|
|
33
36
|
};
|
|
37
|
+
// Mutates `config` with cleaned up values.
|
|
38
|
+
const normalize_config = (config) => {
|
|
39
|
+
// TODO any validation?
|
|
40
|
+
config.task_root_paths = config.task_root_paths.map((p) => resolve(p));
|
|
41
|
+
};
|
|
34
42
|
export const validate_config_module = (config_module, config_path) => {
|
|
35
43
|
const config = config_module.default;
|
|
36
44
|
if (!config) {
|
package/dist/deploy.task.js
CHANGED
|
@@ -5,7 +5,8 @@ import { z } from 'zod';
|
|
|
5
5
|
import { cp, mkdir, readdir, rm } from 'node:fs/promises';
|
|
6
6
|
import { join, resolve } from 'node:path';
|
|
7
7
|
import { Task_Error } from './task.js';
|
|
8
|
-
import {
|
|
8
|
+
import { print_path } from './paths.js';
|
|
9
|
+
import { GRO_DIRNAME, GIT_DIRNAME, SVELTEKIT_BUILD_DIRNAME } from './path_constants.js';
|
|
9
10
|
import { empty_dir, exists } from './fs.js';
|
|
10
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';
|
|
11
12
|
// docs at ./docs/deploy.md
|
|
@@ -13,7 +14,7 @@ import { git_check_clean_workspace, git_checkout, git_local_branch_exists, git_r
|
|
|
13
14
|
// terminal command for testing:
|
|
14
15
|
// npm run build && rm -rf .gro && clear && gro deploy --source no-git-workspace --no-build --dry
|
|
15
16
|
// TODO customize
|
|
16
|
-
const
|
|
17
|
+
const dir = process.cwd();
|
|
17
18
|
const INITIAL_FILE_PATH = '.gitkeep';
|
|
18
19
|
const INITIAL_FILE_CONTENTS = '';
|
|
19
20
|
const DEPLOY_DIR = GRO_DIRNAME + '/deploy';
|
|
@@ -121,7 +122,7 @@ export const task = {
|
|
|
121
122
|
if (!(await exists(resolved_deploy_dir))) {
|
|
122
123
|
const local_deploy_branch_exists = await git_local_branch_exists(target);
|
|
123
124
|
await git_fetch(origin, ('+' + target + ':' + target)); // fetch+merge and allow non-fastforward updates with the +
|
|
124
|
-
await git_clone_locally(origin, target,
|
|
125
|
+
await git_clone_locally(origin, target, dir, resolved_deploy_dir);
|
|
125
126
|
// Clean up if we created the target branch in the cwd
|
|
126
127
|
if (!local_deploy_branch_exists) {
|
|
127
128
|
await git_delete_local_branch(target);
|
|
@@ -145,7 +146,7 @@ export const task = {
|
|
|
145
146
|
}
|
|
146
147
|
// Create the target branch locally and remotely.
|
|
147
148
|
// This is more complex to avoid churning the cwd.
|
|
148
|
-
await git_clone_locally(origin, source,
|
|
149
|
+
await git_clone_locally(origin, source, dir, resolved_deploy_dir);
|
|
149
150
|
await spawn(`git checkout --orphan ${target} && ` +
|
|
150
151
|
// TODO there's definitely a better way to do this
|
|
151
152
|
`git rm -rf . && ` +
|
package/dist/docs/config.md
CHANGED
|
@@ -44,6 +44,7 @@ export interface Create_Gro_Config {
|
|
|
44
44
|
export interface Gro_Config {
|
|
45
45
|
plugins: Create_Config_Plugins;
|
|
46
46
|
map_package_json: Map_Package_Json | null;
|
|
47
|
+
task_root_paths: string[];
|
|
47
48
|
}
|
|
48
49
|
```
|
|
49
50
|
|
|
@@ -80,6 +81,20 @@ const config: Create_Gro_Config = async (cfg) => {
|
|
|
80
81
|
export default config;
|
|
81
82
|
```
|
|
82
83
|
|
|
84
|
+
You can also export a config object and use `create_empty_config` to get the defaults:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import {create_empty_config} from '@ryanatkn/gro/config.js';
|
|
88
|
+
|
|
89
|
+
const config = create_empty_config();
|
|
90
|
+
|
|
91
|
+
// config.plugins = ...;
|
|
92
|
+
// config.map_package_json = ...;
|
|
93
|
+
// config.task_root_paths = ...;
|
|
94
|
+
|
|
95
|
+
export default config;
|
|
96
|
+
```
|
|
97
|
+
|
|
83
98
|
See also [Gro's own internal config](/gro.config.ts).
|
|
84
99
|
|
|
85
100
|
## `plugins`
|
|
@@ -160,3 +175,13 @@ export interface Map_Package_Json {
|
|
|
160
175
|
(package_json: Package_Json): Package_Json | null | Promise<Package_Json | null>;
|
|
161
176
|
}
|
|
162
177
|
```
|
|
178
|
+
|
|
179
|
+
## `task_root_paths`
|
|
180
|
+
|
|
181
|
+
The Gro config option `task_root_paths` allows customizing Gro's task resolution.
|
|
182
|
+
When calling `gro [input_path]`, absolute and explicitly relative paths starting with `.`
|
|
183
|
+
are resolved according to normal filesystem rules,
|
|
184
|
+
but non-explicit input paths, like `foo`, are resolved by searching
|
|
185
|
+
through `task_root_paths` in order until a matching file or directory is found on the filesystem.
|
|
186
|
+
|
|
187
|
+
The default task paths are `./src/lib`, then `.`, and then Gro's dist directory.
|
package/dist/docs/gen.md
CHANGED
|
@@ -91,6 +91,22 @@ Outputs `src/script.ts`:
|
|
|
91
91
|
console.log('generated a string');
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
### gen context
|
|
95
|
+
|
|
96
|
+
The `Gen` function receives one argument, the `Gen_Context` object:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
export interface Gen_Context {
|
|
100
|
+
config: Gro_Config;
|
|
101
|
+
/**
|
|
102
|
+
* Same as `import.meta.url` but in path form.
|
|
103
|
+
*/
|
|
104
|
+
origin_id: string;
|
|
105
|
+
log: Logger;
|
|
106
|
+
}
|
|
107
|
+
// export const gen: Gen = ({config, origin_id, log}) => {
|
|
108
|
+
```
|
|
109
|
+
|
|
94
110
|
### generate other filetypes
|
|
95
111
|
|
|
96
112
|
Files with any extension can be generated without configuration.
|
package/dist/docs/task.md
CHANGED
|
@@ -21,30 +21,29 @@ and defers composition to the user in regular TypeScript modules.
|
|
|
21
21
|
> use the `gro run` task, which works like the normal `node` CLI
|
|
22
22
|
> but uses the Gro loader to support `.ts`.
|
|
23
23
|
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
- tasks are defined by naming files with the `.task.ts` and `.task.js` suffixes
|
|
25
|
+
- tasks can be run from the CLI via a name (`gro foo`),
|
|
26
|
+
which uses Gro's task resolution (see more below),
|
|
27
|
+
or via paths that are absolute (`gro /path/to/foo`) or explicitly relative (`gro ./foo`)
|
|
28
|
+
- Gro automatically discovers all `*.task.ts|js` files
|
|
29
|
+
in its configurable directory, so creating a new task
|
|
30
|
+
is as simple as [creating a new file](#define-a-task), no config needed
|
|
31
|
+
(defaults to `src/lib`, see the config option [`task_root_paths`](./config.md#task_root_paths))
|
|
32
|
+
- to view [the available tasks](https://github.com/ryanatkn/gro/blob/main/src/lib/docs/tasks.md)
|
|
33
|
+
run `gro` with no arguments
|
|
28
34
|
- task definitions are just objects with an async `run` function and some optional properties,
|
|
29
35
|
so composing tasks is explicit in your code, just like any other module
|
|
30
|
-
(but there's also the helper `invoke_task
|
|
31
|
-
-
|
|
32
|
-
so running them is as simple as `gro <task>`,
|
|
33
|
-
and in code the task object's `run` function has access to CLI args;
|
|
34
|
-
to view [the available tasks](https://github.com/ryanatkn/gro/blob/main/src/lib/docs/tasks.md)
|
|
35
|
-
run `gro` with no arguments
|
|
36
|
+
(but there's also the helper `invoke_task`, see more below)
|
|
37
|
+
- the task object's `run` function has access to CLI args
|
|
36
38
|
- tasks optionally use [zod](https://github.com/colinhacks/zod) schemas
|
|
37
39
|
for `args` types, runtime parsing with helpful validation errors,
|
|
38
|
-
and
|
|
39
|
-
- it's easy to
|
|
40
|
-
like [`gro test`](/src/lib/test.task.ts) and [`gro gen`](/src/lib/gen.task.ts)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- the
|
|
45
|
-
for both development/build tasks and one-off script authoring/execution;
|
|
46
|
-
it attempts to be portable and extensibile, but there's a _lot_ of room for improvement
|
|
47
|
-
- it's fast because it imports only the modules that your chosen tasks need
|
|
40
|
+
and generated help docs (`gro foo --help`), with DRY co-located definitions
|
|
41
|
+
- it's easy to call into or override any of Gro's builtin tasks,
|
|
42
|
+
like [`gro test`](/src/lib/test.task.ts) and [`gro gen`](/src/lib/gen.task.ts) -
|
|
43
|
+
your own versions with the same name take precedence, and you can invoke the base
|
|
44
|
+
tasks using the `gro/` prefix, e.g. `gro gro/test`
|
|
45
|
+
(tasks are also copy-paste friendly! just update the imports)
|
|
46
|
+
- it's fast because it imports only the modules imported by your invoked tasks, not every task's
|
|
48
47
|
|
|
49
48
|
The task runner's purpose is to provide an ergonomic interface
|
|
50
49
|
between the CLI, build tools, and app code.
|
|
@@ -55,18 +54,24 @@ As a developer, it's nice to be able to reuse TypeScript modules in every contex
|
|
|
55
54
|
### show all available tasks
|
|
56
55
|
|
|
57
56
|
```bash
|
|
58
|
-
# This looks through `src
|
|
59
|
-
#
|
|
57
|
+
# This looks through `src/lib` in both the current working directory and Gro's source
|
|
58
|
+
# for all files matching `*.task.ts|js` and logs them out with their args docs.
|
|
60
59
|
$ gro
|
|
61
60
|
```
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
The [config](./config.md) option [task_root_paths](./config.md#task_root_paths)
|
|
63
|
+
tells Gro where to search for tasks.
|
|
64
|
+
|
|
65
|
+
> Currently, only the first directory specified in `task_root_paths` that's found on the filesystem
|
|
66
|
+
> will be used to automatically discover tasks, like when running `gro` without args.
|
|
67
|
+
> Please open an issue if you would like to see Gro be able to discover
|
|
68
|
+
> tasks in more than one directory - it will take some reworking of internals
|
|
69
|
+
> but it seems like the right design.
|
|
65
70
|
|
|
66
71
|
### show tasks in a directory
|
|
67
72
|
|
|
68
73
|
```bash
|
|
69
|
-
# Logs all `*.task.ts` files in `src/lib/some/dir` and `gro/src/lib/some/dir`.
|
|
74
|
+
# Logs all `*.task.ts|js` files in `src/lib/some/dir` and `gro/src/lib/some/dir`.
|
|
70
75
|
# If no tasks are found, it displays an error.
|
|
71
76
|
$ gro some/dir
|
|
72
77
|
```
|
|
@@ -329,7 +334,7 @@ export const task: Task = {
|
|
|
329
334
|
|
|
330
335
|
## why?
|
|
331
336
|
|
|
332
|
-
Gro usage on the command line (`gro <
|
|
337
|
+
Gro usage on the command line (`gro <task_name_or_directory> [...flags]`)
|
|
333
338
|
looks a lot like using `node`.
|
|
334
339
|
What makes Gro different?
|
|
335
340
|
|
|
@@ -337,14 +342,15 @@ What makes Gro different?
|
|
|
337
342
|
contains task modules that conform to some interface.
|
|
338
343
|
This allows them to be discoverable by convention,
|
|
339
344
|
so running `gro` displays them all without any config, and it puts generic handles on them,
|
|
340
|
-
enabling various verbs (e.g. `run`) and
|
|
341
|
-
|
|
345
|
+
enabling various verbs (e.g. `run`) and
|
|
346
|
+
structured metadata (e.g. `summary` and args schemas for docs and validation).
|
|
347
|
+
- Tasks aren't just a script on the filesystem, they can be composed and inspected in code.
|
|
342
348
|
Task modules do not have any side effects when imported,
|
|
343
349
|
while Node scripts just execute when imported -
|
|
344
|
-
their primary purpose is to cause side effects.
|
|
350
|
+
their primary purpose is to cause side effects, and they're limited to the filesystem API.
|
|
345
351
|
This is useful in many cases - for example `gro taskname --help`
|
|
346
352
|
inspects the args schema and other metadata to print help to the console,
|
|
347
|
-
and `gro` prints the `summary` property of each task it
|
|
353
|
+
and `gro` prints the `summary` property of each task it discovers.
|
|
348
354
|
There's lots more to explore here, like task composition
|
|
349
355
|
and improved DX with new capabilities.
|
|
350
356
|
- Tasks support CLI args that are validated and typesafe
|
|
@@ -353,8 +359,8 @@ What makes Gro different?
|
|
|
353
359
|
- When a task name is given to Gro,
|
|
354
360
|
it first searches `src/lib/` in the current working directory and
|
|
355
361
|
falls back to searching the Gro directory.
|
|
356
|
-
This allows your code and CLI commands to
|
|
357
|
-
or override
|
|
362
|
+
This allows your code and CLI commands to compose Gro's builtin tasks
|
|
363
|
+
or override them without changing how you invoke them.
|
|
358
364
|
Gro reserves no special behavior for its own commands -
|
|
359
365
|
`gro test`, `gro gen`, and all the rest are just tasks that all follow the same rules.
|
|
360
366
|
(see its task at [`src/lib/test.task.ts`](/src/lib/test.task.ts)).
|
|
@@ -4,7 +4,7 @@ import { strip_start } from '@ryanatkn/belt/string.js';
|
|
|
4
4
|
import { to_output_file_name } from '../gen.js';
|
|
5
5
|
import { paths, base_path_to_source_id } from '../paths.js';
|
|
6
6
|
import { load_task_modules } from '../task_module.js';
|
|
7
|
-
import { log_error_reasons } from '../
|
|
7
|
+
import { log_error_reasons } from '../task_logging.js';
|
|
8
8
|
// This is the first simple implementation of Gro's automated docs.
|
|
9
9
|
// It combines Gro's gen and task systems
|
|
10
10
|
// to generate a markdown file describing all of the project's tasks.
|
|
@@ -14,14 +14,13 @@ import { log_error_reasons } from '../print_task.js';
|
|
|
14
14
|
// TODO display more info about each task, including a summary and params
|
|
15
15
|
// TODO needs some cleanup and better APIs - paths are confusing and verbose!
|
|
16
16
|
// TODO add backlinks to every document that links to this one
|
|
17
|
-
export const gen = async ({ origin_id, log }) => {
|
|
18
|
-
const result = await load_task_modules();
|
|
17
|
+
export const gen = async ({ config, origin_id, log }) => {
|
|
18
|
+
const result = await load_task_modules([paths.lib], config.task_root_paths);
|
|
19
19
|
if (!result.ok) {
|
|
20
20
|
log_error_reasons(log, result.reasons);
|
|
21
21
|
throw new Error(result.type);
|
|
22
22
|
}
|
|
23
23
|
const tasks = result.modules;
|
|
24
|
-
// TODO need to get this from project config or something
|
|
25
24
|
const root_path = parse_path_segments(paths.root).at(-1);
|
|
26
25
|
const origin_dir = dirname(origin_id);
|
|
27
26
|
const origin_base = basename(origin_id);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild';
|
|
2
2
|
import { basename } from 'node:path';
|
|
3
|
-
import { cwd } from 'node:process';
|
|
4
3
|
import { print_build_result, to_define_import_meta_env } from './esbuild_helpers.js';
|
|
5
4
|
import { resolve_specifier } from './resolve_specifier.js';
|
|
6
5
|
import { esbuild_plugin_sveltekit_shim_alias } from './esbuild_plugin_sveltekit_shim_alias.js';
|
|
@@ -8,7 +7,7 @@ import { esbuild_plugin_sveltekit_shim_env } from './esbuild_plugin_sveltekit_sh
|
|
|
8
7
|
import { esbuild_plugin_sveltekit_shim_app } from './esbuild_plugin_sveltekit_shim_app.js';
|
|
9
8
|
import { esbuild_plugin_sveltekit_local_imports } from './esbuild_plugin_sveltekit_local_imports.js';
|
|
10
9
|
import { esbuild_plugin_svelte } from './esbuild_plugin_svelte.js';
|
|
11
|
-
export const esbuild_plugin_external_worker = ({ dev, build_options, dir = cwd(), svelte_compile_options, svelte_preprocessors, svelte_compile_module_options, alias, base_url, assets_url, public_prefix, private_prefix, env_dir, env_files, ambient_env, log, }) => ({
|
|
10
|
+
export const esbuild_plugin_external_worker = ({ dev, build_options, dir = process.cwd(), svelte_compile_options, svelte_preprocessors, svelte_compile_module_options, alias, base_url, assets_url, public_prefix, private_prefix, env_dir, env_files, ambient_env, log, }) => ({
|
|
12
11
|
name: 'external_worker',
|
|
13
12
|
setup: (build) => {
|
|
14
13
|
const builds = new Map();
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { compile, compileModule, preprocess, } from 'svelte/compiler';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { relative } from 'node:path';
|
|
4
|
-
import { cwd } from 'node:process';
|
|
5
4
|
import { SVELTE_MATCHER, SVELTE_RUNES_MATCHER } from './svelte_helpers.js';
|
|
6
5
|
export const esbuild_plugin_svelte = (options = {}) => {
|
|
7
|
-
const { dir = cwd(), svelte_compile_options = {}, svelte_compile_module_options = {}, svelte_preprocessors, } = options;
|
|
6
|
+
const { dir = process.cwd(), svelte_compile_options = {}, svelte_compile_module_options = {}, svelte_preprocessors, } = options;
|
|
8
7
|
return {
|
|
9
8
|
name: 'svelte',
|
|
10
9
|
setup: (build) => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { escape_regexp } from '@ryanatkn/belt/regexp.js';
|
|
2
|
-
import { cwd } from 'node:process';
|
|
3
2
|
import { join } from 'node:path';
|
|
4
|
-
export const esbuild_plugin_sveltekit_shim_alias = ({ dir = cwd(), alias, }) => ({
|
|
3
|
+
export const esbuild_plugin_sveltekit_shim_alias = ({ dir = process.cwd(), alias, }) => ({
|
|
5
4
|
name: 'sveltekit_shim_alias',
|
|
6
5
|
setup: (build) => {
|
|
7
6
|
const aliases = { $lib: 'src/lib', ...alias };
|
package/dist/format_directory.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { spawn } from '@ryanatkn/belt/process.js';
|
|
2
|
-
import {
|
|
2
|
+
import { paths } from './paths.js';
|
|
3
|
+
import { GITHUB_DIRNAME, README_FILENAME, SVELTEKIT_CONFIG_FILENAME, VITE_CONFIG_FILENAME, TSCONFIG_FILENAME, GRO_CONFIG_PATH, } from './path_constants.js';
|
|
3
4
|
import { print_command_args, serialize_args, to_forwarded_args } from './args.js';
|
|
4
5
|
const DEFAULT_EXTENSIONS = 'ts,js,json,svelte,html,css,md,yml';
|
|
5
6
|
const DEFAULT_ROOT_PATHS = `${[
|
|
6
7
|
README_FILENAME,
|
|
7
|
-
|
|
8
|
+
GRO_CONFIG_PATH,
|
|
8
9
|
SVELTEKIT_CONFIG_FILENAME,
|
|
9
10
|
VITE_CONFIG_FILENAME,
|
|
10
11
|
TSCONFIG_FILENAME,
|
package/dist/gen.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Logger } from '@ryanatkn/belt/log.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import type { Gro_Config } from './config.js';
|
|
3
4
|
export type Gen_Result = {
|
|
4
5
|
origin_id: string;
|
|
5
6
|
files: Gen_File[];
|
|
@@ -14,6 +15,10 @@ export interface Gen {
|
|
|
14
15
|
(ctx: Gen_Context): Raw_Gen_Result | Promise<Raw_Gen_Result>;
|
|
15
16
|
}
|
|
16
17
|
export interface Gen_Context {
|
|
18
|
+
config: Gro_Config;
|
|
19
|
+
/**
|
|
20
|
+
* Same as `import.meta.url` but in path form.
|
|
21
|
+
*/
|
|
17
22
|
origin_id: string;
|
|
18
23
|
log: Logger;
|
|
19
24
|
}
|
package/dist/gen.task.js
CHANGED
|
@@ -7,14 +7,14 @@ import { mkdir, writeFile } from 'node:fs/promises';
|
|
|
7
7
|
import { Task_Error } from './task.js';
|
|
8
8
|
import { run_gen } from './run_gen.js';
|
|
9
9
|
import { load_gen_module, check_gen_modules, find_gen_modules } from './gen_module.js';
|
|
10
|
-
import {
|
|
10
|
+
import { Raw_Input_Path, to_input_paths } from './input_path.js';
|
|
11
11
|
import { load_modules } from './modules.js';
|
|
12
12
|
import { format_file } from './format_file.js';
|
|
13
|
-
import { print_path } from './paths.js';
|
|
14
|
-
import { log_error_reasons } from './
|
|
13
|
+
import { paths, print_path } from './paths.js';
|
|
14
|
+
import { log_error_reasons } from './task_logging.js';
|
|
15
15
|
export const Args = z
|
|
16
16
|
.object({
|
|
17
|
-
_: z.array(
|
|
17
|
+
_: z.array(Raw_Input_Path, { description: 'paths to generate' }).default([]),
|
|
18
18
|
check: z
|
|
19
19
|
.boolean({ description: 'exit with a nonzero code if any files need to be generated' })
|
|
20
20
|
.default(false),
|
|
@@ -25,10 +25,9 @@ export const Args = z
|
|
|
25
25
|
export const task = {
|
|
26
26
|
summary: 'run code generation scripts',
|
|
27
27
|
Args,
|
|
28
|
-
run: async ({ args, log, timings }) => {
|
|
28
|
+
run: async ({ args, log, timings, config }) => {
|
|
29
29
|
const { _: raw_input_paths, check } = args;
|
|
30
|
-
|
|
31
|
-
const input_paths = resolve_input_paths(raw_input_paths);
|
|
30
|
+
const input_paths = raw_input_paths.length ? to_input_paths(raw_input_paths) : [paths.source];
|
|
32
31
|
// load all of the gen modules
|
|
33
32
|
const find_modules_result = await find_gen_modules(input_paths);
|
|
34
33
|
if (!find_modules_result.ok) {
|
|
@@ -49,7 +48,7 @@ export const task = {
|
|
|
49
48
|
}
|
|
50
49
|
// run `gen` on each of the modules
|
|
51
50
|
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);
|
|
51
|
+
const gen_results = await run_gen(load_modules_result.modules, config, log, timings, format_file);
|
|
53
52
|
timing_to_generate_code();
|
|
54
53
|
const fail_count = gen_results.failures.length;
|
|
55
54
|
if (check) {
|
package/dist/gen_module.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Module_Meta, type Load_Module_Result, type Find_Modules_Result } from './modules.js';
|
|
2
2
|
import type { Gen, Gen_Results, Gen_File } from './gen.js';
|
|
3
|
+
import { Input_Path } from './input_path.js';
|
|
3
4
|
export declare const GEN_FILE_PATTERN_TEXT = "gen";
|
|
4
5
|
export declare const GEN_FILE_PATTERN: string;
|
|
5
6
|
export declare const is_gen_path: (path: string) => boolean;
|
|
@@ -43,4 +44,4 @@ export type Check_Gen_Module_Result = {
|
|
|
43
44
|
};
|
|
44
45
|
export declare const check_gen_modules: (gen_results: Gen_Results) => Promise<Check_Gen_Module_Result[]>;
|
|
45
46
|
export declare const check_gen_module: (file: Gen_File) => Promise<Check_Gen_Module_Result>;
|
|
46
|
-
export declare const find_gen_modules: (input_paths?:
|
|
47
|
+
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,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { load_module, find_modules, } from './modules.js';
|
|
3
|
-
import { get_possible_source_ids } from './input_path.js';
|
|
3
|
+
import { Input_Path, get_possible_source_ids } from './input_path.js';
|
|
4
4
|
import { paths } from './paths.js';
|
|
5
5
|
import { search_fs } from './search_fs.js';
|
|
6
6
|
import { exists } from './fs.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { gro_plugin_sveltekit_library } from './gro_plugin_sveltekit_library.js';
|
|
2
2
|
import { has_server, gro_plugin_server } from './gro_plugin_server.js';
|
|
3
|
-
import {
|
|
3
|
+
import { gro_plugin_sveltekit_app } from './gro_plugin_sveltekit_app.js';
|
|
4
|
+
import { has_sveltekit_app, has_sveltekit_library } from './sveltekit_helpers.js';
|
|
4
5
|
/**
|
|
5
6
|
* This is the default config that's passed to `gro.config.ts`
|
|
6
7
|
* if it exists in the current project, and if not, this is the final config.
|
package/dist/gro_helpers.js
CHANGED
|
@@ -3,7 +3,12 @@ import { join, resolve } from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { spawn } from '@ryanatkn/belt/process.js';
|
|
5
5
|
import { exists } from './fs.js';
|
|
6
|
-
import { NODE_MODULES_DIRNAME } from './
|
|
6
|
+
import { NODE_MODULES_DIRNAME, SVELTEKIT_DIST_DIRNAME } from './path_constants.js';
|
|
7
|
+
/*
|
|
8
|
+
|
|
9
|
+
This module is intended to have minimal dependencies to avoid over-imports in the CLI.
|
|
10
|
+
|
|
11
|
+
*/
|
|
7
12
|
/**
|
|
8
13
|
* Resolves a path to an internal Gro file.
|
|
9
14
|
* Prefers any local installation of Gro and falls back to the current CLI context.
|
|
@@ -40,26 +45,22 @@ import { NODE_MODULES_DIRNAME } from './paths.js';
|
|
|
40
45
|
*/
|
|
41
46
|
export const resolve_gro_module_path = async (path = '') => {
|
|
42
47
|
const gro_bin_path = resolve(NODE_MODULES_DIRNAME, '.bin/gro');
|
|
48
|
+
// case 1
|
|
49
|
+
// Prefer any locally installed version of Gro.
|
|
43
50
|
if (await exists(gro_bin_path)) {
|
|
44
|
-
// case 1
|
|
45
|
-
// Prefer any locally installed version of Gro.
|
|
46
51
|
return join(await realpath(gro_bin_path), '..', path);
|
|
47
52
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if ((await exists(join(base_path, 'gro.js'))) && (await exists(join(base_path, path)))) {
|
|
55
|
-
return join(file_path, '../..', base_path, path);
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
// case 3
|
|
59
|
-
// Fall back to the version associated with the running CLI.
|
|
60
|
-
return join(file_path, '..', path);
|
|
61
|
-
}
|
|
53
|
+
// case 2
|
|
54
|
+
// If running Gro inside its own repo, require the local dist.
|
|
55
|
+
// If the local dist is not yet built it will fall back to the global.
|
|
56
|
+
if ((await exists(join(SVELTEKIT_DIST_DIRNAME, 'gro.js'))) &&
|
|
57
|
+
(await exists(join(SVELTEKIT_DIST_DIRNAME, path)))) {
|
|
58
|
+
return resolve(SVELTEKIT_DIST_DIRNAME, path);
|
|
62
59
|
}
|
|
60
|
+
// case 3
|
|
61
|
+
// Fall back to the version associated with the running CLI.
|
|
62
|
+
const file_path = fileURLToPath(import.meta.url);
|
|
63
|
+
return join(file_path, '..', path);
|
|
63
64
|
};
|
|
64
65
|
/**
|
|
65
66
|
* Runs a file using the Gro loader.
|