@fuzdev/gro 0.192.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/args.d.ts +37 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +102 -0
- package/dist/build.task.d.ts +20 -0
- package/dist/build.task.d.ts.map +1 -0
- package/dist/build.task.js +119 -0
- package/dist/build_cache.d.ts +100 -0
- package/dist/build_cache.d.ts.map +1 -0
- package/dist/build_cache.js +299 -0
- package/dist/changelog.d.ts +11 -0
- package/dist/changelog.d.ts.map +1 -0
- package/dist/changelog.js +47 -0
- package/dist/changeset.task.d.ts +35 -0
- package/dist/changeset.task.d.ts.map +1 -0
- package/dist/changeset.task.js +151 -0
- package/dist/changeset_helpers.d.ts +17 -0
- package/dist/changeset_helpers.d.ts.map +1 -0
- package/dist/changeset_helpers.js +7 -0
- package/dist/check.task.d.ts +28 -0
- package/dist/check.task.d.ts.map +1 -0
- package/dist/check.task.js +104 -0
- package/dist/child_process_logging.d.ts +10 -0
- package/dist/child_process_logging.d.ts.map +1 -0
- package/dist/child_process_logging.js +26 -0
- package/dist/clean.task.d.ts +15 -0
- package/dist/clean.task.d.ts.map +1 -0
- package/dist/clean.task.js +40 -0
- package/dist/clean_fs.d.ts +9 -0
- package/dist/clean_fs.d.ts.map +1 -0
- package/dist/clean_fs.js +28 -0
- package/dist/cli.d.ts +34 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +61 -0
- package/dist/commit.task.d.ts +11 -0
- package/dist/commit.task.d.ts.map +1 -0
- package/dist/commit.task.js +24 -0
- package/dist/constants.d.ts +46 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +52 -0
- package/dist/deploy.task.d.ts +29 -0
- package/dist/deploy.task.d.ts.map +1 -0
- package/dist/deploy.task.js +217 -0
- package/dist/dev.task.d.ts +16 -0
- package/dist/dev.task.d.ts.map +1 -0
- package/dist/dev.task.js +44 -0
- package/dist/disknode.d.ts +23 -0
- package/dist/disknode.d.ts.map +1 -0
- package/dist/disknode.js +1 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +49 -0
- package/dist/esbuild_helpers.d.ts +16 -0
- package/dist/esbuild_helpers.d.ts.map +1 -0
- package/dist/esbuild_helpers.js +36 -0
- package/dist/esbuild_plugin_external_worker.d.ts +23 -0
- package/dist/esbuild_plugin_external_worker.d.ts.map +1 -0
- package/dist/esbuild_plugin_external_worker.js +55 -0
- package/dist/esbuild_plugin_svelte.d.ts +15 -0
- package/dist/esbuild_plugin_svelte.d.ts.map +1 -0
- package/dist/esbuild_plugin_svelte.js +83 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.d.ts +8 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_local_imports.js +30 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.d.ts +7 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_shim_alias.js +18 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.d.ts +9 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_shim_app.js +22 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.d.ts +11 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.d.ts.map +1 -0
- package/dist/esbuild_plugin_sveltekit_shim_env.js +18 -0
- package/dist/filer.d.ts +33 -0
- package/dist/filer.d.ts.map +1 -0
- package/dist/filer.js +385 -0
- package/dist/format.task.d.ts +11 -0
- package/dist/format.task.d.ts.map +1 -0
- package/dist/format.task.js +27 -0
- package/dist/format_directory.d.ts +13 -0
- package/dist/format_directory.d.ts.map +1 -0
- package/dist/format_directory.js +40 -0
- package/dist/format_file.d.ts +9 -0
- package/dist/format_file.d.ts.map +1 -0
- package/dist/format_file.js +42 -0
- package/dist/gen.d.ts +142 -0
- package/dist/gen.d.ts.map +1 -0
- package/dist/gen.js +199 -0
- package/dist/gen.task.d.ts +12 -0
- package/dist/gen.task.d.ts.map +1 -0
- package/dist/gen.task.js +149 -0
- package/dist/gen_helpers.d.ts +11 -0
- package/dist/gen_helpers.d.ts.map +1 -0
- package/dist/gen_helpers.js +76 -0
- package/dist/github.d.ts +19 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +33 -0
- package/dist/gro.config.default.d.ts +13 -0
- package/dist/gro.config.default.d.ts.map +1 -0
- package/dist/gro.config.default.js +33 -0
- package/dist/gro.d.ts +3 -0
- package/dist/gro.d.ts.map +1 -0
- package/dist/gro.js +21 -0
- package/dist/gro_config.d.ts +115 -0
- package/dist/gro_config.d.ts.map +1 -0
- package/dist/gro_config.js +114 -0
- package/dist/gro_helpers.d.ts +49 -0
- package/dist/gro_helpers.d.ts.map +1 -0
- package/dist/gro_helpers.js +97 -0
- package/dist/gro_plugin_gen.d.ts +12 -0
- package/dist/gro_plugin_gen.d.ts.map +1 -0
- package/dist/gro_plugin_gen.js +101 -0
- package/dist/gro_plugin_server.d.ts +80 -0
- package/dist/gro_plugin_server.d.ts.map +1 -0
- package/dist/gro_plugin_server.js +167 -0
- package/dist/gro_plugin_sveltekit_app.d.ts +9 -0
- package/dist/gro_plugin_sveltekit_app.d.ts.map +1 -0
- package/dist/gro_plugin_sveltekit_app.js +42 -0
- package/dist/gro_plugin_sveltekit_library.d.ts +16 -0
- package/dist/gro_plugin_sveltekit_library.d.ts.map +1 -0
- package/dist/gro_plugin_sveltekit_library.js +34 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/input_path.d.ts +64 -0
- package/dist/input_path.d.ts.map +1 -0
- package/dist/input_path.js +199 -0
- package/dist/invoke.d.ts +2 -0
- package/dist/invoke.d.ts.map +1 -0
- package/dist/invoke.js +28 -0
- package/dist/invoke_task.d.ts +30 -0
- package/dist/invoke_task.d.ts.map +1 -0
- package/dist/invoke_task.js +104 -0
- package/dist/lint.task.d.ts +11 -0
- package/dist/lint.task.d.ts.map +1 -0
- package/dist/lint.task.js +32 -0
- package/dist/loader.d.ts +6 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +192 -0
- package/dist/module.d.ts +4 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +6 -0
- package/dist/modules.d.ts +36 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +71 -0
- package/dist/package_json.d.ts +32 -0
- package/dist/package_json.d.ts.map +1 -0
- package/dist/package_json.js +178 -0
- package/dist/parse_exports.d.ts +20 -0
- package/dist/parse_exports.d.ts.map +1 -0
- package/dist/parse_exports.js +65 -0
- package/dist/parse_exports_context.d.ts +21 -0
- package/dist/parse_exports_context.d.ts.map +1 -0
- package/dist/parse_exports_context.js +332 -0
- package/dist/parse_imports.d.ts +5 -0
- package/dist/parse_imports.d.ts.map +1 -0
- package/dist/parse_imports.js +140 -0
- package/dist/paths.d.ts +41 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +69 -0
- package/dist/plugin.d.ts +36 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +78 -0
- package/dist/publish.task.d.ts +26 -0
- package/dist/publish.task.d.ts.map +1 -0
- package/dist/publish.task.js +176 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +2 -0
- package/dist/reinstall.task.d.ts +8 -0
- package/dist/reinstall.task.d.ts.map +1 -0
- package/dist/reinstall.task.js +35 -0
- package/dist/release.task.d.ts +8 -0
- package/dist/release.task.d.ts.map +1 -0
- package/dist/release.task.js +20 -0
- package/dist/resolve.task.d.ts +11 -0
- package/dist/resolve.task.d.ts.map +1 -0
- package/dist/resolve.task.js +38 -0
- package/dist/resolve_specifier.d.ts +22 -0
- package/dist/resolve_specifier.d.ts.map +1 -0
- package/dist/resolve_specifier.js +57 -0
- package/dist/run.task.d.ts +16 -0
- package/dist/run.task.d.ts.map +1 -0
- package/dist/run.task.js +52 -0
- package/dist/run_gen.d.ts +10 -0
- package/dist/run_gen.d.ts.map +1 -0
- package/dist/run_gen.js +73 -0
- package/dist/run_task.d.ts +17 -0
- package/dist/run_task.d.ts.map +1 -0
- package/dist/run_task.js +45 -0
- package/dist/source_json.d.ts +7 -0
- package/dist/source_json.d.ts.map +1 -0
- package/dist/source_json.js +145 -0
- package/dist/svelte_config.d.ts +57 -0
- package/dist/svelte_config.d.ts.map +1 -0
- package/dist/svelte_config.js +81 -0
- package/dist/sveltekit_helpers.d.ts +75 -0
- package/dist/sveltekit_helpers.d.ts.map +1 -0
- package/dist/sveltekit_helpers.js +94 -0
- package/dist/sveltekit_shim_app.d.ts +11 -0
- package/dist/sveltekit_shim_app.d.ts.map +1 -0
- package/dist/sveltekit_shim_app.js +31 -0
- package/dist/sveltekit_shim_app_environment.d.ts +13 -0
- package/dist/sveltekit_shim_app_environment.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_environment.js +14 -0
- package/dist/sveltekit_shim_app_forms.d.ts +5 -0
- package/dist/sveltekit_shim_app_forms.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_forms.js +6 -0
- package/dist/sveltekit_shim_app_navigation.d.ts +10 -0
- package/dist/sveltekit_shim_app_navigation.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_navigation.js +11 -0
- package/dist/sveltekit_shim_app_paths.d.ts +17 -0
- package/dist/sveltekit_shim_app_paths.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_paths.js +10 -0
- package/dist/sveltekit_shim_app_state.d.ts +5 -0
- package/dist/sveltekit_shim_app_state.d.ts.map +1 -0
- package/dist/sveltekit_shim_app_state.js +26 -0
- package/dist/sveltekit_shim_env.d.ts +5 -0
- package/dist/sveltekit_shim_env.d.ts.map +1 -0
- package/dist/sveltekit_shim_env.js +23 -0
- package/dist/sync.task.d.ts +16 -0
- package/dist/sync.task.d.ts.map +1 -0
- package/dist/sync.task.js +39 -0
- package/dist/task.d.ts +98 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +109 -0
- package/dist/task_logging.d.ts +6 -0
- package/dist/task_logging.d.ts.map +1 -0
- package/dist/task_logging.js +201 -0
- package/dist/test.task.d.ts +13 -0
- package/dist/test.task.d.ts.map +1 -0
- package/dist/test.task.js +53 -0
- package/dist/typecheck.task.d.ts +13 -0
- package/dist/typecheck.task.d.ts.map +1 -0
- package/dist/typecheck.task.js +68 -0
- package/dist/upgrade.task.d.ts +20 -0
- package/dist/upgrade.task.d.ts.map +1 -0
- package/dist/upgrade.task.js +111 -0
- package/dist/watch_dir.d.ts +36 -0
- package/dist/watch_dir.d.ts.map +1 -0
- package/dist/watch_dir.js +69 -0
- package/package.json +149 -0
- package/src/lib/args.ts +115 -0
- package/src/lib/build.task.ts +151 -0
- package/src/lib/build_cache.ts +378 -0
- package/src/lib/changelog.ts +69 -0
- package/src/lib/changeset.task.ts +228 -0
- package/src/lib/changeset_helpers.ts +14 -0
- package/src/lib/check.task.ts +132 -0
- package/src/lib/child_process_logging.ts +38 -0
- package/src/lib/clean.task.ts +48 -0
- package/src/lib/clean_fs.ts +54 -0
- package/src/lib/cli.ts +98 -0
- package/src/lib/commit.task.ts +34 -0
- package/src/lib/constants.ts +56 -0
- package/src/lib/deploy.task.ts +287 -0
- package/src/lib/dev.task.ts +52 -0
- package/src/lib/disknode.ts +26 -0
- package/src/lib/env.ts +78 -0
- package/src/lib/esbuild_helpers.ts +49 -0
- package/src/lib/esbuild_plugin_external_worker.ts +94 -0
- package/src/lib/esbuild_plugin_svelte.ts +134 -0
- package/src/lib/esbuild_plugin_sveltekit_local_imports.ts +38 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_alias.ts +27 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_app.ts +42 -0
- package/src/lib/esbuild_plugin_sveltekit_shim_env.ts +47 -0
- package/src/lib/filer.ts +458 -0
- package/src/lib/format.task.ts +44 -0
- package/src/lib/format_directory.ts +65 -0
- package/src/lib/format_file.ts +49 -0
- package/src/lib/gen.task.ts +206 -0
- package/src/lib/gen.ts +406 -0
- package/src/lib/gen_helpers.ts +131 -0
- package/src/lib/github.ts +46 -0
- package/src/lib/gro.config.default.ts +42 -0
- package/src/lib/gro.ts +29 -0
- package/src/lib/gro_config.ts +254 -0
- package/src/lib/gro_helpers.ts +108 -0
- package/src/lib/gro_plugin_gen.ts +149 -0
- package/src/lib/gro_plugin_server.ts +288 -0
- package/src/lib/gro_plugin_sveltekit_app.ts +58 -0
- package/src/lib/gro_plugin_sveltekit_library.ts +63 -0
- package/src/lib/index.ts +8 -0
- package/src/lib/input_path.ts +254 -0
- package/src/lib/invoke.ts +34 -0
- package/src/lib/invoke_task.ts +139 -0
- package/src/lib/lint.task.ts +39 -0
- package/src/lib/loader.ts +229 -0
- package/src/lib/module.ts +13 -0
- package/src/lib/modules.ts +117 -0
- package/src/lib/package_json.ts +255 -0
- package/src/lib/parse_exports.ts +100 -0
- package/src/lib/parse_exports_context.ts +395 -0
- package/src/lib/parse_imports.ts +180 -0
- package/src/lib/paths.ts +111 -0
- package/src/lib/plugin.ts +106 -0
- package/src/lib/publish.task.ts +228 -0
- package/src/lib/register.ts +3 -0
- package/src/lib/reinstall.task.ts +45 -0
- package/src/lib/release.task.ts +26 -0
- package/src/lib/resolve.task.ts +43 -0
- package/src/lib/resolve_specifier.ts +81 -0
- package/src/lib/run.task.ts +65 -0
- package/src/lib/run_gen.ts +110 -0
- package/src/lib/run_task.ts +82 -0
- package/src/lib/source_json.ts +183 -0
- package/src/lib/svelte_config.ts +140 -0
- package/src/lib/sveltekit_helpers.ts +193 -0
- package/src/lib/sveltekit_shim_app.ts +41 -0
- package/src/lib/sveltekit_shim_app_environment.ts +16 -0
- package/src/lib/sveltekit_shim_app_forms.ts +13 -0
- package/src/lib/sveltekit_shim_app_navigation.ts +23 -0
- package/src/lib/sveltekit_shim_app_paths.ts +26 -0
- package/src/lib/sveltekit_shim_app_state.ts +35 -0
- package/src/lib/sveltekit_shim_env.ts +45 -0
- package/src/lib/sync.task.ts +47 -0
- package/src/lib/task.ts +245 -0
- package/src/lib/task_logging.ts +255 -0
- package/src/lib/test.task.ts +63 -0
- package/src/lib/typecheck.task.ts +81 -0
- package/src/lib/upgrade.task.ts +148 -0
- package/src/lib/watch_dir.ts +115 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import {dirname, isAbsolute, join, resolve} from 'node:path';
|
|
2
|
+
import {stat} from 'node:fs/promises';
|
|
3
|
+
import {fs_exists, fs_search} from '@fuzdev/fuz_util/fs.js';
|
|
4
|
+
import {strip_start} from '@fuzdev/fuz_util/string.js';
|
|
5
|
+
import {z} from 'zod';
|
|
6
|
+
import type {Flavored} from '@fuzdev/fuz_util/types.js';
|
|
7
|
+
import type {PathInfo, PathId, ResolvedPath} from '@fuzdev/fuz_util/path.js';
|
|
8
|
+
|
|
9
|
+
import {GRO_PACKAGE_DIR, GRO_DIST_DIR} from './paths.ts';
|
|
10
|
+
import {TASK_FILE_SUFFIX_JS} from './task.ts';
|
|
11
|
+
|
|
12
|
+
// TODO Flavored doesn't work when used in schemas, use Zod brand instead? problem is ergonomics
|
|
13
|
+
export const InputPath = z.string();
|
|
14
|
+
export type InputPath = Flavored<z.infer<typeof InputPath>, 'InputPath'>;
|
|
15
|
+
|
|
16
|
+
export const RawInputPath = z.string();
|
|
17
|
+
export type RawInputPath = Flavored<z.infer<typeof RawInputPath>, 'RawInputPath'>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Raw input paths are paths that users provide to Gro to reference files for tasks and gen.
|
|
21
|
+
*
|
|
22
|
+
* A raw input path can be to a file or directory in the following forms:
|
|
23
|
+
*
|
|
24
|
+
* - an absolute path, preserved
|
|
25
|
+
* - an explicit relative path, e.g. `./src/foo`, resolved to `root_path` which defaults to the cwd
|
|
26
|
+
* - an implicit relative path, e.g. `src/foo`, preserved
|
|
27
|
+
* - an implicit relative path prefixed with `gro/`, transformed to absolute in the Gro directory
|
|
28
|
+
*
|
|
29
|
+
* Thus, input paths are either absolute or implicitly relative.
|
|
30
|
+
*/
|
|
31
|
+
export const to_input_path = (
|
|
32
|
+
raw_input_path: RawInputPath,
|
|
33
|
+
root_path = process.cwd(), // TODO @many isn't passed in anywhere, maybe hoist to `invoke_task` and others
|
|
34
|
+
): InputPath => {
|
|
35
|
+
if (raw_input_path.startsWith(GRO_PACKAGE_DIR)) {
|
|
36
|
+
return GRO_DIST_DIR + strip_start(raw_input_path, GRO_PACKAGE_DIR);
|
|
37
|
+
} else if (raw_input_path[0] === '.') {
|
|
38
|
+
return resolve(root_path, raw_input_path);
|
|
39
|
+
}
|
|
40
|
+
return raw_input_path as InputPath;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const to_input_paths = (
|
|
44
|
+
raw_input_paths: Array<RawInputPath>,
|
|
45
|
+
root_path?: string, // TODO @many isn't passed in anywhere, maybe hoist to `invoke_task` and others
|
|
46
|
+
): Array<InputPath> => raw_input_paths.map((p) => to_input_path(p, root_path));
|
|
47
|
+
|
|
48
|
+
export interface PossiblePath {
|
|
49
|
+
id: PathId;
|
|
50
|
+
input_path: InputPath;
|
|
51
|
+
root_dir: PathId;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Gets a list of possible source ids for each input path with `extensions`,
|
|
56
|
+
* duplicating each under `root_dirs`, without checking the filesystem.
|
|
57
|
+
*/
|
|
58
|
+
export const get_possible_paths = async (
|
|
59
|
+
input_path: InputPath,
|
|
60
|
+
root_dirs: Array<PathId>,
|
|
61
|
+
extensions: Array<string>,
|
|
62
|
+
): Promise<Array<PossiblePath>> => {
|
|
63
|
+
const possible_paths: Set<PossiblePath> = new Set();
|
|
64
|
+
|
|
65
|
+
const add_possible_paths = (path: string, root_dir: PathId) => {
|
|
66
|
+
// Specifically for paths to the Gro package dist, optimize by only looking for `.task.js`.
|
|
67
|
+
if (path.startsWith(GRO_DIST_DIR)) {
|
|
68
|
+
possible_paths.add({
|
|
69
|
+
id: (path.endsWith('/') || path.endsWith(TASK_FILE_SUFFIX_JS)
|
|
70
|
+
? path
|
|
71
|
+
: path + TASK_FILE_SUFFIX_JS) as PathId,
|
|
72
|
+
input_path,
|
|
73
|
+
root_dir,
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
possible_paths.add({id: path as PathId, input_path, root_dir});
|
|
77
|
+
if (!path.endsWith('/') && !extensions.some((e) => path.endsWith(e))) {
|
|
78
|
+
for (const extension of extensions) {
|
|
79
|
+
possible_paths.add({id: path + extension, input_path, root_dir});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (isAbsolute(input_path)) {
|
|
86
|
+
const exists = await fs_exists(input_path);
|
|
87
|
+
const is_directory = exists && (await stat(input_path)).isDirectory();
|
|
88
|
+
add_possible_paths(input_path, is_directory ? input_path : dirname(input_path));
|
|
89
|
+
} else {
|
|
90
|
+
for (const root_dir of root_dirs) {
|
|
91
|
+
add_possible_paths(join(root_dir, input_path), root_dir);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return Array.from(possible_paths);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export interface ResolvedInputPath {
|
|
98
|
+
input_path: InputPath;
|
|
99
|
+
id: PathId;
|
|
100
|
+
is_directory: boolean;
|
|
101
|
+
root_dir: PathId;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface ResolvedInputFile {
|
|
105
|
+
id: PathId;
|
|
106
|
+
input_path: InputPath;
|
|
107
|
+
resolved_input_path: ResolvedInputPath;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface ResolvedInputPaths {
|
|
111
|
+
resolved_input_paths: Array<ResolvedInputPath>;
|
|
112
|
+
possible_paths_by_input_path: Map<InputPath, Array<PossiblePath>>;
|
|
113
|
+
unmapped_input_paths: Array<InputPath>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Gets the path data for each input path, checking the filesystem for the possibilities
|
|
118
|
+
* and stopping at the first existing file or falling back to the first existing directory.
|
|
119
|
+
* If none is found for an input path, it's added to `unmapped_input_paths`.
|
|
120
|
+
*/
|
|
121
|
+
export const resolve_input_paths = async (
|
|
122
|
+
input_paths: Array<InputPath>,
|
|
123
|
+
root_dirs: Array<PathId>,
|
|
124
|
+
extensions: Array<string>,
|
|
125
|
+
): Promise<ResolvedInputPaths> => {
|
|
126
|
+
const resolved_input_paths: Array<ResolvedInputPath> = [];
|
|
127
|
+
const possible_paths_by_input_path: Map<InputPath, Array<PossiblePath>> = new Map();
|
|
128
|
+
const unmapped_input_paths: Array<InputPath> = [];
|
|
129
|
+
for (const input_path of input_paths) {
|
|
130
|
+
let found_file: [PathInfo, PossiblePath] | null = null;
|
|
131
|
+
let found_dirs: Array<[PathInfo, PossiblePath]> | null = null;
|
|
132
|
+
// eslint-disable-next-line no-await-in-loop
|
|
133
|
+
const possible_paths = await get_possible_paths(input_path, root_dirs, extensions);
|
|
134
|
+
possible_paths_by_input_path.set(input_path, possible_paths);
|
|
135
|
+
|
|
136
|
+
// Find the first existing file path or fallback to the first directory path.
|
|
137
|
+
for (const possible_path of possible_paths) {
|
|
138
|
+
// eslint-disable-next-line no-await-in-loop
|
|
139
|
+
if (!(await fs_exists(possible_path.id))) continue;
|
|
140
|
+
// eslint-disable-next-line no-await-in-loop
|
|
141
|
+
const stats = await stat(possible_path.id);
|
|
142
|
+
if (stats.isDirectory()) {
|
|
143
|
+
found_dirs ??= [];
|
|
144
|
+
found_dirs.push([{id: possible_path.id, is_directory: stats.isDirectory()}, possible_path]);
|
|
145
|
+
} else {
|
|
146
|
+
found_file = [{id: possible_path.id, is_directory: stats.isDirectory()}, possible_path];
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (found_file) {
|
|
151
|
+
resolved_input_paths.push({
|
|
152
|
+
input_path,
|
|
153
|
+
id: found_file[0].id,
|
|
154
|
+
is_directory: found_file[0].is_directory,
|
|
155
|
+
root_dir: found_file[1].root_dir,
|
|
156
|
+
});
|
|
157
|
+
} else if (found_dirs) {
|
|
158
|
+
for (const found_dir of found_dirs) {
|
|
159
|
+
resolved_input_paths.push({
|
|
160
|
+
input_path,
|
|
161
|
+
id: found_dir[0].id,
|
|
162
|
+
is_directory: found_dir[0].is_directory,
|
|
163
|
+
root_dir: found_dir[1].root_dir,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
unmapped_input_paths.push(input_path);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
resolved_input_paths,
|
|
172
|
+
possible_paths_by_input_path,
|
|
173
|
+
unmapped_input_paths,
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export interface ResolvedInputFiles {
|
|
178
|
+
resolved_input_files: Array<ResolvedInputFile>;
|
|
179
|
+
resolved_input_files_by_root_dir: Map<PathId, Array<ResolvedInputFile>>;
|
|
180
|
+
input_directories_with_no_files: Array<InputPath>;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Finds all of the matching files for the given input paths.
|
|
185
|
+
* De-dupes source ids.
|
|
186
|
+
*/
|
|
187
|
+
export const resolve_input_files = async (
|
|
188
|
+
resolved_input_paths: Array<ResolvedInputPath>,
|
|
189
|
+
search: (dir: string) => Promise<Array<ResolvedPath>> = fs_search,
|
|
190
|
+
): Promise<ResolvedInputFiles> => {
|
|
191
|
+
const resolved_input_files: Array<ResolvedInputFile> = [];
|
|
192
|
+
// Add all input paths initially, and remove each when resolved to a file.
|
|
193
|
+
const existing_path_ids: Set<PathId> = new Set();
|
|
194
|
+
|
|
195
|
+
let remaining = resolved_input_paths.slice();
|
|
196
|
+
const handle_found = (input_path: InputPath, id: PathId) => {
|
|
197
|
+
remaining = remaining.filter(
|
|
198
|
+
(r) => !(r.id === id || r.input_path === input_path || r.input_path === id), // `r.input_path === id` may be unnecessary
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// TODO parallelize but would need to de-dupe and retain order
|
|
203
|
+
for (const resolved_input_path of resolved_input_paths) {
|
|
204
|
+
const {input_path, id, is_directory} = resolved_input_path;
|
|
205
|
+
if (is_directory) {
|
|
206
|
+
// Handle input paths that resolve to directories.
|
|
207
|
+
// eslint-disable-next-line no-await-in-loop
|
|
208
|
+
const files = await search(id);
|
|
209
|
+
if (!files.length) continue;
|
|
210
|
+
const path_ids: Array<PathId> = [];
|
|
211
|
+
for (const {path, is_directory} of files) {
|
|
212
|
+
if (is_directory) continue;
|
|
213
|
+
const path_id = join(id, path);
|
|
214
|
+
if (!existing_path_ids.has(path_id)) {
|
|
215
|
+
existing_path_ids.add(path_id);
|
|
216
|
+
path_ids.push(path_id);
|
|
217
|
+
}
|
|
218
|
+
handle_found(input_path, path_id);
|
|
219
|
+
}
|
|
220
|
+
if (!path_ids.length) continue;
|
|
221
|
+
const resolved_input_files_for_input_path: Array<ResolvedInputFile> = [];
|
|
222
|
+
for (const path_id of path_ids) {
|
|
223
|
+
const resolved_input_file: ResolvedInputFile = {
|
|
224
|
+
id: path_id,
|
|
225
|
+
input_path,
|
|
226
|
+
resolved_input_path,
|
|
227
|
+
};
|
|
228
|
+
resolved_input_files.push(resolved_input_file);
|
|
229
|
+
resolved_input_files_for_input_path.push(resolved_input_file);
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
if (!existing_path_ids.has(id)) {
|
|
233
|
+
// Handle input paths that resolve to files.
|
|
234
|
+
existing_path_ids.add(id);
|
|
235
|
+
const resolved_input_file: ResolvedInputFile = {id, input_path, resolved_input_path};
|
|
236
|
+
resolved_input_files.push(resolved_input_file);
|
|
237
|
+
}
|
|
238
|
+
handle_found(input_path, id);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
resolved_input_files,
|
|
243
|
+
resolved_input_files_by_root_dir: resolved_input_files.reduce((map, resolved_input_file) => {
|
|
244
|
+
const {root_dir} = resolved_input_file.resolved_input_path;
|
|
245
|
+
if (map.has(root_dir)) {
|
|
246
|
+
map.get(root_dir)!.push(resolved_input_file);
|
|
247
|
+
} else {
|
|
248
|
+
map.set(root_dir, [resolved_input_file]);
|
|
249
|
+
}
|
|
250
|
+
return map;
|
|
251
|
+
}, new Map<PathId, Array<ResolvedInputFile>>()),
|
|
252
|
+
input_directories_with_no_files: remaining.map((r) => r.input_path),
|
|
253
|
+
};
|
|
254
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {attach_process_error_handler} from '@fuzdev/fuz_util/process.js';
|
|
2
|
+
import {configure_print_colors} from '@fuzdev/fuz_util/print.js';
|
|
3
|
+
|
|
4
|
+
import {invoke_task} from './invoke_task.ts';
|
|
5
|
+
import {to_task_args} from './args.ts';
|
|
6
|
+
import {load_gro_config} from './gro_config.ts';
|
|
7
|
+
import {sveltekit_sync_if_obviously_needed} from './sveltekit_helpers.ts';
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
|
|
11
|
+
This module invokes the Gro CLI which in turn invokes tasks.
|
|
12
|
+
Tasks are the CLI's primary concept.
|
|
13
|
+
To learn more about them, see `src/docs/task.md`.
|
|
14
|
+
|
|
15
|
+
When the CLI is invoked it passes the first CLI arg as `task_name` to `invoke_task`,
|
|
16
|
+
and the rest of the args are forwarded to the task's `run` function.
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// handle uncaught errors
|
|
21
|
+
attach_process_error_handler({
|
|
22
|
+
to_error_label: (err) => (err.constructor.name === 'TaskError' ? 'TaskError' : null),
|
|
23
|
+
map_error_text: (err) => (err.constructor.name === 'SilentError' ? '' : null),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (!process.env.NO_COLOR) {
|
|
27
|
+
const {styleText} = await import('node:util');
|
|
28
|
+
configure_print_colors(styleText);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await sveltekit_sync_if_obviously_needed();
|
|
32
|
+
|
|
33
|
+
const {task_name, args} = to_task_args();
|
|
34
|
+
await invoke_task(task_name, args, await load_gro_config());
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type {Args} from '@fuzdev/fuz_util/args.js';
|
|
2
|
+
import {Logger} from '@fuzdev/fuz_util/log.js';
|
|
3
|
+
import {print_ms, print_timings} from '@fuzdev/fuz_util/print.js';
|
|
4
|
+
import {create_stopwatch, Timings} from '@fuzdev/fuz_util/timings.js';
|
|
5
|
+
import {styleText as st} from 'node:util';
|
|
6
|
+
|
|
7
|
+
import {to_forwarded_args} from './args.ts';
|
|
8
|
+
import {run_task} from './run_task.ts';
|
|
9
|
+
import {to_input_path, RawInputPath} from './input_path.ts';
|
|
10
|
+
import {find_tasks, load_tasks, SilentError} from './task.ts';
|
|
11
|
+
import {package_json_load_for_gro} from './package_json.ts';
|
|
12
|
+
import {log_tasks, log_error_reasons} from './task_logging.ts';
|
|
13
|
+
import type {GroConfig} from './gro_config.ts';
|
|
14
|
+
import {Filer} from './filer.ts';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Invokes Gro tasks by name using the filesystem as the source.
|
|
18
|
+
*
|
|
19
|
+
* When a task is invoked,
|
|
20
|
+
* Gro first searches for tasks in the current working directory.
|
|
21
|
+
* and falls back to searching Gro's directory, if the two are different.
|
|
22
|
+
* See `src/lib/input_path.ts` for info about what "task_name" can refer to.
|
|
23
|
+
* If it matches a directory, all of the tasks within it are logged,
|
|
24
|
+
* both in the current working directory and Gro.
|
|
25
|
+
*
|
|
26
|
+
* This code is particularly hairy because
|
|
27
|
+
* we're accepting a wide range of user input
|
|
28
|
+
* and trying to do the right thing.
|
|
29
|
+
* Precise error messages are especially difficult and
|
|
30
|
+
* there are some subtle differences in the complex logical branches.
|
|
31
|
+
* The comments describe each condition.
|
|
32
|
+
*
|
|
33
|
+
* @param task_name - The name of the task to invoke.
|
|
34
|
+
* @param args - The CLI args to pass to the task.
|
|
35
|
+
* @param config - The Gro configuration.
|
|
36
|
+
* @param initial_timings - The timings to use for the top-level task, `null` for composed tasks.
|
|
37
|
+
*/
|
|
38
|
+
export const invoke_task = async (
|
|
39
|
+
task_name: RawInputPath,
|
|
40
|
+
args: Args | undefined,
|
|
41
|
+
config: GroConfig,
|
|
42
|
+
initial_filer?: Filer,
|
|
43
|
+
initial_timings?: Timings | null,
|
|
44
|
+
parent_log?: Logger,
|
|
45
|
+
): Promise<void> => {
|
|
46
|
+
// Create child logger if parent exists, otherwise root logger
|
|
47
|
+
const log_label = task_name || 'gro';
|
|
48
|
+
const log = parent_log ? parent_log.child(log_label) : new Logger(log_label);
|
|
49
|
+
log.info('invoking', task_name ? st('cyan', task_name) : 'gro');
|
|
50
|
+
|
|
51
|
+
// track if we created the filer
|
|
52
|
+
const owns_filer = !initial_filer;
|
|
53
|
+
const filer = initial_filer ?? new Filer({log: log.child('filer'), ...config.filer_options});
|
|
54
|
+
|
|
55
|
+
const owns_timings = !initial_timings;
|
|
56
|
+
const timings = initial_timings ?? new Timings();
|
|
57
|
+
|
|
58
|
+
const total_timing = create_stopwatch();
|
|
59
|
+
const finish = async () => {
|
|
60
|
+
// cleanup filer only if we created it and it was initialized
|
|
61
|
+
if (owns_filer && filer.inited) {
|
|
62
|
+
await filer.close();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (owns_timings) return; // kinda weird, print timings only for the top-level task
|
|
66
|
+
print_timings(timings, log);
|
|
67
|
+
log.info(`🕒 ${print_ms(total_timing())}`);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Check if the caller just wants to see the version.
|
|
71
|
+
if (!task_name && (args?.version || args?.v)) {
|
|
72
|
+
const gro_package_json = await package_json_load_for_gro();
|
|
73
|
+
log.info(`${st('gray', 'v')}${st('cyan', gro_package_json.version)}`);
|
|
74
|
+
await finish();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Resolve the input path for the provided task name.
|
|
79
|
+
const input_path = to_input_path(task_name);
|
|
80
|
+
|
|
81
|
+
const {task_root_dirs} = config;
|
|
82
|
+
|
|
83
|
+
// Find the task or directory specified by the `input_path`.
|
|
84
|
+
// Fall back to searching the Gro directory as well.
|
|
85
|
+
const found = await find_tasks([input_path], task_root_dirs, config);
|
|
86
|
+
if (!found.ok) {
|
|
87
|
+
log_error_reasons(log, found.reasons);
|
|
88
|
+
throw new SilentError();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Found a match either in the current working directory or Gro's directory.
|
|
92
|
+
const found_tasks = found.value;
|
|
93
|
+
const {resolved_input_files} = found_tasks;
|
|
94
|
+
|
|
95
|
+
// Load the task module.
|
|
96
|
+
const loaded = await load_tasks(found_tasks);
|
|
97
|
+
if (!loaded.ok) {
|
|
98
|
+
log_error_reasons(log, loaded.reasons);
|
|
99
|
+
throw new SilentError();
|
|
100
|
+
}
|
|
101
|
+
const loaded_tasks = loaded.value;
|
|
102
|
+
|
|
103
|
+
if (
|
|
104
|
+
resolved_input_files.length > 1 ||
|
|
105
|
+
resolved_input_files[0]!.resolved_input_path.is_directory
|
|
106
|
+
) {
|
|
107
|
+
// The input path matches a directory. Log the tasks but don't run them.
|
|
108
|
+
log_tasks(log, loaded_tasks);
|
|
109
|
+
await finish();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The input path matches a file that's presumable a task, so load and run it.
|
|
114
|
+
if (loaded_tasks.modules.length !== 1) throw Error('expected one loaded task'); // run only one task at a time
|
|
115
|
+
const task = loaded_tasks.modules[0]!;
|
|
116
|
+
log.info(
|
|
117
|
+
`→ ${st('cyan', task.name)} ${(task.mod.task.summary && st('gray', task.mod.task.summary)) ?? ''}`,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const timing_to_run_task = timings.start('run task ' + task_name);
|
|
121
|
+
const result = await run_task(
|
|
122
|
+
task,
|
|
123
|
+
{...args, ...to_forwarded_args(`gro ${task.name}`)},
|
|
124
|
+
invoke_task,
|
|
125
|
+
config,
|
|
126
|
+
filer,
|
|
127
|
+
log,
|
|
128
|
+
timings,
|
|
129
|
+
);
|
|
130
|
+
timing_to_run_task();
|
|
131
|
+
if (!result.ok) {
|
|
132
|
+
log.info(`${st('red', '🞩')} ${st('cyan', task.name)}`);
|
|
133
|
+
log_error_reasons(log, [result.reason]);
|
|
134
|
+
throw result.error;
|
|
135
|
+
}
|
|
136
|
+
log.info(`✓ ${st('cyan', task.name)}`);
|
|
137
|
+
|
|
138
|
+
await finish();
|
|
139
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {args_serialize} from '@fuzdev/fuz_util/args.js';
|
|
2
|
+
import {print_spawn_result} from '@fuzdev/fuz_util/process.js';
|
|
3
|
+
import {z} from 'zod';
|
|
4
|
+
|
|
5
|
+
import {to_forwarded_args} from './args.ts';
|
|
6
|
+
import {find_cli, spawn_cli} from './cli.ts';
|
|
7
|
+
import {TaskError, type Task} from './task.ts';
|
|
8
|
+
|
|
9
|
+
const ESLINT_CLI = 'eslint';
|
|
10
|
+
|
|
11
|
+
/** @nodocs */
|
|
12
|
+
export const Args = z.strictObject({
|
|
13
|
+
_: z.array(z.string()).meta({description: 'paths to serve'}).default([]),
|
|
14
|
+
eslint_cli: z.string().meta({description: 'the ESLint CLI to use'}).default(ESLINT_CLI),
|
|
15
|
+
});
|
|
16
|
+
export type Args = z.infer<typeof Args>;
|
|
17
|
+
|
|
18
|
+
/** @nodocs */
|
|
19
|
+
export const task: Task<Args> = {
|
|
20
|
+
summary: 'run eslint',
|
|
21
|
+
Args,
|
|
22
|
+
run: async ({log, args}): Promise<void> => {
|
|
23
|
+
const {_, eslint_cli} = args;
|
|
24
|
+
|
|
25
|
+
const found_eslint_cli = await find_cli(eslint_cli);
|
|
26
|
+
if (!found_eslint_cli) {
|
|
27
|
+
// TODO maybe make this an option?
|
|
28
|
+
log.info('ESLint is not installed; skipping linting');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const forwarded_args = {_, 'max-warnings': 0, ...to_forwarded_args(eslint_cli)};
|
|
33
|
+
const serialized_args = args_serialize(forwarded_args);
|
|
34
|
+
const eslintResult = await spawn_cli(found_eslint_cli, serialized_args, log);
|
|
35
|
+
if (!eslintResult?.ok) {
|
|
36
|
+
throw new TaskError(`ESLint found some problems. ${print_spawn_result(eslintResult!)}`);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import {compile, compileModule, preprocess} from 'svelte/compiler';
|
|
2
|
+
import {fileURLToPath, pathToFileURL} from 'node:url';
|
|
3
|
+
import {dirname, join} from 'node:path';
|
|
4
|
+
import type {LoadHook, ResolveHook} from 'node:module';
|
|
5
|
+
import {readFileSync} from 'node:fs';
|
|
6
|
+
import ts_blank_space from 'ts-blank-space';
|
|
7
|
+
|
|
8
|
+
import {render_env_shim_module} from './sveltekit_shim_env.ts';
|
|
9
|
+
import {
|
|
10
|
+
render_sveltekit_shim_app_environment,
|
|
11
|
+
render_sveltekit_shim_app_paths,
|
|
12
|
+
SVELTEKIT_SHIM_APP_ENVIRONMENT_MATCHER,
|
|
13
|
+
SVELTEKIT_SHIM_APP_PATHS_MATCHER,
|
|
14
|
+
sveltekit_shim_app_specifiers,
|
|
15
|
+
} from './sveltekit_shim_app.ts';
|
|
16
|
+
import {default_svelte_config} from './svelte_config.ts';
|
|
17
|
+
import {paths} from './paths.ts';
|
|
18
|
+
import {TS_MATCHER, SVELTE_MATCHER, SVELTE_RUNES_MATCHER} from './constants.ts';
|
|
19
|
+
import {resolve_specifier} from './resolve_specifier.ts';
|
|
20
|
+
import {map_sveltekit_aliases} from './sveltekit_helpers.ts';
|
|
21
|
+
|
|
22
|
+
// TODO get out of the loader business, starting with https://nodejs.org/api/typescript.html#type-stripping
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
|
|
26
|
+
Usage via `$lib/register.ts`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node --import @fuzdev/gro/register.js foo.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Usage via `$lib/run.task.ts`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
gro run foo.ts
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Direct usage without register (see also `$lib/gro.ts`):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
node --import 'data:text/javascript,import {register} from "node:module"; import {pathToFileURL} from "node:url"; register("@fuzdev/gro/loader.js", pathToFileURL("./"));' --experimental-import-meta-resolve --experimental-strip-types' foo.ts
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
TODO how to improve that gnarly import line? was originally designed for the now-deprecated `--loader`
|
|
45
|
+
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
// TODO sourcemaps for the svelte preprocessors
|
|
49
|
+
// TODO `import.meta.resolve` wasn't available in loaders when this was first implemented, but might be now
|
|
50
|
+
|
|
51
|
+
// dev is always true in the loader
|
|
52
|
+
const dev = true;
|
|
53
|
+
|
|
54
|
+
const dir = paths.root;
|
|
55
|
+
|
|
56
|
+
const {
|
|
57
|
+
alias,
|
|
58
|
+
base_url,
|
|
59
|
+
assets_url,
|
|
60
|
+
env_dir,
|
|
61
|
+
private_prefix,
|
|
62
|
+
public_prefix,
|
|
63
|
+
svelte_compile_options,
|
|
64
|
+
svelte_compile_module_options,
|
|
65
|
+
svelte_preprocessors,
|
|
66
|
+
} = default_svelte_config;
|
|
67
|
+
|
|
68
|
+
const aliases = Object.entries(alias);
|
|
69
|
+
|
|
70
|
+
const RAW_MATCHER = /(%3Fraw|\.css|\.svg)$/; // TODO others? configurable?
|
|
71
|
+
|
|
72
|
+
/** @nodocs */
|
|
73
|
+
export const load: LoadHook = async (url, context, nextLoad) => {
|
|
74
|
+
// console.log(`url`, url);
|
|
75
|
+
if (SVELTEKIT_SHIM_APP_PATHS_MATCHER.test(url)) {
|
|
76
|
+
// SvelteKit `$app/paths` shim
|
|
77
|
+
return {
|
|
78
|
+
format: 'module',
|
|
79
|
+
shortCircuit: true,
|
|
80
|
+
source: render_sveltekit_shim_app_paths(base_url, assets_url),
|
|
81
|
+
};
|
|
82
|
+
} else if (SVELTEKIT_SHIM_APP_ENVIRONMENT_MATCHER.test(url)) {
|
|
83
|
+
// SvelteKit `$app/environment` shim
|
|
84
|
+
return {
|
|
85
|
+
format: 'module',
|
|
86
|
+
shortCircuit: true,
|
|
87
|
+
source: render_sveltekit_shim_app_environment(dev),
|
|
88
|
+
};
|
|
89
|
+
} else if (SVELTE_RUNES_MATCHER.test(url)) {
|
|
90
|
+
// Svelte runes in js/ts, `.svelte.ts`
|
|
91
|
+
const filename = fileURLToPath(url);
|
|
92
|
+
const loaded = await nextLoad(url, {...context, format: 'module-typescript'});
|
|
93
|
+
const raw_source = loaded.source?.toString(); // eslint-disable-line @typescript-eslint/no-base-to-string
|
|
94
|
+
if (raw_source == null) throw Error(`Failed to load ${url}`);
|
|
95
|
+
// TODO should be nice if we could use Node's builtin amaro transform, but I couldn't find a way after digging into the source, AFAICT it's internal and not exposed
|
|
96
|
+
const source = ts_blank_space(raw_source); // TODO was using oxc-transform and probably should, but this doesn't require sourcemaps, and it's still alpha as of May 2025
|
|
97
|
+
const transformed = compileModule(source, {
|
|
98
|
+
...svelte_compile_module_options,
|
|
99
|
+
dev,
|
|
100
|
+
filename,
|
|
101
|
+
});
|
|
102
|
+
return {format: 'module', shortCircuit: true, source: transformed.js.code};
|
|
103
|
+
} else if (TS_MATCHER.test(url)) {
|
|
104
|
+
// ts but not `.svelte.ts`
|
|
105
|
+
return nextLoad(url, {...context, format: 'module-typescript'});
|
|
106
|
+
} else if (SVELTE_MATCHER.test(url)) {
|
|
107
|
+
// Svelte, `.svelte`
|
|
108
|
+
const loaded = await nextLoad(url, {...context, format: 'module'});
|
|
109
|
+
const raw_source = loaded.source!.toString(); // eslint-disable-line @typescript-eslint/no-base-to-string
|
|
110
|
+
const filename = fileURLToPath(url);
|
|
111
|
+
const preprocessed = svelte_preprocessors // TODO @many use sourcemaps (and diagnostics?)
|
|
112
|
+
? await preprocess(raw_source, svelte_preprocessors, {filename})
|
|
113
|
+
: null;
|
|
114
|
+
const source = preprocessed?.code ?? raw_source;
|
|
115
|
+
const transformed = compile(source, {...svelte_compile_options, dev, filename});
|
|
116
|
+
return {format: 'module', shortCircuit: true, source: transformed.js.code};
|
|
117
|
+
} else if (context.importAttributes.type === 'json') {
|
|
118
|
+
// json - any file extension
|
|
119
|
+
// TODO probably follow esbuild and also export every top-level property for objects from the module for good treeshaking - https://esbuild.github.io/content-types/#json (type generation?)
|
|
120
|
+
// TODO why is removing the importAttributes needed? can't pass no context either -
|
|
121
|
+
// error: `Module "file:///home/user/dev/repo/foo.json" is not of type "json"`
|
|
122
|
+
const loaded = await nextLoad(url, {...context, importAttributes: undefined});
|
|
123
|
+
const raw_source = loaded.source?.toString(); // eslint-disable-line @typescript-eslint/no-base-to-string
|
|
124
|
+
if (raw_source == null) throw Error(`Failed to load ${url}`);
|
|
125
|
+
const source = `export default ` + raw_source;
|
|
126
|
+
return {format: 'module', shortCircuit: true, source};
|
|
127
|
+
} else if (RAW_MATCHER.test(url)) {
|
|
128
|
+
// raw text imports like `?raw`, `.css`, `.svg`
|
|
129
|
+
const filename = fileURLToPath(url.endsWith('%3Fraw') ? url.substring(0, url.length - 6) : url);
|
|
130
|
+
const raw_source = readFileSync(filename, 'utf8');
|
|
131
|
+
const source =
|
|
132
|
+
'export default `' + raw_source.replaceAll('\\', '\\\\').replaceAll('`', '\\`') + '`;';
|
|
133
|
+
return {format: 'module', shortCircuit: true, source};
|
|
134
|
+
} else {
|
|
135
|
+
// SvelteKit `$env`
|
|
136
|
+
// TODO use `format` from the resolve hook to speed this up and make it simpler
|
|
137
|
+
if (context.format === 'sveltekit-env') {
|
|
138
|
+
let mode: 'static' | 'dynamic';
|
|
139
|
+
let visibility: 'public' | 'private';
|
|
140
|
+
switch (context.importAttributes.virtual) {
|
|
141
|
+
case '$env/static/public': {
|
|
142
|
+
mode = 'static';
|
|
143
|
+
visibility = 'public';
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case '$env/static/private': {
|
|
147
|
+
mode = 'static';
|
|
148
|
+
visibility = 'private';
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case '$env/dynamic/public': {
|
|
152
|
+
mode = 'dynamic';
|
|
153
|
+
visibility = 'public';
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case '$env/dynamic/private': {
|
|
157
|
+
mode = 'dynamic';
|
|
158
|
+
visibility = 'private';
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
default: {
|
|
162
|
+
throw Error(`Unknown $env import: ${context.importAttributes.virtual}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const source = render_env_shim_module(
|
|
166
|
+
dev,
|
|
167
|
+
mode,
|
|
168
|
+
visibility,
|
|
169
|
+
public_prefix,
|
|
170
|
+
private_prefix,
|
|
171
|
+
env_dir,
|
|
172
|
+
);
|
|
173
|
+
return {format: 'module', shortCircuit: true, source};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// fallback to default behavior
|
|
178
|
+
return nextLoad(url, context);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/** @nodocs */
|
|
182
|
+
export const resolve: ResolveHook = async (specifier, context, nextResolve) => {
|
|
183
|
+
let s = specifier;
|
|
184
|
+
|
|
185
|
+
// Support SvelteKit `$env` imports
|
|
186
|
+
if (
|
|
187
|
+
s === '$env/static/public' ||
|
|
188
|
+
s === '$env/static/private' ||
|
|
189
|
+
s === '$env/dynamic/public' ||
|
|
190
|
+
s === '$env/dynamic/private'
|
|
191
|
+
) {
|
|
192
|
+
// The returned `url` is validated before `load` is called,
|
|
193
|
+
// so we need a slightly roundabout strategy to pass through the specifier for virtual files.
|
|
194
|
+
return {
|
|
195
|
+
url: pathToFileURL(join(dir, 'src/lib', s)).href,
|
|
196
|
+
format: 'sveltekit-env',
|
|
197
|
+
importAttributes: {virtual: s}, // TODO idk I'm just making this up
|
|
198
|
+
shortCircuit: true,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Support SvelteKit `$app` imports, including from node_modules
|
|
203
|
+
const shimmed = sveltekit_shim_app_specifiers.get(s);
|
|
204
|
+
if (shimmed !== undefined) {
|
|
205
|
+
return nextResolve(shimmed, context);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Apply SvelteKit aliases (handles self-referencing packages like @fuzdev/fuz_util -> src/lib)
|
|
209
|
+
s = map_sveltekit_aliases(s, aliases);
|
|
210
|
+
|
|
211
|
+
// Bare specifiers (not starting with . or /) use Node's default resolution
|
|
212
|
+
if (s[0] !== '.' && s[0] !== '/') {
|
|
213
|
+
return nextResolve(s, context);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Resolve paths using Vite conventions
|
|
217
|
+
const parent_url = context.parentURL;
|
|
218
|
+
if (!parent_url) {
|
|
219
|
+
return nextResolve(s, context);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const resolved = await resolve_specifier(s, dirname(fileURLToPath(parent_url)));
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
url: pathToFileURL(resolved.path_id_with_querystring).href,
|
|
226
|
+
format: 'module',
|
|
227
|
+
shortCircuit: true,
|
|
228
|
+
};
|
|
229
|
+
};
|