@ryanatkn/gro 0.112.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +257 -0
  3. package/dist/args.d.ts +59 -0
  4. package/dist/args.js +132 -0
  5. package/dist/args.test.d.ts +1 -0
  6. package/dist/args.test.js +43 -0
  7. package/dist/build.task.d.ts +11 -0
  8. package/dist/build.task.js +24 -0
  9. package/dist/changelog.d.ts +8 -0
  10. package/dist/changelog.js +47 -0
  11. package/dist/changelog.test.d.ts +1 -0
  12. package/dist/changelog.test.js +118 -0
  13. package/dist/changeset.task.d.ts +49 -0
  14. package/dist/changeset.task.js +141 -0
  15. package/dist/check.task.d.ts +47 -0
  16. package/dist/check.task.js +77 -0
  17. package/dist/clean.task.d.ts +26 -0
  18. package/dist/clean.task.js +41 -0
  19. package/dist/clean_fs.d.ts +9 -0
  20. package/dist/clean_fs.js +27 -0
  21. package/dist/cli.d.ts +11 -0
  22. package/dist/cli.js +25 -0
  23. package/dist/commit.task.d.ts +11 -0
  24. package/dist/commit.task.js +22 -0
  25. package/dist/config.d.ts +21 -0
  26. package/dist/config.js +42 -0
  27. package/dist/config.test.d.ts +1 -0
  28. package/dist/config.test.js +8 -0
  29. package/dist/deploy.task.d.ts +47 -0
  30. package/dist/deploy.task.js +198 -0
  31. package/dist/dev.task.d.ts +22 -0
  32. package/dist/dev.task.js +32 -0
  33. package/dist/docs/README.gen.md.d.ts +5 -0
  34. package/dist/docs/README.gen.md.js +53 -0
  35. package/dist/docs/README.md +20 -0
  36. package/dist/docs/build.md +41 -0
  37. package/dist/docs/config.md +162 -0
  38. package/dist/docs/deploy.md +32 -0
  39. package/dist/docs/dev.md +40 -0
  40. package/dist/docs/gen.md +241 -0
  41. package/dist/docs/gro_plugin_sveltekit_frontend.md +97 -0
  42. package/dist/docs/package_json.md +29 -0
  43. package/dist/docs/plugin.md +50 -0
  44. package/dist/docs/publish.md +144 -0
  45. package/dist/docs/task.md +377 -0
  46. package/dist/docs/tasks.gen.md.d.ts +2 -0
  47. package/dist/docs/tasks.gen.md.js +60 -0
  48. package/dist/docs/tasks.md +35 -0
  49. package/dist/docs/test.md +52 -0
  50. package/dist/env.d.ts +10 -0
  51. package/dist/env.js +47 -0
  52. package/dist/esbuild_helpers.d.ts +14 -0
  53. package/dist/esbuild_helpers.js +36 -0
  54. package/dist/esbuild_plugin_external_worker.d.ts +22 -0
  55. package/dist/esbuild_plugin_external_worker.js +49 -0
  56. package/dist/esbuild_plugin_svelte.d.ts +9 -0
  57. package/dist/esbuild_plugin_svelte.js +49 -0
  58. package/dist/esbuild_plugin_sveltekit_local_imports.d.ts +7 -0
  59. package/dist/esbuild_plugin_sveltekit_local_imports.js +30 -0
  60. package/dist/esbuild_plugin_sveltekit_shim_alias.d.ts +6 -0
  61. package/dist/esbuild_plugin_sveltekit_shim_alias.js +16 -0
  62. package/dist/esbuild_plugin_sveltekit_shim_app.d.ts +8 -0
  63. package/dist/esbuild_plugin_sveltekit_shim_app.js +23 -0
  64. package/dist/esbuild_plugin_sveltekit_shim_env.d.ts +10 -0
  65. package/dist/esbuild_plugin_sveltekit_shim_env.js +18 -0
  66. package/dist/format.task.d.ts +11 -0
  67. package/dist/format.task.js +24 -0
  68. package/dist/format_directory.d.ts +2 -0
  69. package/dist/format_directory.js +27 -0
  70. package/dist/format_file.d.ts +8 -0
  71. package/dist/format_file.js +42 -0
  72. package/dist/format_file.test.d.ts +1 -0
  73. package/dist/format_file.test.js +16 -0
  74. package/dist/fs.d.ts +7 -0
  75. package/dist/fs.js +19 -0
  76. package/dist/fs.test.d.ts +1 -0
  77. package/dist/fs.test.js +16 -0
  78. package/dist/gen.d.ts +57 -0
  79. package/dist/gen.js +81 -0
  80. package/dist/gen.task.d.ts +14 -0
  81. package/dist/gen.task.js +103 -0
  82. package/dist/gen.test.d.ts +1 -0
  83. package/dist/gen.test.js +239 -0
  84. package/dist/gen_module.d.ts +46 -0
  85. package/dist/gen_module.js +54 -0
  86. package/dist/gen_module.test.d.ts +1 -0
  87. package/dist/gen_module.test.js +30 -0
  88. package/dist/git.d.ts +76 -0
  89. package/dist/git.js +200 -0
  90. package/dist/git.test.d.ts +1 -0
  91. package/dist/git.test.js +18 -0
  92. package/dist/github.d.ts +35 -0
  93. package/dist/github.js +32 -0
  94. package/dist/gro.config.default.d.ts +12 -0
  95. package/dist/gro.config.default.js +31 -0
  96. package/dist/gro.d.ts +2 -0
  97. package/dist/gro.js +19 -0
  98. package/dist/gro_helpers.d.ts +43 -0
  99. package/dist/gro_helpers.js +79 -0
  100. package/dist/gro_plugin_gen.d.ts +6 -0
  101. package/dist/gro_plugin_gen.js +80 -0
  102. package/dist/gro_plugin_server.d.ts +77 -0
  103. package/dist/gro_plugin_server.js +152 -0
  104. package/dist/gro_plugin_sveltekit_app.d.ts +27 -0
  105. package/dist/gro_plugin_sveltekit_app.js +180 -0
  106. package/dist/gro_plugin_sveltekit_library.d.ts +4 -0
  107. package/dist/gro_plugin_sveltekit_library.js +42 -0
  108. package/dist/hash.d.ts +5 -0
  109. package/dist/hash.js +14 -0
  110. package/dist/hash.test.d.ts +1 -0
  111. package/dist/hash.test.js +25 -0
  112. package/dist/index.d.ts +4 -0
  113. package/dist/index.js +3 -0
  114. package/dist/input_path.d.ts +48 -0
  115. package/dist/input_path.js +161 -0
  116. package/dist/input_path.test.d.ts +1 -0
  117. package/dist/input_path.test.js +106 -0
  118. package/dist/invoke.d.ts +1 -0
  119. package/dist/invoke.js +18 -0
  120. package/dist/invoke_task.d.ts +20 -0
  121. package/dist/invoke_task.js +140 -0
  122. package/dist/lint.task.d.ts +11 -0
  123. package/dist/lint.task.js +29 -0
  124. package/dist/loader.d.ts +4 -0
  125. package/dist/loader.js +153 -0
  126. package/dist/module.d.ts +3 -0
  127. package/dist/module.js +6 -0
  128. package/dist/module.test.d.ts +1 -0
  129. package/dist/module.test.js +41 -0
  130. package/dist/modules.d.ts +60 -0
  131. package/dist/modules.js +103 -0
  132. package/dist/modules.test.d.ts +1 -0
  133. package/dist/modules.test.js +182 -0
  134. package/dist/package.d.ts +939 -0
  135. package/dist/package.gen.d.ts +7 -0
  136. package/dist/package.gen.js +26 -0
  137. package/dist/package.js +887 -0
  138. package/dist/package_json.d.ts +342 -0
  139. package/dist/package_json.js +212 -0
  140. package/dist/package_json.test.d.ts +1 -0
  141. package/dist/package_json.test.js +77 -0
  142. package/dist/path.d.ts +12 -0
  143. package/dist/path.js +8 -0
  144. package/dist/paths.d.ts +60 -0
  145. package/dist/paths.js +128 -0
  146. package/dist/paths.test.d.ts +1 -0
  147. package/dist/paths.test.js +49 -0
  148. package/dist/plugin.d.ts +36 -0
  149. package/dist/plugin.js +80 -0
  150. package/dist/plugin.test.d.ts +1 -0
  151. package/dist/plugin.test.js +54 -0
  152. package/dist/print_task.d.ts +4 -0
  153. package/dist/print_task.js +124 -0
  154. package/dist/publish.task.d.ts +32 -0
  155. package/dist/publish.task.js +125 -0
  156. package/dist/release.task.d.ts +5 -0
  157. package/dist/release.task.js +18 -0
  158. package/dist/resolve_node_specifier.d.ts +8 -0
  159. package/dist/resolve_node_specifier.js +39 -0
  160. package/dist/resolve_node_specifier.test.d.ts +1 -0
  161. package/dist/resolve_node_specifier.test.js +21 -0
  162. package/dist/resolve_specifier.d.ts +15 -0
  163. package/dist/resolve_specifier.js +51 -0
  164. package/dist/resolve_specifier.test.d.ts +1 -0
  165. package/dist/resolve_specifier.test.js +66 -0
  166. package/dist/run.task.d.ts +11 -0
  167. package/dist/run.task.js +31 -0
  168. package/dist/run_gen.d.ts +6 -0
  169. package/dist/run_gen.js +74 -0
  170. package/dist/run_gen.test.d.ts +1 -0
  171. package/dist/run_gen.test.js +182 -0
  172. package/dist/run_task.d.ts +13 -0
  173. package/dist/run_task.js +44 -0
  174. package/dist/run_task.test.d.ts +1 -0
  175. package/dist/run_task.test.js +63 -0
  176. package/dist/search_fs.d.ts +11 -0
  177. package/dist/search_fs.js +22 -0
  178. package/dist/search_fs.test.d.ts +1 -0
  179. package/dist/search_fs.test.js +46 -0
  180. package/dist/src_json.d.ts +256 -0
  181. package/dist/src_json.js +110 -0
  182. package/dist/src_json.test.d.ts +1 -0
  183. package/dist/src_json.test.js +52 -0
  184. package/dist/sveltekit_config.d.ts +36 -0
  185. package/dist/sveltekit_config.js +51 -0
  186. package/dist/sveltekit_shim_app.d.ts +10 -0
  187. package/dist/sveltekit_shim_app.js +31 -0
  188. package/dist/sveltekit_shim_app_environment.d.ts +10 -0
  189. package/dist/sveltekit_shim_app_environment.js +12 -0
  190. package/dist/sveltekit_shim_app_forms.d.ts +5 -0
  191. package/dist/sveltekit_shim_app_forms.js +13 -0
  192. package/dist/sveltekit_shim_app_navigation.d.ts +10 -0
  193. package/dist/sveltekit_shim_app_navigation.js +11 -0
  194. package/dist/sveltekit_shim_app_paths.d.ts +11 -0
  195. package/dist/sveltekit_shim_app_paths.js +6 -0
  196. package/dist/sveltekit_shim_app_stores.d.ts +6 -0
  197. package/dist/sveltekit_shim_app_stores.js +17 -0
  198. package/dist/sveltekit_shim_env.d.ts +4 -0
  199. package/dist/sveltekit_shim_env.js +23 -0
  200. package/dist/sync.task.d.ts +30 -0
  201. package/dist/sync.task.js +45 -0
  202. package/dist/task.d.ts +29 -0
  203. package/dist/task.js +17 -0
  204. package/dist/task.test.d.ts +1 -0
  205. package/dist/task.test.js +22 -0
  206. package/dist/task_module.d.ts +14 -0
  207. package/dist/task_module.js +19 -0
  208. package/dist/task_module.test.d.ts +1 -0
  209. package/dist/task_module.test.js +70 -0
  210. package/dist/test.task.d.ts +20 -0
  211. package/dist/test.task.js +43 -0
  212. package/dist/throttle.d.ts +16 -0
  213. package/dist/throttle.js +59 -0
  214. package/dist/throttle.test.d.ts +1 -0
  215. package/dist/throttle.test.js +49 -0
  216. package/dist/typecheck.task.d.ts +5 -0
  217. package/dist/typecheck.task.js +38 -0
  218. package/dist/upgrade.task.d.ts +14 -0
  219. package/dist/upgrade.task.js +37 -0
  220. package/dist/watch_dir.d.ts +30 -0
  221. package/dist/watch_dir.js +59 -0
  222. package/package.json +422 -0
@@ -0,0 +1,60 @@
1
+ import type { Flavored } from '@ryanatkn/belt/types.js';
2
+ import { z } from 'zod';
3
+ export declare const SOURCE_DIRNAME = "src";
4
+ export declare const GRO_DIRNAME = ".gro";
5
+ export declare const GRO_DIST_PREFIX = "dist_";
6
+ export declare const SERVER_DIST_PATH = "dist_server";
7
+ export declare const LIB_DIRNAME = "lib";
8
+ export declare const ROUTES_DIRNAME = "routes";
9
+ export declare const GRO_DEV_DIRNAME: string;
10
+ export declare const SOURCE_DIR: string;
11
+ export declare const GRO_DIR: string;
12
+ export declare const GRO_DEV_DIR: string;
13
+ export declare const LIB_PATH: string;
14
+ export declare const LIB_DIR: string;
15
+ export declare const CONFIG_PATH = "gro.config.ts";
16
+ export declare const README_FILENAME = "README.md";
17
+ export declare const SVELTEKIT_CONFIG_FILENAME = "svelte.config.js";
18
+ export declare const VITE_CONFIG_FILENAME = "vite.config.ts";
19
+ export declare const SVELTEKIT_DEV_DIRNAME = ".svelte-kit";
20
+ export declare const SVELTEKIT_BUILD_DIRNAME = "build";
21
+ export declare const SVELTEKIT_DIST_DIRNAME = "dist";
22
+ export declare const NODE_MODULES_DIRNAME = "node_modules";
23
+ export declare const SVELTEKIT_VITE_CACHE_PATH: string;
24
+ export declare const GITHUB_DIRNAME = ".github";
25
+ export declare const GIT_DIRNAME = ".git";
26
+ export declare const TSCONFIG_FILENAME = "tsconfig.json";
27
+ export interface Paths {
28
+ root: string;
29
+ source: string;
30
+ lib: string;
31
+ build: string;
32
+ build_dev: string;
33
+ config: string;
34
+ }
35
+ export declare const Url: z.ZodString;
36
+ export type Url = Flavored<z.infer<typeof Url>, 'Url'>;
37
+ export declare const Email: z.ZodString;
38
+ export type Email = Flavored<z.infer<typeof Email>, 'Email'>;
39
+ export declare const Source_Id: z.ZodString;
40
+ export type Source_Id = Flavored<z.infer<typeof Source_Id>, 'Source_Id'>;
41
+ export declare const Build_Id: z.ZodString;
42
+ export type Build_Id = Flavored<z.infer<typeof Build_Id>, 'Build_Id'>;
43
+ export declare const create_paths: (root_dir: string) => Paths;
44
+ export declare const paths_from_id: (id: string) => Paths;
45
+ export declare const is_gro_id: (id: string) => boolean;
46
+ export declare const to_root_path: (id: string, p?: Paths) => string;
47
+ export declare const source_id_to_base_path: (source_id: Flavored<string, "Source_Id">, p?: Paths) => string;
48
+ export declare const base_path_to_source_id: (base_path: string, p?: Paths) => Flavored<string, "Source_Id">;
49
+ export declare const lib_path_to_import_id: (base_path: string, p?: Paths) => Flavored<string, "Source_Id">;
50
+ export declare const import_id_to_lib_path: (import_id: string, p?: Paths) => string;
51
+ export declare const to_gro_input_path: (input_path: string) => string;
52
+ export declare const replace_root_dir: (id: string, root_dir: string, p?: Paths) => string;
53
+ export declare const print_path: (path: string, p?: Paths, prefix?: string) => string;
54
+ export declare const print_path_or_gro_path: (path: string, from_paths?: Paths) => string;
55
+ export declare const replace_extension: (path: string, new_extension: string) => string;
56
+ export declare const gro_dir_basename: string;
57
+ export declare const paths: Paths;
58
+ export declare const is_this_project_gro: boolean;
59
+ export declare const gro_paths: Paths;
60
+ export declare const gro_sveltekit_dist_dir: string;
package/dist/paths.js ADDED
@@ -0,0 +1,128 @@
1
+ import { join, basename, extname, relative } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { strip_end, strip_start } from '@ryanatkn/belt/string.js';
4
+ import { gray } from 'kleur/colors';
5
+ import { z } from 'zod';
6
+ /*
7
+
8
+ A path `id` is an absolute path to the source/.gro/dist directory.
9
+ It's the same nomenclature that Rollup uses.
10
+
11
+ A `base_path` is the format used by `CheapWatch`.
12
+ It's a bare relative path without a source or .gro directory,
13
+ e.g. 'foo/bar.ts'.
14
+
15
+ `CheapWatch` also uses an array of `path_parts`.
16
+ For path './foo/bar/baz.ts',
17
+ the `path_parts` are `['foo', 'foo/bar', 'foo/bar/baz.ts']`.
18
+
19
+ */
20
+ // TODO pass these to `create_paths` and override from gro config
21
+ // TODO this is kinda gross - do we want to maintain the convention to have the trailing slash in most usage?
22
+ export const SOURCE_DIRNAME = 'src';
23
+ export const GRO_DIRNAME = '.gro';
24
+ export const GRO_DIST_PREFIX = 'dist_'; //
25
+ export const SERVER_DIST_PATH = 'dist_server'; // TODO should all of these be `_PATH` or should this be `DIRNAME`?
26
+ export const LIB_DIRNAME = 'lib'; // TODO use Svelte config `files.lib`
27
+ export const ROUTES_DIRNAME = 'routes'; // TODO use Svelte config `files.lib`
28
+ export const GRO_DEV_DIRNAME = GRO_DIRNAME + '/dev';
29
+ export const SOURCE_DIR = SOURCE_DIRNAME + '/';
30
+ export const GRO_DIR = GRO_DIRNAME + '/';
31
+ export const GRO_DEV_DIR = GRO_DEV_DIRNAME + '/';
32
+ export const LIB_PATH = SOURCE_DIR + LIB_DIRNAME;
33
+ export const LIB_DIR = LIB_PATH + '/'; // TODO @multiple get from the sveltekit config
34
+ export const CONFIG_PATH = 'gro.config.ts';
35
+ export const README_FILENAME = 'README.md';
36
+ export const SVELTEKIT_CONFIG_FILENAME = 'svelte.config.js';
37
+ export const VITE_CONFIG_FILENAME = 'vite.config.ts';
38
+ export const SVELTEKIT_DEV_DIRNAME = '.svelte-kit'; // TODO use Svelte config value `outDir`
39
+ export const SVELTEKIT_BUILD_DIRNAME = 'build';
40
+ export const SVELTEKIT_DIST_DIRNAME = 'dist';
41
+ export const NODE_MODULES_DIRNAME = 'node_modules';
42
+ export const SVELTEKIT_VITE_CACHE_PATH = NODE_MODULES_DIRNAME + '/.vite';
43
+ export const GITHUB_DIRNAME = '.github';
44
+ export const GIT_DIRNAME = '.git';
45
+ export const TSCONFIG_FILENAME = 'tsconfig.json';
46
+ // TODO upstream to util, and probably add `Path`/`FilePath` and `FileUrl`
47
+ export const Url = z.string();
48
+ export const Email = z.string();
49
+ export const Source_Id = z.string();
50
+ export const Build_Id = z.string();
51
+ export const create_paths = (root_dir) => {
52
+ // TODO remove reliance on trailing slash towards windows support
53
+ const root = strip_end(root_dir, '/') + '/';
54
+ return {
55
+ root,
56
+ source: root + SOURCE_DIR,
57
+ lib: root + LIB_DIR, // TODO @multiple get from the sveltekit config
58
+ build: root + GRO_DIR,
59
+ build_dev: root + GRO_DEV_DIR,
60
+ config: root + CONFIG_PATH,
61
+ };
62
+ };
63
+ export const paths_from_id = (id) => (is_gro_id(id) ? gro_paths : paths);
64
+ export const is_gro_id = (id) => id.startsWith(gro_paths.root);
65
+ // TODO maybe infer `p` for the functions that take in ids using `paths_from_id`?
66
+ // '/home/me/app/src/foo/bar/baz.ts' → 'src/foo/bar/baz.ts'
67
+ export const to_root_path = (id, p = paths) => strip_start(id, p.root);
68
+ // '/home/me/app/src/foo/bar/baz.ts' → 'foo/bar/baz.ts'
69
+ export const source_id_to_base_path = (source_id, p = paths) => relative(p.source, source_id);
70
+ // TODO base_path is an obsolete concept, it was a remnant from forcing `src/`
71
+ // 'foo/bar/baz.ts' → '/home/me/app/src/foo/bar/baz.ts'
72
+ export const base_path_to_source_id = (base_path, p = paths) => join(p.source, base_path);
73
+ // To run Gro's tasks from its own project, we resolve from dist/ instead of src/.
74
+ // 'foo/bar/baz.ts' → '/home/me/app/src/lib/foo/bar/baz.ts'
75
+ // 'foo/bar/baz.ts' → '/home/me/app/dist/foo/bar/baz.ts'
76
+ export const lib_path_to_import_id = (base_path, p = paths) => {
77
+ if (p.root === gro_paths.root) {
78
+ return p.root + 'dist/' + base_path;
79
+ }
80
+ else {
81
+ return base_path_to_source_id(LIB_DIRNAME + '/' + base_path, p);
82
+ }
83
+ };
84
+ // An `import_id` can be a source_id in a project,
85
+ // or a Gro source_id when running inside Gro,
86
+ // or a `gro/dist/` file id in node_modules when inside another project.
87
+ export const import_id_to_lib_path = (import_id, p = paths_from_id(import_id)) => {
88
+ if (p.root === gro_paths.root) {
89
+ const stripped = strip_start(strip_start(import_id, p.lib), gro_sveltekit_dist_dir); // TODO hacky, needs more work to clarify related things
90
+ const lib_path = is_this_project_gro ? stripped : replace_extension(stripped, '.ts');
91
+ return lib_path;
92
+ }
93
+ else {
94
+ return strip_start(import_id, p.lib);
95
+ }
96
+ };
97
+ export const to_gro_input_path = (input_path) => {
98
+ const base_path = input_path === paths.lib.slice(0, -1) ? '' : strip_start(input_path, paths.lib);
99
+ return gro_sveltekit_dist_dir + base_path;
100
+ };
101
+ // Can be used to map a source id from e.g. the cwd to gro's.
102
+ export const replace_root_dir = (id, root_dir, p = paths) => join(root_dir, to_root_path(id, p));
103
+ export const print_path = (path, p = paths, prefix = './') => {
104
+ const root_path = path === gro_sveltekit_dist_dir ? 'gro' : to_root_path(path, p);
105
+ return gray(`${prefix}${root_path}`);
106
+ };
107
+ export const print_path_or_gro_path = (path, from_paths = paths) => {
108
+ const inferred_paths = paths_from_id(path);
109
+ if (from_paths === gro_paths || inferred_paths === from_paths) {
110
+ return print_path(path, inferred_paths, '');
111
+ }
112
+ return print_path(path, gro_paths, '');
113
+ };
114
+ export const replace_extension = (path, new_extension) => {
115
+ const { length } = extname(path);
116
+ return (length === 0 ? path : path.substring(0, path.length - length)) + new_extension;
117
+ };
118
+ const filename = fileURLToPath(import.meta.url);
119
+ const gro_dir = join(filename, filename.includes('/gro/src/lib/')
120
+ ? '../../../'
121
+ : filename.includes('/gro/dist/')
122
+ ? '../../'
123
+ : '../');
124
+ export const gro_dir_basename = basename(gro_dir) + '/';
125
+ export const paths = create_paths(process.cwd() + '/');
126
+ export const is_this_project_gro = gro_dir === paths.root;
127
+ export const gro_paths = is_this_project_gro ? paths : create_paths(gro_dir);
128
+ export const gro_sveltekit_dist_dir = gro_paths.root + SVELTEKIT_DIST_DIRNAME + '/';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ import { suite } from 'uvu';
2
+ import * as assert from 'uvu/assert';
3
+ import { resolve, join } from 'node:path';
4
+ import { create_paths, paths, gro_paths, is_gro_id, to_root_path, source_id_to_base_path, base_path_to_source_id, } from './paths.js';
5
+ /* test__create_paths */
6
+ const test__create_paths = suite('create_paths');
7
+ test__create_paths('basic behavior', () => {
8
+ const root = resolve('../fake');
9
+ const p = create_paths(root);
10
+ assert.is(p.root, join(root, '/'));
11
+ assert.is(p.source, join(root, 'src/'));
12
+ });
13
+ test__create_paths('paths object has the same identity as the gro_paths object', () => {
14
+ assert.is(paths, gro_paths); // because we're testing inside the Gro project
15
+ });
16
+ test__create_paths.run();
17
+ /* test__create_paths */
18
+ /* test__is_gro_id */
19
+ const test__is_gro_id = suite('is_gro_id');
20
+ test__is_gro_id('basic behavior', () => {
21
+ assert.ok(is_gro_id(resolve(paths.source)));
22
+ assert.ok(!is_gro_id(resolve('../fake/src')));
23
+ });
24
+ test__is_gro_id.run();
25
+ /* test__is_gro_id */
26
+ /* test__to_root_path */
27
+ const test__to_root_path = suite('to_root_path');
28
+ test__to_root_path('basic behavior', () => {
29
+ assert.is(to_root_path(resolve('foo/bar')), 'foo/bar');
30
+ });
31
+ test__to_root_path.run();
32
+ /* test__to_root_path */
33
+ /* test__source_id_to_base_path */
34
+ const test__source_id_to_base_path = suite('source_id_to_base_path');
35
+ test__source_id_to_base_path('basic behavior', () => {
36
+ assert.is(source_id_to_base_path(resolve('src/foo/bar/baz.ts')), 'foo/bar/baz.ts');
37
+ });
38
+ test__source_id_to_base_path.run();
39
+ /* test__source_id_to_base_path */
40
+ /* test__base_path_to_source_id */
41
+ const test__base_path_to_source_id = suite('base_path_to_source_id');
42
+ test__base_path_to_source_id('basic behavior', () => {
43
+ assert.is(base_path_to_source_id('foo/bar/baz.ts'), resolve('src/foo/bar/baz.ts'));
44
+ });
45
+ test__base_path_to_source_id('does not change extension', () => {
46
+ assert.is(base_path_to_source_id('foo/bar/baz.js'), resolve('src/foo/bar/baz.js'));
47
+ });
48
+ test__base_path_to_source_id.run();
49
+ /* test__base_path_to_source_id */
@@ -0,0 +1,36 @@
1
+ import type { Task_Context } from './task.js';
2
+ /**
3
+ * Gro `Plugin`s enable custom behavior during `gro dev` and `gro build`.
4
+ * In contrast, `Adapter`s use the results of `gro build` to produce final artifacts.
5
+ */
6
+ export interface Plugin<T_Plugin_Context extends Plugin_Context = Plugin_Context> {
7
+ name: string;
8
+ setup?: (ctx: T_Plugin_Context) => void | Promise<void>;
9
+ adapt?: (ctx: T_Plugin_Context) => void | Promise<void>;
10
+ teardown?: (ctx: T_Plugin_Context) => void | Promise<void>;
11
+ }
12
+ export interface Create_Config_Plugins<T_Plugin_Context extends Plugin_Context = Plugin_Context> {
13
+ (ctx: T_Plugin_Context): (Plugin<T_Plugin_Context> | null | Array<Plugin<T_Plugin_Context> | null>) | Promise<Plugin<T_Plugin_Context> | null | Array<Plugin<T_Plugin_Context> | null>>;
14
+ }
15
+ export interface Plugin_Context<T_Args = object> extends Task_Context<T_Args> {
16
+ dev: boolean;
17
+ watch: boolean;
18
+ }
19
+ export declare class Plugins<T_Plugin_Context extends Plugin_Context> {
20
+ private ctx;
21
+ private instances;
22
+ constructor(ctx: T_Plugin_Context, instances: Plugin[]);
23
+ static create<T_Plugin_Context extends Plugin_Context>(ctx: T_Plugin_Context): Promise<Plugins<T_Plugin_Context>>;
24
+ setup(): Promise<void>;
25
+ adapt(): Promise<void>;
26
+ teardown(): Promise<void>;
27
+ }
28
+ /**
29
+ * Replaces a plugin by name in `plugins` without mutating the param.
30
+ * Throws if the plugin name cannot be found.
31
+ * @param plugins - accepts the same types as the return value of `Create_Config_Plugins`
32
+ * @param new_plugin
33
+ * @param name - @default new_plugin.name
34
+ * @returns `plugins` with `new_plugin` at the index of the plugin with `name`
35
+ */
36
+ export declare const replace_plugin: <T_Plugins extends T_Plugin | (T_Plugin | null)[] | null, T_Plugin extends Plugin<Plugin_Context<object>>>(plugins: T_Plugins, new_plugin: Plugin, name?: string) => T_Plugin[];
package/dist/plugin.js ADDED
@@ -0,0 +1,80 @@
1
+ import { to_array } from '@ryanatkn/belt/array.js';
2
+ export class Plugins {
3
+ ctx;
4
+ instances;
5
+ /* prefer `Plugins.create` to the constructor */
6
+ constructor(ctx, instances) {
7
+ this.ctx = ctx;
8
+ this.instances = instances;
9
+ }
10
+ static async create(ctx) {
11
+ const { timings } = ctx;
12
+ const timing_to_create = timings.start('plugins.create');
13
+ const instances = to_array(await ctx.config.plugins(ctx)).filter(Boolean);
14
+ const plugins = new Plugins(ctx, instances);
15
+ timing_to_create();
16
+ return plugins;
17
+ }
18
+ async setup() {
19
+ const { ctx, instances } = this;
20
+ if (!instances.length)
21
+ return;
22
+ const { timings, log } = ctx;
23
+ const timing_to_setup = timings.start('plugins.setup');
24
+ for (const plugin of instances) {
25
+ if (!plugin.setup)
26
+ continue;
27
+ log.debug('setup plugin', plugin.name);
28
+ const timing = timings.start(`setup:${plugin.name}`);
29
+ await plugin.setup(ctx); // eslint-disable-line no-await-in-loop
30
+ timing();
31
+ }
32
+ timing_to_setup();
33
+ }
34
+ async adapt() {
35
+ const { ctx, instances } = this;
36
+ const { timings } = ctx;
37
+ const timing_to_run_adapters = timings.start('plugins.adapt');
38
+ for (const plugin of instances) {
39
+ if (!plugin.adapt)
40
+ continue;
41
+ const timing = timings.start(`adapt:${plugin.name}`);
42
+ await plugin.adapt(ctx); // eslint-disable-line no-await-in-loop
43
+ timing();
44
+ }
45
+ timing_to_run_adapters();
46
+ }
47
+ async teardown() {
48
+ const { ctx, instances } = this;
49
+ if (!instances.length)
50
+ return;
51
+ const { timings, log } = ctx;
52
+ const timing_to_teardown = timings.start('plugins.teardown');
53
+ for (const plugin of instances) {
54
+ if (!plugin.teardown)
55
+ continue;
56
+ log.debug('teardown plugin', plugin.name);
57
+ const timing = timings.start(`teardown:${plugin.name}`);
58
+ await plugin.teardown(ctx); // eslint-disable-line no-await-in-loop
59
+ timing();
60
+ }
61
+ timing_to_teardown();
62
+ }
63
+ }
64
+ /**
65
+ * Replaces a plugin by name in `plugins` without mutating the param.
66
+ * Throws if the plugin name cannot be found.
67
+ * @param plugins - accepts the same types as the return value of `Create_Config_Plugins`
68
+ * @param new_plugin
69
+ * @param name - @default new_plugin.name
70
+ * @returns `plugins` with `new_plugin` at the index of the plugin with `name`
71
+ */
72
+ export const replace_plugin = (plugins, new_plugin, name = new_plugin.name) => {
73
+ const array = to_array(plugins).filter(Boolean);
74
+ const index = array.findIndex((p) => p.name === name);
75
+ if (index === -1)
76
+ throw Error('Failed to find plugin to replace: ' + name);
77
+ const replaced = array.slice();
78
+ replaced[index] = new_plugin;
79
+ return replaced;
80
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ import { test } from 'uvu';
2
+ import * as assert from 'uvu/assert';
3
+ import { replace_plugin } from './plugin.js';
4
+ test('replace_plugin', async () => {
5
+ const a = { name: 'a' };
6
+ const b = { name: 'b' };
7
+ const c = { name: 'c' };
8
+ const plugins = [a, b, c];
9
+ const a2 = { name: 'a' };
10
+ const b2 = { name: 'b' };
11
+ const c2 = { name: 'c' };
12
+ let p = plugins;
13
+ p = replace_plugin(p, a2);
14
+ assert.is(p[0], a2);
15
+ assert.is(p[1], b);
16
+ assert.is(p[2], c);
17
+ p = replace_plugin(p, b2);
18
+ assert.is(p[0], a2);
19
+ assert.is(p[1], b2);
20
+ assert.is(p[2], c);
21
+ // allows duplicate names in the array
22
+ p = replace_plugin(p, c2, 'a');
23
+ assert.is(p[0], c2);
24
+ assert.is(p[1], b2);
25
+ assert.is(p[2], c);
26
+ p = replace_plugin(p, a2, 'c');
27
+ assert.is(p[0], a2);
28
+ assert.is(p[1], b2);
29
+ assert.is(p[2], c);
30
+ p = replace_plugin(p, c2);
31
+ assert.is(p[0], a2);
32
+ assert.is(p[1], b2);
33
+ assert.is(p[2], c2);
34
+ });
35
+ test('replace_plugin without an array', async () => {
36
+ const a = { name: 'a' };
37
+ const a2 = { name: 'a' };
38
+ const p = replace_plugin(a, a2);
39
+ assert.is(p[0], a2);
40
+ });
41
+ test('replace_plugin throws if it cannot find the given name', async () => {
42
+ const a = { name: 'a' };
43
+ const plugins = [a];
44
+ let err;
45
+ try {
46
+ replace_plugin(plugins, { name: 'b' });
47
+ }
48
+ catch (_err) {
49
+ err = _err;
50
+ }
51
+ if (!err)
52
+ assert.unreachable('should have failed');
53
+ });
54
+ test.run();
@@ -0,0 +1,4 @@
1
+ import { type Task_Module_Meta } from './task_module.js';
2
+ export declare const log_available_tasks: (log: Logger, dir_label: string, source_ids_by_input_path: Map<string, string[]>, print_intro?: boolean) => Promise<void>;
3
+ export declare const log_error_reasons: (log: Logger, reasons: string[]) => void;
4
+ export declare const print_task_help: (log: Logger, meta: Task_Module_Meta) => void;
@@ -0,0 +1,124 @@
1
+ import { cyan, gray, green, red } from 'kleur/colors';
2
+ import { plural } from '@ryanatkn/belt/string.js';
3
+ import { print_value } from '@ryanatkn/belt/print.js';
4
+ import { ZodFirstPartyTypeKind } from 'zod';
5
+ import { load_modules } from './modules.js';
6
+ import { load_task_module } from './task_module.js';
7
+ export const log_available_tasks = async (log, dir_label, source_ids_by_input_path, print_intro = true) => {
8
+ const source_ids = Array.from(source_ids_by_input_path.values()).flat();
9
+ if (source_ids.length) {
10
+ // Load all of the tasks so we can print their summary, and args for the `--help` flag.
11
+ const load_modules_result = await load_modules(source_ids_by_input_path, load_task_module);
12
+ if (!load_modules_result.ok) {
13
+ log_error_reasons(log, load_modules_result.reasons);
14
+ process.exit(1);
15
+ }
16
+ const printed = [
17
+ `${print_intro ? '\n\n' : ''}${source_ids.length} task${plural(source_ids.length)} in ${dir_label}:\n`,
18
+ ];
19
+ if (print_intro) {
20
+ printed.unshift(`\n\n${gray('Run a task:')} gro [name]`, `\n${gray('View help:')} gro [name] --help`);
21
+ }
22
+ const longest_task_name = to_max_length(load_modules_result.modules, (m) => m.name);
23
+ for (const meta of load_modules_result.modules) {
24
+ printed.push('\n' + cyan(pad(meta.name, longest_task_name)), ' ', meta.mod.task.summary || '');
25
+ }
26
+ log[print_intro ? 'info' : 'plain'](printed.join('') + '\n');
27
+ }
28
+ else {
29
+ log.info(`No tasks found in ${dir_label}.`);
30
+ }
31
+ };
32
+ export const log_error_reasons = (log, reasons) => {
33
+ for (const reason of reasons) {
34
+ log.error(red(reason));
35
+ }
36
+ };
37
+ const ARGS_PROPERTY_NAME = '[...args]';
38
+ export const print_task_help = (log, meta) => {
39
+ const { name, mod: { task }, } = meta;
40
+ const printed = [];
41
+ printed.push(cyan(name), 'help', cyan(`\n\ngro ${name}`) + `: ${task.summary || '(no summary available)'}\n`);
42
+ if (task.Args) {
43
+ const properties = to_arg_properties(task.Args._def, meta);
44
+ // TODO hacky padding for some quick and dirty tables
45
+ const longest_task_name = Math.max(ARGS_PROPERTY_NAME.length, to_max_length(properties, (p) => p.name));
46
+ const longest_type = to_max_length(properties, (p) => p.schema.type);
47
+ const longest_default = to_max_length(properties, (p) => print_value(p.schema.default));
48
+ for (const property of properties) {
49
+ const name = property.name === '_' ? ARGS_PROPERTY_NAME : property.name;
50
+ printed.push(`\n${green(pad(name, longest_task_name))} `, gray(pad(property.schema.type, longest_type)) + ' ', pad(print_value(property.schema.default), longest_default) + ' ', property.schema.description || '(no description available)');
51
+ }
52
+ if (!properties.length) {
53
+ printed.push('\n' + gray('this task has no args'));
54
+ }
55
+ }
56
+ log.info(...printed, '\n');
57
+ };
58
+ const to_arg_properties = (def, meta) => {
59
+ const type_name = to_type_name(def);
60
+ if (type_name !== ZodFirstPartyTypeKind.ZodObject) {
61
+ throw Error(`Expected Args for task "${meta.name}" to be a ZodObject schema but got ${type_name}`);
62
+ }
63
+ const shape = def.shape();
64
+ const properties = [];
65
+ for (const name in shape) {
66
+ if ('no-' + name in shape)
67
+ continue;
68
+ const s = shape[name];
69
+ const schema = {
70
+ type: to_args_schema_type(s),
71
+ description: to_args_schema_description(s),
72
+ default: to_args_schema_default(s),
73
+ };
74
+ properties.push({ name, schema });
75
+ }
76
+ return properties;
77
+ };
78
+ // quick n dirty padding logic
79
+ const pad = (s, n) => s + ' '.repeat(n - s.length);
80
+ const to_max_length = (items, toString) => items.reduce((max, m) => Math.max(toString(m).length, max), 0);
81
+ // The following Zod helpers only need to support single-depth schemas for CLI args,
82
+ // but there's generic recursion to handle things like `ZodOptional` and `ZodDefault`.
83
+ const to_type_name = (def) => def.typeName;
84
+ const to_args_schema_type = ({ _def }) => {
85
+ const t = to_type_name(_def);
86
+ switch (t) {
87
+ case ZodFirstPartyTypeKind.ZodBoolean:
88
+ return 'boolean';
89
+ case ZodFirstPartyTypeKind.ZodString:
90
+ return 'string';
91
+ case ZodFirstPartyTypeKind.ZodNumber:
92
+ return 'number';
93
+ case ZodFirstPartyTypeKind.ZodArray:
94
+ return 'string[]'; // TODO support arrays of arbitrary types, or more hardcoded ones as needed
95
+ case ZodFirstPartyTypeKind.ZodEnum:
96
+ return _def.values.map((v) => `'${v}'`).join(' | ');
97
+ case ZodFirstPartyTypeKind.ZodUnion:
98
+ return 'string | string[]'; // TODO support unions of arbitrary types, or more hardcoded ones as needed
99
+ default: {
100
+ if ('innerType' in _def) {
101
+ return to_args_schema_type(_def.innerType);
102
+ }
103
+ else {
104
+ throw Error('Unknown zod type ' + t);
105
+ }
106
+ }
107
+ }
108
+ };
109
+ const to_args_schema_description = ({ _def }) => {
110
+ if (_def.description)
111
+ return _def.description;
112
+ if ('innerType' in _def) {
113
+ return to_args_schema_description(_def.innerType);
114
+ }
115
+ return '';
116
+ };
117
+ const to_args_schema_default = ({ _def }) => {
118
+ if (_def.defaultValue)
119
+ return _def.defaultValue();
120
+ if ('innerType' in _def) {
121
+ return to_args_schema_default(_def.innerType);
122
+ }
123
+ return undefined;
124
+ };
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { type Task } from './task.js';
3
+ export declare const Args: z.ZodObject<{
4
+ branch: z.ZodDefault<z.ZodString>;
5
+ changelog: z.ZodDefault<z.ZodString>;
6
+ preserve_changelog: z.ZodDefault<z.ZodBoolean>;
7
+ dry: z.ZodDefault<z.ZodBoolean>;
8
+ check: z.ZodDefault<z.ZodBoolean>;
9
+ 'no-check': z.ZodDefault<z.ZodBoolean>;
10
+ install: z.ZodDefault<z.ZodBoolean>;
11
+ 'no-install': z.ZodDefault<z.ZodBoolean>;
12
+ }, "strict", z.ZodTypeAny, {
13
+ install: boolean;
14
+ branch: string;
15
+ changelog: string;
16
+ 'no-install': boolean;
17
+ check: boolean;
18
+ dry: boolean;
19
+ preserve_changelog: boolean;
20
+ 'no-check': boolean;
21
+ }, {
22
+ branch?: string | undefined;
23
+ changelog?: string | undefined;
24
+ preserve_changelog?: boolean | undefined;
25
+ dry?: boolean | undefined;
26
+ check?: boolean | undefined;
27
+ 'no-check'?: boolean | undefined;
28
+ install?: boolean | undefined;
29
+ 'no-install'?: boolean | undefined;
30
+ }>;
31
+ export type Args = z.infer<typeof Args>;
32
+ export declare const task: Task<Args>;