@endo/compartment-mapper 2.0.0 → 2.1.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/package.json +23 -9
- package/src/archive-lite.js +3 -3
- package/src/capture-lite.d.ts.map +1 -1
- package/src/capture-lite.js +29 -3
- package/src/compartment-map.d.ts.map +1 -1
- package/src/compartment-map.js +3 -2
- package/src/digest.js +1 -1
- package/src/generic-graph.d.ts +7 -25
- package/src/generic-graph.d.ts.map +1 -1
- package/src/generic-graph.js +75 -105
- package/src/import-hook.d.ts.map +1 -1
- package/src/import-hook.js +4 -3
- package/src/infer-exports.d.ts +4 -2
- package/src/infer-exports.d.ts.map +1 -1
- package/src/infer-exports.js +158 -19
- package/src/link.d.ts.map +1 -1
- package/src/link.js +61 -3
- package/src/node-modules.d.ts.map +1 -1
- package/src/node-modules.js +33 -39
- package/src/pattern-replacement.d.ts +6 -0
- package/src/pattern-replacement.d.ts.map +1 -0
- package/src/pattern-replacement.js +198 -0
- package/src/types/compartment-map-schema.d.ts +8 -1
- package/src/types/compartment-map-schema.d.ts.map +1 -1
- package/src/types/compartment-map-schema.ts +9 -0
- package/src/types/external.d.ts +79 -55
- package/src/types/external.d.ts.map +1 -1
- package/src/types/external.ts +104 -62
- package/src/types/generic-graph.d.ts +8 -2
- package/src/types/generic-graph.d.ts.map +1 -1
- package/src/types/generic-graph.ts +7 -2
- package/src/types/internal.d.ts +8 -8
- package/src/types/internal.d.ts.map +1 -1
- package/src/types/internal.ts +9 -8
- package/src/types/node-modules.d.ts +45 -8
- package/src/types/node-modules.d.ts.map +1 -1
- package/src/types/node-modules.ts +56 -15
- package/src/types/pattern-replacement.d.ts +62 -0
- package/src/types/pattern-replacement.d.ts.map +1 -0
- package/src/types/pattern-replacement.ts +70 -0
- package/src/types/powers.d.ts +11 -9
- package/src/types/powers.d.ts.map +1 -1
- package/src/types/powers.ts +11 -10
package/src/infer-exports.js
CHANGED
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @import {LanguageForExtension, PackageDescriptor} from './types.js'
|
|
13
|
-
* @import {
|
|
13
|
+
* @import {LogFn} from './types/external.js'
|
|
14
|
+
* @import {Exports, Imports, Node} from './types/node-modules.js'
|
|
15
|
+
* @import {PatternDescriptor} from './types/pattern-replacement.js'
|
|
14
16
|
*/
|
|
15
17
|
|
|
16
|
-
import {
|
|
18
|
+
import { relativize } from './node-module-specifier.js';
|
|
17
19
|
|
|
18
|
-
const { entries, fromEntries
|
|
20
|
+
const { entries, fromEntries } = Object;
|
|
19
21
|
const { isArray } = Array;
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -60,15 +62,20 @@ function* interpretBrowserField(name, browser, main = 'index.js') {
|
|
|
60
62
|
|
|
61
63
|
/**
|
|
62
64
|
* @param {string} name - the name of the referrer package.
|
|
63
|
-
* @param {
|
|
65
|
+
* @param {Exports} exports - the `exports` field from a package.json.
|
|
64
66
|
* @param {Set<string>} conditions - build conditions about the target environment
|
|
65
67
|
* for selecting relevant exports, e.g., "browser" or "node".
|
|
66
68
|
* @param {LanguageForExtension} types - an object to populate
|
|
67
69
|
* with any recognized module's type, if implied by a tag.
|
|
68
|
-
* @yields {[string, string]}
|
|
69
|
-
* @returns {Generator<[string, string]>}
|
|
70
|
+
* @yields {[string, string | null]}
|
|
71
|
+
* @returns {Generator<[string, string | null]>}
|
|
70
72
|
*/
|
|
71
73
|
function* interpretExports(name, exports, conditions, types) {
|
|
74
|
+
// Null targets are exclusions (Node.js semantics).
|
|
75
|
+
if (exports === null) {
|
|
76
|
+
yield [name, null];
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
72
79
|
if (isArray(exports)) {
|
|
73
80
|
for (const section of exports) {
|
|
74
81
|
const results = [...interpretExports(name, section, conditions, types)];
|
|
@@ -94,11 +101,7 @@ function* interpretExports(name, exports, conditions, types) {
|
|
|
94
101
|
// eslint-disable-next-line no-continue
|
|
95
102
|
continue; // or no-op
|
|
96
103
|
} else if (key.startsWith('./') || key === '.') {
|
|
97
|
-
|
|
98
|
-
yield* interpretExports(key, value, conditions, types);
|
|
99
|
-
} else {
|
|
100
|
-
yield* interpretExports(join(name, key), value, conditions, types);
|
|
101
|
-
}
|
|
104
|
+
yield* interpretExports(key, value, conditions, types);
|
|
102
105
|
} else if (conditions.has(key)) {
|
|
103
106
|
if (types && key === 'import' && typeof value === 'string') {
|
|
104
107
|
// In this one case, the key "import" has carried a hint that the
|
|
@@ -115,6 +118,54 @@ function* interpretExports(name, exports, conditions, types) {
|
|
|
115
118
|
}
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Interprets the `imports` field from a package.json file.
|
|
123
|
+
* The imports field provides self-referencing subpath patterns that
|
|
124
|
+
* can be used to create private internal mappings.
|
|
125
|
+
*
|
|
126
|
+
* @param {Imports} imports - the `imports` field from a package.json.
|
|
127
|
+
* @param {Set<string>} conditions - build conditions about the target environment
|
|
128
|
+
* @param {LogFn} log
|
|
129
|
+
* @yields {[string, string | null]}
|
|
130
|
+
* @returns {Generator<[string, string | null]>}
|
|
131
|
+
*/
|
|
132
|
+
function* interpretImports(imports, conditions, log) {
|
|
133
|
+
if (Object(imports) !== imports || Array.isArray(imports)) {
|
|
134
|
+
throw Error(
|
|
135
|
+
`Cannot interpret package.json imports property, must be object, got ${imports}`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
for (const [key, value] of entries(imports)) {
|
|
139
|
+
// imports keys must start with '#'
|
|
140
|
+
if (!key.startsWith('#')) {
|
|
141
|
+
log(`Ignoring invalid imports key "${key}": must start with "#"`);
|
|
142
|
+
// eslint-disable-next-line no-continue
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (value === null) {
|
|
146
|
+
// Null targets are exclusions (Node.js semantics).
|
|
147
|
+
yield [key, null];
|
|
148
|
+
} else if (typeof value === 'string') {
|
|
149
|
+
yield [key, relativize(value)];
|
|
150
|
+
} else if (Object(value) === value && !isArray(value)) {
|
|
151
|
+
// Handle conditional imports
|
|
152
|
+
for (const [condition, target] of entries(value)) {
|
|
153
|
+
if (conditions.has(condition)) {
|
|
154
|
+
if (target === null) {
|
|
155
|
+
yield [key, null];
|
|
156
|
+
} else if (typeof target === 'string') {
|
|
157
|
+
yield [key, relativize(target)];
|
|
158
|
+
}
|
|
159
|
+
// Take only the first matching condition
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
log(`Ignoring unsupported imports value for "${key}": ${typeof value}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
118
169
|
/**
|
|
119
170
|
* Given an unpacked `package.json`, generate a series of `[name, target]`
|
|
120
171
|
* pairs to represent what this package exports. `name` is what the
|
|
@@ -130,7 +181,7 @@ function* interpretExports(name, exports, conditions, types) {
|
|
|
130
181
|
* for selecting relevant exports, e.g., "browser" or "node".
|
|
131
182
|
* @param {LanguageForExtension} types - an object to populate
|
|
132
183
|
* with any recognized module's type, if implied by a tag.
|
|
133
|
-
* @yields {[string, string]}
|
|
184
|
+
* @yields {[string, string | null]}
|
|
134
185
|
*/
|
|
135
186
|
export const inferExportsEntries = function* inferExportsEntries(
|
|
136
187
|
{ main, module, exports },
|
|
@@ -177,27 +228,115 @@ export const inferExports = (descriptor, conditions, types) =>
|
|
|
177
228
|
fromEntries(inferExportsEntries(descriptor, conditions, types));
|
|
178
229
|
|
|
179
230
|
/**
|
|
231
|
+
* Determines if a key or value contains a wildcard pattern.
|
|
232
|
+
*
|
|
233
|
+
* @param {string} key
|
|
234
|
+
* @param {string | null} value
|
|
235
|
+
* @returns {boolean}
|
|
236
|
+
*/
|
|
237
|
+
const hasWildcard = (key, value) =>
|
|
238
|
+
key.includes('*') || (value?.includes('*') ?? false);
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Returns the number of `*` characters in a string.
|
|
242
|
+
*
|
|
243
|
+
* @param {string} str
|
|
244
|
+
* @returns {number}
|
|
245
|
+
*/
|
|
246
|
+
const countWildcards = str => (str.match(/\*/g) || []).length;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Validates a wildcard pattern entry and logs warnings for invalid patterns.
|
|
250
|
+
* Returns true if the pattern is valid and should be used.
|
|
251
|
+
*
|
|
252
|
+
* @param {string} key
|
|
253
|
+
* @param {string} value
|
|
254
|
+
* @param {LogFn} log
|
|
255
|
+
* @returns {boolean}
|
|
256
|
+
*/
|
|
257
|
+
const validateWildcardPattern = (key, value, log) => {
|
|
258
|
+
const keyCount = countWildcards(key);
|
|
259
|
+
const valueCount = countWildcards(value);
|
|
260
|
+
if (keyCount > 1 || valueCount > 1) {
|
|
261
|
+
log(`Ignoring pattern with multiple wildcards "${key}": "${value}"`);
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
if (keyCount !== valueCount) {
|
|
265
|
+
log(
|
|
266
|
+
`Ignoring pattern with mismatched wildcard count "${key}" (${keyCount}) vs "${value}" (${valueCount})`,
|
|
267
|
+
);
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
return true;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Infers exports, internal aliases, and wildcard patterns from a package descriptor.
|
|
275
|
+
* Extracts wildcard patterns from the `exports` and `imports` fields.
|
|
180
276
|
*
|
|
181
277
|
* @param {PackageDescriptor} descriptor
|
|
182
278
|
* @param {Node['externalAliases']} externalAliases
|
|
183
279
|
* @param {Node['internalAliases']} internalAliases
|
|
280
|
+
* @param {PatternDescriptor[]} patterns - array to populate with wildcard patterns
|
|
184
281
|
* @param {Set<string>} conditions
|
|
185
282
|
* @param {Record<string, string>} types
|
|
283
|
+
* @param {LogFn} log
|
|
186
284
|
*/
|
|
187
|
-
export const
|
|
285
|
+
export const inferExportsAliasesAndPatterns = (
|
|
188
286
|
descriptor,
|
|
189
287
|
externalAliases,
|
|
190
288
|
internalAliases,
|
|
289
|
+
patterns,
|
|
191
290
|
conditions,
|
|
192
291
|
types,
|
|
292
|
+
log,
|
|
193
293
|
) => {
|
|
194
|
-
const { name, type, main, module, exports, browser } = descriptor;
|
|
294
|
+
const { name, type, main, module, exports, imports, browser } = descriptor;
|
|
295
|
+
|
|
296
|
+
// Process exports field - separate wildcards from concrete exports.
|
|
297
|
+
for (const [key, value] of inferExportsEntries(
|
|
298
|
+
descriptor,
|
|
299
|
+
conditions,
|
|
300
|
+
types,
|
|
301
|
+
)) {
|
|
302
|
+
if (value === null) {
|
|
303
|
+
// Null targets are exclusions.
|
|
304
|
+
// Only wildcard null targets need to be stored as patterns;
|
|
305
|
+
// concrete null targets are excluded by omission from aliases.
|
|
306
|
+
if (key.includes('*')) {
|
|
307
|
+
patterns.push({ from: key, to: null });
|
|
308
|
+
}
|
|
309
|
+
// eslint-disable-next-line no-continue
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (hasWildcard(key, value)) {
|
|
313
|
+
if (validateWildcardPattern(key, value, log)) {
|
|
314
|
+
patterns.push({ from: key, to: value });
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
externalAliases[key] = value;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
195
320
|
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
321
|
+
// Process imports field (package self-referencing).
|
|
322
|
+
if (imports !== undefined) {
|
|
323
|
+
for (const [key, value] of interpretImports(imports, conditions, log)) {
|
|
324
|
+
if (value === null) {
|
|
325
|
+
if (key.includes('*')) {
|
|
326
|
+
patterns.push({ from: key, to: null });
|
|
327
|
+
}
|
|
328
|
+
// eslint-disable-next-line no-continue
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (hasWildcard(key, value)) {
|
|
332
|
+
if (validateWildcardPattern(key, value, log)) {
|
|
333
|
+
patterns.push({ from: key, to: value });
|
|
334
|
+
}
|
|
335
|
+
} else {
|
|
336
|
+
internalAliases[key] = value;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
201
340
|
|
|
202
341
|
// expose default module as package root
|
|
203
342
|
// may be overwritten by browser field
|
package/src/link.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["link.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["link.js"],"names":[],"mappings":"AAyTO,sEAJI,+BAA+B,GAAC,4BAA4B,WAC5D,WAAW,GACT,UAAU,CAgLtB;AAOM,yCAJI,+BAA+B,WAC/B,WAAW,eAIqB;qDAhdjC,YAAY;kDAAZ,YAAY;iCAAZ,YAAY;gCAAZ,YAAY"}
|
package/src/link.js
CHANGED
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
* FileCompartmentMapDescriptor,
|
|
30
30
|
* FileCompartmentDescriptor,
|
|
31
31
|
* FileModuleConfiguration,
|
|
32
|
-
* MakeModuleMapHookOptions,
|
|
33
32
|
* } from './types.js'
|
|
33
|
+
* @import {SubpathReplacer} from './types/pattern-replacement.js'
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
import { makeMapParsers } from './map-parser.js';
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
isCompartmentModuleConfiguration,
|
|
46
46
|
isExitModuleConfiguration,
|
|
47
47
|
} from './guards.js';
|
|
48
|
+
import { makeMultiSubpathReplacer } from './pattern-replacement.js';
|
|
48
49
|
|
|
49
50
|
const { assign, create, entries, freeze } = Object;
|
|
50
51
|
const { hasOwnProperty } = Object.prototype;
|
|
@@ -101,7 +102,7 @@ const trimModuleSpecifierPrefix = (moduleSpecifier, prefix) => {
|
|
|
101
102
|
*
|
|
102
103
|
* @param {FileCompartmentDescriptor|PackageCompartmentDescriptor} compartmentDescriptor
|
|
103
104
|
* @param {Record<string, Compartment>} compartments
|
|
104
|
-
* @param {
|
|
105
|
+
* @param {FileUrlString} compartmentName
|
|
105
106
|
* @param {Record<string, FileModuleConfiguration|CompartmentModuleConfiguration>} moduleDescriptors
|
|
106
107
|
* @param {Record<string, ScopeDescriptor<FileUrlString>>} scopeDescriptors
|
|
107
108
|
* @returns {ModuleMapHook | undefined}
|
|
@@ -113,6 +114,14 @@ const makeModuleMapHook = (
|
|
|
113
114
|
moduleDescriptors,
|
|
114
115
|
scopeDescriptors,
|
|
115
116
|
) => {
|
|
117
|
+
// Build pattern matcher once per compartment if patterns exist.
|
|
118
|
+
const { patterns } = /** @type {Partial<PackageCompartmentDescriptor>} */ (
|
|
119
|
+
compartmentDescriptor
|
|
120
|
+
);
|
|
121
|
+
/** @type {SubpathReplacer | null} */
|
|
122
|
+
const matchPattern =
|
|
123
|
+
patterns && patterns.length > 0 ? makeMultiSubpathReplacer(patterns) : null;
|
|
124
|
+
|
|
116
125
|
/**
|
|
117
126
|
* @type {ModuleMapHook}
|
|
118
127
|
*/
|
|
@@ -162,6 +171,55 @@ const makeModuleMapHook = (
|
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
173
|
|
|
174
|
+
// Check patterns for wildcard matches (before scopes).
|
|
175
|
+
// Patterns may resolve within the same compartment (internal patterns)
|
|
176
|
+
// or to a foreign compartment (dependency export patterns).
|
|
177
|
+
if (matchPattern) {
|
|
178
|
+
const match = matchPattern(moduleSpecifier);
|
|
179
|
+
if (match !== null) {
|
|
180
|
+
const { result: resolvedPath, compartment: foreignCompartmentName } =
|
|
181
|
+
match;
|
|
182
|
+
|
|
183
|
+
// Null result means the specifier is explicitly excluded.
|
|
184
|
+
if (resolvedPath === null) {
|
|
185
|
+
throw Error(
|
|
186
|
+
`Cannot find module ${q(moduleSpecifier)} — excluded by null target pattern in ${q(compartmentName)}`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
const targetCompartmentName =
|
|
190
|
+
/** @type {FileUrlString} */
|
|
191
|
+
(foreignCompartmentName || compartmentName);
|
|
192
|
+
|
|
193
|
+
// Write back to moduleDescriptors for caching, archival, and
|
|
194
|
+
// policy enforcement. The write-back must precede the policy
|
|
195
|
+
// check because enforcePolicyByModule verifies the specifier
|
|
196
|
+
// exists in compartmentDescriptor.modules (the same object).
|
|
197
|
+
moduleDescriptors[moduleSpecifier] = {
|
|
198
|
+
retained: true,
|
|
199
|
+
compartment: targetCompartmentName,
|
|
200
|
+
module: resolvedPath,
|
|
201
|
+
__createdBy: 'link-pattern',
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Policy enforcement for pattern-matched modules
|
|
205
|
+
enforcePolicyByModule(moduleSpecifier, compartmentDescriptor, {
|
|
206
|
+
exit: false,
|
|
207
|
+
errorHint: `Pattern matched in compartment ${q(compartmentName)}: module specifier ${q(moduleSpecifier)} mapped to ${q(resolvedPath)}`,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const targetCompartment = compartments[targetCompartmentName];
|
|
211
|
+
if (targetCompartment === undefined) {
|
|
212
|
+
throw Error(
|
|
213
|
+
`Cannot import module specifier ${q(moduleSpecifier)} from missing compartment ${q(targetCompartmentName)}`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
compartment: targetCompartment,
|
|
218
|
+
namespace: resolvedPath,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
165
223
|
// Search for a scope that shares a prefix with the requested module
|
|
166
224
|
// specifier.
|
|
167
225
|
// This might be better with a trie, but only a benchmark on real-world
|
|
@@ -299,7 +357,7 @@ export const link = (
|
|
|
299
357
|
});
|
|
300
358
|
|
|
301
359
|
const compartmentDescriptorEntries =
|
|
302
|
-
/** @type {[
|
|
360
|
+
/** @type {[FileUrlString, PackageCompartmentDescriptor|FileCompartmentDescriptor][]} */ (
|
|
303
361
|
entries(compartmentDescriptors)
|
|
304
362
|
);
|
|
305
363
|
for (const [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-modules.d.ts","sourceRoot":"","sources":["node-modules.js"],"names":[],"mappings":"AA4LO,mCAHI,MAAM,GACJ,MAAM,CAYlB;
|
|
1
|
+
{"version":3,"file":"node-modules.d.ts","sourceRoot":"","sources":["node-modules.js"],"names":[],"mappings":"AA4LO,mCAHI,MAAM,GACJ,MAAM,CAYlB;AA+kCM,0DARI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,wBACnE,aAAa,oBACb,GAAG,CAAC,MAAM,CAAC,qBACX,iBAAiB,wBACjB,MAAM,YACN,mCAAmC,GACjC,OAAO,CAAC,+BAA+B,CAAC,CA0HpD;AAaM,2CALI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,kBACnE,MAAM,2HACN,qBAAqB,GACnB,OAAO,CAAC,+BAA+B,CAAC,CA6CpD;AAhLM,yDARI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,wBACnE,aAAa,oBACb,GAAG,CAAC,MAAM,CAAC,qBACX,iBAAiB,wBACjB,MAAM,YACN,mCAAmC,GACjC,OAAO,CAAC,+BAA+B,CAAC,CA0HpD;4BAt1CS,YAAY;mCAAZ,YAAY;gCAAZ,YAAY;qCAAZ,YAAY;uCAAZ,YAAY;yDAAZ,YAAY;qDAAZ,YAAY;2CAAZ,YAAY"}
|
package/src/node-modules.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
/* eslint no-shadow: 0 */
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { inferExportsAliasesAndPatterns } from './infer-exports.js';
|
|
18
18
|
import { parseLocatedJson } from './json.js';
|
|
19
19
|
import { join } from './node-module-specifier.js';
|
|
20
20
|
import {
|
|
@@ -386,37 +386,6 @@ const inferParsers = (descriptor, location, languageOptions) => {
|
|
|
386
386
|
return { ...commonjsLanguageForExtension, ...packageLanguageForExtension };
|
|
387
387
|
};
|
|
388
388
|
|
|
389
|
-
/**
|
|
390
|
-
* This returns the "weight" of a package name, which is used when determining
|
|
391
|
-
* the shortest path.
|
|
392
|
-
*
|
|
393
|
-
* It is an analogue of the `pathCompare` function.
|
|
394
|
-
*
|
|
395
|
-
* The weight is calculated as follows:
|
|
396
|
-
*
|
|
397
|
-
* 1. The {@link String.length length} of the package name contributes a fixed
|
|
398
|
-
* value of `0x10000` per character. This is because the `pathCompare`
|
|
399
|
-
* algorithm first compares strings by length and only evaluates code unit
|
|
400
|
-
* values if the lengths of two strings are equal. `0x10000` is one (1)
|
|
401
|
-
* greater than the maximum value that {@link String.charCodeAt charCodeAt}
|
|
402
|
-
* can return (`0xFFFF`), which guarantees longer strings will have higher
|
|
403
|
-
* weights.
|
|
404
|
-
* 2. Each character in the package name contributes its UTF-16 code unit value
|
|
405
|
-
* (`0x0` thru `0xFFFF`) to the total. This is the same operation used when
|
|
406
|
-
* comparing two strings using comparison operators.
|
|
407
|
-
* 3. The total weight is the sum of 1. and 2.
|
|
408
|
-
*
|
|
409
|
-
* @param {string} packageName - Name of package to calculate weight for.
|
|
410
|
-
* @returns {number} Numeric weight
|
|
411
|
-
*/
|
|
412
|
-
const calculatePackageWeight = packageName => {
|
|
413
|
-
let totalCodeValue = packageName.length * 65536; // each character contributes 65536
|
|
414
|
-
for (let i = 0; i < packageName.length; i += 1) {
|
|
415
|
-
totalCodeValue += packageName.charCodeAt(i);
|
|
416
|
-
}
|
|
417
|
-
return totalCodeValue;
|
|
418
|
-
};
|
|
419
|
-
|
|
420
389
|
/**
|
|
421
390
|
* `graphPackage` and {@link gatherDependency} are mutually recursive functions that
|
|
422
391
|
* gather the metadata for a package and its transitive dependencies.
|
|
@@ -577,13 +546,17 @@ const graphPackage = async (
|
|
|
577
546
|
const externalAliases = {};
|
|
578
547
|
/** @type {Node['internalAliases']} */
|
|
579
548
|
const internalAliases = {};
|
|
549
|
+
/** @type {Node['patterns']} */
|
|
550
|
+
const patterns = [];
|
|
580
551
|
|
|
581
|
-
|
|
552
|
+
inferExportsAliasesAndPatterns(
|
|
582
553
|
packageDescriptor,
|
|
583
554
|
externalAliases,
|
|
584
555
|
internalAliases,
|
|
556
|
+
patterns,
|
|
585
557
|
conditions,
|
|
586
558
|
types,
|
|
559
|
+
log,
|
|
587
560
|
);
|
|
588
561
|
|
|
589
562
|
const parsers = inferParsers(
|
|
@@ -602,6 +575,7 @@ const graphPackage = async (
|
|
|
602
575
|
explicitExports: exportsDescriptor !== undefined,
|
|
603
576
|
externalAliases,
|
|
604
577
|
internalAliases,
|
|
578
|
+
patterns,
|
|
605
579
|
dependencyLocations,
|
|
606
580
|
types,
|
|
607
581
|
parsers,
|
|
@@ -703,11 +677,7 @@ const gatherDependency = async (
|
|
|
703
677
|
|
|
704
678
|
dependencyLocations[name] = dependency.packageLocation;
|
|
705
679
|
|
|
706
|
-
logicalPathGraph.addEdge(
|
|
707
|
-
packageLocation,
|
|
708
|
-
dependency.packageLocation,
|
|
709
|
-
calculatePackageWeight(name),
|
|
710
|
-
);
|
|
680
|
+
logicalPathGraph.addEdge(packageLocation, dependency.packageLocation);
|
|
711
681
|
|
|
712
682
|
await graphPackage(
|
|
713
683
|
name,
|
|
@@ -955,6 +925,7 @@ const translateGraph = (
|
|
|
955
925
|
label,
|
|
956
926
|
sourceDirname,
|
|
957
927
|
internalAliases,
|
|
928
|
+
patterns,
|
|
958
929
|
parsers,
|
|
959
930
|
types,
|
|
960
931
|
packageDescriptor,
|
|
@@ -983,7 +954,11 @@ const translateGraph = (
|
|
|
983
954
|
* @param {PackageCompartmentDescriptorName} packageLocation
|
|
984
955
|
*/
|
|
985
956
|
const digestExternalAliases = (dependencyName, packageLocation) => {
|
|
986
|
-
const {
|
|
957
|
+
const {
|
|
958
|
+
externalAliases,
|
|
959
|
+
explicitExports,
|
|
960
|
+
patterns: dependencyPatterns,
|
|
961
|
+
} = graph[packageLocation];
|
|
987
962
|
for (const exportPath of keys(externalAliases).sort()) {
|
|
988
963
|
const targetPath = externalAliases[exportPath];
|
|
989
964
|
// dependency name may be different from package's name,
|
|
@@ -996,6 +971,24 @@ const translateGraph = (
|
|
|
996
971
|
module: targetPath,
|
|
997
972
|
};
|
|
998
973
|
}
|
|
974
|
+
// Propagate export patterns from dependencies.
|
|
975
|
+
// Each dependency pattern like "./features/*.js" -> "./src/features/*.js"
|
|
976
|
+
// becomes "dep/features/*.js" -> "./src/features/*.js" on the dependee,
|
|
977
|
+
// resolving within the dependency's compartment.
|
|
978
|
+
if (dependencyPatterns) {
|
|
979
|
+
for (const { from, to } of dependencyPatterns) {
|
|
980
|
+
// Only propagate export patterns (starting with "./"), not
|
|
981
|
+
// import patterns (starting with "#") which are internal.
|
|
982
|
+
if (from.startsWith('./') || from === '.') {
|
|
983
|
+
const externalFrom = join(dependencyName, from);
|
|
984
|
+
patterns.push({
|
|
985
|
+
from: externalFrom,
|
|
986
|
+
to,
|
|
987
|
+
compartment: packageLocation,
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
999
992
|
// if the exports field is not present, then all modules must be accessible
|
|
1000
993
|
if (!explicitExports) {
|
|
1001
994
|
scopes[dependencyName] = {
|
|
@@ -1032,6 +1025,7 @@ const translateGraph = (
|
|
|
1032
1025
|
sourceDirname,
|
|
1033
1026
|
modules: moduleDescriptors,
|
|
1034
1027
|
scopes,
|
|
1028
|
+
...(patterns.length > 0 ? { patterns } : {}),
|
|
1035
1029
|
parsers,
|
|
1036
1030
|
types,
|
|
1037
1031
|
policy: /** @type {SomePackagePolicy} */ (packagePolicy),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function assertMatchingWildcardCount(pattern: string, replacement: string): void;
|
|
2
|
+
export function makeMultiSubpathReplacer(mapping: PatternDescriptor[] | SubpathMapping): SubpathReplacer;
|
|
3
|
+
import type { PatternDescriptor } from './types/pattern-replacement.js';
|
|
4
|
+
import type { SubpathMapping } from './types/pattern-replacement.js';
|
|
5
|
+
import type { SubpathReplacer } from './types/pattern-replacement.js';
|
|
6
|
+
//# sourceMappingURL=pattern-replacement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-replacement.d.ts","sourceRoot":"","sources":["pattern-replacement.js"],"names":[],"mappings":"AA6BO,qDAJI,MAAM,eACN,MAAM,QAWhB;AAwFM,kDAHI,iBAAiB,EAAE,GAAG,cAAc,GAClC,eAAe,CA0E3B;uCAtLS,gCAAgC;oCAAhC,gCAAgC;qCAAhC,gCAAgC"}
|