@endo/compartment-mapper 1.6.3 → 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 +24 -14
- package/src/archive-lite.d.ts +7 -7
- package/src/archive-lite.d.ts.map +1 -1
- package/src/archive-lite.js +81 -30
- package/src/archive.d.ts.map +1 -1
- package/src/archive.js +7 -0
- package/src/bundle-lite.d.ts +3 -3
- package/src/bundle-lite.d.ts.map +1 -1
- package/src/bundle-lite.js +19 -24
- package/src/bundle.d.ts +3 -3
- package/src/bundle.d.ts.map +1 -1
- package/src/bundle.js +19 -24
- package/src/capture-lite.d.ts +2 -2
- package/src/capture-lite.d.ts.map +1 -1
- package/src/capture-lite.js +243 -25
- package/src/compartment-map.d.ts +9 -2
- package/src/compartment-map.d.ts.map +1 -1
- package/src/compartment-map.js +738 -254
- package/src/digest.d.ts +22 -2
- package/src/digest.d.ts.map +1 -1
- package/src/digest.js +180 -57
- package/src/generic-graph.d.ts +7 -25
- package/src/generic-graph.d.ts.map +1 -1
- package/src/generic-graph.js +83 -108
- package/src/guards.d.ts +18 -0
- package/src/guards.d.ts.map +1 -0
- package/src/guards.js +109 -0
- package/src/hooks.md +124 -0
- package/src/import-archive-lite.d.ts.map +1 -1
- package/src/import-archive-lite.js +15 -11
- package/src/import-archive.d.ts +5 -19
- package/src/import-archive.d.ts.map +1 -1
- package/src/import-archive.js +7 -27
- package/src/import-hook.d.ts +4 -3
- package/src/import-hook.d.ts.map +1 -1
- package/src/import-hook.js +140 -70
- package/src/import-lite.d.ts +6 -6
- package/src/import-lite.d.ts.map +1 -1
- package/src/import-lite.js +8 -5
- package/src/import.d.ts +3 -3
- package/src/import.d.ts.map +1 -1
- package/src/import.js +16 -6
- package/src/infer-exports.d.ts +4 -2
- package/src/infer-exports.d.ts.map +1 -1
- package/src/infer-exports.js +172 -23
- package/src/link.d.ts +4 -3
- package/src/link.d.ts.map +1 -1
- package/src/link.js +122 -52
- package/src/node-modules.d.ts +4 -3
- package/src/node-modules.d.ts.map +1 -1
- package/src/node-modules.js +513 -151
- package/src/parse-cjs-shared-export-wrapper.d.ts.map +1 -1
- package/src/parse-cjs-shared-export-wrapper.js +3 -1
- 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/policy-format.d.ts +22 -5
- package/src/policy-format.d.ts.map +1 -1
- package/src/policy-format.js +342 -108
- package/src/policy.d.ts +13 -28
- package/src/policy.d.ts.map +1 -1
- package/src/policy.js +161 -106
- package/src/types/canonical-name.d.ts +97 -0
- package/src/types/canonical-name.d.ts.map +1 -0
- package/src/types/canonical-name.ts +151 -0
- package/src/types/compartment-map-schema.d.ts +121 -35
- package/src/types/compartment-map-schema.d.ts.map +1 -1
- package/src/types/compartment-map-schema.ts +211 -37
- package/src/types/external.d.ts +240 -76
- package/src/types/external.d.ts.map +1 -1
- package/src/types/external.ts +305 -74
- 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 +31 -50
- package/src/types/internal.d.ts.map +1 -1
- package/src/types/internal.ts +60 -58
- package/src/types/node-modules.d.ts +112 -14
- package/src/types/node-modules.d.ts.map +1 -1
- package/src/types/node-modules.ts +152 -13
- 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/policy-schema.d.ts +26 -11
- package/src/types/policy-schema.d.ts.map +1 -1
- package/src/types/policy-schema.ts +29 -16
- package/src/types/policy.d.ts +6 -2
- package/src/types/policy.d.ts.map +1 -1
- package/src/types/policy.ts +7 -2
- 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/types/typescript.d.ts +28 -0
- package/src/types/typescript.d.ts.map +1 -1
- package/src/types/typescript.ts +37 -1
package/src/generic-graph.js
CHANGED
|
@@ -2,38 +2,56 @@
|
|
|
2
2
|
* Provides {@link GenericGraph} and {@link makeShortestPath}.
|
|
3
3
|
*
|
|
4
4
|
* Portions adapted from
|
|
5
|
-
*
|
|
5
|
+
* [graph data structure](https://github.com/datavis-tech/graph-data-structure),
|
|
6
6
|
* which is Copyright (c) 2016 Curran Kelleher and licensed under the MIT
|
|
7
7
|
* License.
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { pathCompare } from '@endo/path-compare';
|
|
13
|
+
|
|
12
14
|
/**
|
|
13
|
-
* @import {TraversalContext} from './types/generic-graph.js';
|
|
15
|
+
* @import {GenericGraphNode, TraversalContext} from './types/generic-graph.js';
|
|
14
16
|
*/
|
|
15
17
|
|
|
16
|
-
const {
|
|
18
|
+
const { quote: q } = assert;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Returns `true` if the cost of path `a` is less than the cost of path `b`.
|
|
22
|
+
*
|
|
23
|
+
* @template {GenericGraphNode} [T=string]
|
|
24
|
+
* @param {T[]} [pathA]
|
|
25
|
+
* @param {T[]} [pathB]
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
const isLowerCost = (pathA, pathB) =>
|
|
29
|
+
pathCompare(pathA?.map(String), pathB?.map(String)) < 0;
|
|
17
30
|
|
|
18
31
|
/**
|
|
19
32
|
* Remove the node with the minimum weight from the priority queue.
|
|
20
33
|
*
|
|
21
34
|
* Performs linear search.
|
|
22
|
-
*
|
|
35
|
+
*
|
|
36
|
+
* @template {GenericGraphNode} [T=string]
|
|
23
37
|
* @param {TraversalContext<T>} tracks
|
|
24
38
|
* @returns {T|undefined}
|
|
25
39
|
*/
|
|
26
|
-
const extractMin = ({
|
|
27
|
-
|
|
40
|
+
const extractMin = ({ paths, queue }) => {
|
|
41
|
+
/** @type {T[]|undefined} */
|
|
42
|
+
let minPath;
|
|
28
43
|
|
|
29
44
|
/** @type {T|undefined} */
|
|
30
45
|
let minNode;
|
|
31
46
|
|
|
32
47
|
queue.forEach(node => {
|
|
33
|
-
const
|
|
48
|
+
const path = paths.get(node);
|
|
49
|
+
if (!path) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
34
52
|
|
|
35
|
-
if (
|
|
36
|
-
|
|
53
|
+
if (!minPath || isLowerCost(path, minPath)) {
|
|
54
|
+
minPath = path;
|
|
37
55
|
minNode = node;
|
|
38
56
|
}
|
|
39
57
|
});
|
|
@@ -48,32 +66,23 @@ const extractMin = ({ distances, queue }) => {
|
|
|
48
66
|
};
|
|
49
67
|
|
|
50
68
|
/**
|
|
51
|
-
* Update context
|
|
52
|
-
*
|
|
69
|
+
* Update context to include the current lowest-cost path to a target node
|
|
70
|
+
* reachable by a single edge from a source node.
|
|
53
71
|
*
|
|
54
|
-
* @template [T=string]
|
|
55
|
-
* @param {
|
|
56
|
-
* @param {TraversalContext<NoInfer<T>>} context
|
|
72
|
+
* @template {GenericGraphNode} [T=string]
|
|
73
|
+
* @param {TraversalContext<T>} context
|
|
57
74
|
* @param {NoInfer<T>} source
|
|
58
75
|
* @param {NoInfer<T>} target
|
|
59
76
|
*/
|
|
60
|
-
const relax = (
|
|
61
|
-
const
|
|
77
|
+
const relax = ({ paths, predecessors }, source, target) => {
|
|
78
|
+
const pathSource = paths.get(source);
|
|
79
|
+
assert(pathSource, `Missing path to source ${q(source)}`);
|
|
62
80
|
|
|
63
|
-
const
|
|
64
|
-
const
|
|
81
|
+
const pathTarget = paths.get(target);
|
|
82
|
+
const newPath = [...pathSource, target];
|
|
65
83
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
`Missing distance for source ${q(source)}`,
|
|
69
|
-
);
|
|
70
|
-
assert(
|
|
71
|
-
distanceTarget !== undefined,
|
|
72
|
-
`Missing distance for target ${q(target)} target`,
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
if (distanceTarget > distanceSource + number) {
|
|
76
|
-
distances.set(target, distanceSource + number);
|
|
84
|
+
if (!pathTarget || isLowerCost(newPath, pathTarget)) {
|
|
85
|
+
paths.set(target, newPath);
|
|
77
86
|
predecessors.set(target, source);
|
|
78
87
|
}
|
|
79
88
|
};
|
|
@@ -82,7 +91,7 @@ const relax = (graph, { distances, predecessors }, source, target) => {
|
|
|
82
91
|
* Assembles the shortest path by traversing the
|
|
83
92
|
* predecessor subgraph from destination to source.
|
|
84
93
|
*
|
|
85
|
-
* @template [T=string]
|
|
94
|
+
* @template {GenericGraphNode} [T=string]
|
|
86
95
|
* @param {TraversalContext<NoInfer<T>>} context Traversal context object
|
|
87
96
|
* @param {NoInfer<T>} source Source node
|
|
88
97
|
* @param {NoInfer<T>} target Destination node
|
|
@@ -94,6 +103,11 @@ const getPath = ({ predecessors }, source, target) => {
|
|
|
94
103
|
/** @type {T[]} */
|
|
95
104
|
const nodeList = [];
|
|
96
105
|
|
|
106
|
+
assert(
|
|
107
|
+
source !== target,
|
|
108
|
+
`Source ${q(source)} cannot be the same as target ${q(target)}`,
|
|
109
|
+
);
|
|
110
|
+
|
|
97
111
|
let node = target;
|
|
98
112
|
|
|
99
113
|
while (predecessors.has(node)) {
|
|
@@ -102,24 +116,27 @@ const getPath = ({ predecessors }, source, target) => {
|
|
|
102
116
|
node = currentNode;
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
assert.equal(
|
|
119
|
+
assert.equal(
|
|
120
|
+
node,
|
|
121
|
+
source,
|
|
122
|
+
`No path found from ${q(String(source))} to ${q(String(target))}`,
|
|
123
|
+
);
|
|
106
124
|
|
|
107
125
|
nodeList.push(node);
|
|
108
126
|
|
|
109
127
|
assert(
|
|
110
128
|
nodeList.length >= 2,
|
|
111
|
-
`The path from ${source} to ${target} should have
|
|
129
|
+
`The path from ${source} to ${target} should have at least two nodes`,
|
|
112
130
|
);
|
|
113
131
|
|
|
114
132
|
return /** @type {[T, T, ...T[]]} */ (nodeList.reverse());
|
|
115
133
|
};
|
|
116
134
|
|
|
117
135
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* A generic graph implementation with edge weights.
|
|
136
|
+
* A generic graph implementation.
|
|
121
137
|
*
|
|
122
|
-
*
|
|
138
|
+
* @template {GenericGraphNode} [T=string] The type of nodes in the graph. If
|
|
139
|
+
* `T` is not a string, relative paths will be compared by coercion to strings.
|
|
123
140
|
*/
|
|
124
141
|
export class GenericGraph {
|
|
125
142
|
/**
|
|
@@ -132,16 +149,10 @@ export class GenericGraph {
|
|
|
132
149
|
*/
|
|
133
150
|
#edges;
|
|
134
151
|
|
|
135
|
-
/**
|
|
136
|
-
* @type {Map<T, Map<T, number>>}
|
|
137
|
-
*/
|
|
138
|
-
#edgeWeights;
|
|
139
|
-
|
|
140
152
|
/**
|
|
141
153
|
* Initializes internal data structures.
|
|
142
154
|
*/
|
|
143
155
|
constructor() {
|
|
144
|
-
this.#edgeWeights = new Map();
|
|
145
156
|
this.#edges = new Map();
|
|
146
157
|
this.#nodes = new Set();
|
|
147
158
|
}
|
|
@@ -194,42 +205,6 @@ export class GenericGraph {
|
|
|
194
205
|
return this.#edges.get(node);
|
|
195
206
|
}
|
|
196
207
|
|
|
197
|
-
/**
|
|
198
|
-
* Sets the weight of the given edge between `source` and `target`.
|
|
199
|
-
*
|
|
200
|
-
* @param {T} source Source node
|
|
201
|
-
* @param {T} target Target node
|
|
202
|
-
* @param {number} weight New edge weight
|
|
203
|
-
* @returns {this}
|
|
204
|
-
*/
|
|
205
|
-
setEdgeWeight(source, target, weight) {
|
|
206
|
-
if (!this.#edgeWeights.has(source)) {
|
|
207
|
-
this.#edgeWeights.set(source, new Map());
|
|
208
|
-
}
|
|
209
|
-
const weights = /** @type {Map<T, number>} */ (
|
|
210
|
-
this.#edgeWeights.get(source)
|
|
211
|
-
);
|
|
212
|
-
weights.set(target, weight);
|
|
213
|
-
return this;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Gets the weight of the given edge between `source` and `target`.
|
|
218
|
-
*
|
|
219
|
-
* @param {T} source Source node
|
|
220
|
-
* @param {T} target Target node
|
|
221
|
-
* @returns {number} Edge weight from source to target
|
|
222
|
-
*/
|
|
223
|
-
getEdgeWeight(source, target) {
|
|
224
|
-
const weight = this.#edgeWeights.get(source)?.get(target);
|
|
225
|
-
if (weight === undefined) {
|
|
226
|
-
throw new ReferenceError(
|
|
227
|
-
`Edge weight from ${q(source)} to ${q(target)} is not set`,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
return weight;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
208
|
/**
|
|
234
209
|
* Adds an edge from the `source` node to `target` node.
|
|
235
210
|
*
|
|
@@ -240,17 +215,15 @@ export class GenericGraph {
|
|
|
240
215
|
*
|
|
241
216
|
* @param {T} source Source node
|
|
242
217
|
* @param {T} target Target node
|
|
243
|
-
* @param {number} weight Edge weight from source to target
|
|
244
218
|
* @returns {this} This graph instance
|
|
245
219
|
*/
|
|
246
|
-
addEdge(source, target
|
|
220
|
+
addEdge(source, target) {
|
|
247
221
|
this.addNode(source);
|
|
248
222
|
this.addNode(target);
|
|
249
223
|
const adjacentNodes = this.adjacent(source);
|
|
250
224
|
assert(adjacentNodes, `Source ${q(source)} should have adjacent nodes`);
|
|
251
225
|
|
|
252
226
|
adjacentNodes.add(target);
|
|
253
|
-
this.setEdgeWeight(source, target, weight);
|
|
254
227
|
return this;
|
|
255
228
|
}
|
|
256
229
|
|
|
@@ -279,42 +252,32 @@ export class GenericGraph {
|
|
|
279
252
|
}
|
|
280
253
|
|
|
281
254
|
/**
|
|
282
|
-
* Dijkstra's
|
|
283
|
-
*
|
|
255
|
+
* Dijkstra's single-source shortest path algorithm.
|
|
256
|
+
*
|
|
257
|
+
* Computes shortest paths from `source` to **all** reachable nodes.
|
|
258
|
+
*
|
|
259
|
+
* @template {GenericGraphNode} [T=string] The type of nodes in the graph
|
|
284
260
|
* @param {GenericGraph<T>} graph
|
|
285
261
|
* @param {T} source
|
|
286
|
-
* @param {T} target
|
|
287
262
|
* @returns {TraversalContext<T>}
|
|
288
263
|
*/
|
|
289
|
-
const dijkstra = (graph, source
|
|
264
|
+
const dijkstra = (graph, source) => {
|
|
290
265
|
const { nodes } = graph;
|
|
291
266
|
/** @type {TraversalContext<T>} */
|
|
292
267
|
const context = {
|
|
293
|
-
|
|
268
|
+
paths: new Map(),
|
|
294
269
|
predecessors: new Map(),
|
|
295
|
-
queue:
|
|
270
|
+
queue: nodes,
|
|
296
271
|
};
|
|
297
|
-
const { queue,
|
|
298
|
-
|
|
299
|
-
for (const node of nodes) {
|
|
300
|
-
distances.set(node, Infinity);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
assert(
|
|
304
|
-
distances.get(source) === Infinity,
|
|
305
|
-
`Source ${q(source)} is not in the graph`,
|
|
306
|
-
);
|
|
307
|
-
assert(
|
|
308
|
-
distances.get(target) === Infinity,
|
|
309
|
-
`Target ${q(target)} is not in the graph`,
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
distances.set(source, 0);
|
|
272
|
+
const { queue, paths } = context;
|
|
313
273
|
|
|
314
274
|
for (const node of nodes) {
|
|
315
275
|
queue.add(node);
|
|
316
276
|
}
|
|
317
277
|
|
|
278
|
+
assert(queue.has(source), `Source ${q(source)} is not in the graph`);
|
|
279
|
+
paths.set(source, []);
|
|
280
|
+
|
|
318
281
|
while (queue.size !== 0) {
|
|
319
282
|
const node = extractMin(context);
|
|
320
283
|
if (node === undefined) {
|
|
@@ -323,7 +286,7 @@ const dijkstra = (graph, source, target) => {
|
|
|
323
286
|
const adjacent = graph.adjacent(node);
|
|
324
287
|
if (adjacent) {
|
|
325
288
|
for (const edge of adjacent) {
|
|
326
|
-
relax(
|
|
289
|
+
relax(context, node, edge);
|
|
327
290
|
}
|
|
328
291
|
}
|
|
329
292
|
}
|
|
@@ -331,20 +294,32 @@ const dijkstra = (graph, source, target) => {
|
|
|
331
294
|
};
|
|
332
295
|
|
|
333
296
|
/**
|
|
334
|
-
* Returns a function which
|
|
335
|
-
*
|
|
297
|
+
* Returns a function which computes the shortest path from `source` to
|
|
298
|
+
* `target` in the given `graph`.
|
|
336
299
|
*
|
|
337
|
-
*
|
|
300
|
+
* Dijkstra's algorithm is a _single-source_ shortest path algorithm: one run
|
|
301
|
+
* produces shortest paths to every reachable node. The returned function
|
|
302
|
+
* caches the traversal context by source, so the first call for a given source
|
|
303
|
+
* pays O(V²) and every subsequent call with the same source is O(path length).
|
|
304
|
+
*
|
|
305
|
+
* @template {GenericGraphNode} [T=string]
|
|
338
306
|
* @param {GenericGraph<T>} graph Graph to use
|
|
339
307
|
*/
|
|
340
308
|
export const makeShortestPath = graph => {
|
|
309
|
+
/** @type {Map<T, TraversalContext<T>>} */
|
|
310
|
+
const contextCache = new Map();
|
|
311
|
+
|
|
341
312
|
/**
|
|
342
313
|
* @param {NoInfer<T>} source Source node
|
|
343
314
|
* @param {NoInfer<T>} target Target node
|
|
344
315
|
* @returns {[T, T, ...T[]]} Nodes from `source` to `target` inclusive (minimum of two nodes)
|
|
345
316
|
*/
|
|
346
317
|
const shortestPath = (source, target) => {
|
|
347
|
-
|
|
318
|
+
let context = contextCache.get(source);
|
|
319
|
+
if (!context) {
|
|
320
|
+
context = dijkstra(graph, source);
|
|
321
|
+
contextCache.set(source, context);
|
|
322
|
+
}
|
|
348
323
|
return getPath(context, source, target);
|
|
349
324
|
};
|
|
350
325
|
return shortestPath;
|
package/src/guards.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function isErrorModuleConfiguration(value: ModuleConfiguration): value is ErrorModuleConfiguration;
|
|
2
|
+
export function isFileModuleConfiguration(value: ModuleConfiguration): value is FileModuleConfiguration;
|
|
3
|
+
export function isExitModuleConfiguration(value: ModuleConfiguration): value is ExitModuleConfiguration;
|
|
4
|
+
export function isCompartmentModuleConfiguration(value: ModuleConfiguration): value is CompartmentModuleConfiguration;
|
|
5
|
+
export function isErrorModuleSource(value: ModuleSource): value is ErrorModuleSource;
|
|
6
|
+
export function isExitModuleSource(value: ModuleSource): value is ExitModuleSource;
|
|
7
|
+
export function isLocalModuleSource(value: ModuleSource): value is LocalModuleSource;
|
|
8
|
+
export function isNonNullableObject(value: unknown): value is object;
|
|
9
|
+
import type { ModuleConfiguration } from './types.js';
|
|
10
|
+
import type { ErrorModuleConfiguration } from './types.js';
|
|
11
|
+
import type { FileModuleConfiguration } from './types.js';
|
|
12
|
+
import type { ExitModuleConfiguration } from './types.js';
|
|
13
|
+
import type { CompartmentModuleConfiguration } from './types.js';
|
|
14
|
+
import type { ModuleSource } from './types.js';
|
|
15
|
+
import type { ErrorModuleSource } from './types.js';
|
|
16
|
+
import type { ExitModuleSource } from './types.js';
|
|
17
|
+
import type { LocalModuleSource } from './types.js';
|
|
18
|
+
//# sourceMappingURL=guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["guards.js"],"names":[],"mappings":"AA2BO,kDAHI,mBAAmB,GACjB,KAAK,IAAI,wBAAwB,CAIU;AAQjD,iDAHI,mBAAmB,GACjB,KAAK,IAAI,uBAAuB,CAKT;AAO7B,iDAHI,mBAAmB,GACjB,KAAK,IAAI,uBAAuB,CAKT;AAO7B,wDAHI,mBAAmB,GACjB,KAAK,IAAI,8BAA8B,CAOhB;AAO7B,2CAHI,YAAY,GACV,KAAK,IAAI,iBAAiB,CAIiB;AAQjD,0CAHI,YAAY,GACV,KAAK,IAAI,gBAAgB,CAKT;AAQtB,2CAHI,YAAY,GACV,KAAK,IAAI,iBAAiB,CAWV;AAQtB,2CAHI,OAAO,GACL,KAAK,IAAI,MAAM,CAGiB;yCAzFnC,YAAY;8CAAZ,YAAY;6CAAZ,YAAY;6CAAZ,YAAY;oDAAZ,YAAY;kCAAZ,YAAY;uCAAZ,YAAY;sCAAZ,YAAY;uCAAZ,YAAY"}
|
package/src/guards.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common type guards.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { hasOwn } = Object;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @import {
|
|
11
|
+
* ModuleConfiguration,
|
|
12
|
+
* FileModuleConfiguration,
|
|
13
|
+
* ErrorModuleConfiguration,
|
|
14
|
+
* ModuleSource,
|
|
15
|
+
* ExitModuleSource,
|
|
16
|
+
* ErrorModuleSource,
|
|
17
|
+
* LocalModuleSource,
|
|
18
|
+
* ExitModuleConfiguration,
|
|
19
|
+
* CompartmentModuleConfiguration
|
|
20
|
+
* } from './types.js';
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Type guard for an {@link ErrorModuleConfiguration}.
|
|
25
|
+
* @param {ModuleConfiguration} value
|
|
26
|
+
* @returns {value is ErrorModuleConfiguration}
|
|
27
|
+
*/
|
|
28
|
+
export const isErrorModuleConfiguration = value =>
|
|
29
|
+
hasOwn(value, 'deferredError') &&
|
|
30
|
+
/** @type {any} */ (value).deferredError !== undefined;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Type guard for a {@link FileModuleConfiguration}.
|
|
34
|
+
*
|
|
35
|
+
* @param {ModuleConfiguration} value
|
|
36
|
+
* @returns {value is FileModuleConfiguration}
|
|
37
|
+
*/
|
|
38
|
+
export const isFileModuleConfiguration = value =>
|
|
39
|
+
hasOwn(value, 'parser') &&
|
|
40
|
+
/** @type {any} */ (value).parser !== undefined &&
|
|
41
|
+
!isErrorModuleConfiguration(value);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Type guard for an {@link ExitModuleConfiguration}.
|
|
45
|
+
* @param {ModuleConfiguration} value
|
|
46
|
+
* @returns {value is ExitModuleConfiguration}
|
|
47
|
+
*/
|
|
48
|
+
export const isExitModuleConfiguration = value =>
|
|
49
|
+
hasOwn(value, 'exit') &&
|
|
50
|
+
/** @type {any} */ (value).exit !== undefined &&
|
|
51
|
+
!isErrorModuleConfiguration(value);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Type guard for an {@link CompartmentModuleConfiguration}.
|
|
55
|
+
* @param {ModuleConfiguration} value
|
|
56
|
+
* @returns {value is CompartmentModuleConfiguration}
|
|
57
|
+
*/
|
|
58
|
+
export const isCompartmentModuleConfiguration = value =>
|
|
59
|
+
hasOwn(value, 'compartment') &&
|
|
60
|
+
/** @type {any} */ (value).compartment !== undefined &&
|
|
61
|
+
hasOwn(value, 'module') &&
|
|
62
|
+
/** @type {any} */ (value).module !== undefined &&
|
|
63
|
+
!isErrorModuleConfiguration(value);
|
|
64
|
+
/**
|
|
65
|
+
* Type guard for an {@link ErrorModuleSource}.
|
|
66
|
+
*
|
|
67
|
+
* @param {ModuleSource} value
|
|
68
|
+
* @returns {value is ErrorModuleSource}
|
|
69
|
+
*/
|
|
70
|
+
export const isErrorModuleSource = value =>
|
|
71
|
+
hasOwn(value, 'deferredError') &&
|
|
72
|
+
/** @type {any} */ (value).deferredError !== undefined;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Type guard for an {@link ExitModuleSource}.
|
|
76
|
+
*
|
|
77
|
+
* @param {ModuleSource} value
|
|
78
|
+
* @returns {value is ExitModuleSource}
|
|
79
|
+
*/
|
|
80
|
+
export const isExitModuleSource = value =>
|
|
81
|
+
hasOwn(value, 'exit') &&
|
|
82
|
+
/** @type {any} */ (value).exit !== undefined &&
|
|
83
|
+
!isErrorModuleSource(value);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Type guard for an {@link LocalModuleSource}.
|
|
87
|
+
*
|
|
88
|
+
* @param {ModuleSource} value
|
|
89
|
+
* @returns {value is LocalModuleSource}
|
|
90
|
+
*/
|
|
91
|
+
export const isLocalModuleSource = value =>
|
|
92
|
+
hasOwn(value, 'bytes') &&
|
|
93
|
+
/** @type {any} */ (value).bytes !== undefined &&
|
|
94
|
+
hasOwn(value, 'parser') &&
|
|
95
|
+
/** @type {any} */ (value).parser !== undefined &&
|
|
96
|
+
hasOwn(value, 'sourceDirname') &&
|
|
97
|
+
/** @type {any} */ (value).sourceDirname !== undefined &&
|
|
98
|
+
hasOwn(value, 'location') &&
|
|
99
|
+
/** @type {any} */ (value).location !== undefined &&
|
|
100
|
+
!isErrorModuleSource(value);
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Type guard for a non-nullable object
|
|
104
|
+
*
|
|
105
|
+
* @param {unknown} value
|
|
106
|
+
* @returns {value is object}
|
|
107
|
+
*/
|
|
108
|
+
export const isNonNullableObject = value =>
|
|
109
|
+
typeof value === 'object' && value !== null;
|
package/src/hooks.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Review of compartment-mapper hooks
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
| Hook Name | Description |
|
|
6
|
+
|-------------------------- | --- |
|
|
7
|
+
| `packageDataHook` | Receives all found package descriptors data before graph translation. |
|
|
8
|
+
| `packageDependenciesHook` | Allows dynamic mutation of dependencies during node_modules graph translation. |
|
|
9
|
+
| `unknownCanonicalNameHook`| Called when the policy references unknown canonical names, can suggest typos/similar names. |
|
|
10
|
+
| `moduleSourceHook` | Invoked when a module source is created. |
|
|
11
|
+
| `packageConnectionsHook` | Surfaces connections during digest. (ignored in archiving) |
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
[Type declarations for the hooks](./types/external.ts)
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
graph TB
|
|
19
|
+
|
|
20
|
+
exports((public exports))
|
|
21
|
+
exports -.- compartmentMapForNodeModules
|
|
22
|
+
exports -.- mapNodeModules
|
|
23
|
+
exports -.- loadLocation
|
|
24
|
+
exports -.- importLocation
|
|
25
|
+
exports -.- captureFromMap
|
|
26
|
+
exports -.- importFromMap
|
|
27
|
+
exports -.- loadFromMap
|
|
28
|
+
exports -.- digestCompartmentMap
|
|
29
|
+
exports -.- makeFunctor
|
|
30
|
+
exports -.- makeScript
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
subgraph "import-hook.js"
|
|
34
|
+
moduleSourceHook{{moduleSourceHook}} -.- note5["for all module sources read"]
|
|
35
|
+
makeDeferError --> moduleSourceHook
|
|
36
|
+
makeImportHookMaker --> makeDeferError
|
|
37
|
+
makeImportNowHookMaker --> makeDeferError
|
|
38
|
+
makeImportNowHookMaker -- via importNowHook --> chooseModuleDescriptor --> executeLocalModuleSourceHook--> moduleSourceHook
|
|
39
|
+
makeImportHookMaker --via importHook exitModule logic--> moduleSourceHook
|
|
40
|
+
makeImportHookMaker --via importHook call--> chooseModuleDescriptor
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
subgraph "node-modules.js"
|
|
44
|
+
compartmentMapForNodeModules --> packageDataHook{{packageDataHook}} -.- note0["called once"]
|
|
45
|
+
compartmentMapForNodeModules --> unknownCanonicalNameHook{{unknownCanonicalNameHook}} -.- note1["for all issues from policy;<br>after defaultUnknownCanonicalNameHandler"]
|
|
46
|
+
compartmentMapForNodeModules --> translateGraph --> packageDependenciesHook{{packageDependenciesHook}} -.-note3["for all locatons in graph<br>after defaultPackageDependenciesFilter"]
|
|
47
|
+
mapNodeModules --> compartmentMapForNodeModules
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
subgraph "digest.js"
|
|
52
|
+
digestCompartmentMap --> translateCompartmentMap --> packageConnectionsHook{{packageConnectionsHook}} -.- note4["for all retained compartments"]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
subgraph "bundle.js"
|
|
56
|
+
makeFunctor -- options:can include hooks ----------> mapNodeModules
|
|
57
|
+
makeScript -- options:can include hooks ----------> mapNodeModules
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
subgraph "import-lite.js"
|
|
62
|
+
importFromMap --> loadFromMap ---> makeImportHookMaker
|
|
63
|
+
loadFromMap ----> makeImportNowHookMaker
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
subgraph "capture-lite.js"
|
|
68
|
+
captureFromMap -----> makeImportHookMaker
|
|
69
|
+
captureFromMap --> captureCompartmentMap --> digestCompartmentMap
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
subgraph "import.js"
|
|
74
|
+
loadLocation ----------> mapNodeModules
|
|
75
|
+
importLocation --> loadLocation
|
|
76
|
+
loadLocation --> loadFromMap
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
%% STYLING
|
|
81
|
+
classDef note fill:#999, stroke:#ccb
|
|
82
|
+
class note0,note1,note2,note3,note4,note5 note
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
<details>
|
|
89
|
+
<summary>Bundle and Archive bits of the diagram that don't use hooks</summary>
|
|
90
|
+
|
|
91
|
+
These are calling the functions accepting hooks but don't pass them
|
|
92
|
+
|
|
93
|
+
> [TODO]
|
|
94
|
+
> copy-paste this to the main diagram whenever the connections are made.
|
|
95
|
+
|
|
96
|
+
```mermaid
|
|
97
|
+
|
|
98
|
+
graph TB
|
|
99
|
+
|
|
100
|
+
subgraph "bundle.js"
|
|
101
|
+
makeFunctor -- options:transparently ----------> mapNodeModules
|
|
102
|
+
makeScript -- options:transparently ----------> mapNodeModules
|
|
103
|
+
makeFunctorFromMap -- no moduleSourceHook ----x makeImportHookMaker
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
subgraph "bundle-lite.js"
|
|
107
|
+
makeFunctorFromMap2 --no moduleSourceHook -----x makeImportHookMaker
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
subgraph "archive-lite.js"
|
|
111
|
+
digestFromMap -- no moduleSourceHook -----x makeImportHookMaker
|
|
112
|
+
makeArchiveCompartmentMap --no packageConnectionsHook----x digestCompartmentMap
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
subgraph "archive.js"
|
|
116
|
+
archive(("multiple <br> methods")) --no hooks passed-----------x mapNodeModules
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
</details>
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-archive-lite.d.ts","sourceRoot":"","sources":["import-archive-lite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"import-archive-lite.d.ts","sourceRoot":"","sources":["import-archive-lite.js"],"names":[],"mappings":"AA0PO,2CALI,UAAU,oBACV,MAAM,YACN,mBAAmB,GACjB,OAAO,CAAC,WAAW,CAAC,CAiKhC;AAQM,wCALI,MAAM,GAAG,UAAU,mBACnB,MAAM,YACN,kBAAkB,GAChB,OAAO,CAAC,WAAW,CAAC,CAwBhC;AAQM,0CALI,MAAM,GAAG,UAAU,mBACnB,MAAM,WACN,kBAAkB,GAChB,OAAO,CAAC,UAAU,CAAC,CAK/B;yCA5ZS,YAAY;iCAAZ,YAAY;4BAAZ,YAAY;gCAAZ,YAAY;wCAAZ,YAAY;gCAAZ,YAAY"}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* } from 'ses';
|
|
24
24
|
* @import {
|
|
25
25
|
* Application,
|
|
26
|
-
*
|
|
26
|
+
* FileCompartmentDescriptor,
|
|
27
27
|
* ComputeSourceLocationHook,
|
|
28
28
|
* ComputeSourceMapLocationHook,
|
|
29
29
|
* ExecuteFn,
|
|
@@ -44,9 +44,13 @@ import { link } from './link.js';
|
|
|
44
44
|
import { parseLocatedJson } from './json.js';
|
|
45
45
|
import { unpackReadPowers } from './powers.js';
|
|
46
46
|
import { join } from './node-module-specifier.js';
|
|
47
|
-
import {
|
|
47
|
+
import { assertFileCompartmentMap } from './compartment-map.js';
|
|
48
48
|
import { exitModuleImportHookMaker } from './import-hook.js';
|
|
49
|
-
import { attenuateModuleHook,
|
|
49
|
+
import { attenuateModuleHook, enforcePolicyByModule } from './policy.js';
|
|
50
|
+
import {
|
|
51
|
+
isErrorModuleConfiguration,
|
|
52
|
+
isFileModuleConfiguration,
|
|
53
|
+
} from './guards.js';
|
|
50
54
|
|
|
51
55
|
const { Fail, quote: q } = assert;
|
|
52
56
|
|
|
@@ -77,7 +81,7 @@ const postponeErrorToExecute = errorMessage => {
|
|
|
77
81
|
|
|
78
82
|
/**
|
|
79
83
|
* @param {(path: string) => Uint8Array} get
|
|
80
|
-
* @param {Record<string,
|
|
84
|
+
* @param {Record<string, FileCompartmentDescriptor>} compartments
|
|
81
85
|
* @param {string} archiveLocation
|
|
82
86
|
* @param {ParserForLanguage} parserForLanguage
|
|
83
87
|
* @param {HashFn} [computeSha512]
|
|
@@ -118,7 +122,7 @@ const makeArchiveImportHookMaker = (
|
|
|
118
122
|
// At this point in archive importing, if a module is not found and
|
|
119
123
|
// exitModuleImportHook exists, the only possibility is that the
|
|
120
124
|
// module is a "builtin" module and the policy needs to be enforced.
|
|
121
|
-
|
|
125
|
+
enforcePolicyByModule(moduleSpecifier, compartmentDescriptor, {
|
|
122
126
|
exit: true,
|
|
123
127
|
errorHint: `Blocked in loading. ${q(
|
|
124
128
|
moduleSpecifier,
|
|
@@ -161,22 +165,22 @@ const makeArchiveImportHookMaker = (
|
|
|
161
165
|
)} in archive ${q(archiveLocation)}`,
|
|
162
166
|
);
|
|
163
167
|
}
|
|
164
|
-
if (module
|
|
168
|
+
if (isErrorModuleConfiguration(module)) {
|
|
165
169
|
return postponeErrorToExecute(module.deferredError);
|
|
166
170
|
}
|
|
167
|
-
if (module
|
|
171
|
+
if (!isFileModuleConfiguration(module)) {
|
|
168
172
|
throw Error(
|
|
169
173
|
`Cannot parse module ${q(moduleSpecifier)} in package ${q(
|
|
170
174
|
packageLocation,
|
|
171
|
-
)} in archive ${q(archiveLocation)}`,
|
|
175
|
+
)} in archive ${q(archiveLocation)}; missing parser`,
|
|
172
176
|
);
|
|
173
177
|
}
|
|
174
178
|
const parser = parserForLanguage[module.parser];
|
|
175
179
|
if (parser === undefined) {
|
|
176
180
|
throw Error(
|
|
177
|
-
`Cannot parse
|
|
181
|
+
`Cannot parse module ${q(
|
|
178
182
|
moduleSpecifier,
|
|
179
|
-
)} in package ${q(packageLocation)} in archive ${q(archiveLocation)}`,
|
|
183
|
+
)} in package ${q(packageLocation)} in archive ${q(archiveLocation)}; unknown parser (${q(module.parser)})`,
|
|
180
184
|
);
|
|
181
185
|
}
|
|
182
186
|
const { parse } = parser;
|
|
@@ -306,7 +310,7 @@ export const parseArchive = async (
|
|
|
306
310
|
compartmentMapText,
|
|
307
311
|
'compartment-map.json',
|
|
308
312
|
);
|
|
309
|
-
|
|
313
|
+
assertFileCompartmentMap(compartmentMap, archiveLocation);
|
|
310
314
|
|
|
311
315
|
const {
|
|
312
316
|
compartments,
|