@endo/compartment-mapper 1.6.2 → 2.0.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 +12 -16
- package/src/archive-lite.d.ts +7 -7
- package/src/archive-lite.d.ts.map +1 -1
- package/src/archive-lite.js +78 -27
- 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 +217 -25
- package/src/compartment-map.d.ts +9 -2
- package/src/compartment-map.d.ts.map +1 -1
- package/src/compartment-map.js +737 -254
- package/src/digest.d.ts +22 -2
- package/src/digest.d.ts.map +1 -1
- package/src/digest.js +179 -56
- package/src/generic-graph.d.ts +84 -0
- package/src/generic-graph.d.ts.map +1 -0
- package/src/generic-graph.js +356 -0
- 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 +156 -71
- 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.map +1 -1
- package/src/infer-exports.js +16 -6
- package/src/json.d.ts +1 -1
- package/src/json.d.ts.map +1 -1
- package/src/json.js +10 -3
- package/src/link.d.ts +4 -3
- package/src/link.d.ts.map +1 -1
- package/src/link.js +70 -58
- package/src/node-modules.d.ts +5 -3
- package/src/node-modules.d.ts.map +1 -1
- package/src/node-modules.js +648 -245
- package/src/node-powers.d.ts +6 -5
- package/src/node-powers.d.ts.map +1 -1
- package/src/node-powers.js +11 -8
- package/src/parse-cjs-shared-export-wrapper.d.ts.map +1 -1
- package/src/parse-cjs-shared-export-wrapper.js +3 -1
- 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 +114 -35
- package/src/types/compartment-map-schema.d.ts.map +1 -1
- package/src/types/compartment-map-schema.ts +202 -37
- package/src/types/external.d.ts +173 -29
- package/src/types/external.d.ts.map +1 -1
- package/src/types/external.ts +221 -27
- package/src/types/generic-graph.d.ts +17 -0
- package/src/types/generic-graph.d.ts.map +1 -0
- package/src/types/generic-graph.ts +17 -0
- package/src/types/internal.d.ts +24 -42
- package/src/types/internal.d.ts.map +1 -1
- package/src/types/internal.ts +52 -50
- package/src/types/node-modules.d.ts +101 -17
- package/src/types/node-modules.d.ts.map +1 -1
- package/src/types/node-modules.ts +142 -17
- 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 +38 -11
- package/src/types/powers.d.ts.map +1 -1
- package/src/types/powers.ts +50 -17
- package/src/types/typescript.d.ts +28 -0
- package/src/types/typescript.d.ts.map +1 -1
- package/src/types/typescript.ts +37 -1
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides {@link GenericGraph} and {@link makeShortestPath}.
|
|
3
|
+
*
|
|
4
|
+
* Portions adapted from
|
|
5
|
+
* [graph data structure](https://github.com/datavis-tech/graph-data-structure),
|
|
6
|
+
* which is Copyright (c) 2016 Curran Kelleher and licensed under the MIT
|
|
7
|
+
* License.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @import {TraversalContext} from './types/generic-graph.js';
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { quote: q } = assert;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Remove the node with the minimum weight from the priority queue.
|
|
20
|
+
*
|
|
21
|
+
* Performs linear search.
|
|
22
|
+
* @template [T=string]
|
|
23
|
+
* @param {TraversalContext<T>} tracks
|
|
24
|
+
* @returns {T|undefined}
|
|
25
|
+
*/
|
|
26
|
+
const extractMin = ({ distances, queue }) => {
|
|
27
|
+
let min = Infinity;
|
|
28
|
+
|
|
29
|
+
/** @type {T|undefined} */
|
|
30
|
+
let minNode;
|
|
31
|
+
|
|
32
|
+
queue.forEach(node => {
|
|
33
|
+
const nodeWeight = distances.get(node) ?? Infinity;
|
|
34
|
+
|
|
35
|
+
if (nodeWeight < min) {
|
|
36
|
+
min = nodeWeight;
|
|
37
|
+
minNode = node;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (minNode === undefined) {
|
|
42
|
+
queue.clear();
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
queue.delete(minNode);
|
|
47
|
+
return minNode;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Update context with the new distance to the target node if the distance
|
|
52
|
+
* through the source node is shorter than the current distance.
|
|
53
|
+
*
|
|
54
|
+
* @template [T=string]
|
|
55
|
+
* @param {GenericGraph<T>} graph
|
|
56
|
+
* @param {TraversalContext<NoInfer<T>>} context
|
|
57
|
+
* @param {NoInfer<T>} source
|
|
58
|
+
* @param {NoInfer<T>} target
|
|
59
|
+
*/
|
|
60
|
+
const relax = (graph, { distances, predecessors }, source, target) => {
|
|
61
|
+
const number = graph.getEdgeWeight(source, target);
|
|
62
|
+
|
|
63
|
+
const distanceSource = distances.get(source);
|
|
64
|
+
const distanceTarget = distances.get(target);
|
|
65
|
+
|
|
66
|
+
assert(
|
|
67
|
+
distanceSource !== undefined,
|
|
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);
|
|
77
|
+
predecessors.set(target, source);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Assembles the shortest path by traversing the
|
|
83
|
+
* predecessor subgraph from destination to source.
|
|
84
|
+
*
|
|
85
|
+
* @template [T=string]
|
|
86
|
+
* @param {TraversalContext<NoInfer<T>>} context Traversal context object
|
|
87
|
+
* @param {NoInfer<T>} source Source node
|
|
88
|
+
* @param {NoInfer<T>} target Destination node
|
|
89
|
+
* @returns {[T, T, ...T[]]} Nodes from `source` to `target` inclusive
|
|
90
|
+
* @throws If no path is found
|
|
91
|
+
* @throws If the path has less than two nodes
|
|
92
|
+
*/
|
|
93
|
+
const getPath = ({ predecessors }, source, target) => {
|
|
94
|
+
/** @type {T[]} */
|
|
95
|
+
const nodeList = [];
|
|
96
|
+
|
|
97
|
+
assert(
|
|
98
|
+
source !== target,
|
|
99
|
+
`Source ${q(source)} cannot be the same as target ${q(target)}`,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
let node = target;
|
|
103
|
+
|
|
104
|
+
while (predecessors.has(node)) {
|
|
105
|
+
const currentNode = /** @type {T} */ (predecessors.get(node));
|
|
106
|
+
nodeList.push(node);
|
|
107
|
+
node = currentNode;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
assert.equal(node, source, `No path found from ${q(source)} to ${q(target)}`);
|
|
111
|
+
|
|
112
|
+
nodeList.push(node);
|
|
113
|
+
|
|
114
|
+
assert(
|
|
115
|
+
nodeList.length >= 2,
|
|
116
|
+
`The path from ${source} to ${target} should have at least two nodes`,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
return /** @type {[T, T, ...T[]]} */ (nodeList.reverse());
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @template [T=string] The type of nodes in the graph
|
|
124
|
+
*
|
|
125
|
+
* A generic graph implementation with edge weights.
|
|
126
|
+
*
|
|
127
|
+
* Edge weights are assumed to be non-negative numbers (including `Infinity`)
|
|
128
|
+
*/
|
|
129
|
+
export class GenericGraph {
|
|
130
|
+
/**
|
|
131
|
+
* @type {Set<T>}
|
|
132
|
+
*/
|
|
133
|
+
#nodes;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @type {Map<T, Set<T>>}
|
|
137
|
+
*/
|
|
138
|
+
#edges;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @type {Map<T, Map<T, number>>}
|
|
142
|
+
*/
|
|
143
|
+
#edgeWeights;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Initializes internal data structures.
|
|
147
|
+
*/
|
|
148
|
+
constructor() {
|
|
149
|
+
this.#edgeWeights = new Map();
|
|
150
|
+
this.#edges = new Map();
|
|
151
|
+
this.#nodes = new Set();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Returns a shallow copy of the `Set` of nodes in the graph.
|
|
156
|
+
*/
|
|
157
|
+
get nodes() {
|
|
158
|
+
return new Set(this.#nodes);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Adds a node to the graph.
|
|
163
|
+
* If node was already added, this function does nothing.
|
|
164
|
+
* If node was not already added, this function sets up an empty adjacency list.
|
|
165
|
+
* @param {T} node Node to add
|
|
166
|
+
* @returns {this} This graph instance
|
|
167
|
+
*/
|
|
168
|
+
addNode(node) {
|
|
169
|
+
if (!this.#nodes.has(node)) {
|
|
170
|
+
this.#nodes.add(node);
|
|
171
|
+
}
|
|
172
|
+
if (!this.#edges.has(node)) {
|
|
173
|
+
this.#edges.set(node, new Set());
|
|
174
|
+
}
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Removes a node from the graph.
|
|
180
|
+
* Also removes incoming and outgoing edges.
|
|
181
|
+
* @param {T} node
|
|
182
|
+
* @returns {this}
|
|
183
|
+
*/
|
|
184
|
+
removeNode(node) {
|
|
185
|
+
this.#edges.delete(node);
|
|
186
|
+
this.#nodes.delete(node);
|
|
187
|
+
for (const adjacentNodes of this.#edges.values()) {
|
|
188
|
+
adjacentNodes.delete(node);
|
|
189
|
+
}
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Gets the adjacent nodes set for the given node.
|
|
195
|
+
* @param {T} node
|
|
196
|
+
* @returns {Set<T>|undefined}
|
|
197
|
+
*/
|
|
198
|
+
adjacent(node) {
|
|
199
|
+
return this.#edges.get(node);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Sets the weight of the given edge between `source` and `target`.
|
|
204
|
+
*
|
|
205
|
+
* @param {T} source Source node
|
|
206
|
+
* @param {T} target Target node
|
|
207
|
+
* @param {number} weight New edge weight
|
|
208
|
+
* @returns {this}
|
|
209
|
+
*/
|
|
210
|
+
setEdgeWeight(source, target, weight) {
|
|
211
|
+
if (!this.#edgeWeights.has(source)) {
|
|
212
|
+
this.#edgeWeights.set(source, new Map());
|
|
213
|
+
}
|
|
214
|
+
const weights = /** @type {Map<T, number>} */ (
|
|
215
|
+
this.#edgeWeights.get(source)
|
|
216
|
+
);
|
|
217
|
+
weights.set(target, weight);
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Gets the weight of the given edge between `source` and `target`.
|
|
223
|
+
*
|
|
224
|
+
* @param {T} source Source node
|
|
225
|
+
* @param {T} target Target node
|
|
226
|
+
* @returns {number} Edge weight from source to target
|
|
227
|
+
*/
|
|
228
|
+
getEdgeWeight(source, target) {
|
|
229
|
+
const weight = this.#edgeWeights.get(source)?.get(target);
|
|
230
|
+
if (weight === undefined) {
|
|
231
|
+
throw new ReferenceError(
|
|
232
|
+
`Edge weight from ${q(source)} to ${q(target)} is not set`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return weight;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Adds an edge from the `source` node to `target` node.
|
|
240
|
+
*
|
|
241
|
+
* This method will create the `source` and `target` node(s) if they do not
|
|
242
|
+
* already exist.
|
|
243
|
+
*
|
|
244
|
+
* If {@link T `T`} is an object, the comparison is by-reference.
|
|
245
|
+
*
|
|
246
|
+
* @param {T} source Source node
|
|
247
|
+
* @param {T} target Target node
|
|
248
|
+
* @param {number} weight Edge weight from source to target
|
|
249
|
+
* @returns {this} This graph instance
|
|
250
|
+
*/
|
|
251
|
+
addEdge(source, target, weight) {
|
|
252
|
+
this.addNode(source);
|
|
253
|
+
this.addNode(target);
|
|
254
|
+
const adjacentNodes = this.adjacent(source);
|
|
255
|
+
assert(adjacentNodes, `Source ${q(source)} should have adjacent nodes`);
|
|
256
|
+
|
|
257
|
+
adjacentNodes.add(target);
|
|
258
|
+
this.setEdgeWeight(source, target, weight);
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Removes the edge from the `source` node to `target` node.
|
|
264
|
+
* Does not remove the nodes themselves.
|
|
265
|
+
* Does nothing if the edge does not exist.
|
|
266
|
+
* @param {T} source
|
|
267
|
+
* @param {T} target
|
|
268
|
+
* @returns {this}
|
|
269
|
+
*/
|
|
270
|
+
removeEdge(source, target) {
|
|
271
|
+
this.#edges.get(source)?.delete(target);
|
|
272
|
+
return this;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Returns true if there is an edge from the `source` node to `target` node.
|
|
277
|
+
* @param {T} source
|
|
278
|
+
* @param {T} target
|
|
279
|
+
* @returns {boolean}
|
|
280
|
+
*/
|
|
281
|
+
hasEdge(source, target) {
|
|
282
|
+
return this.#edges.get(source)?.has(target) ?? false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Dijkstra's algorithm for shortest paths in a graph.
|
|
288
|
+
* @template [T=string] The type of nodes in the graph
|
|
289
|
+
* @param {GenericGraph<T>} graph
|
|
290
|
+
* @param {T} source
|
|
291
|
+
* @param {T} target
|
|
292
|
+
* @returns {TraversalContext<T>}
|
|
293
|
+
*/
|
|
294
|
+
const dijkstra = (graph, source, target) => {
|
|
295
|
+
const { nodes } = graph;
|
|
296
|
+
/** @type {TraversalContext<T>} */
|
|
297
|
+
const context = {
|
|
298
|
+
distances: new Map(),
|
|
299
|
+
predecessors: new Map(),
|
|
300
|
+
queue: new Set(),
|
|
301
|
+
};
|
|
302
|
+
const { queue, distances } = context;
|
|
303
|
+
|
|
304
|
+
for (const node of nodes) {
|
|
305
|
+
distances.set(node, Infinity);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
assert(
|
|
309
|
+
distances.get(source) === Infinity,
|
|
310
|
+
`Source ${q(source)} is not in the graph`,
|
|
311
|
+
);
|
|
312
|
+
assert(
|
|
313
|
+
distances.get(target) === Infinity,
|
|
314
|
+
`Target ${q(target)} is not in the graph`,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
distances.set(source, 0);
|
|
318
|
+
|
|
319
|
+
for (const node of nodes) {
|
|
320
|
+
queue.add(node);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
while (queue.size !== 0) {
|
|
324
|
+
const node = extractMin(context);
|
|
325
|
+
if (node === undefined) {
|
|
326
|
+
return context;
|
|
327
|
+
}
|
|
328
|
+
const adjacent = graph.adjacent(node);
|
|
329
|
+
if (adjacent) {
|
|
330
|
+
for (const edge of adjacent) {
|
|
331
|
+
relax(graph, context, node, edge);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return context;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Returns a function which uses Dijkstra's shortest path algorithm to compute
|
|
340
|
+
* the shortest path from `source` to `destination` in the given `graph`.
|
|
341
|
+
*
|
|
342
|
+
* @template [T=string]
|
|
343
|
+
* @param {GenericGraph<T>} graph Graph to use
|
|
344
|
+
*/
|
|
345
|
+
export const makeShortestPath = graph => {
|
|
346
|
+
/**
|
|
347
|
+
* @param {NoInfer<T>} source Source node
|
|
348
|
+
* @param {NoInfer<T>} target Target node
|
|
349
|
+
* @returns {[T, T, ...T[]]} Nodes from `source` to `target` inclusive (minimum of two nodes)
|
|
350
|
+
*/
|
|
351
|
+
const shortestPath = (source, target) => {
|
|
352
|
+
const context = dijkstra(graph, source, target);
|
|
353
|
+
return getPath(context, source, target);
|
|
354
|
+
};
|
|
355
|
+
return shortestPath;
|
|
356
|
+
};
|
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,
|