@ryanatkn/gro 0.119.1 → 0.120.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/changelog.d.ts +1 -0
- package/dist/changeset.task.js +4 -5
- package/dist/clean_fs.d.ts +1 -2
- package/dist/clean_fs.js +3 -2
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +2 -2
- package/dist/config.d.ts +14 -1
- package/dist/config.js +17 -5
- package/dist/config.test.js +50 -1
- package/dist/deploy.task.js +8 -7
- package/dist/docs/README.gen.md.js +3 -3
- package/dist/docs/config.md +22 -6
- package/dist/docs/gen.md +2 -1
- package/dist/docs/task.md +4 -3
- package/dist/docs/tasks.gen.md.js +17 -10
- package/dist/docs/tasks.md +1 -0
- package/dist/env.d.ts +2 -3
- package/dist/env.js +2 -2
- package/dist/esbuild_helpers.d.ts +2 -1
- package/dist/esbuild_plugin_external_worker.d.ts +0 -1
- package/dist/esbuild_plugin_external_worker.js +7 -7
- package/dist/esbuild_plugin_svelte.d.ts +0 -1
- package/dist/esbuild_plugin_sveltekit_local_imports.js +2 -2
- package/dist/format_directory.d.ts +1 -0
- package/dist/fs.d.ts +1 -3
- package/dist/fs.js +3 -13
- package/dist/fs.test.js +5 -5
- package/dist/gen.d.ts +66 -13
- package/dist/gen.js +78 -9
- package/dist/gen.task.d.ts +3 -0
- package/dist/gen.task.js +24 -19
- package/dist/gen.test.js +48 -35
- package/dist/git.d.ts +0 -1
- package/dist/git.js +3 -3
- package/dist/gro_helpers.js +4 -4
- package/dist/gro_plugin_gen.js +7 -7
- package/dist/gro_plugin_server.d.ts +2 -2
- package/dist/gro_plugin_server.js +5 -5
- package/dist/gro_plugin_sveltekit_app.js +8 -8
- package/dist/hash.d.ts +1 -2
- package/dist/input_path.d.ts +34 -16
- package/dist/input_path.js +119 -67
- package/dist/input_path.test.js +150 -46
- package/dist/invoke_task.d.ts +2 -1
- package/dist/invoke_task.js +33 -79
- package/dist/loader.d.ts +0 -1
- package/dist/loader.js +4 -4
- package/dist/modules.d.ts +17 -36
- package/dist/modules.js +29 -68
- package/dist/modules.test.js +19 -143
- package/dist/package.d.ts +11 -20
- package/dist/package.js +61 -64
- package/dist/package_json.d.ts +1 -0
- package/dist/package_json.js +1 -1
- package/dist/package_meta.d.ts +1 -1
- package/dist/path.d.ts +12 -8
- package/dist/path.js +0 -6
- package/dist/paths.d.ts +7 -12
- package/dist/paths.js +11 -34
- package/dist/paths.test.js +17 -15
- package/dist/plugin.d.ts +1 -1
- package/dist/publish.task.js +3 -3
- package/dist/resolve.task.d.ts +11 -0
- package/dist/resolve.task.js +24 -0
- package/dist/resolve_node_specifier.d.ts +2 -2
- package/dist/resolve_node_specifier.js +3 -3
- package/dist/resolve_specifier.d.ts +2 -1
- package/dist/resolve_specifier.js +16 -16
- package/dist/resolve_specifier.test.js +9 -9
- package/dist/run.task.js +2 -2
- package/dist/run_gen.d.ts +4 -4
- package/dist/run_gen.js +9 -16
- package/dist/run_gen.test.js +10 -15
- package/dist/run_task.d.ts +2 -1
- package/dist/run_task.js +2 -0
- package/dist/search_fs.d.ts +20 -7
- package/dist/search_fs.js +40 -18
- package/dist/search_fs.test.js +9 -11
- package/dist/src_json.js +2 -2
- package/dist/sveltekit_config.d.ts +0 -1
- package/dist/sveltekit_helpers.js +4 -4
- package/dist/sveltekit_shim_app.d.ts +1 -1
- package/dist/sveltekit_shim_app_forms.d.ts +0 -1
- package/dist/sveltekit_shim_app_navigation.d.ts +0 -1
- package/dist/sveltekit_shim_app_paths.d.ts +0 -1
- package/dist/sveltekit_shim_app_stores.d.ts +0 -1
- package/dist/sveltekit_shim_env.d.ts +1 -1
- package/dist/task.d.ts +65 -1
- package/dist/task.js +86 -13
- package/dist/task.test.js +25 -11
- package/dist/task_logging.d.ts +3 -6
- package/dist/task_logging.js +18 -36
- package/dist/watch_dir.d.ts +2 -2
- package/dist/watch_dir.js +14 -16
- package/package.json +18 -23
- package/dist/gen_module.d.ts +0 -34
- package/dist/gen_module.js +0 -32
- package/dist/gen_module.test.d.ts +0 -1
- package/dist/gen_module.test.js +0 -30
- package/dist/task_module.d.ts +0 -15
- package/dist/task_module.js +0 -18
- package/dist/task_module.test.d.ts +0 -1
- package/dist/task_module.test.js +0 -67
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ It includes:
|
|
|
76
76
|
|
|
77
77
|
## install
|
|
78
78
|
|
|
79
|
-
> depends on node >=
|
|
79
|
+
> depends on node >=22.3
|
|
80
80
|
|
|
81
81
|
Typical usage installs [@ryanatkn/gro](https://www.npmjs.com/package/@ryanatkn/gro)
|
|
82
82
|
as a dev dependency:
|
|
@@ -107,7 +107,7 @@ gro # prints available tasks - defers to any local gro installation
|
|
|
107
107
|
Run a task: gro [name]
|
|
108
108
|
View help: gro [name] --help
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
19 tasks in gro:
|
|
111
111
|
|
|
112
112
|
build build the project
|
|
113
113
|
changeset call changeset with gro patterns
|
|
@@ -122,6 +122,7 @@ lint run eslint
|
|
|
122
122
|
publish bump version, publish to npm, and git push
|
|
123
123
|
reinstall refreshes package-lock.json with the latest and cleanest deps
|
|
124
124
|
release publish and deploy
|
|
125
|
+
resolve run `gro gen`, update `package.json`, and optionally `npm i` to sync up
|
|
125
126
|
run execute a file with the loader, like `node` but works for TypeScript
|
|
126
127
|
sync run `gro gen`, update `package.json`, and optionally `npm i` to sync up
|
|
127
128
|
test run tests with uvu
|
package/dist/changelog.d.ts
CHANGED
package/dist/changeset.task.js
CHANGED
|
@@ -3,9 +3,8 @@ import { spawn } from '@ryanatkn/belt/process.js';
|
|
|
3
3
|
import { red, blue } from 'kleur/colors';
|
|
4
4
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import {
|
|
6
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
7
7
|
import { Task_Error } from './task.js';
|
|
8
|
-
import { exists } from './fs.js';
|
|
9
8
|
import { load_package_json } from './package_json.js';
|
|
10
9
|
import { find_cli, spawn_cli } from './cli.js';
|
|
11
10
|
import { Git_Origin, git_check_fully_staged_workspace, git_push_to_create } from './git.js';
|
|
@@ -67,7 +66,7 @@ export const task = {
|
|
|
67
66
|
throw new Task_Error('Failed to find SvelteKit library: ' + has_sveltekit_library_result.message);
|
|
68
67
|
}
|
|
69
68
|
const path = join(dir, 'config.json');
|
|
70
|
-
const inited =
|
|
69
|
+
const inited = existsSync(path);
|
|
71
70
|
if (!inited) {
|
|
72
71
|
await spawn_cli('changeset', ['init']);
|
|
73
72
|
const access = access_arg ?? package_json.private ? RESTRICTED_ACCESS : PUBLIC_ACCESS;
|
|
@@ -109,9 +108,9 @@ export const task = {
|
|
|
109
108
|
* @see https://github.com/changesets/changesets/pull/1121
|
|
110
109
|
*/
|
|
111
110
|
const create_changeset_adder = async (repo_name, dir, message, bump) => {
|
|
112
|
-
const filenames_before =
|
|
111
|
+
const filenames_before = readdirSync(dir);
|
|
113
112
|
return async () => {
|
|
114
|
-
const filenames_after =
|
|
113
|
+
const filenames_after = readdirSync(dir);
|
|
115
114
|
const filenames_added = filenames_after.filter((p) => !filenames_before.includes(p));
|
|
116
115
|
if (!filenames_added.length) {
|
|
117
116
|
throw Error('expected to find a new changeset file');
|
package/dist/clean_fs.d.ts
CHANGED
package/dist/clean_fs.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { rm
|
|
1
|
+
import { rm } from 'node:fs/promises';
|
|
2
|
+
import { readdirSync } from 'node:fs';
|
|
2
3
|
import { paths } from './paths.js';
|
|
3
4
|
import { NODE_MODULES_DIRNAME, GRO_DIST_PREFIX, SVELTEKIT_DEV_DIRNAME, SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_VITE_CACHE_PATH, SVELTEKIT_DIST_DIRNAME, } from './path_constants.js';
|
|
4
5
|
export const clean_fs = async ({ build = false, build_dev = false, build_dist = false, sveltekit = false, nodemodules = false, }, rm_options = { force: true, recursive: true }) => {
|
|
@@ -10,7 +11,7 @@ export const clean_fs = async ({ build = false, build_dev = false, build_dist =
|
|
|
10
11
|
promises.push(rm(paths.build_dev, rm_options));
|
|
11
12
|
}
|
|
12
13
|
if (build || build_dist) {
|
|
13
|
-
const paths = (
|
|
14
|
+
const paths = readdirSync('.').filter((p) => p.startsWith(GRO_DIST_PREFIX));
|
|
14
15
|
for (const path of paths) {
|
|
15
16
|
promises.push(rm(path, rm_options));
|
|
16
17
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import type { SpawnOptions } from 'node:child_process';
|
|
3
2
|
import { type Spawn_Result } from '@ryanatkn/belt/process.js';
|
|
4
3
|
/**
|
|
5
4
|
* Looks for the CLI `name`, first local to the cwd and then globally.
|
|
6
5
|
*/
|
|
7
|
-
export declare const find_cli: (name: string) => Promise<
|
|
6
|
+
export declare const find_cli: (name: string) => Promise<"local" | "global" | null>;
|
|
8
7
|
/**
|
|
9
8
|
* Calls the CLI `name` if available, first local to the cwd and then globally.
|
|
10
9
|
*/
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { spawn, spawn_out } from '@ryanatkn/belt/process.js';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
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
|
*/
|
|
8
8
|
export const find_cli = async (name) => {
|
|
9
|
-
if (
|
|
9
|
+
if (existsSync(join(NODE_MODULES_DIRNAME, `.bin/${name}`))) {
|
|
10
10
|
return 'local';
|
|
11
11
|
}
|
|
12
12
|
const { stdout } = await spawn_out('which', [name]);
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Create_Config_Plugins } from './plugin.js';
|
|
2
2
|
import type { Map_Package_Json } from './package_json.js';
|
|
3
|
+
import type { Path_Filter } from './path.js';
|
|
3
4
|
export interface Gro_Config {
|
|
4
5
|
plugins: Create_Config_Plugins;
|
|
5
6
|
/**
|
|
@@ -12,12 +13,24 @@ export interface Gro_Config {
|
|
|
12
13
|
* The root directories to search for tasks given implicit relative input paths.
|
|
13
14
|
* Defaults to `./src/lib`, then the cwd, then the Gro package dist.
|
|
14
15
|
*/
|
|
15
|
-
|
|
16
|
+
task_root_dirs: string[];
|
|
17
|
+
/**
|
|
18
|
+
* When searching the filsystem for tasks and genfiles,
|
|
19
|
+
* directories and files are included if they pass all of these filters.
|
|
20
|
+
*/
|
|
21
|
+
search_filters: Path_Filter | Path_Filter[] | null;
|
|
16
22
|
}
|
|
17
23
|
export interface Create_Gro_Config {
|
|
18
24
|
(base_config: Gro_Config): Gro_Config | Promise<Gro_Config>;
|
|
19
25
|
}
|
|
20
26
|
export declare const create_empty_config: () => Gro_Config;
|
|
27
|
+
/**
|
|
28
|
+
* The regexp used by default to exclude directories and files
|
|
29
|
+
* when searching the filesystem for tasks and genfiles.
|
|
30
|
+
* Customize via `search_filters` in the `Gro_Config`.
|
|
31
|
+
* See the test cases for the exact behavior.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_SEARCH_EXCLUDER: RegExp;
|
|
21
34
|
export declare const DEFAULT_EXPORTS_EXCLUDER: RegExp;
|
|
22
35
|
export interface Gro_Config_Module {
|
|
23
36
|
readonly default: Gro_Config | Create_Gro_Config;
|
package/dist/config.js
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import { join, resolve } from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
2
3
|
import { GRO_DIST_DIR, IS_THIS_GRO, paths } from './paths.js';
|
|
3
|
-
import { GRO_CONFIG_PATH } from './path_constants.js';
|
|
4
|
+
import { GRO_CONFIG_PATH, NODE_MODULES_DIRNAME, SERVER_DIST_PATH, SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_DIST_DIRNAME, } from './path_constants.js';
|
|
4
5
|
import create_default_config from './gro.config.default.js';
|
|
5
|
-
import { exists } from './fs.js';
|
|
6
6
|
export const create_empty_config = () => ({
|
|
7
7
|
plugins: () => [],
|
|
8
8
|
// TODO maybe disable if no SvelteKit `lib` directory? or other detection to improve defaults
|
|
9
9
|
map_package_json: default_map_package_json,
|
|
10
|
-
|
|
10
|
+
task_root_dirs: [
|
|
11
|
+
paths.lib,
|
|
12
|
+
IS_THIS_GRO ? null : paths.root,
|
|
13
|
+
IS_THIS_GRO ? null : GRO_DIST_DIR,
|
|
14
|
+
].filter(Boolean),
|
|
15
|
+
search_filters: [(id) => !DEFAULT_SEARCH_EXCLUDER.test(id)],
|
|
11
16
|
});
|
|
17
|
+
/**
|
|
18
|
+
* The regexp used by default to exclude directories and files
|
|
19
|
+
* when searching the filesystem for tasks and genfiles.
|
|
20
|
+
* Customize via `search_filters` in the `Gro_Config`.
|
|
21
|
+
* See the test cases for the exact behavior.
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_SEARCH_EXCLUDER = new RegExp(`((^|/)\\.[^/]+|/?${NODE_MODULES_DIRNAME}|(^|/)${SVELTEKIT_BUILD_DIRNAME}|(?<!(^|/)gro/)${SVELTEKIT_DIST_DIRNAME}|(^|/)${SERVER_DIST_PATH})($|/)`, 'u');
|
|
12
24
|
const default_map_package_json = async (package_json) => {
|
|
13
25
|
if (package_json.exports) {
|
|
14
26
|
package_json.exports = Object.fromEntries(Object.entries(package_json.exports).filter(([k]) => !DEFAULT_EXPORTS_EXCLUDER.test(k)));
|
|
@@ -20,7 +32,7 @@ export const load_config = async (dir = paths.root) => {
|
|
|
20
32
|
const default_config = await create_default_config(create_empty_config());
|
|
21
33
|
const config_path = join(dir, GRO_CONFIG_PATH);
|
|
22
34
|
let config;
|
|
23
|
-
if (
|
|
35
|
+
if (existsSync(config_path)) {
|
|
24
36
|
const config_module = await import(config_path);
|
|
25
37
|
validate_config_module(config_module, config_path);
|
|
26
38
|
config =
|
|
@@ -37,7 +49,7 @@ export const load_config = async (dir = paths.root) => {
|
|
|
37
49
|
// Mutates `config` with cleaned up values.
|
|
38
50
|
const normalize_config = (config) => {
|
|
39
51
|
// TODO any validation?
|
|
40
|
-
config.
|
|
52
|
+
config.task_root_dirs = config.task_root_dirs.map((p) => resolve(p));
|
|
41
53
|
};
|
|
42
54
|
export const validate_config_module = (config_module, config_path) => {
|
|
43
55
|
const config = config_module.default;
|
package/dist/config.test.js
CHANGED
|
@@ -1,8 +1,57 @@
|
|
|
1
1
|
import { test } from 'uvu';
|
|
2
2
|
import * as assert from 'uvu/assert';
|
|
3
|
-
import { load_config } from './config.js';
|
|
3
|
+
import { DEFAULT_SEARCH_EXCLUDER, load_config } from './config.js';
|
|
4
4
|
test('load_config', async () => {
|
|
5
5
|
const config = await load_config();
|
|
6
6
|
assert.ok(config);
|
|
7
7
|
});
|
|
8
|
+
test('DEFAULT_SEARCH_EXCLUDER', () => {
|
|
9
|
+
const assert_excludes = (dirname) => {
|
|
10
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`a/${dirname}/c`), 'should exclude: ' + dirname);
|
|
11
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`a/${dirname}/c/d.js`), 'should exclude: ' + dirname);
|
|
12
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`a/${dirname}/`), 'should exclude: ' + dirname);
|
|
13
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`a/${dirname}`), 'should exclude: ' + dirname);
|
|
14
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/a/${dirname}/c`), 'should exclude: ' + dirname);
|
|
15
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/a/${dirname}/c/d.js`), 'should exclude: ' + dirname);
|
|
16
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/a/${dirname}/`), 'should exclude: ' + dirname);
|
|
17
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/a/${dirname}`), 'should exclude: ' + dirname);
|
|
18
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/${dirname}/a`), 'should exclude: ' + dirname);
|
|
19
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/${dirname}/a/b.js`), 'should exclude: ' + dirname);
|
|
20
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/${dirname}/`), 'should exclude: ' + dirname);
|
|
21
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`/${dirname}`), 'should exclude: ' + dirname);
|
|
22
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`./${dirname}/a`), 'should exclude: ' + dirname);
|
|
23
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`./${dirname}/a/b.js`), 'should exclude: ' + dirname);
|
|
24
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`./${dirname}/`), 'should exclude: ' + dirname);
|
|
25
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`./${dirname}`), 'should exclude: ' + dirname);
|
|
26
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`${dirname}/a`), 'should exclude: ' + dirname);
|
|
27
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`${dirname}/a/b.js`), 'should exclude: ' + dirname);
|
|
28
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`${dirname}/`), 'should exclude: ' + dirname);
|
|
29
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test(`${dirname}`), 'should exclude: ' + dirname);
|
|
30
|
+
};
|
|
31
|
+
assert_excludes('node_modules');
|
|
32
|
+
assert_excludes('dist');
|
|
33
|
+
assert_excludes('build');
|
|
34
|
+
assert_excludes('.git');
|
|
35
|
+
assert_excludes('.gro');
|
|
36
|
+
assert_excludes('.svelte-kit');
|
|
37
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('nodemodules'));
|
|
38
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('a/b/c'));
|
|
39
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('/a/b/c'));
|
|
40
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('/a/b/c.js'));
|
|
41
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('/a/b/c.d.js'));
|
|
42
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('./a/b/c'));
|
|
43
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('./a/b/c.d.js'));
|
|
44
|
+
// Special exception for `gro/dist/`:
|
|
45
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test('/home/not_gro/dist/a.task.js'));
|
|
46
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test('/home/grodist/a.task.js'));
|
|
47
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test('not_gro/dist/a.task.js'));
|
|
48
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test('not_dist/a.task.js'));
|
|
49
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test('grodist/a.task.js'));
|
|
50
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('/home/gro/dist/a.task.js'));
|
|
51
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('gro/dist/a.task.js'));
|
|
52
|
+
assert.ok(!DEFAULT_SEARCH_EXCLUDER.test('./gro/dist/a.task.js'));
|
|
53
|
+
// But not `gro/build/` and others because they're not usecases:
|
|
54
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test('/home/gro/build/a.task.js'));
|
|
55
|
+
assert.ok(DEFAULT_SEARCH_EXCLUDER.test('/home/gro/node_modules/a.task.js'));
|
|
56
|
+
});
|
|
8
57
|
test.run();
|
package/dist/deploy.task.js
CHANGED
|
@@ -2,12 +2,13 @@ import { spawn } from '@ryanatkn/belt/process.js';
|
|
|
2
2
|
import { print_error } from '@ryanatkn/belt/print.js';
|
|
3
3
|
import { green, red } from 'kleur/colors';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { cp, mkdir,
|
|
5
|
+
import { cp, mkdir, rm } from 'node:fs/promises';
|
|
6
6
|
import { join, resolve } from 'node:path';
|
|
7
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
7
8
|
import { Task_Error } from './task.js';
|
|
8
9
|
import { print_path } from './paths.js';
|
|
9
10
|
import { GRO_DIRNAME, GIT_DIRNAME, SVELTEKIT_BUILD_DIRNAME } from './path_constants.js';
|
|
10
|
-
import { empty_dir
|
|
11
|
+
import { empty_dir } from './fs.js';
|
|
11
12
|
import { git_check_clean_workspace, git_checkout, git_local_branch_exists, git_remote_branch_exists, Git_Origin, Git_Branch, git_delete_local_branch, git_push_to_create, git_reset_branch_to_first_commit, git_pull, git_fetch, git_check_setting_pull_rebase, git_clone_locally, git_current_branch_name, } from './git.js';
|
|
12
13
|
// docs at ./docs/deploy.md
|
|
13
14
|
// terminal command for testing:
|
|
@@ -96,7 +97,7 @@ export const task = {
|
|
|
96
97
|
// First, check if the deploy dir exists, and if so, attempt to sync it.
|
|
97
98
|
// If anything goes wrong, delete the directory and we'll initialize it
|
|
98
99
|
// using the same code path as if it didn't exist in the first place.
|
|
99
|
-
if (
|
|
100
|
+
if (existsSync(resolved_deploy_dir)) {
|
|
100
101
|
if (target !== (await git_current_branch_name(target_spawn_options))) {
|
|
101
102
|
// We're in a bad state because the target branch has changed,
|
|
102
103
|
// so delete the directory and continue as if it wasn't there.
|
|
@@ -114,7 +115,7 @@ export const task = {
|
|
|
114
115
|
}
|
|
115
116
|
// Second, initialize the deploy dir if needed.
|
|
116
117
|
// It may not exist, or it may have been deleted after failing to sync above.
|
|
117
|
-
if (!(
|
|
118
|
+
if (!existsSync(resolved_deploy_dir)) {
|
|
118
119
|
const local_deploy_branch_exists = await git_local_branch_exists(target);
|
|
119
120
|
await git_fetch(origin, ('+' + target + ':' + target)); // fetch+merge and allow non-fastforward updates with the +
|
|
120
121
|
await git_clone_locally(origin, target, dir, resolved_deploy_dir);
|
|
@@ -131,7 +132,7 @@ export const task = {
|
|
|
131
132
|
else {
|
|
132
133
|
// Remote target branch does not exist, so start from scratch
|
|
133
134
|
// Delete the deploy dir and recreate it
|
|
134
|
-
if (
|
|
135
|
+
if (existsSync(resolved_deploy_dir)) {
|
|
135
136
|
await rm(resolved_deploy_dir, { recursive: true });
|
|
136
137
|
await mkdir(resolved_deploy_dir, { recursive: true });
|
|
137
138
|
}
|
|
@@ -160,7 +161,7 @@ export const task = {
|
|
|
160
161
|
if (build) {
|
|
161
162
|
await invoke_task('build');
|
|
162
163
|
}
|
|
163
|
-
if (!(
|
|
164
|
+
if (!existsSync(build_dir)) {
|
|
164
165
|
log.error(red('directory to deploy does not exist after building:'), build_dir);
|
|
165
166
|
return;
|
|
166
167
|
}
|
|
@@ -173,7 +174,7 @@ export const task = {
|
|
|
173
174
|
throw new Task_Error(`Deploy safely canceled due to build failure. See the error above.`);
|
|
174
175
|
}
|
|
175
176
|
// Copy the build
|
|
176
|
-
await Promise.all((
|
|
177
|
+
await Promise.all(readdirSync(build_dir).map((path) => cp(join(build_dir, path), join(resolved_deploy_dir, path), { recursive: true })));
|
|
177
178
|
// At this point, `dist/` is ready to be committed and deployed!
|
|
178
179
|
if (dry) {
|
|
179
180
|
log.info(green('dry deploy complete:'), 'files at', print_path(resolved_deploy_dir));
|
|
@@ -2,7 +2,7 @@ import { dirname, relative, basename } from 'node:path';
|
|
|
2
2
|
import { parse_path_parts, parse_path_segments } from '@ryanatkn/belt/path.js';
|
|
3
3
|
import { strip_start } from '@ryanatkn/belt/string.js';
|
|
4
4
|
import { to_output_file_name } from '../gen.js';
|
|
5
|
-
import { paths,
|
|
5
|
+
import { paths, base_path_to_path_id } from '../paths.js';
|
|
6
6
|
import { search_fs } from '../search_fs.js';
|
|
7
7
|
// TODO look at `tasks.gen.md.ts` to refactor and generalize
|
|
8
8
|
// TODO show nested structure, not a flat list
|
|
@@ -24,7 +24,7 @@ export const gen = async ({ origin_id }) => {
|
|
|
24
24
|
const root_link = `[${root_path}](/../..)`;
|
|
25
25
|
const doc_files = await search_fs(origin_dir);
|
|
26
26
|
const doc_paths = [];
|
|
27
|
-
for (const path of doc_files
|
|
27
|
+
for (const { path } of doc_files) {
|
|
28
28
|
if (path === output_file_name || !path.endsWith('.md')) {
|
|
29
29
|
continue;
|
|
30
30
|
}
|
|
@@ -37,7 +37,7 @@ export const gen = async ({ origin_id }) => {
|
|
|
37
37
|
const segment = parse_path_segments(relative_path_part).at(-1);
|
|
38
38
|
return is_index_file && relative_path_part === relative_dir
|
|
39
39
|
? segment
|
|
40
|
-
: `[${segment}](${relative(origin_dir,
|
|
40
|
+
: `[${segment}](${relative(origin_dir, base_path_to_path_id(relative_path_part)) || './'})`;
|
|
41
41
|
});
|
|
42
42
|
const breadcrumbs = '> <sub>' + [root_link, ...path_parts, output_file_name].join(' / ') + '</sub>';
|
|
43
43
|
// TODO render the footer with the origin_id
|
package/dist/docs/config.md
CHANGED
|
@@ -44,7 +44,8 @@ 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
|
-
|
|
47
|
+
task_root_dirs: string[];
|
|
48
|
+
search_filters: Path_Filter | Path_Filter[] | null;
|
|
48
49
|
}
|
|
49
50
|
```
|
|
50
51
|
|
|
@@ -55,7 +56,11 @@ import type {Create_Gro_Config} from '@ryanatkn/gro';
|
|
|
55
56
|
import {gro_plugin_sveltekit_app} from '@ryanatkn/gro/gro_plugin_sveltekit_app.js';
|
|
56
57
|
|
|
57
58
|
const config: Create_Gro_Config = async (cfg) => {
|
|
58
|
-
//
|
|
59
|
+
// `cfg`, which is equal to `create_empty_config()`,
|
|
60
|
+
// can be mutated or you can return your own.
|
|
61
|
+
// A return value is required to avoid potential errors and reduce ambiguity.
|
|
62
|
+
|
|
63
|
+
// example setting your own plugins):
|
|
59
64
|
cfg.plugins = async () => [
|
|
60
65
|
gro_plugin_sveltekit_app(),
|
|
61
66
|
(await import('./src/custom_plugin.js')).plugin(),
|
|
@@ -90,7 +95,8 @@ const config = create_empty_config();
|
|
|
90
95
|
|
|
91
96
|
// config.plugins = ...;
|
|
92
97
|
// config.map_package_json = ...;
|
|
93
|
-
// config.
|
|
98
|
+
// config.task_root_dirs = ...;
|
|
99
|
+
// config.search_filters = ...;
|
|
94
100
|
|
|
95
101
|
export default config;
|
|
96
102
|
```
|
|
@@ -176,12 +182,22 @@ export interface Map_Package_Json {
|
|
|
176
182
|
}
|
|
177
183
|
```
|
|
178
184
|
|
|
179
|
-
## `
|
|
185
|
+
## `task_root_dirs`
|
|
180
186
|
|
|
181
|
-
The Gro config option `
|
|
187
|
+
The Gro config option `task_root_dirs` allows customizing Gro's task resolution.
|
|
182
188
|
When calling `gro [input_path]`, absolute and explicitly relative paths starting with `.`
|
|
183
189
|
are resolved according to normal filesystem rules,
|
|
184
190
|
but non-explicit input paths, like `foo`, are resolved by searching
|
|
185
|
-
through `
|
|
191
|
+
through `task_root_dirs` in order until a matching file or directory is found on the filesystem.
|
|
186
192
|
|
|
187
193
|
The default task paths are `./src/lib`, then `.`, and then Gro's dist directory.
|
|
194
|
+
|
|
195
|
+
## `search_filters`
|
|
196
|
+
|
|
197
|
+
The Gro config option `search_filters` allows customizing
|
|
198
|
+
how Gro searches for tasks and genfiles on the filesystem.
|
|
199
|
+
Directories and files are included if they pass all of these filters.
|
|
200
|
+
|
|
201
|
+
By default, it uses the `DEFAULT_SEARCH_EXCLUDER` to exclude
|
|
202
|
+
dot-prefixed directories, node_modules,
|
|
203
|
+
and the build and dist directories for SvelteKit and Gro.
|
package/dist/docs/gen.md
CHANGED
|
@@ -109,10 +109,11 @@ The `Gen` function receives one argument, the `Gen_Context` object:
|
|
|
109
109
|
```ts
|
|
110
110
|
export interface Gen_Context {
|
|
111
111
|
config: Gro_Config;
|
|
112
|
+
sveltekit_config: Parsed_Sveltekit_Config;
|
|
112
113
|
/**
|
|
113
114
|
* Same as `import.meta.url` but in path form.
|
|
114
115
|
*/
|
|
115
|
-
origin_id:
|
|
116
|
+
origin_id: Path_Id;
|
|
116
117
|
log: Logger;
|
|
117
118
|
}
|
|
118
119
|
// export const gen: Gen = ({config, origin_id, log}) => {
|
package/dist/docs/task.md
CHANGED
|
@@ -28,7 +28,7 @@ and defers composition to the user in regular TypeScript modules.
|
|
|
28
28
|
- Gro automatically discovers all `*.task.ts|js` files
|
|
29
29
|
in its configurable directory, so creating a new task
|
|
30
30
|
is as simple as [creating a new file](#define-a-task), no config needed
|
|
31
|
-
(defaults to `src/lib`, see the config option [`
|
|
31
|
+
(defaults to `src/lib`, see the config option [`task_root_dirs`](./config.md#task_root_dirs))
|
|
32
32
|
- to view [the available tasks](https://github.com/ryanatkn/gro/blob/main/src/lib/docs/tasks.md)
|
|
33
33
|
run `gro` with no arguments
|
|
34
34
|
- task definitions are just objects with an async `run` function and some optional properties,
|
|
@@ -59,10 +59,10 @@ As a developer, it's nice to be able to reuse TypeScript modules in every contex
|
|
|
59
59
|
$ gro
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
The [config](./config.md) option [
|
|
62
|
+
The [config](./config.md) option [task_root_dirs](./config.md#task_root_dirs)
|
|
63
63
|
tells Gro where to search for tasks.
|
|
64
64
|
|
|
65
|
-
> Currently, only the first directory specified in `
|
|
65
|
+
> Currently, only the first directory specified in `task_root_dirs` that's found on the filesystem
|
|
66
66
|
> will be used to automatically discover tasks, like when running `gro` without args.
|
|
67
67
|
> Please open an issue if you would like to see Gro be able to discover
|
|
68
68
|
> tasks in more than one directory - it will take some reworking of internals
|
|
@@ -162,6 +162,7 @@ import type {Task_Context} from '@ryanatkn/gro';
|
|
|
162
162
|
export interface Task_Context<T_Args = object> {
|
|
163
163
|
args: T_Args;
|
|
164
164
|
config: Gro_Config;
|
|
165
|
+
sveltekit_config: Parsed_Sveltekit_Config;
|
|
165
166
|
log: Logger;
|
|
166
167
|
timings: Timings;
|
|
167
168
|
invoke_task: (task_name: string, args?: Args, config?: Gro_Config) => Promise<void>;
|
|
@@ -2,25 +2,32 @@ import { dirname, relative, basename } from 'node:path';
|
|
|
2
2
|
import { parse_path_parts, parse_path_segments } from '@ryanatkn/belt/path.js';
|
|
3
3
|
import { strip_start } from '@ryanatkn/belt/string.js';
|
|
4
4
|
import { to_output_file_name } from '../gen.js';
|
|
5
|
-
import { paths,
|
|
6
|
-
import { load_task_modules } from '../task_module.js';
|
|
5
|
+
import { paths, base_path_to_path_id } from '../paths.js';
|
|
7
6
|
import { log_error_reasons } from '../task_logging.js';
|
|
7
|
+
import { find_tasks, load_tasks, Task_Error } from '../task.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
|
-
// to generate a markdown file
|
|
10
|
+
// to generate a markdown file with a summary of all of Gro's tasks.
|
|
11
11
|
// Other projects that use Gro should be able to import this module
|
|
12
12
|
// or other otherwise get frictionless access to this specific use case,
|
|
13
13
|
// and they should be able to extend or customize it to any degree.
|
|
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 ({
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
20
|
-
log_error_reasons(log,
|
|
21
|
-
throw new
|
|
17
|
+
export const gen = async ({ origin_id, log, config }) => {
|
|
18
|
+
const found = await find_tasks(['.'], [paths.lib], config);
|
|
19
|
+
if (!found.ok) {
|
|
20
|
+
log_error_reasons(log, found.reasons);
|
|
21
|
+
throw new Task_Error(`Failed to generate task docs: ${found.type}`);
|
|
22
22
|
}
|
|
23
|
-
const
|
|
23
|
+
const found_tasks = found.value;
|
|
24
|
+
const loaded = await load_tasks(found_tasks);
|
|
25
|
+
if (!loaded.ok) {
|
|
26
|
+
log_error_reasons(log, loaded.reasons);
|
|
27
|
+
throw new Task_Error(`Failed to generate task docs: ${loaded.type}`);
|
|
28
|
+
}
|
|
29
|
+
const loaded_tasks = loaded.value;
|
|
30
|
+
const tasks = loaded_tasks.modules;
|
|
24
31
|
const root_path = parse_path_segments(paths.root).at(-1);
|
|
25
32
|
const origin_dir = dirname(origin_id);
|
|
26
33
|
const origin_base = basename(origin_id);
|
|
@@ -33,7 +40,7 @@ export const gen = async ({ config, origin_id, log }) => {
|
|
|
33
40
|
const root_link = `[${root_path}](/../..)`;
|
|
34
41
|
// TODO do we want to use absolute paths instead of relative paths,
|
|
35
42
|
// because GitHub works with them and it simplifies the code?
|
|
36
|
-
const path_parts = parse_path_parts(relative_dir).map((relative_path_part) => `[${parse_path_segments(relative_path_part).at(-1)}](${relative(origin_dir,
|
|
43
|
+
const path_parts = parse_path_parts(relative_dir).map((relative_path_part) => `[${parse_path_segments(relative_path_part).at(-1)}](${relative(origin_dir, base_path_to_path_id(relative_path_part)) || './'})`);
|
|
37
44
|
const breadcrumbs = '> <sub>' + [root_link, ...path_parts, output_file_name].join(' / ') + '</sub>';
|
|
38
45
|
// TODO render the footer with the origin_id
|
|
39
46
|
return `# tasks
|
package/dist/docs/tasks.md
CHANGED
|
@@ -19,6 +19,7 @@ What is a `Task`? See [`task.md`](./task.md).
|
|
|
19
19
|
- [publish](../publish.task.ts) - bump version, publish to npm, and git push
|
|
20
20
|
- [reinstall](../reinstall.task.ts) - refreshes package-lock.json with the latest and cleanest deps
|
|
21
21
|
- [release](../release.task.ts) - publish and deploy
|
|
22
|
+
- [resolve](../resolve.task.ts) - diagnostic that logs the info resolved from the filesystem for the given input paths
|
|
22
23
|
- [run](../run.task.ts) - execute a file with the loader, like `node` but works for TypeScript
|
|
23
24
|
- [sync](../sync.task.ts) - run `gro gen`, update `package.json`, and optionally `npm i` to sync up
|
|
24
25
|
- [test](../test.task.ts) - run tests with uvu
|
package/dist/env.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const merge_envs: (envs: Array<Record<string, string | undefined>>, visibility: 'public' | 'private', public_prefix: string, private_prefix: string) => Record<string, string>;
|
|
1
|
+
export declare const load_env: (dev: boolean, visibility: "public" | "private", public_prefix: string, private_prefix: string, env_dir?: string, env_files?: string[], ambient_env?: NodeJS.ProcessEnv) => Promise<Record<string, string>>;
|
|
2
|
+
export declare const merge_envs: (envs: Array<Record<string, string | undefined>>, visibility: "public" | "private", public_prefix: string, private_prefix: string) => Record<string, string>;
|
|
4
3
|
export declare const is_private_env: (key: string, public_prefix: string, private_prefix: string) => boolean;
|
|
5
4
|
export declare const is_public_env: (key: string, public_prefix: string, private_prefix: string) => boolean;
|
|
6
5
|
/**
|
package/dist/env.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import dotenv from 'dotenv';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
5
|
export const load_env = async (dev, visibility, public_prefix, private_prefix, env_dir, env_files = ['.env', '.env.' + (dev ? 'development' : 'production')], ambient_env = process.env) => {
|
|
6
6
|
const envs = await Promise.all(env_files
|
|
7
7
|
.map(async (path) => (await load(env_dir === undefined ? path : resolve(env_dir, path))))
|
|
@@ -10,7 +10,7 @@ export const load_env = async (dev, visibility, public_prefix, private_prefix, e
|
|
|
10
10
|
return merge_envs(envs, visibility, public_prefix, private_prefix);
|
|
11
11
|
};
|
|
12
12
|
const load = async (path) => {
|
|
13
|
-
if (!(
|
|
13
|
+
if (!existsSync(path))
|
|
14
14
|
return undefined;
|
|
15
15
|
const loaded = await readFile(path, 'utf8');
|
|
16
16
|
return dotenv.parse(loaded);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logger } from '@ryanatkn/belt/log.js';
|
|
1
2
|
import type * as esbuild from 'esbuild';
|
|
2
3
|
import type { Parsed_Sveltekit_Config } from './sveltekit_config.js';
|
|
3
4
|
export declare const print_build_result: (log: Logger, build_result: esbuild.BuildResult) => void;
|
|
@@ -10,5 +11,5 @@ export declare const print_build_result: (log: Logger, build_result: esbuild.Bui
|
|
|
10
11
|
* @param mode
|
|
11
12
|
* @returns
|
|
12
13
|
*/
|
|
13
|
-
export declare const to_define_import_meta_env: (dev: boolean, base_url: Parsed_Sveltekit_Config[
|
|
14
|
+
export declare const to_define_import_meta_env: (dev: boolean, base_url: Parsed_Sveltekit_Config["base_url"], ssr?: boolean, mode?: string) => Record<string, string>;
|
|
14
15
|
export declare const ts_transform_options: esbuild.TransformOptions;
|
|
@@ -11,11 +11,11 @@ export const esbuild_plugin_external_worker = ({ dev, build_options, dir = proce
|
|
|
11
11
|
name: 'external_worker',
|
|
12
12
|
setup: (build) => {
|
|
13
13
|
const builds = new Map();
|
|
14
|
-
const build_worker = async (
|
|
15
|
-
if (builds.has(
|
|
16
|
-
return builds.get(
|
|
14
|
+
const build_worker = async (path_id) => {
|
|
15
|
+
if (builds.has(path_id))
|
|
16
|
+
return builds.get(path_id);
|
|
17
17
|
const building = esbuild.build({
|
|
18
|
-
entryPoints: [
|
|
18
|
+
entryPoints: [path_id],
|
|
19
19
|
plugins: [
|
|
20
20
|
esbuild_plugin_sveltekit_shim_app({ dev, base_url, assets_url }),
|
|
21
21
|
esbuild_plugin_sveltekit_shim_env({
|
|
@@ -38,13 +38,13 @@ export const esbuild_plugin_external_worker = ({ dev, build_options, dir = proce
|
|
|
38
38
|
define: to_define_import_meta_env(dev, base_url),
|
|
39
39
|
...build_options,
|
|
40
40
|
});
|
|
41
|
-
builds.set(
|
|
41
|
+
builds.set(path_id, building);
|
|
42
42
|
return building;
|
|
43
43
|
};
|
|
44
44
|
build.onResolve({ filter: /\.worker(|\.js|\.ts)$/u }, async ({ path, resolveDir }) => {
|
|
45
45
|
const parsed = await resolve_specifier(path, resolveDir);
|
|
46
|
-
const { specifier,
|
|
47
|
-
const build_result = await build_worker(
|
|
46
|
+
const { specifier, path_id, namespace } = parsed;
|
|
47
|
+
const build_result = await build_worker(path_id);
|
|
48
48
|
if (log)
|
|
49
49
|
print_build_result(log, build_result);
|
|
50
50
|
return { path: './' + basename(specifier), external: true, namespace };
|
|
@@ -13,8 +13,8 @@ export const esbuild_plugin_sveltekit_local_imports = () => ({
|
|
|
13
13
|
const { path, importer } = args;
|
|
14
14
|
if (!importer)
|
|
15
15
|
return { path };
|
|
16
|
-
const {
|
|
17
|
-
return { path:
|
|
16
|
+
const { path_id, namespace } = await resolve_specifier(path, dirname(importer));
|
|
17
|
+
return { path: path_id, namespace }; // `namespace` may be `undefined`, but esbuild needs the absolute path for json etc
|
|
18
18
|
});
|
|
19
19
|
build.onLoad({ filter: /.*/u, namespace: 'sveltekit_local_imports_ts' }, async ({ path }) => ({
|
|
20
20
|
contents: await readFile(path),
|
package/dist/fs.d.ts
CHANGED