@ryanatkn/gro 0.146.2 → 0.147.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/dist/filer.d.ts.map +1 -1
- package/dist/filer.js +22 -12
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +2 -15
- package/dist/package.d.ts +0 -11
- package/dist/package.d.ts.map +1 -1
- package/dist/package.js +2 -10
- package/dist/sveltekit_shim_app_forms.d.ts.map +1 -1
- package/dist/sveltekit_shim_app_forms.js +1 -10
- package/package.json +1 -5
- package/src/lib/filer.ts +19 -13
- package/src/lib/loader.ts +3 -16
- package/src/lib/package.ts +2 -10
- package/src/lib/sveltekit_shim_app_forms.ts +1 -10
- package/dist/resolve_node_specifier.d.ts +0 -9
- package/dist/resolve_node_specifier.d.ts.map +0 -1
- package/dist/resolve_node_specifier.js +0 -306
- package/src/lib/resolve_node_specifier.ts +0 -369
package/dist/filer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filer.d.ts","sourceRoot":"../src/lib/","sources":["filer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"filer.d.ts","sourceRoot":"../src/lib/","sources":["filer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AAMzD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,EACN,SAAS,EAET,KAAK,cAAc,EACnB,KAAK,iBAAiB,EAEtB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAIpD,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACtC,YAAY,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;AAEzF,MAAM,WAAW,aAAa;IAC7B,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC,CAAC;IACzE,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAClD;AAED,qBAAa,KAAK;;IACjB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAa;gBAK1C,OAAO,GAAE,aAA4B;IAWjD,SAAS,OAAQ,OAAO,KAAG,WAAW,GAAG,SAAS,CAEhD;IAEF,aAAa,OAAQ,OAAO,KAAG,WAAW,CAkBxC;IA2II,KAAK,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IAKxD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAa5B"}
|
package/dist/filer.js
CHANGED
|
@@ -2,26 +2,25 @@ import { EMPTY_OBJECT } from '@ryanatkn/belt/object.js';
|
|
|
2
2
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import { dirname, resolve } from 'node:path';
|
|
4
4
|
import { wait } from '@ryanatkn/belt/async.js';
|
|
5
|
+
import { isBuiltin } from 'node:module';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { Unreachable_Error } from '@ryanatkn/belt/error.js';
|
|
5
8
|
import { watch_dir, } from './watch_dir.js';
|
|
6
9
|
import { paths } from './paths.js';
|
|
7
10
|
import { parse_imports } from './parse_imports.js';
|
|
8
11
|
import { resolve_specifier } from './resolve_specifier.js';
|
|
9
12
|
import { default_sveltekit_config } from './sveltekit_config.js';
|
|
10
13
|
import { map_sveltekit_aliases } from './sveltekit_helpers.js';
|
|
11
|
-
import { Unreachable_Error } from '@ryanatkn/belt/error.js';
|
|
12
|
-
import { resolve_node_specifier } from './resolve_node_specifier.js';
|
|
13
14
|
const aliases = Object.entries(default_sveltekit_config.alias);
|
|
14
15
|
export class Filer {
|
|
15
16
|
root_dir;
|
|
16
17
|
files = new Map();
|
|
17
18
|
#watch_dir;
|
|
18
19
|
#watch_dir_options;
|
|
19
|
-
#package_json_cache;
|
|
20
20
|
constructor(options = EMPTY_OBJECT) {
|
|
21
21
|
this.#watch_dir = options.watch_dir ?? watch_dir;
|
|
22
22
|
this.#watch_dir_options = options.watch_dir_options ?? EMPTY_OBJECT;
|
|
23
23
|
this.root_dir = resolve(options.watch_dir_options?.dir ?? paths.source);
|
|
24
|
-
this.#package_json_cache = options.package_json_cache ?? {};
|
|
25
24
|
}
|
|
26
25
|
#watching;
|
|
27
26
|
#listeners = new Set();
|
|
@@ -64,15 +63,26 @@ export class Filer {
|
|
|
64
63
|
const dependencies_removed = new Set(dependencies_before);
|
|
65
64
|
const imported = file.contents ? parse_imports(file.id, file.contents) : [];
|
|
66
65
|
for (const specifier of imported) {
|
|
67
|
-
// TODO logic is duplicated from loader
|
|
68
66
|
const path = map_sveltekit_aliases(specifier, aliases);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
let path_id;
|
|
68
|
+
if (path[0] === '.' || path[0] === '/') {
|
|
69
|
+
const resolved = resolve_specifier(path, dir);
|
|
70
|
+
path_id = resolved.path_id;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
if (isBuiltin(path))
|
|
74
|
+
continue;
|
|
75
|
+
try {
|
|
76
|
+
path_id = fileURLToPath(import.meta.resolve(path, file.id));
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
// If it's imported from an external module, ignore any import errors.
|
|
80
|
+
if (error.code === 'ERR_MODULE_NOT_FOUND' && file.external) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
76
86
|
dependencies_removed.delete(path_id);
|
|
77
87
|
if (!dependencies_before.has(path_id)) {
|
|
78
88
|
const d = this.get_or_create(path_id);
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"../src/lib/","sources":["loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,QAAQ,EAAE,WAAW,EAAC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"../src/lib/","sources":["loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,QAAQ,EAAE,WAAW,EAAC,MAAM,aAAa,CAAC;AA4EvD,eAAO,MAAM,IAAI,EAAE,QAwFlB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,WAoDrB,CAAC"}
|
package/dist/loader.js
CHANGED
|
@@ -12,7 +12,6 @@ import { IS_THIS_GRO, paths } from './paths.js';
|
|
|
12
12
|
import { JSON_MATCHER, NODE_MODULES_DIRNAME, TS_MATCHER } from './constants.js';
|
|
13
13
|
import { to_define_import_meta_env, default_ts_transform_options } from './esbuild_helpers.js';
|
|
14
14
|
import { resolve_specifier } from './resolve_specifier.js';
|
|
15
|
-
import { resolve_node_specifier } from './resolve_node_specifier.js';
|
|
16
15
|
import { map_sveltekit_aliases } from './sveltekit_helpers.js';
|
|
17
16
|
/*
|
|
18
17
|
|
|
@@ -52,7 +51,6 @@ const aliases = Object.entries(alias);
|
|
|
52
51
|
const RAW_MATCHER = /(%3Fraw|\.css|\.svg)$/; // TODO others? configurable?
|
|
53
52
|
const ENV_MATCHER = /src\/lib\/\$env\/(static|dynamic)\/(public|private)$/;
|
|
54
53
|
const NODE_MODULES_MATCHER = new RegExp(escape_regexp('/' + NODE_MODULES_DIRNAME + '/'), 'u');
|
|
55
|
-
const package_json_cache = {};
|
|
56
54
|
export const load = async (url, context, nextLoad) => {
|
|
57
55
|
if (SVELTEKIT_SHIM_APP_PATHS_MATCHER.test(url)) {
|
|
58
56
|
// SvelteKit `$app/paths` shim
|
|
@@ -162,20 +160,9 @@ export const resolve = async (specifier, context, nextResolve) => {
|
|
|
162
160
|
}
|
|
163
161
|
s = map_sveltekit_aliases(s, aliases);
|
|
164
162
|
// The specifier has now been mapped to its final form, so we can inspect it.
|
|
163
|
+
// Imports into `node_modules` use the default algorithm, and the rest use use Vite conventions.
|
|
165
164
|
if (s[0] !== '.' && s[0] !== '/') {
|
|
166
|
-
|
|
167
|
-
if (SVELTE_MATCHER.test(s) || JSON_MATCHER.test(s)) {
|
|
168
|
-
// Match the behavior of Vite and esbuild for Svelte and JSON imports.
|
|
169
|
-
const resolved = resolve_node_specifier(s, dir, parent_url, package_json_cache); // `node:` specifiers shouldn't reach this point, so the assertion is safe
|
|
170
|
-
return {
|
|
171
|
-
url: pathToFileURL(resolved.path_id_with_querystring).href,
|
|
172
|
-
format: 'module',
|
|
173
|
-
shortCircuit: true,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
return nextResolve(s, context);
|
|
178
|
-
}
|
|
165
|
+
return nextResolve(s, context);
|
|
179
166
|
}
|
|
180
167
|
const resolved = resolve_specifier(s, dirname(fileURLToPath(parent_url)));
|
|
181
168
|
return {
|
package/dist/package.d.ts
CHANGED
|
@@ -333,10 +333,6 @@ export declare const package_json: {
|
|
|
333
333
|
types: string;
|
|
334
334
|
default: string;
|
|
335
335
|
};
|
|
336
|
-
'./resolve_node_specifier.js': {
|
|
337
|
-
types: string;
|
|
338
|
-
default: string;
|
|
339
|
-
};
|
|
340
336
|
'./resolve_specifier.js': {
|
|
341
337
|
types: string;
|
|
342
338
|
default: string;
|
|
@@ -965,13 +961,6 @@ export declare const src_json: {
|
|
|
965
961
|
kind: "variable";
|
|
966
962
|
}[];
|
|
967
963
|
};
|
|
968
|
-
'./resolve_node_specifier.js': {
|
|
969
|
-
path: string;
|
|
970
|
-
declarations: {
|
|
971
|
-
name: string;
|
|
972
|
-
kind: "function";
|
|
973
|
-
}[];
|
|
974
|
-
};
|
|
975
964
|
'./resolve_specifier.js': {
|
|
976
965
|
path: string;
|
|
977
966
|
declarations: ({
|
package/dist/package.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.d.ts","sourceRoot":"../src/lib/","sources":["package.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"package.d.ts","sourceRoot":"../src/lib/","sources":["package.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmQD,CAAC;AAEzB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAswBD,CAAC"}
|
package/dist/package.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// generated by src/lib/package.gen.ts
|
|
2
2
|
export const package_json = {
|
|
3
3
|
name: '@ryanatkn/gro',
|
|
4
|
-
version: '0.
|
|
4
|
+
version: '0.147.0',
|
|
5
5
|
description: 'task runner and toolkit extending SvelteKit',
|
|
6
6
|
motto: 'generate, run, optimize',
|
|
7
7
|
glyph: '🌰',
|
|
@@ -196,10 +196,6 @@ export const package_json = {
|
|
|
196
196
|
default: './dist/reinstall.task.js',
|
|
197
197
|
},
|
|
198
198
|
'./release.task.js': { types: './dist/release.task.d.ts', default: './dist/release.task.js' },
|
|
199
|
-
'./resolve_node_specifier.js': {
|
|
200
|
-
types: './dist/resolve_node_specifier.d.ts',
|
|
201
|
-
default: './dist/resolve_node_specifier.js',
|
|
202
|
-
},
|
|
203
199
|
'./resolve_specifier.js': {
|
|
204
200
|
types: './dist/resolve_specifier.d.ts',
|
|
205
201
|
default: './dist/resolve_specifier.js',
|
|
@@ -264,7 +260,7 @@ export const package_json = {
|
|
|
264
260
|
};
|
|
265
261
|
export const src_json = {
|
|
266
262
|
name: '@ryanatkn/gro',
|
|
267
|
-
version: '0.
|
|
263
|
+
version: '0.147.0',
|
|
268
264
|
modules: {
|
|
269
265
|
'.': {
|
|
270
266
|
path: 'index.ts',
|
|
@@ -810,10 +806,6 @@ export const src_json = {
|
|
|
810
806
|
{ name: 'task', kind: 'variable' },
|
|
811
807
|
],
|
|
812
808
|
},
|
|
813
|
-
'./resolve_node_specifier.js': {
|
|
814
|
-
path: 'resolve_node_specifier.ts',
|
|
815
|
-
declarations: [{ name: 'resolve_node_specifier', kind: 'function' }],
|
|
816
|
-
},
|
|
817
809
|
'./resolve_specifier.js': {
|
|
818
810
|
path: 'resolve_specifier.ts',
|
|
819
811
|
declarations: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sveltekit_shim_app_forms.d.ts","sourceRoot":"../src/lib/","sources":["sveltekit_shim_app_forms.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,WAAW,IAAI,gBAAgB,EAC/B,WAAW,IAAI,gBAAgB,EAC/B,OAAO,IAAI,YAAY,EACvB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"sveltekit_shim_app_forms.d.ts","sourceRoot":"../src/lib/","sources":["sveltekit_shim_app_forms.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,WAAW,IAAI,gBAAgB,EAC/B,WAAW,IAAI,gBAAgB,EAC/B,OAAO,IAAI,YAAY,EACvB,MAAM,YAAY,CAAC;AAGpB,eAAO,MAAM,WAAW,EAAE,OAAO,gBAA6B,CAAC;AAC/D,eAAO,MAAM,WAAW,EAAE,OAAO,gBAAoC,CAAC;AACtE,eAAO,MAAM,OAAO,EAAE,OAAO,YAAsC,CAAC"}
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
// shim for $app/forms
|
|
2
2
|
// @see https://github.com/sveltejs/kit/issues/1485
|
|
3
3
|
import { noop, noop_async } from '@ryanatkn/belt/function.js';
|
|
4
|
-
// TODO better way todo this?
|
|
5
|
-
// @ts-expect-error
|
|
6
|
-
import * as devalue from 'devalue';
|
|
7
4
|
export const applyAction = noop_async;
|
|
8
|
-
export const deserialize = (
|
|
9
|
-
const parsed = JSON.parse(result);
|
|
10
|
-
if (parsed.data) {
|
|
11
|
-
parsed.data = devalue.parse(parsed.data);
|
|
12
|
-
}
|
|
13
|
-
return parsed;
|
|
14
|
-
};
|
|
5
|
+
export const deserialize = () => ({});
|
|
15
6
|
export const enhance = () => ({ destroy: noop });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryanatkn/gro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.147.0",
|
|
4
4
|
"description": "task runner and toolkit extending SvelteKit",
|
|
5
5
|
"motto": "generate, run, optimize",
|
|
6
6
|
"glyph": "🌰",
|
|
@@ -354,10 +354,6 @@
|
|
|
354
354
|
"types": "./dist/release.task.d.ts",
|
|
355
355
|
"default": "./dist/release.task.js"
|
|
356
356
|
},
|
|
357
|
-
"./resolve_node_specifier.js": {
|
|
358
|
-
"types": "./dist/resolve_node_specifier.d.ts",
|
|
359
|
-
"default": "./dist/resolve_node_specifier.js"
|
|
360
|
-
},
|
|
361
357
|
"./resolve_specifier.js": {
|
|
362
358
|
"types": "./dist/resolve_specifier.d.ts",
|
|
363
359
|
"default": "./dist/resolve_specifier.js"
|
package/src/lib/filer.ts
CHANGED
|
@@ -3,6 +3,9 @@ import {existsSync, readFileSync, statSync} from 'node:fs';
|
|
|
3
3
|
import {dirname, resolve} from 'node:path';
|
|
4
4
|
import type {Omit_Strict} from '@ryanatkn/belt/types.js';
|
|
5
5
|
import {wait} from '@ryanatkn/belt/async.js';
|
|
6
|
+
import {isBuiltin} from 'node:module';
|
|
7
|
+
import {fileURLToPath} from 'node:url';
|
|
8
|
+
import {Unreachable_Error} from '@ryanatkn/belt/error.js';
|
|
6
9
|
|
|
7
10
|
import type {Path_Id} from './path.js';
|
|
8
11
|
import {
|
|
@@ -17,8 +20,6 @@ import {parse_imports} from './parse_imports.js';
|
|
|
17
20
|
import {resolve_specifier} from './resolve_specifier.js';
|
|
18
21
|
import {default_sveltekit_config} from './sveltekit_config.js';
|
|
19
22
|
import {map_sveltekit_aliases} from './sveltekit_helpers.js';
|
|
20
|
-
import {Unreachable_Error} from '@ryanatkn/belt/error.js';
|
|
21
|
-
import {resolve_node_specifier} from './resolve_node_specifier.js';
|
|
22
23
|
import type {Package_Json} from './package_json.js';
|
|
23
24
|
|
|
24
25
|
const aliases = Object.entries(default_sveltekit_config.alias);
|
|
@@ -58,13 +59,10 @@ export class Filer {
|
|
|
58
59
|
#watch_dir: typeof watch_dir;
|
|
59
60
|
#watch_dir_options: Partial<Watch_Dir_Options>;
|
|
60
61
|
|
|
61
|
-
#package_json_cache: Record<string, Package_Json>;
|
|
62
|
-
|
|
63
62
|
constructor(options: Filer_Options = EMPTY_OBJECT) {
|
|
64
63
|
this.#watch_dir = options.watch_dir ?? watch_dir;
|
|
65
64
|
this.#watch_dir_options = options.watch_dir_options ?? EMPTY_OBJECT;
|
|
66
65
|
this.root_dir = resolve(options.watch_dir_options?.dir ?? paths.source);
|
|
67
|
-
this.#package_json_cache = options.package_json_cache ?? {};
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
#watching: Watch_Node_Fs | undefined;
|
|
@@ -118,16 +116,24 @@ export class Filer {
|
|
|
118
116
|
|
|
119
117
|
const imported = file.contents ? parse_imports(file.id, file.contents) : [];
|
|
120
118
|
for (const specifier of imported) {
|
|
121
|
-
// TODO logic is duplicated from loader
|
|
122
119
|
const path = map_sveltekit_aliases(specifier, aliases);
|
|
123
120
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
121
|
+
let path_id;
|
|
122
|
+
if (path[0] === '.' || path[0] === '/') {
|
|
123
|
+
const resolved = resolve_specifier(path, dir);
|
|
124
|
+
path_id = resolved.path_id;
|
|
125
|
+
} else {
|
|
126
|
+
if (isBuiltin(path)) continue;
|
|
127
|
+
try {
|
|
128
|
+
path_id = fileURLToPath(import.meta.resolve(path, file.id));
|
|
129
|
+
} catch (error) {
|
|
130
|
+
// If it's imported from an external module, ignore any import errors.
|
|
131
|
+
if (error.code === 'ERR_MODULE_NOT_FOUND' && file.external) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
131
137
|
dependencies_removed.delete(path_id);
|
|
132
138
|
if (!dependencies_before.has(path_id)) {
|
|
133
139
|
const d = this.get_or_create(path_id);
|
package/src/lib/loader.ts
CHANGED
|
@@ -20,8 +20,6 @@ import {IS_THIS_GRO, paths} from './paths.js';
|
|
|
20
20
|
import {JSON_MATCHER, NODE_MODULES_DIRNAME, TS_MATCHER} from './constants.js';
|
|
21
21
|
import {to_define_import_meta_env, default_ts_transform_options} from './esbuild_helpers.js';
|
|
22
22
|
import {resolve_specifier} from './resolve_specifier.js';
|
|
23
|
-
import {resolve_node_specifier} from './resolve_node_specifier.js';
|
|
24
|
-
import type {Package_Json} from './package_json.js';
|
|
25
23
|
import {map_sveltekit_aliases} from './sveltekit_helpers.js';
|
|
26
24
|
|
|
27
25
|
/*
|
|
@@ -80,8 +78,6 @@ const RAW_MATCHER = /(%3Fraw|\.css|\.svg)$/; // TODO others? configurable?
|
|
|
80
78
|
const ENV_MATCHER = /src\/lib\/\$env\/(static|dynamic)\/(public|private)$/;
|
|
81
79
|
const NODE_MODULES_MATCHER = new RegExp(escape_regexp('/' + NODE_MODULES_DIRNAME + '/'), 'u');
|
|
82
80
|
|
|
83
|
-
const package_json_cache: Record<string, Package_Json> = {};
|
|
84
|
-
|
|
85
81
|
export const load: LoadHook = async (url, context, nextLoad) => {
|
|
86
82
|
if (SVELTEKIT_SHIM_APP_PATHS_MATCHER.test(url)) {
|
|
87
83
|
// SvelteKit `$app/paths` shim
|
|
@@ -211,19 +207,10 @@ export const resolve: ResolveHook = async (specifier, context, nextResolve) => {
|
|
|
211
207
|
s = map_sveltekit_aliases(s, aliases);
|
|
212
208
|
|
|
213
209
|
// The specifier has now been mapped to its final form, so we can inspect it.
|
|
210
|
+
|
|
211
|
+
// Imports into `node_modules` use the default algorithm, and the rest use use Vite conventions.
|
|
214
212
|
if (s[0] !== '.' && s[0] !== '/') {
|
|
215
|
-
|
|
216
|
-
if (SVELTE_MATCHER.test(s) || JSON_MATCHER.test(s)) {
|
|
217
|
-
// Match the behavior of Vite and esbuild for Svelte and JSON imports.
|
|
218
|
-
const resolved = resolve_node_specifier(s, dir, parent_url, package_json_cache)!; // `node:` specifiers shouldn't reach this point, so the assertion is safe
|
|
219
|
-
return {
|
|
220
|
-
url: pathToFileURL(resolved.path_id_with_querystring).href,
|
|
221
|
-
format: 'module',
|
|
222
|
-
shortCircuit: true,
|
|
223
|
-
};
|
|
224
|
-
} else {
|
|
225
|
-
return nextResolve(s, context);
|
|
226
|
-
}
|
|
213
|
+
return nextResolve(s, context);
|
|
227
214
|
}
|
|
228
215
|
|
|
229
216
|
const resolved = resolve_specifier(s, dirname(fileURLToPath(parent_url)));
|
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.
|
|
8
|
+
version: '0.147.0',
|
|
9
9
|
description: 'task runner and toolkit extending SvelteKit',
|
|
10
10
|
motto: 'generate, run, optimize',
|
|
11
11
|
glyph: '🌰',
|
|
@@ -201,10 +201,6 @@ export const package_json = {
|
|
|
201
201
|
default: './dist/reinstall.task.js',
|
|
202
202
|
},
|
|
203
203
|
'./release.task.js': {types: './dist/release.task.d.ts', default: './dist/release.task.js'},
|
|
204
|
-
'./resolve_node_specifier.js': {
|
|
205
|
-
types: './dist/resolve_node_specifier.d.ts',
|
|
206
|
-
default: './dist/resolve_node_specifier.js',
|
|
207
|
-
},
|
|
208
204
|
'./resolve_specifier.js': {
|
|
209
205
|
types: './dist/resolve_specifier.d.ts',
|
|
210
206
|
default: './dist/resolve_specifier.js',
|
|
@@ -270,7 +266,7 @@ export const package_json = {
|
|
|
270
266
|
|
|
271
267
|
export const src_json = {
|
|
272
268
|
name: '@ryanatkn/gro',
|
|
273
|
-
version: '0.
|
|
269
|
+
version: '0.147.0',
|
|
274
270
|
modules: {
|
|
275
271
|
'.': {
|
|
276
272
|
path: 'index.ts',
|
|
@@ -816,10 +812,6 @@ export const src_json = {
|
|
|
816
812
|
{name: 'task', kind: 'variable'},
|
|
817
813
|
],
|
|
818
814
|
},
|
|
819
|
-
'./resolve_node_specifier.js': {
|
|
820
|
-
path: 'resolve_node_specifier.ts',
|
|
821
|
-
declarations: [{name: 'resolve_node_specifier', kind: 'function'}],
|
|
822
|
-
},
|
|
823
815
|
'./resolve_specifier.js': {
|
|
824
816
|
path: 'resolve_specifier.ts',
|
|
825
817
|
declarations: [
|
|
@@ -7,16 +7,7 @@ import type {
|
|
|
7
7
|
enhance as base_enhance,
|
|
8
8
|
} from '$app/forms';
|
|
9
9
|
import {noop, noop_async} from '@ryanatkn/belt/function.js';
|
|
10
|
-
// TODO better way todo this?
|
|
11
|
-
// @ts-expect-error
|
|
12
|
-
import * as devalue from 'devalue';
|
|
13
10
|
|
|
14
11
|
export const applyAction: typeof base_applyAction = noop_async;
|
|
15
|
-
export const deserialize: typeof base_deserialize = (
|
|
16
|
-
const parsed = JSON.parse(result);
|
|
17
|
-
if (parsed.data) {
|
|
18
|
-
parsed.data = devalue.parse(parsed.data);
|
|
19
|
-
}
|
|
20
|
-
return parsed;
|
|
21
|
-
};
|
|
12
|
+
export const deserialize: typeof base_deserialize = () => ({}) as any;
|
|
22
13
|
export const enhance: typeof base_enhance = () => ({destroy: noop});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Package_Json } from './package_json.js';
|
|
2
|
-
import type { Resolved_Specifier } from './resolve_specifier.js';
|
|
3
|
-
/**
|
|
4
|
-
* Ideally Gro would just use `import.meta.resolve`, but it can't be used in custom loaders,
|
|
5
|
-
* which Gro relies on for TypeScript.
|
|
6
|
-
* This likely has differences from Node - they should be fixed on a case-by-case basis.
|
|
7
|
-
*/
|
|
8
|
-
export declare const resolve_node_specifier: (specifier: string, dir?: string, parent_path?: string, package_json_cache?: Record<string, Package_Json>, throw_on_missing_package?: boolean, exports_conditions?: string[]) => Resolved_Specifier | null;
|
|
9
|
-
//# sourceMappingURL=resolve_node_specifier.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolve_node_specifier.d.ts","sourceRoot":"../src/lib/","sources":["resolve_node_specifier.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,YAAY,EAAoB,MAAM,mBAAmB,CAAC;AAGhF,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,cACvB,MAAM,8BAEH,MAAM,uBACC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,wEAG/C,kBAAkB,GAAG,IAsFvB,CAAC"}
|
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { join, extname } from 'node:path';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { DEV } from 'esm-env';
|
|
4
|
-
import { escape_regexp } from '@ryanatkn/belt/regexp.js';
|
|
5
|
-
import { Export_Value, Package_Json, load_package_json } from './package_json.js';
|
|
6
|
-
import { paths } from './paths.js';
|
|
7
|
-
import { NODE_MODULES_DIRNAME } from './constants.js';
|
|
8
|
-
/**
|
|
9
|
-
* Ideally Gro would just use `import.meta.resolve`, but it can't be used in custom loaders,
|
|
10
|
-
* which Gro relies on for TypeScript.
|
|
11
|
-
* This likely has differences from Node - they should be fixed on a case-by-case basis.
|
|
12
|
-
*/
|
|
13
|
-
export const resolve_node_specifier = (specifier, dir = paths.root, parent_path, package_json_cache, throw_on_missing_package = true, exports_conditions = DEV ? ['development', 'node', 'import'] : ['production', 'node', 'import']) => {
|
|
14
|
-
const raw = specifier.endsWith('?raw');
|
|
15
|
-
const mapped_specifier = raw ? specifier.substring(0, specifier.length - 4) : specifier;
|
|
16
|
-
const specifier_slash_path_index = get_specifier_slash_path_index(mapped_specifier);
|
|
17
|
-
const pkg_name = specifier_slash_path_index === -1
|
|
18
|
-
? mapped_specifier
|
|
19
|
-
: mapped_specifier.substring(0, specifier_slash_path_index);
|
|
20
|
-
const module_path = specifier_slash_path_index === -1
|
|
21
|
-
? ''
|
|
22
|
-
: mapped_specifier.substring(specifier_slash_path_index + 1);
|
|
23
|
-
const subpath = module_path ? './' + module_path : '.';
|
|
24
|
-
const package_dir = join(dir, NODE_MODULES_DIRNAME, pkg_name);
|
|
25
|
-
// Check package_json cache first
|
|
26
|
-
let package_json;
|
|
27
|
-
if (package_json_cache?.[pkg_name]) {
|
|
28
|
-
package_json = package_json_cache[pkg_name];
|
|
29
|
-
}
|
|
30
|
-
else if (!existsSync(package_dir)) {
|
|
31
|
-
if (throw_on_missing_package) {
|
|
32
|
-
throw Error(`Package not found at ${package_dir} for specifier ${specifier}, you may need to install packages or fix the path` +
|
|
33
|
-
(parent_path ? ` imported from ${parent_path}` : ''));
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
package_json = load_package_json(package_dir, package_json_cache, false);
|
|
41
|
-
}
|
|
42
|
-
// Handle self-referencing
|
|
43
|
-
if (parent_path?.startsWith(package_dir)) {
|
|
44
|
-
if (!package_json.exports) {
|
|
45
|
-
throw Error(`Self-referencing is only available if package.json has "exports" field: ${specifier}` +
|
|
46
|
-
(parent_path ? ` imported from ${parent_path}` : ''));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
const exported = resolve_subpath(package_json, subpath);
|
|
50
|
-
if (typeof exported === 'string') {
|
|
51
|
-
const validated = validate_export_target(exported, throw_on_missing_package);
|
|
52
|
-
if (validated === null) {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (!exported) {
|
|
57
|
-
if (throw_on_missing_package) {
|
|
58
|
-
throw Error(`[ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath '${subpath}' is not defined by 'exports' in ${package_dir}/package.json` +
|
|
59
|
-
(parent_path ? ` imported from ${parent_path}` : ''));
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const exported_value = resolve_exported_value(exported, exports_conditions);
|
|
66
|
-
if (exported_value === undefined) {
|
|
67
|
-
if (throw_on_missing_package) {
|
|
68
|
-
throw Error(`No valid export found for subpath '${subpath}' in ${package_dir}/package.json with the following conditions: ${exports_conditions.join(', ')}` +
|
|
69
|
-
(parent_path ? ` imported from ${parent_path}` : ''));
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const path_id = normalize_extension(join(package_dir, exported_value));
|
|
76
|
-
return {
|
|
77
|
-
path_id,
|
|
78
|
-
path_id_with_querystring: raw ? path_id + '?raw' : path_id,
|
|
79
|
-
raw,
|
|
80
|
-
specifier,
|
|
81
|
-
mapped_specifier,
|
|
82
|
-
namespace: undefined,
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
const replace_wildcards = (pattern, wildcards) => {
|
|
86
|
-
if (!pattern.includes('*'))
|
|
87
|
-
return pattern;
|
|
88
|
-
let result = pattern;
|
|
89
|
-
let wildcard_index = 0;
|
|
90
|
-
while (result.includes('*') && wildcard_index < wildcards.length) {
|
|
91
|
-
result = result.replace('*', wildcards[wildcard_index++]);
|
|
92
|
-
}
|
|
93
|
-
return result;
|
|
94
|
-
};
|
|
95
|
-
const resolve_subpath = (package_json, subpath) => {
|
|
96
|
-
// If no exports field exists, fallback to main field for the root subpath
|
|
97
|
-
if (!package_json.exports) {
|
|
98
|
-
return subpath === '.' && package_json.main ? package_json.main : null;
|
|
99
|
-
}
|
|
100
|
-
const exports = package_json.exports;
|
|
101
|
-
// Handle exports sugar syntax
|
|
102
|
-
if (typeof exports === 'string') {
|
|
103
|
-
return subpath === '.' ? exports : null;
|
|
104
|
-
}
|
|
105
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
106
|
-
if (typeof exports === 'object' && exports !== null) {
|
|
107
|
-
// Check for exact match first
|
|
108
|
-
if (subpath in exports) {
|
|
109
|
-
return exports[subpath];
|
|
110
|
-
}
|
|
111
|
-
// TODO some of this may be wrong, will just need to patch as we go
|
|
112
|
-
// Sort patterns by specificity
|
|
113
|
-
const patterns = Object.entries(exports)
|
|
114
|
-
.filter(([pattern]) => pattern.includes('*'))
|
|
115
|
-
.map(([pattern, target]) => ({
|
|
116
|
-
pattern,
|
|
117
|
-
target,
|
|
118
|
-
static_prefix: pattern.split('*')[0],
|
|
119
|
-
segments: pattern.split('/').length,
|
|
120
|
-
wildcards: (pattern.match(/\*/g) ?? []).length,
|
|
121
|
-
}))
|
|
122
|
-
.sort((a, b) => {
|
|
123
|
-
// Sort by static prefix length first
|
|
124
|
-
const prefix_diff = b.static_prefix.length - a.static_prefix.length;
|
|
125
|
-
if (prefix_diff !== 0)
|
|
126
|
-
return prefix_diff;
|
|
127
|
-
// Then by number of segments
|
|
128
|
-
const segment_diff = b.segments - a.segments;
|
|
129
|
-
if (segment_diff !== 0)
|
|
130
|
-
return segment_diff;
|
|
131
|
-
// Then by number of wildcards (fewer is more specific)
|
|
132
|
-
const wildcard_diff = a.wildcards - b.wildcards;
|
|
133
|
-
if (wildcard_diff !== 0)
|
|
134
|
-
return wildcard_diff;
|
|
135
|
-
// Finally by total pattern length
|
|
136
|
-
return b.pattern.length - a.pattern.length;
|
|
137
|
-
});
|
|
138
|
-
// Track matched wildcards for later use
|
|
139
|
-
let matched_wildcards = [];
|
|
140
|
-
// Check patterns in order of specificity
|
|
141
|
-
for (const { pattern, target } of patterns) {
|
|
142
|
-
// Convert pattern to regex, handling path segments properly
|
|
143
|
-
const regex_pattern = pattern.split('*').map(escape_regexp).join('([^/]+)');
|
|
144
|
-
const regex = new RegExp(`^${regex_pattern}$`);
|
|
145
|
-
const match = subpath.match(regex);
|
|
146
|
-
if (match) {
|
|
147
|
-
// If this is a null pattern and it matches, block access
|
|
148
|
-
if (target === null)
|
|
149
|
-
return null;
|
|
150
|
-
// Extract captured wildcards and store them
|
|
151
|
-
matched_wildcards = match.slice(1);
|
|
152
|
-
if (typeof target === 'string') {
|
|
153
|
-
return replace_wildcards(target, matched_wildcards);
|
|
154
|
-
}
|
|
155
|
-
if (typeof target === 'object' && target !== null) {
|
|
156
|
-
// For conditional exports, return an object with resolved wildcards
|
|
157
|
-
return Object.fromEntries(Object.entries(target).map(([key, value]) => {
|
|
158
|
-
if (typeof value === 'string') {
|
|
159
|
-
return [key, replace_wildcards(value, matched_wildcards)];
|
|
160
|
-
}
|
|
161
|
-
// Handle nested conditions
|
|
162
|
-
if (typeof value === 'object' && value !== null) {
|
|
163
|
-
return [
|
|
164
|
-
key,
|
|
165
|
-
Object.fromEntries(Object.entries(value).map(([nested_key, nested_value]) => [
|
|
166
|
-
nested_key,
|
|
167
|
-
typeof nested_value === 'string'
|
|
168
|
-
? replace_wildcards(nested_value, matched_wildcards)
|
|
169
|
-
: nested_value,
|
|
170
|
-
])),
|
|
171
|
-
];
|
|
172
|
-
}
|
|
173
|
-
return [key, value];
|
|
174
|
-
}));
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
// Handle catch-all patterns for remaining cases
|
|
179
|
-
const catch_all_patterns = patterns.filter(({ pattern }) => pattern.endsWith('/*') || pattern === './*');
|
|
180
|
-
for (const { pattern, target } of catch_all_patterns) {
|
|
181
|
-
const base_pattern = pattern.slice(0, -1); // Remove trailing '*'
|
|
182
|
-
if (subpath.startsWith(base_pattern)) {
|
|
183
|
-
if (target === null)
|
|
184
|
-
return null;
|
|
185
|
-
const remainder = subpath.slice(base_pattern.length);
|
|
186
|
-
if (typeof target === 'string') {
|
|
187
|
-
return target.slice(0, -1) + remainder;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return null;
|
|
193
|
-
};
|
|
194
|
-
const resolve_exported_value = (exported, conditions) => {
|
|
195
|
-
if (typeof exported === 'string') {
|
|
196
|
-
return exported;
|
|
197
|
-
}
|
|
198
|
-
if (typeof exported !== 'object' || exported === null) {
|
|
199
|
-
return undefined;
|
|
200
|
-
}
|
|
201
|
-
const exported_obj = exported;
|
|
202
|
-
let default_value; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents
|
|
203
|
-
// For each key in exported_obj, in order
|
|
204
|
-
for (const [condition, value] of Object.entries(exported_obj)) {
|
|
205
|
-
// Skip invalid conditions
|
|
206
|
-
if (!is_valid_condition(condition)) {
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
if (condition === 'default') {
|
|
210
|
-
// Store default value to try last
|
|
211
|
-
default_value = value;
|
|
212
|
-
}
|
|
213
|
-
else if (conditions.includes(condition)) {
|
|
214
|
-
const resolved = resolve_exported_value(value, conditions);
|
|
215
|
-
if (resolved !== undefined) {
|
|
216
|
-
return resolved;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// If no conditions matched, try default
|
|
221
|
-
if (default_value !== undefined) {
|
|
222
|
-
const resolved = resolve_exported_value(default_value, conditions);
|
|
223
|
-
if (resolved !== undefined) {
|
|
224
|
-
return resolved;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return undefined;
|
|
228
|
-
};
|
|
229
|
-
const is_valid_condition = (condition) => {
|
|
230
|
-
if (condition.length === 0 ||
|
|
231
|
-
condition.startsWith('.') ||
|
|
232
|
-
condition.includes(',') ||
|
|
233
|
-
/^\d+$/.test(condition)) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
return /^[a-zA-Z0-9:_\-=]+$/.test(condition);
|
|
237
|
-
};
|
|
238
|
-
const normalize_extension = (path) => {
|
|
239
|
-
if (path.endsWith('.d.ts')) {
|
|
240
|
-
return path.slice(0, -5) + '.js';
|
|
241
|
-
}
|
|
242
|
-
// No extension handling needed if path already has an extension
|
|
243
|
-
if (extname(path)) {
|
|
244
|
-
return path;
|
|
245
|
-
}
|
|
246
|
-
// If no extension at all, add .js
|
|
247
|
-
return path + '.js';
|
|
248
|
-
};
|
|
249
|
-
const validate_export_target = (target, throw_on_missing_package) => {
|
|
250
|
-
// Must start with './'
|
|
251
|
-
if (!target.startsWith('./') && !target.startsWith('../')) {
|
|
252
|
-
if (throw_on_missing_package) {
|
|
253
|
-
throw new Error('ERR_INVALID_PACKAGE_TARGET: Export target must start with "./" or "../"');
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
// Can't contain node_modules
|
|
260
|
-
if (target.includes('node_modules')) {
|
|
261
|
-
if (throw_on_missing_package) {
|
|
262
|
-
throw new Error('ERR_INVALID_PACKAGE_TARGET: Export target cannot contain node_modules');
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
// Check for package boundary escape
|
|
269
|
-
const parts = target.split('/');
|
|
270
|
-
let depth = 0;
|
|
271
|
-
for (const part of parts) {
|
|
272
|
-
if (part === '..') {
|
|
273
|
-
depth--;
|
|
274
|
-
// If we go above root, it's escaping the package boundary
|
|
275
|
-
if (depth < 0) {
|
|
276
|
-
if (throw_on_missing_package) {
|
|
277
|
-
throw new Error('ERR_INVALID_PACKAGE_TARGET: Export target cannot escape package boundary');
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
else if (part !== '.' && part !== '') {
|
|
285
|
-
depth++;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
const get_specifier_slash_path_index = (mapped_specifier) => {
|
|
290
|
-
let index = -1;
|
|
291
|
-
if (mapped_specifier[0] === '@') {
|
|
292
|
-
let count = 0;
|
|
293
|
-
for (let i = 0; i < mapped_specifier.length; i++) {
|
|
294
|
-
if (mapped_specifier[i] === '/')
|
|
295
|
-
count++;
|
|
296
|
-
if (count === 2) {
|
|
297
|
-
index = i;
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
index = mapped_specifier.indexOf('/');
|
|
304
|
-
}
|
|
305
|
-
return index;
|
|
306
|
-
};
|
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
import {join, extname} from 'node:path';
|
|
2
|
-
import {existsSync} from 'node:fs';
|
|
3
|
-
import {DEV} from 'esm-env';
|
|
4
|
-
import {escape_regexp} from '@ryanatkn/belt/regexp.js';
|
|
5
|
-
|
|
6
|
-
import {Export_Value, Package_Json, load_package_json} from './package_json.js';
|
|
7
|
-
import {paths} from './paths.js';
|
|
8
|
-
import {NODE_MODULES_DIRNAME} from './constants.js';
|
|
9
|
-
import type {Resolved_Specifier} from './resolve_specifier.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Ideally Gro would just use `import.meta.resolve`, but it can't be used in custom loaders,
|
|
13
|
-
* which Gro relies on for TypeScript.
|
|
14
|
-
* This likely has differences from Node - they should be fixed on a case-by-case basis.
|
|
15
|
-
*/
|
|
16
|
-
export const resolve_node_specifier = (
|
|
17
|
-
specifier: string,
|
|
18
|
-
dir = paths.root,
|
|
19
|
-
parent_path?: string,
|
|
20
|
-
package_json_cache?: Record<string, Package_Json>,
|
|
21
|
-
throw_on_missing_package = true,
|
|
22
|
-
exports_conditions = DEV ? ['development', 'node', 'import'] : ['production', 'node', 'import'],
|
|
23
|
-
): Resolved_Specifier | null => {
|
|
24
|
-
const raw = specifier.endsWith('?raw');
|
|
25
|
-
const mapped_specifier = raw ? specifier.substring(0, specifier.length - 4) : specifier;
|
|
26
|
-
|
|
27
|
-
const specifier_slash_path_index = get_specifier_slash_path_index(mapped_specifier);
|
|
28
|
-
|
|
29
|
-
const pkg_name =
|
|
30
|
-
specifier_slash_path_index === -1
|
|
31
|
-
? mapped_specifier
|
|
32
|
-
: mapped_specifier.substring(0, specifier_slash_path_index);
|
|
33
|
-
const module_path =
|
|
34
|
-
specifier_slash_path_index === -1
|
|
35
|
-
? ''
|
|
36
|
-
: mapped_specifier.substring(specifier_slash_path_index + 1);
|
|
37
|
-
const subpath = module_path ? './' + module_path : '.';
|
|
38
|
-
const package_dir = join(dir, NODE_MODULES_DIRNAME, pkg_name);
|
|
39
|
-
|
|
40
|
-
// Check package_json cache first
|
|
41
|
-
let package_json: Package_Json | undefined;
|
|
42
|
-
if (package_json_cache?.[pkg_name]) {
|
|
43
|
-
package_json = package_json_cache[pkg_name];
|
|
44
|
-
} else if (!existsSync(package_dir)) {
|
|
45
|
-
if (throw_on_missing_package) {
|
|
46
|
-
throw Error(
|
|
47
|
-
`Package not found at ${package_dir} for specifier ${specifier}, you may need to install packages or fix the path` +
|
|
48
|
-
(parent_path ? ` imported from ${parent_path}` : ''),
|
|
49
|
-
);
|
|
50
|
-
} else {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
package_json = load_package_json(package_dir, package_json_cache, false);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Handle self-referencing
|
|
58
|
-
if (parent_path?.startsWith(package_dir)) {
|
|
59
|
-
if (!package_json.exports) {
|
|
60
|
-
throw Error(
|
|
61
|
-
`Self-referencing is only available if package.json has "exports" field: ${specifier}` +
|
|
62
|
-
(parent_path ? ` imported from ${parent_path}` : ''),
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const exported = resolve_subpath(package_json, subpath);
|
|
68
|
-
|
|
69
|
-
if (typeof exported === 'string') {
|
|
70
|
-
const validated = validate_export_target(exported, throw_on_missing_package);
|
|
71
|
-
if (validated === null) {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (!exported) {
|
|
77
|
-
if (throw_on_missing_package) {
|
|
78
|
-
throw Error(
|
|
79
|
-
`[ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath '${subpath}' is not defined by 'exports' in ${package_dir}/package.json` +
|
|
80
|
-
(parent_path ? ` imported from ${parent_path}` : ''),
|
|
81
|
-
);
|
|
82
|
-
} else {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const exported_value = resolve_exported_value(exported, exports_conditions);
|
|
88
|
-
if (exported_value === undefined) {
|
|
89
|
-
if (throw_on_missing_package) {
|
|
90
|
-
throw Error(
|
|
91
|
-
`No valid export found for subpath '${subpath}' in ${package_dir}/package.json with the following conditions: ${exports_conditions.join(', ')}` +
|
|
92
|
-
(parent_path ? ` imported from ${parent_path}` : ''),
|
|
93
|
-
);
|
|
94
|
-
} else {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const path_id = normalize_extension(join(package_dir, exported_value));
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
path_id,
|
|
103
|
-
path_id_with_querystring: raw ? path_id + '?raw' : path_id,
|
|
104
|
-
raw,
|
|
105
|
-
specifier,
|
|
106
|
-
mapped_specifier,
|
|
107
|
-
namespace: undefined,
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const replace_wildcards = (pattern: string, wildcards: string[]): string => {
|
|
112
|
-
if (!pattern.includes('*')) return pattern;
|
|
113
|
-
|
|
114
|
-
let result = pattern;
|
|
115
|
-
let wildcard_index = 0;
|
|
116
|
-
while (result.includes('*') && wildcard_index < wildcards.length) {
|
|
117
|
-
result = result.replace('*', wildcards[wildcard_index++]);
|
|
118
|
-
}
|
|
119
|
-
return result;
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const resolve_subpath = (package_json: Package_Json, subpath: string): unknown => {
|
|
123
|
-
// If no exports field exists, fallback to main field for the root subpath
|
|
124
|
-
if (!package_json.exports) {
|
|
125
|
-
return subpath === '.' && package_json.main ? package_json.main : null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const exports = package_json.exports;
|
|
129
|
-
|
|
130
|
-
// Handle exports sugar syntax
|
|
131
|
-
if (typeof exports === 'string') {
|
|
132
|
-
return subpath === '.' ? exports : null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
136
|
-
if (typeof exports === 'object' && exports !== null) {
|
|
137
|
-
// Check for exact match first
|
|
138
|
-
if (subpath in exports) {
|
|
139
|
-
return exports[subpath];
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// TODO some of this may be wrong, will just need to patch as we go
|
|
143
|
-
// Sort patterns by specificity
|
|
144
|
-
const patterns = Object.entries(exports)
|
|
145
|
-
.filter(([pattern]) => pattern.includes('*'))
|
|
146
|
-
.map(([pattern, target]) => ({
|
|
147
|
-
pattern,
|
|
148
|
-
target,
|
|
149
|
-
static_prefix: pattern.split('*')[0],
|
|
150
|
-
segments: pattern.split('/').length,
|
|
151
|
-
wildcards: (pattern.match(/\*/g) ?? []).length,
|
|
152
|
-
}))
|
|
153
|
-
.sort((a, b) => {
|
|
154
|
-
// Sort by static prefix length first
|
|
155
|
-
const prefix_diff = b.static_prefix.length - a.static_prefix.length;
|
|
156
|
-
if (prefix_diff !== 0) return prefix_diff;
|
|
157
|
-
|
|
158
|
-
// Then by number of segments
|
|
159
|
-
const segment_diff = b.segments - a.segments;
|
|
160
|
-
if (segment_diff !== 0) return segment_diff;
|
|
161
|
-
|
|
162
|
-
// Then by number of wildcards (fewer is more specific)
|
|
163
|
-
const wildcard_diff = a.wildcards - b.wildcards;
|
|
164
|
-
if (wildcard_diff !== 0) return wildcard_diff;
|
|
165
|
-
|
|
166
|
-
// Finally by total pattern length
|
|
167
|
-
return b.pattern.length - a.pattern.length;
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// Track matched wildcards for later use
|
|
171
|
-
let matched_wildcards: string[] = [];
|
|
172
|
-
|
|
173
|
-
// Check patterns in order of specificity
|
|
174
|
-
for (const {pattern, target} of patterns) {
|
|
175
|
-
// Convert pattern to regex, handling path segments properly
|
|
176
|
-
const regex_pattern = pattern.split('*').map(escape_regexp).join('([^/]+)');
|
|
177
|
-
const regex = new RegExp(`^${regex_pattern}$`);
|
|
178
|
-
const match = subpath.match(regex);
|
|
179
|
-
|
|
180
|
-
if (match) {
|
|
181
|
-
// If this is a null pattern and it matches, block access
|
|
182
|
-
if (target === null) return null;
|
|
183
|
-
|
|
184
|
-
// Extract captured wildcards and store them
|
|
185
|
-
matched_wildcards = match.slice(1);
|
|
186
|
-
|
|
187
|
-
if (typeof target === 'string') {
|
|
188
|
-
return replace_wildcards(target, matched_wildcards);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (typeof target === 'object' && target !== null) {
|
|
192
|
-
// For conditional exports, return an object with resolved wildcards
|
|
193
|
-
return Object.fromEntries(
|
|
194
|
-
Object.entries(target).map(([key, value]) => {
|
|
195
|
-
if (typeof value === 'string') {
|
|
196
|
-
return [key, replace_wildcards(value, matched_wildcards)];
|
|
197
|
-
}
|
|
198
|
-
// Handle nested conditions
|
|
199
|
-
if (typeof value === 'object' && value !== null) {
|
|
200
|
-
return [
|
|
201
|
-
key,
|
|
202
|
-
Object.fromEntries(
|
|
203
|
-
Object.entries(value).map(([nested_key, nested_value]) => [
|
|
204
|
-
nested_key,
|
|
205
|
-
typeof nested_value === 'string'
|
|
206
|
-
? replace_wildcards(nested_value, matched_wildcards)
|
|
207
|
-
: nested_value,
|
|
208
|
-
]),
|
|
209
|
-
),
|
|
210
|
-
];
|
|
211
|
-
}
|
|
212
|
-
return [key, value];
|
|
213
|
-
}),
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Handle catch-all patterns for remaining cases
|
|
220
|
-
const catch_all_patterns = patterns.filter(
|
|
221
|
-
({pattern}) => pattern.endsWith('/*') || pattern === './*',
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
for (const {pattern, target} of catch_all_patterns) {
|
|
225
|
-
const base_pattern = pattern.slice(0, -1); // Remove trailing '*'
|
|
226
|
-
if (subpath.startsWith(base_pattern)) {
|
|
227
|
-
if (target === null) return null;
|
|
228
|
-
|
|
229
|
-
const remainder = subpath.slice(base_pattern.length);
|
|
230
|
-
if (typeof target === 'string') {
|
|
231
|
-
return target.slice(0, -1) + remainder;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return null;
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
const resolve_exported_value = (
|
|
241
|
-
exported: Export_Value,
|
|
242
|
-
conditions: string[],
|
|
243
|
-
): string | undefined => {
|
|
244
|
-
if (typeof exported === 'string') {
|
|
245
|
-
return exported;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (typeof exported !== 'object' || exported === null) {
|
|
249
|
-
return undefined;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const exported_obj = exported as Record<string, unknown>;
|
|
253
|
-
|
|
254
|
-
let default_value: Export_Value | undefined; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents
|
|
255
|
-
|
|
256
|
-
// For each key in exported_obj, in order
|
|
257
|
-
for (const [condition, value] of Object.entries(exported_obj)) {
|
|
258
|
-
// Skip invalid conditions
|
|
259
|
-
if (!is_valid_condition(condition)) {
|
|
260
|
-
continue;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (condition === 'default') {
|
|
264
|
-
// Store default value to try last
|
|
265
|
-
default_value = value;
|
|
266
|
-
} else if (conditions.includes(condition)) {
|
|
267
|
-
const resolved = resolve_exported_value(value, conditions);
|
|
268
|
-
if (resolved !== undefined) {
|
|
269
|
-
return resolved;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// If no conditions matched, try default
|
|
275
|
-
if (default_value !== undefined) {
|
|
276
|
-
const resolved = resolve_exported_value(default_value, conditions);
|
|
277
|
-
if (resolved !== undefined) {
|
|
278
|
-
return resolved;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return undefined;
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
const is_valid_condition = (condition: string): boolean => {
|
|
286
|
-
if (
|
|
287
|
-
condition.length === 0 ||
|
|
288
|
-
condition.startsWith('.') ||
|
|
289
|
-
condition.includes(',') ||
|
|
290
|
-
/^\d+$/.test(condition)
|
|
291
|
-
) {
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
294
|
-
return /^[a-zA-Z0-9:_\-=]+$/.test(condition);
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
const normalize_extension = (path: string): string => {
|
|
298
|
-
if (path.endsWith('.d.ts')) {
|
|
299
|
-
return path.slice(0, -5) + '.js';
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// No extension handling needed if path already has an extension
|
|
303
|
-
if (extname(path)) {
|
|
304
|
-
return path;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// If no extension at all, add .js
|
|
308
|
-
return path + '.js';
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
const validate_export_target = (target: string, throw_on_missing_package: boolean): void | null => {
|
|
312
|
-
// Must start with './'
|
|
313
|
-
if (!target.startsWith('./') && !target.startsWith('../')) {
|
|
314
|
-
if (throw_on_missing_package) {
|
|
315
|
-
throw new Error('ERR_INVALID_PACKAGE_TARGET: Export target must start with "./" or "../"');
|
|
316
|
-
} else {
|
|
317
|
-
return null;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Can't contain node_modules
|
|
322
|
-
if (target.includes('node_modules')) {
|
|
323
|
-
if (throw_on_missing_package) {
|
|
324
|
-
throw new Error('ERR_INVALID_PACKAGE_TARGET: Export target cannot contain node_modules');
|
|
325
|
-
} else {
|
|
326
|
-
return null;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Check for package boundary escape
|
|
331
|
-
const parts = target.split('/');
|
|
332
|
-
let depth = 0;
|
|
333
|
-
|
|
334
|
-
for (const part of parts) {
|
|
335
|
-
if (part === '..') {
|
|
336
|
-
depth--;
|
|
337
|
-
// If we go above root, it's escaping the package boundary
|
|
338
|
-
if (depth < 0) {
|
|
339
|
-
if (throw_on_missing_package) {
|
|
340
|
-
throw new Error(
|
|
341
|
-
'ERR_INVALID_PACKAGE_TARGET: Export target cannot escape package boundary',
|
|
342
|
-
);
|
|
343
|
-
} else {
|
|
344
|
-
return null;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
} else if (part !== '.' && part !== '') {
|
|
348
|
-
depth++;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
const get_specifier_slash_path_index = (mapped_specifier: string): number => {
|
|
354
|
-
let index: number = -1;
|
|
355
|
-
if (mapped_specifier[0] === '@') {
|
|
356
|
-
let count = 0;
|
|
357
|
-
for (let i = 0; i < mapped_specifier.length; i++) {
|
|
358
|
-
if (mapped_specifier[i] === '/') count++;
|
|
359
|
-
if (count === 2) {
|
|
360
|
-
index = i;
|
|
361
|
-
break;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
} else {
|
|
365
|
-
index = mapped_specifier.indexOf('/');
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return index;
|
|
369
|
-
};
|