@ryanatkn/gro 0.117.0 → 0.119.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +37 -19
  2. package/dist/build.task.d.ts +3 -0
  3. package/dist/build.task.js +5 -1
  4. package/dist/changeset.task.d.ts +2 -2
  5. package/dist/changeset.task.js +10 -6
  6. package/dist/check.task.js +1 -1
  7. package/dist/clean_fs.js +2 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/config.js +3 -2
  10. package/dist/deploy.task.d.ts +0 -6
  11. package/dist/deploy.task.js +7 -11
  12. package/dist/dev.task.d.ts +2 -2
  13. package/dist/docs/gen.md +27 -0
  14. package/dist/docs/publish.md +1 -8
  15. package/dist/docs/task.md +7 -0
  16. package/dist/docs/tasks.gen.md.js +2 -3
  17. package/dist/docs/tasks.md +1 -0
  18. package/dist/esbuild_plugin_external_worker.js +1 -2
  19. package/dist/esbuild_plugin_svelte.js +1 -2
  20. package/dist/esbuild_plugin_sveltekit_shim_alias.js +1 -2
  21. package/dist/format_directory.d.ts +8 -2
  22. package/dist/format_directory.js +18 -12
  23. package/dist/gen.d.ts +19 -0
  24. package/dist/gen.js +45 -0
  25. package/dist/gen.task.js +19 -19
  26. package/dist/gen_module.d.ts +1 -14
  27. package/dist/gen_module.js +0 -22
  28. package/dist/git.d.ts +5 -0
  29. package/dist/git.js +15 -0
  30. package/dist/git.test.js +4 -1
  31. package/dist/gro.config.default.js +8 -11
  32. package/dist/gro_helpers.js +18 -17
  33. package/dist/gro_plugin_gen.js +1 -1
  34. package/dist/gro_plugin_server.d.ts +4 -1
  35. package/dist/gro_plugin_server.js +15 -6
  36. package/dist/gro_plugin_sveltekit_app.d.ts +0 -1
  37. package/dist/gro_plugin_sveltekit_app.js +2 -4
  38. package/dist/gro_plugin_sveltekit_library.d.ts +0 -2
  39. package/dist/gro_plugin_sveltekit_library.js +10 -11
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.js +0 -1
  42. package/dist/input_path.d.ts +1 -1
  43. package/dist/input_path.js +1 -1
  44. package/dist/input_path.test.js +3 -3
  45. package/dist/invoke.js +2 -0
  46. package/dist/invoke_task.d.ts +1 -1
  47. package/dist/invoke_task.js +10 -11
  48. package/dist/lint.task.js +1 -1
  49. package/dist/loader.js +11 -4
  50. package/dist/module.d.ts +1 -1
  51. package/dist/module.js +2 -2
  52. package/dist/modules.test.js +2 -2
  53. package/dist/package.d.ts +52 -0
  54. package/dist/package.js +80 -36
  55. package/dist/package_json.d.ts +5 -0
  56. package/dist/package_json.js +8 -3
  57. package/dist/package_meta.d.ts +1 -2
  58. package/dist/path_constants.d.ts +21 -0
  59. package/dist/path_constants.js +28 -0
  60. package/dist/paths.d.ts +2 -26
  61. package/dist/paths.js +10 -33
  62. package/dist/publish.task.d.ts +9 -6
  63. package/dist/publish.task.js +26 -14
  64. package/dist/register.d.ts +1 -0
  65. package/dist/register.js +2 -0
  66. package/dist/reinstall.task.d.ts +5 -0
  67. package/dist/reinstall.task.js +32 -0
  68. package/dist/release.task.js +5 -7
  69. package/dist/resolve_node_specifier.js +2 -1
  70. package/dist/run.task.js +1 -1
  71. package/dist/run_gen.d.ts +2 -1
  72. package/dist/run_gen.js +2 -2
  73. package/dist/run_gen.test.js +3 -2
  74. package/dist/run_task.js +1 -1
  75. package/dist/sveltekit_config.d.ts +1 -1
  76. package/dist/sveltekit_config.js +9 -5
  77. package/dist/sveltekit_config_global.d.ts +4 -0
  78. package/dist/sveltekit_config_global.js +5 -0
  79. package/dist/sveltekit_helpers.d.ts +17 -0
  80. package/dist/sveltekit_helpers.js +54 -0
  81. package/dist/sync.task.d.ts +0 -1
  82. package/dist/sync.task.js +5 -11
  83. package/dist/task.d.ts +1 -1
  84. package/dist/task.js +11 -7
  85. package/dist/task.test.js +9 -13
  86. package/dist/task_logging.d.ts +2 -2
  87. package/dist/task_logging.js +29 -15
  88. package/dist/task_module.d.ts +3 -3
  89. package/dist/task_module.js +6 -6
  90. package/dist/task_module.test.js +4 -7
  91. package/dist/typecheck.task.js +1 -1
  92. package/dist/upgrade.task.d.ts +4 -1
  93. package/dist/upgrade.task.js +30 -5
  94. package/package.json +23 -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
 
@@ -35,8 +36,7 @@ It includes:
35
36
  [`@sveltejs/package`](https://kit.svelte.dev/docs/packaging) for the library
36
37
  - exposes all of its internals in `$lib`
37
38
  - uses [Changesets](https://github.com/changesets/changesets) for versioning and changelogs
38
- - provides a [Node loader](/src/lib/loader.ts) and
39
- [esbuild plugins for the server](/src/lib/gro_plugin_server.ts)
39
+ - provides a [Node loader](/src/lib/loader.ts) with a [register hook](/src/lib/register.ts)
40
40
  - supports importing TypeScript, JSON, and SSR'd Svelte files in tests and tasks
41
41
  - supports [SvelteKit module imports](https://kit.svelte.dev/docs/modules) for
42
42
  `$lib`, `$env`, and `$app` in tasks, tests, Node servers,
@@ -44,8 +44,10 @@ It includes:
44
44
  so you can use SvelteKit patterns everywhere
45
45
  (these are best-effort shims, not perfect)
46
46
  - supports running TypeScript files directly without a task via `gro run a.ts`
47
- - [configurable plugins](/src/lib/docs/plugin.md)
48
- to support SvelteKit, auto-restarting Node servers, and other external build processes
47
+ or `node --import @ryanatkn/gro/register.js a.ts`
48
+ - [configurable plugins](/src/lib/docs/plugin.md) to support SvelteKit,
49
+ [auto-restarting Node servers](/src/lib/gro_plugin_server.ts),
50
+ and other external build processes
49
51
  - see the [Gro config docs](/src/lib/docs/config.md) and
50
52
  [the default config](https://github.com/ryanatkn/gro/blob/main/src/lib/gro.config.default.ts)
51
53
  - see [`fuz_template`](https://github.com/fuz-dev/fuz_template)
@@ -105,7 +107,7 @@ gro # prints available tasks - defers to any local gro installation
105
107
  Run a task: gro [name]
106
108
  View help: gro [name] --help
107
109
 
108
- 17 tasks in gro:
110
+ 18 tasks in gro:
109
111
 
110
112
  build build the project
111
113
  changeset call changeset with gro patterns
@@ -118,6 +120,7 @@ format format source files
118
120
  gen run code generation scripts
119
121
  lint run eslint
120
122
  publish bump version, publish to npm, and git push
123
+ reinstall refreshes package-lock.json with the latest and cleanest deps
121
124
  release publish and deploy
122
125
  run execute a file with the loader, like `node` but works for TypeScript
123
126
  sync run `gro gen`, update `package.json`, and optionally `npm i` to sync up
@@ -126,17 +129,34 @@ typecheck run tsc on the project without emitting any files
126
129
  upgrade upgrade deps
127
130
  ```
128
131
 
129
- Gro matches your CLI input against its filesystem conventions.
132
+ To run tasks, Gro matches your CLI input against its filesystem conventions.
130
133
  It tries to do the right thing, where right is helpful but not surprising,
131
134
  with some magic but not too much:
132
135
 
133
136
  ```bash
134
- gro # print all available tasks, those matching `src/lib/**/*.task.ts` and Gro's builtins
135
- gro some/dir # list all tasks inside `src/lib/some/dir`
136
- gro some/file # run `src/lib/some/file.task.ts`
137
+ gro # displays all available tasks matching `src/lib/**/*.task.ts` and Gro's builtins
138
+ gro a # tries to run `src/lib/a.task.ts`, then `./a.task.ts`, then Gro's builtin if one exists
139
+ gro a --help # displays docs for the "a" task and its args, works for every task
140
+ gro some/dir # lists all tasks inside `src/lib/some/dir`
141
+ gro some/file # runs `src/lib/some/file.task.ts`
137
142
  gro some/file.task.ts # same as above
138
- gro a # run `src/lib/a.task.ts` if it exists, falling back to Gro's builtin
139
- gro a --help # print info about the "a" task; works for every task
143
+ ```
144
+
145
+ Gro can also run non-task TypeScript files directly
146
+ with [the `gro run` task](/src/lib/run.task.ts) or [register hook](/src/lib/register.ts):
147
+
148
+ ```bash
149
+ gro run foo.ts
150
+ node --import @ryanatkn/gro/register.js foo.ts
151
+ ```
152
+
153
+ Or programmatically:
154
+
155
+ ```js
156
+ // myfile.js
157
+ import {register} from 'node:module';
158
+ register('@ryanatkn/gro/loader.js', import.meta.url);
159
+ await import('./foo.ts');
140
160
  ```
141
161
 
142
162
  Gro has a number of builtin tasks that you can run with the CLI.
@@ -200,19 +220,17 @@ To publish: (also see [`src/lib/docs/publish.md`](/src/lib/docs/publish.md))
200
220
  gro publish # flush changeset to changelog, bump version, publish to npm, and git push
201
221
  ```
202
222
 
203
- Etc:
223
+ More:
204
224
 
205
225
  ```bash
206
226
  gro clean # delete all build artifacts from the filesystem
207
227
  gro clean --sveltekit --nodemodules --git # also deletes dirs and prunes git branches
208
228
  gro upgrade excluded-dep-1 excluded-dep-2 # npm updates to the latest everything
209
- ```
210
-
211
- ```bash
212
229
  gro --version # print the Gro version
213
230
  ```
214
231
 
215
- For more see [`src/lib/docs/task.md`](/src/lib/docs/task.md) and [`src/lib/docs`](/src/lib/docs).
232
+ For more see [the tasks index](/src/lib/docs/tasks.md),
233
+ [the task feature docs](/src/lib/docs/task.md), and [the docs index](/src/lib/docs/README.md).
216
234
 
217
235
  ## develop
218
236
 
@@ -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>;
@@ -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: 'run npm install before building' }).default(false),
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
@@ -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
  /**
@@ -8,8 +8,8 @@ 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';
12
- import { has_sveltekit_library } from './gro_plugin_sveltekit_library.js';
11
+ import { Git_Origin, git_check_fully_staged_workspace, git_push_to_create } from './git.js';
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';
@@ -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
- if (!(await has_sveltekit_library(package_json))) {
66
- throw new Task_Error('no SvelteKit library detected');
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 spawn('git', ['commit', '-m', message]);
95
- await git_push_to_create(origin);
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');
@@ -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('failed check for git_check_clean_workspace:' +
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/clean_fs.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { rm, readdir } from 'node:fs/promises';
2
- import { NODE_MODULES_DIRNAME, paths, SVELTEKIT_DEV_DIRNAME, SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_VITE_CACHE_PATH, GRO_DIST_PREFIX, SVELTEKIT_DIST_DIRNAME, } from './paths.js';
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 './paths.js';
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.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { join, resolve } from 'node:path';
2
- import { CONFIG_PATH, GRO_DIST_DIR, IS_THIS_GRO, paths } from './paths.js';
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 = () => ({
@@ -17,7 +18,7 @@ const default_map_package_json = async (package_json) => {
17
18
  export const DEFAULT_EXPORTS_EXCLUDER = /(\.md|\.(test|ignore)\.|\/(test|fixtures|ignore)\/)/u;
18
19
  export const load_config = async (dir = paths.root) => {
19
20
  const default_config = await create_default_config(create_empty_config());
20
- const config_path = join(dir, CONFIG_PATH);
21
+ const config_path = join(dir, GRO_CONFIG_PATH);
21
22
  let config;
22
23
  if (await exists(config_path)) {
23
24
  const config_module = await import(config_path);
@@ -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;
@@ -5,15 +5,15 @@ 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 { GIT_DIRNAME, GRO_DIRNAME, print_path, SVELTEKIT_BUILD_DIRNAME } from './paths.js';
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
12
- // 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)
13
13
  // terminal command for testing:
14
14
  // npm run build && rm -rf .gro && clear && gro deploy --source no-git-workspace --no-build --dry
15
15
  // TODO customize
16
- const cwd = process.cwd();
16
+ const dir = process.cwd();
17
17
  const INITIAL_FILE_PATH = '.gitkeep';
18
18
  const INITIAL_FILE_CONTENTS = '';
19
19
  const DEPLOY_DIR = GRO_DIRNAME + '/deploy';
@@ -45,10 +45,6 @@ export const Args = z
45
45
  description: 'if true, resets the target branch back to the first commit before deploying',
46
46
  })
47
47
  .default(false),
48
- install: z.boolean({ description: 'dual of no-install' }).default(true),
49
- 'no-install': z
50
- .boolean({ description: 'opt out of npm installing before building' })
51
- .default(false),
52
48
  build: z.boolean({ description: 'dual of no-build' }).default(true),
53
49
  'no-build': z.boolean({ description: 'opt out of building' }).default(false),
54
50
  })
@@ -57,7 +53,7 @@ export const task = {
57
53
  summary: 'deploy to a branch',
58
54
  Args,
59
55
  run: async ({ args, log, invoke_task }) => {
60
- const { source, target, origin, build_dir, deploy_dir, dry, force, dangerous, reset, install, build, } = args;
56
+ const { source, target, origin, build_dir, deploy_dir, dry, force, dangerous, reset, build } = args;
61
57
  // Checks
62
58
  if (!force && target !== TARGET_BRANCH) {
63
59
  throw new Task_Error(`Warning! You are deploying to a custom target branch '${target}',` +
@@ -121,7 +117,7 @@ export const task = {
121
117
  if (!(await exists(resolved_deploy_dir))) {
122
118
  const local_deploy_branch_exists = await git_local_branch_exists(target);
123
119
  await git_fetch(origin, ('+' + target + ':' + target)); // fetch+merge and allow non-fastforward updates with the +
124
- await git_clone_locally(origin, target, cwd, resolved_deploy_dir);
120
+ await git_clone_locally(origin, target, dir, resolved_deploy_dir);
125
121
  // Clean up if we created the target branch in the cwd
126
122
  if (!local_deploy_branch_exists) {
127
123
  await git_delete_local_branch(target);
@@ -145,7 +141,7 @@ export const task = {
145
141
  }
146
142
  // Create the target branch locally and remotely.
147
143
  // This is more complex to avoid churning the cwd.
148
- await git_clone_locally(origin, source, cwd, resolved_deploy_dir);
144
+ await git_clone_locally(origin, source, dir, resolved_deploy_dir);
149
145
  await spawn(`git checkout --orphan ${target} && ` +
150
146
  // TODO there's definitely a better way to do this
151
147
  `git rm -rf . && ` +
@@ -162,7 +158,7 @@ export const task = {
162
158
  // Build
163
159
  try {
164
160
  if (build) {
165
- await invoke_task('build', { install });
161
+ await invoke_task('build');
166
162
  }
167
163
  if (!(await exists(build_dir))) {
168
164
  log.error(red('directory to deploy does not exist after building:'), build_dir);
@@ -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.
@@ -91,6 +102,22 @@ Outputs `src/script.ts`:
91
102
  console.log('generated a string');
92
103
  ```
93
104
 
105
+ ### gen context
106
+
107
+ The `Gen` function receives one argument, the `Gen_Context` object:
108
+
109
+ ```ts
110
+ export interface Gen_Context {
111
+ config: Gro_Config;
112
+ /**
113
+ * Same as `import.meta.url` but in path form.
114
+ */
115
+ origin_id: string;
116
+ log: Logger;
117
+ }
118
+ // export const gen: Gen = ({config, origin_id, log}) => {
119
+ ```
120
+
94
121
  ### generate other filetypes
95
122
 
96
123
  Files with any extension can be generated without configuration.
@@ -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 # prints:
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
@@ -14,14 +14,13 @@ import { log_error_reasons } from '../task_logging.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([paths.lib]);
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);
@@ -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,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 };
@@ -1,2 +1,8 @@
1
- import { type Spawn_Result } from '@ryanatkn/belt/process.js';
2
- export declare const format_directory: (log: Logger, directory: string, check?: boolean, extensions?: string, root_paths?: string) => Promise<Spawn_Result>;
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>;
@@ -1,27 +1,33 @@
1
- import { spawn } from '@ryanatkn/belt/process.js';
2
- import { GITHUB_DIRNAME, paths, README_FILENAME, SVELTEKIT_CONFIG_FILENAME, VITE_CONFIG_FILENAME, TSCONFIG_FILENAME, CONFIG_PATH, } from './paths.js';
1
+ import { paths } from './paths.js';
2
+ import { GITHUB_DIRNAME, README_FILENAME, SVELTEKIT_CONFIG_FILENAME, VITE_CONFIG_FILENAME, TSCONFIG_FILENAME, GRO_CONFIG_PATH, } from './path_constants.js';
3
3
  import { print_command_args, serialize_args, to_forwarded_args } from './args.js';
4
+ import { spawn_cli } from './cli.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
- CONFIG_PATH,
8
+ GRO_CONFIG_PATH,
8
9
  SVELTEKIT_CONFIG_FILENAME,
9
10
  VITE_CONFIG_FILENAME,
10
11
  TSCONFIG_FILENAME,
11
12
  GITHUB_DIRNAME,
12
13
  ].join(',')}/**/*`;
13
- // This formats a directory on the filesystem.
14
- // If the source directory is given, it also formats all of the root directory files.
15
- // This is separated from `./format_file` to avoid importing all of the `prettier` code
16
- // inside modules that import this one. (which has a nontrivial cost)
17
- export const format_directory = (log, directory, check = false, extensions = DEFAULT_EXTENSIONS, root_paths = DEFAULT_ROOT_PATHS) => {
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) => {
18
21
  const forwarded_args = to_forwarded_args('prettier');
19
22
  forwarded_args[check ? 'check' : 'write'] = true;
20
- const serialized_args = ['prettier', ...serialize_args(forwarded_args)];
21
- serialized_args.push(`${directory}**/*.{${extensions}}`);
22
- if (directory === paths.source) {
23
+ const serialized_args = serialize_args(forwarded_args);
24
+ serialized_args.push(`${dir}**/*.{${extensions}}`);
25
+ if (dir === paths.source) {
23
26
  serialized_args.push(`${paths.root}{${root_paths}}`);
24
27
  }
25
28
  log.info(print_command_args(serialized_args));
26
- return spawn('npx', serialized_args);
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;
27
33
  };
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
  }
@@ -55,3 +60,17 @@ export type Gen_Module_Result_Failure = {
55
60
  };
56
61
  export declare const to_gen_result: (origin_id: Flavored<string, "Source_Id">, raw_result: Raw_Gen_Result) => Gen_Result;
57
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>;