@ryanatkn/gro 0.135.2 → 0.135.3
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/dist/check.task.d.ts +2 -2
- package/dist/filer.d.ts +29 -0
- package/dist/filer.d.ts.map +1 -0
- package/dist/filer.js +165 -0
- package/dist/gen.task.d.ts +2 -2
- package/dist/gro.config.default.d.ts.map +1 -1
- package/dist/gro.config.default.js +2 -3
- package/dist/gro_plugin_gen.d.ts +9 -2
- package/dist/gro_plugin_gen.d.ts.map +1 -1
- package/dist/gro_plugin_gen.js +67 -37
- package/dist/gro_plugin_sveltekit_library.d.ts.map +1 -1
- package/dist/gro_plugin_sveltekit_library.js +4 -16
- package/dist/invoke_task.d.ts +2 -1
- package/dist/invoke_task.d.ts.map +1 -1
- package/dist/invoke_task.js +4 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +3 -9
- package/dist/package.d.ts +22 -0
- package/dist/package.d.ts.map +1 -1
- package/dist/package.js +39 -13
- package/dist/parse_imports.d.ts +6 -0
- package/dist/parse_imports.d.ts.map +1 -0
- package/dist/parse_imports.js +29 -0
- package/dist/path_constants.d.ts +1 -0
- package/dist/path_constants.d.ts.map +1 -1
- package/dist/path_constants.js +1 -0
- package/dist/paths.d.ts +2 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +3 -1
- package/dist/run_task.d.ts +2 -1
- package/dist/run_task.d.ts.map +1 -1
- package/dist/run_task.js +4 -3
- package/dist/sveltekit_config.d.ts +1 -1
- package/dist/sveltekit_config.d.ts.map +1 -1
- package/dist/sveltekit_config.js +1 -1
- package/dist/sveltekit_helpers.d.ts +6 -0
- package/dist/sveltekit_helpers.d.ts.map +1 -1
- package/dist/sveltekit_helpers.js +32 -0
- package/dist/sync.task.d.ts +2 -2
- package/dist/task.d.ts +2 -0
- package/dist/task.d.ts.map +1 -1
- package/dist/watch_dir.d.ts +1 -1
- package/dist/watch_dir.d.ts.map +1 -1
- package/dist/watch_dir.js +14 -12
- package/package.json +19 -11
- package/src/lib/filer.ts +212 -0
- package/src/lib/gro.config.default.ts +2 -3
- package/src/lib/gro_plugin_gen.ts +90 -43
- package/src/lib/gro_plugin_sveltekit_library.ts +4 -20
- package/src/lib/invoke_task.ts +6 -1
- package/src/lib/loader.ts +3 -10
- package/src/lib/package.ts +39 -13
- package/src/lib/parse_imports.ts +42 -0
- package/src/lib/path_constants.ts +1 -0
- package/src/lib/paths.ts +8 -1
- package/src/lib/run_task.ts +5 -2
- package/src/lib/sveltekit_config.ts +2 -2
- package/src/lib/sveltekit_helpers.ts +46 -0
- package/src/lib/task.ts +2 -0
- package/src/lib/watch_dir.ts +15 -14
package/src/lib/filer.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {EMPTY_OBJECT} from '@ryanatkn/belt/object.js';
|
|
2
|
+
import {existsSync, readFileSync} from 'node:fs';
|
|
3
|
+
import {dirname, resolve} from 'node:path';
|
|
4
|
+
import type {Omit_Strict} from '@ryanatkn/belt/types.js';
|
|
5
|
+
import {wait} from '@ryanatkn/belt/async.js';
|
|
6
|
+
|
|
7
|
+
import type {Path_Id} from './path.js';
|
|
8
|
+
import {
|
|
9
|
+
watch_dir,
|
|
10
|
+
type Watch_Node_Fs,
|
|
11
|
+
type Watcher_Change,
|
|
12
|
+
type Options as Watch_Dir_Options,
|
|
13
|
+
type Watcher_Change_Callback,
|
|
14
|
+
} from './watch_dir.js';
|
|
15
|
+
import {default_file_filter, paths} from './paths.js';
|
|
16
|
+
import {parse_imports} from './parse_imports.js';
|
|
17
|
+
import {resolve_specifier} from './resolve_specifier.js';
|
|
18
|
+
import {default_sveltekit_config} from './sveltekit_config.js';
|
|
19
|
+
import {map_sveltekit_aliases} from './sveltekit_helpers.js';
|
|
20
|
+
import {Unreachable_Error} from '@ryanatkn/belt/error.js';
|
|
21
|
+
|
|
22
|
+
const aliases = Object.entries(default_sveltekit_config.alias);
|
|
23
|
+
|
|
24
|
+
export interface Source_File {
|
|
25
|
+
id: Path_Id;
|
|
26
|
+
/**
|
|
27
|
+
* `null` contents means it doesn't exist.
|
|
28
|
+
* We create the file in memory to track its dependents regardless of its existence on disk.
|
|
29
|
+
*/
|
|
30
|
+
contents: string | null;
|
|
31
|
+
dependents: Map<Path_Id, Source_File>;
|
|
32
|
+
dependencies: Map<Path_Id, Source_File>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type Cleanup_Watch = () => Promise<void>;
|
|
36
|
+
|
|
37
|
+
export type On_Filer_Change = (change: Watcher_Change, source_file: Source_File) => void;
|
|
38
|
+
|
|
39
|
+
export interface Options {
|
|
40
|
+
watch_dir?: typeof watch_dir;
|
|
41
|
+
watch_dir_options?: Partial<Omit_Strict<Watch_Dir_Options, 'on_change'>>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class Filer {
|
|
45
|
+
files: Map<Path_Id, Source_File> = new Map();
|
|
46
|
+
|
|
47
|
+
#watch_dir: typeof watch_dir;
|
|
48
|
+
#watch_dir_options: Partial<Watch_Dir_Options>;
|
|
49
|
+
|
|
50
|
+
constructor(options: Options = EMPTY_OBJECT) {
|
|
51
|
+
this.#watch_dir = options.watch_dir ?? watch_dir;
|
|
52
|
+
this.#watch_dir_options = options.watch_dir_options ?? EMPTY_OBJECT;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#watching: Watch_Node_Fs | undefined;
|
|
56
|
+
#listeners: Set<On_Filer_Change> = new Set();
|
|
57
|
+
|
|
58
|
+
#ready = false;
|
|
59
|
+
|
|
60
|
+
get_by_id = (id: Path_Id): Source_File | undefined => {
|
|
61
|
+
return this.files.get(id);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
get_or_create = (id: Path_Id): Source_File => {
|
|
65
|
+
const existing = this.get_by_id(id);
|
|
66
|
+
if (existing) return existing;
|
|
67
|
+
const file: Source_File = {
|
|
68
|
+
id,
|
|
69
|
+
contents: null,
|
|
70
|
+
dependents: new Map(),
|
|
71
|
+
dependencies: new Map(),
|
|
72
|
+
};
|
|
73
|
+
this.files.set(id, file);
|
|
74
|
+
return file;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
#update(id: Path_Id): Source_File {
|
|
78
|
+
const file = this.get_or_create(id);
|
|
79
|
+
const new_contents = existsSync(id) ? readFileSync(id, 'utf8') : null;
|
|
80
|
+
const contents_changed = file.contents !== new_contents;
|
|
81
|
+
file.contents = new_contents;
|
|
82
|
+
|
|
83
|
+
if (contents_changed) {
|
|
84
|
+
const dir = dirname(file.id);
|
|
85
|
+
|
|
86
|
+
const dependencies_before = new Set(file.dependencies.keys());
|
|
87
|
+
const dependencies_removed = new Set(dependencies_before);
|
|
88
|
+
|
|
89
|
+
const imported = file.contents ? parse_imports(file.id, file.contents) : [];
|
|
90
|
+
for (const specifier of imported) {
|
|
91
|
+
// TODO logic is duplicated from loader
|
|
92
|
+
const path = map_sveltekit_aliases(specifier, aliases);
|
|
93
|
+
|
|
94
|
+
// The specifier `path` has now been mapped to its final form, so we can inspect it.
|
|
95
|
+
if (path[0] === '.' || path[0] === '/') {
|
|
96
|
+
const {path_id} = resolve_specifier(path, dir);
|
|
97
|
+
dependencies_removed.delete(path_id);
|
|
98
|
+
if (!dependencies_before.has(path_id)) {
|
|
99
|
+
const d = this.get_or_create(path_id);
|
|
100
|
+
file.dependencies.set(d.id, d);
|
|
101
|
+
d.dependents.set(file.id, file);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// update any removed dependencies
|
|
107
|
+
for (const dependency_removed of dependencies_removed) {
|
|
108
|
+
const deleted1 = file.dependencies.delete(dependency_removed);
|
|
109
|
+
if (!deleted1) throw Error('expected to delete1 ' + file.id); // TODO @many delete if correct
|
|
110
|
+
const dependency_removed_file = this.get_or_create(dependency_removed);
|
|
111
|
+
const deleted2 = dependency_removed_file.dependents.delete(file.id);
|
|
112
|
+
if (!deleted2) throw Error('expected to delete2 ' + file.id); // TODO @many delete if correct
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return file;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#remove(id: Path_Id): Source_File | undefined {
|
|
120
|
+
const file = this.get_by_id(id);
|
|
121
|
+
if (!file) return; // this is safe because the object would exist if any other file referenced it as a dependency or dependent
|
|
122
|
+
|
|
123
|
+
file.contents = null; // clear contents in case it gets re-added later, we want the change to be detected
|
|
124
|
+
|
|
125
|
+
let found = false;
|
|
126
|
+
for (const d of this.files.values()) {
|
|
127
|
+
if (d.dependencies.has(file.id)) {
|
|
128
|
+
found = true;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!found) this.files.delete(id);
|
|
133
|
+
|
|
134
|
+
return file;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#notify_listener(listener: On_Filer_Change): void {
|
|
138
|
+
if (!this.#ready) return;
|
|
139
|
+
for (const source_file of this.files.values()) {
|
|
140
|
+
listener({type: 'add', path: source_file.id, is_directory: false}, source_file);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#notify_change(change: Watcher_Change, source_file: Source_File): void {
|
|
145
|
+
if (!this.#ready) return;
|
|
146
|
+
for (const listener of this.#listeners) {
|
|
147
|
+
listener(change, source_file);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async #add_listener(listener: On_Filer_Change): Promise<void> {
|
|
152
|
+
this.#listeners.add(listener);
|
|
153
|
+
if (this.#watching) {
|
|
154
|
+
// if already watching, call the listener for all existing files after init
|
|
155
|
+
await this.#watching.init();
|
|
156
|
+
await wait(); // wait a tick to ensure the `this.#ready` value is updated below first
|
|
157
|
+
this.#notify_listener(listener);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.#watching = this.#watch_dir({
|
|
161
|
+
filter: (path, is_directory) => (is_directory ? true : default_file_filter(path)),
|
|
162
|
+
...this.#watch_dir_options,
|
|
163
|
+
dir: resolve(this.#watch_dir_options.dir ?? paths.source),
|
|
164
|
+
on_change: this.#on_change,
|
|
165
|
+
});
|
|
166
|
+
await this.#watching.init();
|
|
167
|
+
this.#ready = true;
|
|
168
|
+
this.#notify_listener(listener);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async #remove_listener(listener: On_Filer_Change): Promise<void> {
|
|
172
|
+
this.#listeners.delete(listener);
|
|
173
|
+
if (this.#listeners.size === 0) {
|
|
174
|
+
await this.close(); // TODO is this right? should `watch` be async?
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#on_change: Watcher_Change_Callback = (change) => {
|
|
179
|
+
if (change.is_directory) return;
|
|
180
|
+
let source_file: Source_File | undefined;
|
|
181
|
+
switch (change.type) {
|
|
182
|
+
case 'add':
|
|
183
|
+
case 'update': {
|
|
184
|
+
source_file = this.#update(change.path);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case 'delete': {
|
|
188
|
+
source_file = this.#remove(change.path);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
default:
|
|
192
|
+
throw new Unreachable_Error(change.type);
|
|
193
|
+
}
|
|
194
|
+
if (source_file) {
|
|
195
|
+
this.#notify_change(change, source_file);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
async watch(listener: On_Filer_Change): Promise<Cleanup_Watch> {
|
|
200
|
+
await this.#add_listener(listener);
|
|
201
|
+
return () => this.#remove_listener(listener);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async close(): Promise<void> {
|
|
205
|
+
this.#ready = false;
|
|
206
|
+
this.#listeners.clear();
|
|
207
|
+
if (this.#watching) {
|
|
208
|
+
await this.#watching.close();
|
|
209
|
+
this.#watching = undefined;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -3,6 +3,7 @@ import {gro_plugin_sveltekit_library} from './gro_plugin_sveltekit_library.js';
|
|
|
3
3
|
import {has_server, gro_plugin_server} from './gro_plugin_server.js';
|
|
4
4
|
import {gro_plugin_sveltekit_app} from './gro_plugin_sveltekit_app.js';
|
|
5
5
|
import {has_sveltekit_app, has_sveltekit_library} from './sveltekit_helpers.js';
|
|
6
|
+
import {gro_plugin_gen} from './gro_plugin_gen.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* This is the default config that's passed to `gro.config.ts`
|
|
@@ -23,9 +24,7 @@ const config: Create_Gro_Config = async (cfg) => {
|
|
|
23
24
|
has_sveltekit_app_result.ok
|
|
24
25
|
? gro_plugin_sveltekit_app({host_target: has_server_result.ok ? 'node' : 'github_pages'})
|
|
25
26
|
: null,
|
|
26
|
-
|
|
27
|
-
// import {gro_plugin_gen} from './gro_plugin_gen.js';
|
|
28
|
-
// gro_plugin_gen(),
|
|
27
|
+
gro_plugin_gen(),
|
|
29
28
|
];
|
|
30
29
|
|
|
31
30
|
return cfg;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
// because we no longer have a normal system build - replace with an esbuild plugin
|
|
3
|
-
// @ts-nocheck
|
|
1
|
+
import {EMPTY_OBJECT} from '@ryanatkn/belt/object.js';
|
|
4
2
|
|
|
5
|
-
import type {Plugin
|
|
3
|
+
import type {Plugin} from './plugin.js';
|
|
6
4
|
import type {Args} from './args.js';
|
|
7
|
-
import {
|
|
5
|
+
import {paths} from './paths.js';
|
|
8
6
|
import {find_genfiles, is_gen_path} from './gen.js';
|
|
9
|
-
import {filter_dependents} from './build/source_file.js';
|
|
10
7
|
import {throttle} from './throttle.js';
|
|
8
|
+
import {spawn_cli} from './cli.js';
|
|
9
|
+
import type {File_Filter, Path_Id} from './path.js';
|
|
10
|
+
import type {Cleanup_Watch, Source_File} from './filer.js';
|
|
11
|
+
import {Unreachable_Error} from '@ryanatkn/belt/error.js';
|
|
11
12
|
|
|
12
13
|
const FLUSH_DEBOUNCE_DELAY = 500;
|
|
13
14
|
|
|
@@ -15,14 +16,28 @@ export interface Task_Args extends Args {
|
|
|
15
16
|
watch?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
export
|
|
19
|
+
export interface Options {
|
|
20
|
+
root_dirs?: string[];
|
|
21
|
+
flush_debounce_delay?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const gro_plugin_gen = ({
|
|
25
|
+
root_dirs = [paths.source],
|
|
26
|
+
flush_debounce_delay = FLUSH_DEBOUNCE_DELAY,
|
|
27
|
+
}: Options = EMPTY_OBJECT): Plugin => {
|
|
28
|
+
const input_path = paths.source; // TODO option?
|
|
19
29
|
let generating = false;
|
|
20
30
|
let regen = false;
|
|
21
|
-
let
|
|
31
|
+
let flushing_timeout: NodeJS.Timeout | undefined;
|
|
22
32
|
const queued_files: Set<string> = new Set();
|
|
23
|
-
const queue_gen = (
|
|
24
|
-
queued_files.add(
|
|
25
|
-
|
|
33
|
+
const queue_gen = (gen_file_id: string) => {
|
|
34
|
+
queued_files.add(gen_file_id);
|
|
35
|
+
if (flushing_timeout === undefined) {
|
|
36
|
+
flushing_timeout = setTimeout(() => {
|
|
37
|
+
flushing_timeout = undefined;
|
|
38
|
+
void flush_gen_queue();
|
|
39
|
+
}); // the timeout batches synchronously
|
|
40
|
+
}
|
|
26
41
|
};
|
|
27
42
|
const flush_gen_queue = throttle(async () => {
|
|
28
43
|
// hacky way to avoid concurrent `gro gen` calls
|
|
@@ -39,57 +54,89 @@ export const plugin = (): Plugin<Plugin_Context<Task_Args>> => {
|
|
|
39
54
|
regen = false;
|
|
40
55
|
void flush_gen_queue();
|
|
41
56
|
}
|
|
42
|
-
},
|
|
57
|
+
}, flush_debounce_delay);
|
|
43
58
|
const gen = (files: string[] = []) => spawn_cli('gro', ['gen', ...files]);
|
|
44
59
|
|
|
60
|
+
let cleanup: Cleanup_Watch | undefined;
|
|
61
|
+
|
|
45
62
|
return {
|
|
46
63
|
name: 'gro_plugin_gen',
|
|
47
|
-
setup: async ({
|
|
64
|
+
setup: async ({watch, dev, log, config, filer}) => {
|
|
48
65
|
// For production builds, we assume `gen` is already fresh,
|
|
49
66
|
// which should be checked by CI via `gro check` which calls `gro gen --check`.
|
|
50
67
|
if (!dev) return;
|
|
51
68
|
|
|
52
|
-
// Run `gen`, first checking if there are any modules to avoid a console error.
|
|
53
|
-
// Some parts of the build may have already happened,
|
|
54
|
-
// making us miss `build` events for gen dependencies,
|
|
55
|
-
// so we run `gen` here even if it's usually wasteful.
|
|
56
|
-
const found = find_genfiles([paths.source], root_dirs, config);
|
|
57
|
-
if (found.ok && found.value.resolved_input_files.size > 0) {
|
|
58
|
-
await gen();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
69
|
// Do we need to just generate everything once and exit?
|
|
62
70
|
// TODO could we have an esbuild context here? problem is watching the right files, maybe a plugin that tracks deps
|
|
63
|
-
if (!
|
|
71
|
+
if (!watch) {
|
|
64
72
|
log.info('generating and exiting early');
|
|
73
|
+
|
|
74
|
+
// Run `gen`, first checking if there are any modules to avoid a console error.
|
|
75
|
+
// Some parts of the build may have already happened,
|
|
76
|
+
// making us miss `build` events for gen dependencies,
|
|
77
|
+
// so we run `gen` here even if it's usually wasteful.
|
|
78
|
+
const found = find_genfiles([input_path], root_dirs, config);
|
|
79
|
+
if (found.ok && found.value.resolved_input_files.length > 0) {
|
|
80
|
+
await gen();
|
|
81
|
+
}
|
|
65
82
|
return;
|
|
66
83
|
}
|
|
67
84
|
|
|
68
85
|
// When a file builds, check it and its tree of dependents
|
|
69
86
|
// for any `.gen.` files that need to run.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
cleanup = await filer.watch((change, source_file) => {
|
|
88
|
+
switch (change.type) {
|
|
89
|
+
case 'add':
|
|
90
|
+
case 'update': {
|
|
91
|
+
// TODO how to handle this now? the loader traces deps for us with `parentPath`,
|
|
92
|
+
// but we probably want to make this an esbuild plugin instead
|
|
93
|
+
if (is_gen_path(source_file.id)) {
|
|
94
|
+
queue_gen(source_file.id);
|
|
95
|
+
}
|
|
96
|
+
const dependent_gen_file_ids = filter_dependents(
|
|
97
|
+
source_file,
|
|
98
|
+
filer.get_by_id,
|
|
99
|
+
is_gen_path,
|
|
100
|
+
);
|
|
101
|
+
for (const dependent_gen_file_id of dependent_gen_file_ids) {
|
|
102
|
+
queue_gen(dependent_gen_file_id);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case 'delete': {
|
|
107
|
+
// TODO delete the generated file(s)? option?
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
default:
|
|
111
|
+
throw new Unreachable_Error(change.type);
|
|
85
112
|
}
|
|
86
|
-
};
|
|
87
|
-
filer.on('build', on_filer_build);
|
|
113
|
+
});
|
|
88
114
|
},
|
|
89
|
-
teardown: (
|
|
90
|
-
if (
|
|
91
|
-
|
|
115
|
+
teardown: async () => {
|
|
116
|
+
if (cleanup !== undefined) {
|
|
117
|
+
await cleanup();
|
|
118
|
+
cleanup = undefined;
|
|
92
119
|
}
|
|
93
120
|
},
|
|
94
121
|
};
|
|
95
122
|
};
|
|
123
|
+
|
|
124
|
+
export const filter_dependents = (
|
|
125
|
+
source_file: Source_File,
|
|
126
|
+
get_by_id: (id: Path_Id) => Source_File | undefined,
|
|
127
|
+
filter?: File_Filter,
|
|
128
|
+
results: Set<string> = new Set(),
|
|
129
|
+
searched: Set<string> = new Set(),
|
|
130
|
+
): Set<string> => {
|
|
131
|
+
const {dependents} = source_file;
|
|
132
|
+
for (const dependent_id of dependents.keys()) {
|
|
133
|
+
if (searched.has(dependent_id)) continue;
|
|
134
|
+
searched.add(dependent_id);
|
|
135
|
+
if (!filter || filter(dependent_id)) {
|
|
136
|
+
results.add(dependent_id);
|
|
137
|
+
}
|
|
138
|
+
const dependent_source_File = get_by_id(dependent_id)!;
|
|
139
|
+
filter_dependents(dependent_source_File, get_by_id, filter, results, searched);
|
|
140
|
+
}
|
|
141
|
+
return results;
|
|
142
|
+
};
|
|
@@ -3,11 +3,9 @@ import {print_spawn_result, spawn} from '@ryanatkn/belt/process.js';
|
|
|
3
3
|
import type {Plugin} from './plugin.js';
|
|
4
4
|
import {Task_Error} from './task.js';
|
|
5
5
|
import {load_package_json} from './package_json.js';
|
|
6
|
-
import {serialize_args, to_forwarded_args} from './args.js';
|
|
7
|
-
import {find_cli, spawn_cli} from './cli.js';
|
|
8
6
|
import {
|
|
9
7
|
SVELTE_PACKAGE_CLI,
|
|
10
|
-
|
|
8
|
+
run_svelte_package,
|
|
11
9
|
type Svelte_Package_Options,
|
|
12
10
|
} from './sveltekit_helpers.js';
|
|
13
11
|
|
|
@@ -30,24 +28,10 @@ export const gro_plugin_sveltekit_library = ({
|
|
|
30
28
|
}: Options = {}): Plugin => {
|
|
31
29
|
return {
|
|
32
30
|
name: 'gro_plugin_sveltekit_library',
|
|
33
|
-
setup: async ({log}) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
throw new Task_Error(
|
|
37
|
-
'Failed to find SvelteKit library: ' + has_sveltekit_library_result.message,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
const found_svelte_package_cli = find_cli(svelte_package_cli);
|
|
41
|
-
if (found_svelte_package_cli?.kind !== 'local') {
|
|
42
|
-
throw new Task_Error(
|
|
43
|
-
`Failed to find SvelteKit packaging CLI \`${svelte_package_cli}\`, do you need to run \`npm i\`?`,
|
|
44
|
-
);
|
|
31
|
+
setup: async ({dev, log}) => {
|
|
32
|
+
if (!dev) {
|
|
33
|
+
await run_svelte_package(svelte_package_options, svelte_package_cli, log);
|
|
45
34
|
}
|
|
46
|
-
const serialized_args = serialize_args({
|
|
47
|
-
...svelte_package_options,
|
|
48
|
-
...to_forwarded_args(svelte_package_cli),
|
|
49
|
-
});
|
|
50
|
-
await spawn_cli(found_svelte_package_cli, serialized_args, log);
|
|
51
35
|
},
|
|
52
36
|
adapt: async ({log, timings}) => {
|
|
53
37
|
const package_json = load_package_json();
|
package/src/lib/invoke_task.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {find_tasks, load_tasks, Silent_Error} from './task.js';
|
|
|
10
10
|
import {load_gro_package_json} from './package_json.js';
|
|
11
11
|
import {log_tasks, log_error_reasons} from './task_logging.js';
|
|
12
12
|
import type {Gro_Config} from './gro_config.js';
|
|
13
|
+
import {Filer} from './filer.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Invokes Gro tasks by name using the filesystem as the source.
|
|
@@ -37,11 +38,14 @@ export const invoke_task = async (
|
|
|
37
38
|
task_name: Raw_Input_Path,
|
|
38
39
|
args: Args | undefined,
|
|
39
40
|
config: Gro_Config,
|
|
40
|
-
|
|
41
|
+
initial_filer?: Filer,
|
|
42
|
+
initial_timings?: Timings | null,
|
|
41
43
|
): Promise<void> => {
|
|
42
44
|
const log = new System_Logger(print_log_label(task_name || 'gro'));
|
|
43
45
|
log.info('invoking', task_name ? st('cyan', task_name) : 'gro');
|
|
44
46
|
|
|
47
|
+
const filer = initial_filer ?? new Filer();
|
|
48
|
+
|
|
45
49
|
const timings = initial_timings ?? new Timings();
|
|
46
50
|
|
|
47
51
|
const total_timing = create_stopwatch();
|
|
@@ -104,6 +108,7 @@ export const invoke_task = async (
|
|
|
104
108
|
{...args, ...to_forwarded_args(`gro ${task.name}`)},
|
|
105
109
|
invoke_task,
|
|
106
110
|
config,
|
|
111
|
+
filer,
|
|
107
112
|
timings,
|
|
108
113
|
);
|
|
109
114
|
timing_to_run_task();
|
package/src/lib/loader.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {to_define_import_meta_env, default_ts_transform_options} from './esbuild
|
|
|
22
22
|
import {resolve_specifier} from './resolve_specifier.js';
|
|
23
23
|
import {resolve_node_specifier} from './resolve_node_specifier.js';
|
|
24
24
|
import type {Package_Json} from './package_json.js';
|
|
25
|
+
import {map_sveltekit_aliases} from './sveltekit_helpers.js';
|
|
25
26
|
|
|
26
27
|
/*
|
|
27
28
|
|
|
@@ -73,7 +74,7 @@ const ts_transform_options: esbuild.TransformOptions = {
|
|
|
73
74
|
sourcemap: 'inline',
|
|
74
75
|
};
|
|
75
76
|
|
|
76
|
-
const aliases = Object.entries(
|
|
77
|
+
const aliases = Object.entries(alias);
|
|
77
78
|
|
|
78
79
|
const RAW_MATCHER = /(%3Fraw|\.css|\.svg)$/; // TODO others? configurable?
|
|
79
80
|
const ENV_MATCHER = /src\/lib\/\$env\/(static|dynamic)\/(public|private)$/;
|
|
@@ -197,15 +198,7 @@ export const resolve: ResolveHook = async (specifier, context, nextResolve) => {
|
|
|
197
198
|
return nextResolve(shimmed, context);
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// Map the path with the SvelteKit aliases.
|
|
203
|
-
for (const [from, to] of aliases) {
|
|
204
|
-
if (path.startsWith(from)) {
|
|
205
|
-
path = join(dir, to, path.substring(from.length));
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
201
|
+
const path = map_sveltekit_aliases(specifier, aliases);
|
|
209
202
|
|
|
210
203
|
// The specifier `path` has now been mapped to its final form, so we can inspect it.
|
|
211
204
|
if (path[0] !== '.' && path[0] !== '/') {
|
package/src/lib/package.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type {Src_Json} from './src_json.js';
|
|
|
5
5
|
|
|
6
6
|
export const package_json = {
|
|
7
7
|
name: '@ryanatkn/gro',
|
|
8
|
-
version: '0.135.
|
|
8
|
+
version: '0.135.3',
|
|
9
9
|
description: 'task runner and toolkit extending SvelteKit',
|
|
10
10
|
motto: 'generate, run, optimize',
|
|
11
11
|
glyph: '🌰',
|
|
@@ -51,7 +51,7 @@ export const package_json = {
|
|
|
51
51
|
'esm-env': '^1.0.0',
|
|
52
52
|
mri: '^1.2.0',
|
|
53
53
|
prettier: '^3.3.3',
|
|
54
|
-
'prettier-plugin-svelte': '^3.2.
|
|
54
|
+
'prettier-plugin-svelte': '^3.2.7',
|
|
55
55
|
'ts-morph': '^23.0.0',
|
|
56
56
|
tslib: '^2.7.0',
|
|
57
57
|
zod: '^3.23.8',
|
|
@@ -60,22 +60,22 @@ export const package_json = {
|
|
|
60
60
|
devDependencies: {
|
|
61
61
|
'@changesets/changelog-git': '^0.2.0',
|
|
62
62
|
'@changesets/types': '^6.0.0',
|
|
63
|
-
'@ryanatkn/eslint-config': '^0.5.
|
|
64
|
-
'@ryanatkn/fuz': '^0.
|
|
63
|
+
'@ryanatkn/eslint-config': '^0.5.4',
|
|
64
|
+
'@ryanatkn/fuz': '^0.129.0',
|
|
65
65
|
'@ryanatkn/moss': '^0.16.1',
|
|
66
66
|
'@sveltejs/adapter-static': '^3.0.5',
|
|
67
|
-
'@sveltejs/kit': '^2.
|
|
67
|
+
'@sveltejs/kit': '^2.6.1',
|
|
68
68
|
'@sveltejs/package': '^2.3.5',
|
|
69
69
|
'@sveltejs/vite-plugin-svelte': '^3.1.2',
|
|
70
70
|
'@types/fs-extra': '^11.0.4',
|
|
71
|
-
'@types/node': '^22.
|
|
71
|
+
'@types/node': '^22.7.4',
|
|
72
72
|
esbuild: '^0.21.5',
|
|
73
|
-
eslint: '^9.11.
|
|
74
|
-
'eslint-plugin-svelte': '^2.44.
|
|
75
|
-
svelte: '^5.0.0-next.
|
|
76
|
-
'svelte-check': '^4.0.
|
|
73
|
+
eslint: '^9.11.1',
|
|
74
|
+
'eslint-plugin-svelte': '^2.44.1',
|
|
75
|
+
svelte: '^5.0.0-next.260',
|
|
76
|
+
'svelte-check': '^4.0.4',
|
|
77
77
|
typescript: '^5.6.2',
|
|
78
|
-
'typescript-eslint': '^8.
|
|
78
|
+
'typescript-eslint': '^8.7.0',
|
|
79
79
|
uvu: '^0.5.6',
|
|
80
80
|
},
|
|
81
81
|
prettier: {
|
|
@@ -138,6 +138,7 @@ export const package_json = {
|
|
|
138
138
|
types: './dist/esbuild_plugin_sveltekit_shim_env.d.ts',
|
|
139
139
|
default: './dist/esbuild_plugin_sveltekit_shim_env.js',
|
|
140
140
|
},
|
|
141
|
+
'./filer.js': {types: './dist/filer.d.ts', default: './dist/filer.js'},
|
|
141
142
|
'./format_directory.js': {
|
|
142
143
|
types: './dist/format_directory.d.ts',
|
|
143
144
|
default: './dist/format_directory.js',
|
|
@@ -184,6 +185,7 @@ export const package_json = {
|
|
|
184
185
|
'./package_meta.js': {types: './dist/package_meta.d.ts', default: './dist/package_meta.js'},
|
|
185
186
|
'./package.gen.js': {types: './dist/package.gen.d.ts', default: './dist/package.gen.js'},
|
|
186
187
|
'./package.js': {types: './dist/package.d.ts', default: './dist/package.js'},
|
|
188
|
+
'./parse_imports.js': {types: './dist/parse_imports.d.ts', default: './dist/parse_imports.js'},
|
|
187
189
|
'./path_constants.js': {
|
|
188
190
|
types: './dist/path_constants.d.ts',
|
|
189
191
|
default: './dist/path_constants.js',
|
|
@@ -268,7 +270,7 @@ export const package_json = {
|
|
|
268
270
|
|
|
269
271
|
export const src_json = {
|
|
270
272
|
name: '@ryanatkn/gro',
|
|
271
|
-
version: '0.135.
|
|
273
|
+
version: '0.135.3',
|
|
272
274
|
modules: {
|
|
273
275
|
'.': {
|
|
274
276
|
path: 'index.ts',
|
|
@@ -435,6 +437,16 @@ export const src_json = {
|
|
|
435
437
|
{name: 'esbuild_plugin_sveltekit_shim_env', kind: 'function'},
|
|
436
438
|
],
|
|
437
439
|
},
|
|
440
|
+
'./filer.js': {
|
|
441
|
+
path: 'filer.ts',
|
|
442
|
+
declarations: [
|
|
443
|
+
{name: 'Source_File', kind: 'type'},
|
|
444
|
+
{name: 'Cleanup_Watch', kind: 'type'},
|
|
445
|
+
{name: 'On_Filer_Change', kind: 'type'},
|
|
446
|
+
{name: 'Options', kind: 'type'},
|
|
447
|
+
{name: 'Filer', kind: 'class'},
|
|
448
|
+
],
|
|
449
|
+
},
|
|
438
450
|
'./format_directory.js': {
|
|
439
451
|
path: 'format_directory.ts',
|
|
440
452
|
declarations: [{name: 'format_directory', kind: 'function'}],
|
|
@@ -552,7 +564,9 @@ export const src_json = {
|
|
|
552
564
|
path: 'gro_plugin_gen.ts',
|
|
553
565
|
declarations: [
|
|
554
566
|
{name: 'Task_Args', kind: 'type'},
|
|
555
|
-
{name: '
|
|
567
|
+
{name: 'Options', kind: 'type'},
|
|
568
|
+
{name: 'gro_plugin_gen', kind: 'function'},
|
|
569
|
+
{name: 'filter_dependents', kind: 'function'},
|
|
556
570
|
],
|
|
557
571
|
},
|
|
558
572
|
'./gro_plugin_server.js': {
|
|
@@ -684,6 +698,14 @@ export const src_json = {
|
|
|
684
698
|
{name: 'src_json', kind: 'variable'},
|
|
685
699
|
],
|
|
686
700
|
},
|
|
701
|
+
'./parse_imports.js': {
|
|
702
|
+
path: 'parse_imports.ts',
|
|
703
|
+
declarations: [
|
|
704
|
+
{name: 'init_lexer', kind: 'function'},
|
|
705
|
+
{name: 'Import_Specifier', kind: 'type'},
|
|
706
|
+
{name: 'parse_imports', kind: 'function'},
|
|
707
|
+
],
|
|
708
|
+
},
|
|
687
709
|
'./path_constants.js': {
|
|
688
710
|
path: 'path_constants.ts',
|
|
689
711
|
declarations: [
|
|
@@ -709,6 +731,7 @@ export const src_json = {
|
|
|
709
731
|
{name: 'GIT_DIRNAME', kind: 'variable'},
|
|
710
732
|
{name: 'TSCONFIG_FILENAME', kind: 'variable'},
|
|
711
733
|
{name: 'TS_MATCHER', kind: 'variable'},
|
|
734
|
+
{name: 'JS_MATCHER', kind: 'variable'},
|
|
712
735
|
{name: 'JSON_MATCHER', kind: 'variable'},
|
|
713
736
|
{name: 'EVERYTHING_MATCHER', kind: 'variable'},
|
|
714
737
|
],
|
|
@@ -745,6 +768,7 @@ export const src_json = {
|
|
|
745
768
|
{name: 'IS_THIS_GRO', kind: 'variable'},
|
|
746
769
|
{name: 'gro_paths', kind: 'variable'},
|
|
747
770
|
{name: 'GRO_DIST_DIR', kind: 'variable'},
|
|
771
|
+
{name: 'default_file_filter', kind: 'function'},
|
|
748
772
|
],
|
|
749
773
|
},
|
|
750
774
|
'./plugin.js': {
|
|
@@ -870,6 +894,8 @@ export const src_json = {
|
|
|
870
894
|
{name: 'sveltekit_sync_if_available', kind: 'function'},
|
|
871
895
|
{name: 'sveltekit_sync_if_obviously_needed', kind: 'function'},
|
|
872
896
|
{name: 'Svelte_Package_Options', kind: 'type'},
|
|
897
|
+
{name: 'run_svelte_package', kind: 'function'},
|
|
898
|
+
{name: 'map_sveltekit_aliases', kind: 'function'},
|
|
873
899
|
],
|
|
874
900
|
},
|
|
875
901
|
'./sveltekit_shim_app_environment.js': {
|