@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/node-modules.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
1
2
|
/**
|
|
2
3
|
* Provides functions for constructing a compartment map that has a
|
|
3
4
|
* compartment descriptor corresponding to every reachable package from an
|
|
@@ -13,15 +14,16 @@
|
|
|
13
14
|
|
|
14
15
|
/* eslint no-shadow: 0 */
|
|
15
16
|
|
|
16
|
-
import {
|
|
17
|
+
import { inferExportsAliasesAndPatterns } from './infer-exports.js';
|
|
17
18
|
import { parseLocatedJson } from './json.js';
|
|
18
19
|
import { join } from './node-module-specifier.js';
|
|
19
|
-
import { assertPolicy } from './policy-format.js';
|
|
20
20
|
import {
|
|
21
|
+
assertPolicy,
|
|
21
22
|
ATTENUATORS_COMPARTMENT,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} from './policy.js';
|
|
23
|
+
ENTRY_COMPARTMENT,
|
|
24
|
+
generateCanonicalName,
|
|
25
|
+
} from './policy-format.js';
|
|
26
|
+
import { dependencyAllowedByPolicy, makePackagePolicy } from './policy.js';
|
|
25
27
|
import { unpackReadPowers } from './powers.js';
|
|
26
28
|
import { search, searchDescriptor } from './search.js';
|
|
27
29
|
import { GenericGraph, makeShortestPath } from './generic-graph.js';
|
|
@@ -41,8 +43,16 @@ import { GenericGraph, makeShortestPath } from './generic-graph.js';
|
|
|
41
43
|
* PackageDescriptor,
|
|
42
44
|
* ReadFn,
|
|
43
45
|
* ReadPowers,
|
|
44
|
-
* SomePackagePolicy,
|
|
45
46
|
* SomePolicy,
|
|
47
|
+
* LogFn,
|
|
48
|
+
* CompartmentModuleConfiguration,
|
|
49
|
+
* PackageCompartmentDescriptor,
|
|
50
|
+
* PackageCompartmentMapDescriptor,
|
|
51
|
+
* ScopeDescriptor,
|
|
52
|
+
* CanonicalName,
|
|
53
|
+
* SomePackagePolicy,
|
|
54
|
+
* PackageCompartmentDescriptorName,
|
|
55
|
+
* PackageData,
|
|
46
56
|
* } from './types.js'
|
|
47
57
|
* @import {
|
|
48
58
|
* Graph,
|
|
@@ -54,21 +64,78 @@ import { GenericGraph, makeShortestPath } from './generic-graph.js';
|
|
|
54
64
|
* GraphPackagesOptions,
|
|
55
65
|
* LogicalPathGraph,
|
|
56
66
|
* PackageDetails,
|
|
67
|
+
* FinalGraph,
|
|
68
|
+
* CanonicalNameMap,
|
|
69
|
+
* FinalNode,
|
|
70
|
+
TranslateGraphOptions,
|
|
57
71
|
* } from './types/node-modules.js'
|
|
58
72
|
*/
|
|
59
73
|
|
|
60
|
-
const { assign, create, keys, values, entries } = Object;
|
|
74
|
+
const { assign, create, keys, values, entries, freeze } = Object;
|
|
61
75
|
|
|
62
76
|
const decoder = new TextDecoder();
|
|
63
77
|
|
|
64
78
|
// q, as in quote, for enquoting strings in error messages.
|
|
65
|
-
const q =
|
|
79
|
+
const { quote: q } = assert;
|
|
66
80
|
|
|
67
81
|
/**
|
|
68
82
|
* Default logger that does nothing.
|
|
69
83
|
*/
|
|
70
84
|
const noop = () => {};
|
|
71
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Default handler for unknown canonical names found in policy.
|
|
88
|
+
* Logs a warning when a canonical name from policy is not found in the compartment map.
|
|
89
|
+
*
|
|
90
|
+
* @param {object} params
|
|
91
|
+
* @param {CanonicalName} params.canonicalName
|
|
92
|
+
* @param {string} params.message
|
|
93
|
+
* @param {LogFn} params.log
|
|
94
|
+
*/
|
|
95
|
+
const defaultUnknownCanonicalNameHandler = ({
|
|
96
|
+
canonicalName,
|
|
97
|
+
message,
|
|
98
|
+
log,
|
|
99
|
+
}) => {
|
|
100
|
+
log(`WARN: Invalid resource ${q(canonicalName)} in policy: ${message}`);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Default filter for package dependencies based on policy.
|
|
105
|
+
* Filters out dependencies not allowed by the package policy.
|
|
106
|
+
*
|
|
107
|
+
* **Note:** This filter is _only_ applied if a policy is provided.
|
|
108
|
+
*
|
|
109
|
+
* @param {object} params - The parameters object
|
|
110
|
+
* @param {CanonicalName} params.canonicalName - The canonical name of the package
|
|
111
|
+
* @param {Readonly<Set<CanonicalName>>} params.dependencies - The set of dependencies
|
|
112
|
+
* @param {LogFn} params.log - The logging function
|
|
113
|
+
* @param {SomePolicy} policy - The policy to check against
|
|
114
|
+
* @returns {Partial<{ dependencies: Set<CanonicalName> }> | void}
|
|
115
|
+
*/
|
|
116
|
+
const prePackageDependenciesFilter = (
|
|
117
|
+
{ canonicalName, dependencies, log },
|
|
118
|
+
policy,
|
|
119
|
+
) => {
|
|
120
|
+
const packagePolicy = makePackagePolicy(canonicalName, { policy });
|
|
121
|
+
if (!packagePolicy) {
|
|
122
|
+
return { dependencies };
|
|
123
|
+
}
|
|
124
|
+
const filteredDependencies = new Set(
|
|
125
|
+
[...dependencies].filter(dependency => {
|
|
126
|
+
const allowed = dependencyAllowedByPolicy(dependency, packagePolicy);
|
|
127
|
+
if (!allowed) {
|
|
128
|
+
log(
|
|
129
|
+
`Excluding dependency ${q(dependency)} of package ${q(canonicalName)} per policy`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return allowed;
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
return { dependencies: filteredDependencies };
|
|
137
|
+
};
|
|
138
|
+
|
|
72
139
|
/**
|
|
73
140
|
* Given a relative path andd URL, return a fully qualified URL string.
|
|
74
141
|
*
|
|
@@ -319,37 +386,6 @@ const inferParsers = (descriptor, location, languageOptions) => {
|
|
|
319
386
|
return { ...commonjsLanguageForExtension, ...packageLanguageForExtension };
|
|
320
387
|
};
|
|
321
388
|
|
|
322
|
-
/**
|
|
323
|
-
* This returns the "weight" of a package name, which is used when determining
|
|
324
|
-
* the shortest path.
|
|
325
|
-
*
|
|
326
|
-
* It is an analogue of the `pathCompare` function.
|
|
327
|
-
*
|
|
328
|
-
* The weight is calculated as follows:
|
|
329
|
-
*
|
|
330
|
-
* 1. The {@link String.length length} of the package name contributes a fixed
|
|
331
|
-
* value of `0x10000` per character. This is because the `pathCompare`
|
|
332
|
-
* algorithm first compares strings by length and only evaluates code unit
|
|
333
|
-
* values if the lengths of two strings are equal. `0x10000` is one (1)
|
|
334
|
-
* greater than the maximum value that {@link String.charCodeAt charCodeAt}
|
|
335
|
-
* can return (`0xFFFF`), which guarantees longer strings will have higher
|
|
336
|
-
* weights.
|
|
337
|
-
* 2. Each character in the package name contributes its UTF-16 code unit value
|
|
338
|
-
* (`0x0` thru `0xFFFF`) to the total. This is the same operation used when
|
|
339
|
-
* comparing two strings using comparison operators.
|
|
340
|
-
* 3. The total weight is the sum of 1. and 2.
|
|
341
|
-
*
|
|
342
|
-
* @param {string} packageName - Name of package to calculate weight for.
|
|
343
|
-
* @returns {number} Numeric weight
|
|
344
|
-
*/
|
|
345
|
-
const calculatePackageWeight = packageName => {
|
|
346
|
-
let totalCodeValue = packageName.length * 65536; // each character contributes 65536
|
|
347
|
-
for (let i = 0; i < packageName.length; i += 1) {
|
|
348
|
-
totalCodeValue += packageName.charCodeAt(i);
|
|
349
|
-
}
|
|
350
|
-
return totalCodeValue;
|
|
351
|
-
};
|
|
352
|
-
|
|
353
389
|
/**
|
|
354
390
|
* `graphPackage` and {@link gatherDependency} are mutually recursive functions that
|
|
355
391
|
* gather the metadata for a package and its transitive dependencies.
|
|
@@ -368,7 +404,7 @@ const calculatePackageWeight = packageName => {
|
|
|
368
404
|
* @param {LanguageOptions} languageOptions
|
|
369
405
|
* @param {boolean} strict
|
|
370
406
|
* @param {LogicalPathGraph} logicalPathGraph
|
|
371
|
-
* @param {GraphPackageOptions}
|
|
407
|
+
* @param {GraphPackageOptions} options
|
|
372
408
|
* @returns {Promise<undefined>}
|
|
373
409
|
*/
|
|
374
410
|
const graphPackage = async (
|
|
@@ -382,7 +418,12 @@ const graphPackage = async (
|
|
|
382
418
|
languageOptions,
|
|
383
419
|
strict,
|
|
384
420
|
logicalPathGraph,
|
|
385
|
-
{
|
|
421
|
+
{
|
|
422
|
+
commonDependencyDescriptors = {},
|
|
423
|
+
log = noop,
|
|
424
|
+
packageDependenciesHook,
|
|
425
|
+
policy,
|
|
426
|
+
} = {},
|
|
386
427
|
) => {
|
|
387
428
|
if (graph[packageLocation] !== undefined) {
|
|
388
429
|
// Returning the promise here would create a causal cycle and stall recursion.
|
|
@@ -397,7 +438,7 @@ const graphPackage = async (
|
|
|
397
438
|
});
|
|
398
439
|
}
|
|
399
440
|
|
|
400
|
-
const result = /** @type {Node} */ ({});
|
|
441
|
+
const result = /** @type {Node} */ ({ location: packageLocation });
|
|
401
442
|
graph[packageLocation] = result;
|
|
402
443
|
|
|
403
444
|
/** @type {Node['dependencyLocations']} */
|
|
@@ -461,7 +502,6 @@ const graphPackage = async (
|
|
|
461
502
|
|
|
462
503
|
for (const dependencyName of [...allDependencies].sort()) {
|
|
463
504
|
const optional = optionals.has(dependencyName);
|
|
464
|
-
const childLogicalPath = [...logicalPath, dependencyName];
|
|
465
505
|
children.push(
|
|
466
506
|
// Mutual recursion ahead:
|
|
467
507
|
// eslint-disable-next-line no-use-before-define
|
|
@@ -477,10 +517,11 @@ const graphPackage = async (
|
|
|
477
517
|
strict,
|
|
478
518
|
logicalPathGraph,
|
|
479
519
|
{
|
|
480
|
-
childLogicalPath,
|
|
481
520
|
optional,
|
|
482
521
|
commonDependencyDescriptors,
|
|
483
522
|
log,
|
|
523
|
+
packageDependenciesHook,
|
|
524
|
+
policy,
|
|
484
525
|
},
|
|
485
526
|
),
|
|
486
527
|
);
|
|
@@ -505,13 +546,17 @@ const graphPackage = async (
|
|
|
505
546
|
const externalAliases = {};
|
|
506
547
|
/** @type {Node['internalAliases']} */
|
|
507
548
|
const internalAliases = {};
|
|
549
|
+
/** @type {Node['patterns']} */
|
|
550
|
+
const patterns = [];
|
|
508
551
|
|
|
509
|
-
|
|
552
|
+
inferExportsAliasesAndPatterns(
|
|
510
553
|
packageDescriptor,
|
|
511
554
|
externalAliases,
|
|
512
555
|
internalAliases,
|
|
556
|
+
patterns,
|
|
513
557
|
conditions,
|
|
514
558
|
types,
|
|
559
|
+
log,
|
|
515
560
|
);
|
|
516
561
|
|
|
517
562
|
const parsers = inferParsers(
|
|
@@ -522,18 +567,21 @@ const graphPackage = async (
|
|
|
522
567
|
|
|
523
568
|
const sourceDirname = basename(packageLocation);
|
|
524
569
|
|
|
525
|
-
|
|
570
|
+
/** @type {Partial<Node>} */
|
|
571
|
+
const partialNode = {
|
|
526
572
|
name,
|
|
527
|
-
path: logicalPath,
|
|
528
573
|
label: `${name}${version ? `-v${version}` : ''}`,
|
|
529
574
|
sourceDirname,
|
|
530
575
|
explicitExports: exportsDescriptor !== undefined,
|
|
531
576
|
externalAliases,
|
|
532
577
|
internalAliases,
|
|
578
|
+
patterns,
|
|
533
579
|
dependencyLocations,
|
|
534
580
|
types,
|
|
535
581
|
parsers,
|
|
536
|
-
|
|
582
|
+
packageDescriptor,
|
|
583
|
+
};
|
|
584
|
+
assign(result, partialNode);
|
|
537
585
|
|
|
538
586
|
await Promise.all(
|
|
539
587
|
values(result.externalAliases).map(async item => {
|
|
@@ -605,10 +653,11 @@ const gatherDependency = async (
|
|
|
605
653
|
strict,
|
|
606
654
|
logicalPathGraph,
|
|
607
655
|
{
|
|
608
|
-
childLogicalPath = [],
|
|
609
656
|
optional = false,
|
|
610
657
|
commonDependencyDescriptors = {},
|
|
611
658
|
log = noop,
|
|
659
|
+
packageDependenciesHook,
|
|
660
|
+
policy,
|
|
612
661
|
} = {},
|
|
613
662
|
) => {
|
|
614
663
|
const dependency = await findPackage(
|
|
@@ -617,6 +666,7 @@ const gatherDependency = async (
|
|
|
617
666
|
packageLocation,
|
|
618
667
|
name,
|
|
619
668
|
);
|
|
669
|
+
|
|
620
670
|
if (dependency === undefined) {
|
|
621
671
|
// allow the dependency to be missing if optional
|
|
622
672
|
if (optional || !strict) {
|
|
@@ -624,13 +674,10 @@ const gatherDependency = async (
|
|
|
624
674
|
}
|
|
625
675
|
throw Error(`Cannot find dependency ${name} for ${packageLocation}`);
|
|
626
676
|
}
|
|
677
|
+
|
|
627
678
|
dependencyLocations[name] = dependency.packageLocation;
|
|
628
679
|
|
|
629
|
-
logicalPathGraph.addEdge(
|
|
630
|
-
packageLocation,
|
|
631
|
-
dependency.packageLocation,
|
|
632
|
-
calculatePackageWeight(name),
|
|
633
|
-
);
|
|
680
|
+
logicalPathGraph.addEdge(packageLocation, dependency.packageLocation);
|
|
634
681
|
|
|
635
682
|
await graphPackage(
|
|
636
683
|
name,
|
|
@@ -645,8 +692,9 @@ const gatherDependency = async (
|
|
|
645
692
|
logicalPathGraph,
|
|
646
693
|
{
|
|
647
694
|
commonDependencyDescriptors,
|
|
648
|
-
logicalPath: childLogicalPath,
|
|
649
695
|
log,
|
|
696
|
+
packageDependenciesHook,
|
|
697
|
+
policy,
|
|
650
698
|
},
|
|
651
699
|
);
|
|
652
700
|
};
|
|
@@ -669,7 +717,7 @@ const gatherDependency = async (
|
|
|
669
717
|
* @param {LanguageOptions} languageOptions
|
|
670
718
|
* @param {boolean} strict
|
|
671
719
|
* @param {LogicalPathGraph} logicalPathGraph
|
|
672
|
-
* @param {GraphPackagesOptions}
|
|
720
|
+
* @param {GraphPackagesOptions} options
|
|
673
721
|
* @returns {Promise<Graph>}
|
|
674
722
|
*/
|
|
675
723
|
const graphPackages = async (
|
|
@@ -683,7 +731,7 @@ const graphPackages = async (
|
|
|
683
731
|
languageOptions,
|
|
684
732
|
strict,
|
|
685
733
|
logicalPathGraph,
|
|
686
|
-
{ log = noop } = {},
|
|
734
|
+
{ log = noop, packageDependenciesHook, policy } = {},
|
|
687
735
|
) => {
|
|
688
736
|
const memo = create(null);
|
|
689
737
|
/**
|
|
@@ -749,6 +797,8 @@ const graphPackages = async (
|
|
|
749
797
|
{
|
|
750
798
|
commonDependencyDescriptors,
|
|
751
799
|
log,
|
|
800
|
+
packageDependenciesHook,
|
|
801
|
+
policy,
|
|
752
802
|
},
|
|
753
803
|
);
|
|
754
804
|
return graph;
|
|
@@ -763,19 +813,101 @@ const graphPackages = async (
|
|
|
763
813
|
* @param {Graph} graph
|
|
764
814
|
* @param {Set<string>} conditions - build conditions about the target environment
|
|
765
815
|
* for selecting relevant exports, e.g., "browser" or "node".
|
|
766
|
-
* @param {
|
|
767
|
-
* @returns {
|
|
816
|
+
* @param {TranslateGraphOptions} [options]
|
|
817
|
+
* @returns {PackageCompartmentMapDescriptor}
|
|
768
818
|
*/
|
|
769
819
|
const translateGraph = (
|
|
770
820
|
entryPackageLocation,
|
|
771
821
|
entryModuleSpecifier,
|
|
772
822
|
graph,
|
|
773
823
|
conditions,
|
|
774
|
-
policy,
|
|
824
|
+
{ policy, log = noop, packageDependenciesHook } = {},
|
|
775
825
|
) => {
|
|
776
|
-
/** @type {
|
|
826
|
+
/** @type {Record<PackageCompartmentDescriptorName, PackageCompartmentDescriptor>} */
|
|
777
827
|
const compartments = create(null);
|
|
778
828
|
|
|
829
|
+
/**
|
|
830
|
+
* Execute package dependencies hooks: default first (if policy exists), then user-provided.
|
|
831
|
+
*
|
|
832
|
+
* @param {CanonicalName} label
|
|
833
|
+
* @param {Record<string, FileUrlString>} dependencyLocations
|
|
834
|
+
* @returns {Record<string, FileUrlString>}
|
|
835
|
+
*/
|
|
836
|
+
const executePackageDependenciesHook = (label, dependencyLocations) => {
|
|
837
|
+
const dependencies = new Set(
|
|
838
|
+
values(dependencyLocations).map(
|
|
839
|
+
dependencyLocation => graph[dependencyLocation].label,
|
|
840
|
+
),
|
|
841
|
+
);
|
|
842
|
+
|
|
843
|
+
const packageDependenciesHookInput = {
|
|
844
|
+
canonicalName: label,
|
|
845
|
+
dependencies: new Set(dependencies),
|
|
846
|
+
log,
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
// Call default filter first if policy exists
|
|
850
|
+
let packageDependenciesHookResult;
|
|
851
|
+
if (policy) {
|
|
852
|
+
packageDependenciesHookResult = prePackageDependenciesFilter(
|
|
853
|
+
packageDependenciesHookInput,
|
|
854
|
+
policy,
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Then call user-provided hook if it exists
|
|
859
|
+
if (packageDependenciesHook) {
|
|
860
|
+
const userResult = packageDependenciesHook(packageDependenciesHookInput);
|
|
861
|
+
// If user hook also returned a result, use it (overrides default)
|
|
862
|
+
if (userResult?.dependencies) {
|
|
863
|
+
packageDependenciesHookResult = userResult;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// if "dependencies" are in here, then something changed the list.
|
|
868
|
+
if (packageDependenciesHookResult?.dependencies) {
|
|
869
|
+
const size = packageDependenciesHookResult.dependencies.size;
|
|
870
|
+
if (typeof size === 'number' && size > 0) {
|
|
871
|
+
// because the list of dependencies contains canonical names, we need to lookup any new ones.
|
|
872
|
+
const nodesByCanonicalName = new Map(
|
|
873
|
+
entries(graph).map(([location, node]) => [
|
|
874
|
+
node.label,
|
|
875
|
+
{
|
|
876
|
+
...node,
|
|
877
|
+
packageLocation: /** @type {FileUrlString} */ (location),
|
|
878
|
+
},
|
|
879
|
+
]),
|
|
880
|
+
);
|
|
881
|
+
|
|
882
|
+
/** @type {typeof dependencyLocations} */
|
|
883
|
+
const newDependencyLocations = {};
|
|
884
|
+
try {
|
|
885
|
+
for (const label of packageDependenciesHookResult.dependencies) {
|
|
886
|
+
const { name, packageLocation } =
|
|
887
|
+
nodesByCanonicalName.get(label) ?? create(null);
|
|
888
|
+
if (name && packageLocation) {
|
|
889
|
+
newDependencyLocations[name] = packageLocation;
|
|
890
|
+
} else {
|
|
891
|
+
log(
|
|
892
|
+
`WARNING: packageDependencies hook returned unknown package with label ${q(label)}`,
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return newDependencyLocations;
|
|
897
|
+
} catch {
|
|
898
|
+
log(
|
|
899
|
+
`WARNING: packageDependencies hook returned invalid value ${q(
|
|
900
|
+
packageDependenciesHookResult,
|
|
901
|
+
)}; using original dependencies`,
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
} else {
|
|
905
|
+
dependencyLocations = create(null);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return dependencyLocations;
|
|
909
|
+
};
|
|
910
|
+
|
|
779
911
|
// For each package, build a map of all the external modules the package can
|
|
780
912
|
// import from other packages.
|
|
781
913
|
// The keys of this map are the full specifiers of those modules from the
|
|
@@ -785,36 +917,25 @@ const translateGraph = (
|
|
|
785
917
|
// The full map includes every exported module from every dependencey
|
|
786
918
|
// package and is a complete list of every external module that the
|
|
787
919
|
// corresponding compartment can import.
|
|
788
|
-
for (const dependeeLocation of
|
|
920
|
+
for (const dependeeLocation of /** @type {PackageCompartmentDescriptorName[]} */ (
|
|
921
|
+
keys(graph).sort()
|
|
922
|
+
)) {
|
|
789
923
|
const {
|
|
790
924
|
name,
|
|
791
|
-
path,
|
|
792
925
|
label,
|
|
793
926
|
sourceDirname,
|
|
794
|
-
dependencyLocations,
|
|
795
927
|
internalAliases,
|
|
928
|
+
patterns,
|
|
796
929
|
parsers,
|
|
797
930
|
types,
|
|
931
|
+
packageDescriptor,
|
|
798
932
|
} = graph[dependeeLocation];
|
|
799
|
-
/** @type {
|
|
933
|
+
/** @type {Record<string, CompartmentModuleConfiguration>} */
|
|
800
934
|
const moduleDescriptors = create(null);
|
|
801
|
-
/** @type {
|
|
935
|
+
/** @type {Record<string, ScopeDescriptor<PackageCompartmentDescriptorName>>} */
|
|
802
936
|
const scopes = create(null);
|
|
803
937
|
|
|
804
|
-
|
|
805
|
-
* List of all the compartments (by name) that this compartment can import from.
|
|
806
|
-
*
|
|
807
|
-
* @type {Set<string>}
|
|
808
|
-
*/
|
|
809
|
-
const compartmentNames = new Set();
|
|
810
|
-
const packagePolicy = getPolicyForPackage(
|
|
811
|
-
{
|
|
812
|
-
isEntry: dependeeLocation === entryPackageLocation,
|
|
813
|
-
name,
|
|
814
|
-
path,
|
|
815
|
-
},
|
|
816
|
-
policy,
|
|
817
|
-
);
|
|
938
|
+
const packagePolicy = makePackagePolicy(label, { policy });
|
|
818
939
|
|
|
819
940
|
/* c8 ignore next */
|
|
820
941
|
if (policy && !packagePolicy) {
|
|
@@ -822,33 +943,50 @@ const translateGraph = (
|
|
|
822
943
|
throw new TypeError('Unexpectedly falsy package policy');
|
|
823
944
|
}
|
|
824
945
|
|
|
946
|
+
let dependencyLocations = graph[dependeeLocation].dependencyLocations;
|
|
947
|
+
dependencyLocations = executePackageDependenciesHook(
|
|
948
|
+
label,
|
|
949
|
+
dependencyLocations,
|
|
950
|
+
);
|
|
951
|
+
|
|
825
952
|
/**
|
|
826
953
|
* @param {string} dependencyName
|
|
827
|
-
* @param {
|
|
954
|
+
* @param {PackageCompartmentDescriptorName} packageLocation
|
|
828
955
|
*/
|
|
829
956
|
const digestExternalAliases = (dependencyName, packageLocation) => {
|
|
830
|
-
const {
|
|
831
|
-
|
|
957
|
+
const {
|
|
958
|
+
externalAliases,
|
|
959
|
+
explicitExports,
|
|
960
|
+
patterns: dependencyPatterns,
|
|
961
|
+
} = graph[packageLocation];
|
|
832
962
|
for (const exportPath of keys(externalAliases).sort()) {
|
|
833
963
|
const targetPath = externalAliases[exportPath];
|
|
834
964
|
// dependency name may be different from package's name,
|
|
835
|
-
// as in the case of browser field dependency replacements
|
|
965
|
+
// as in the case of browser field dependency replacements.
|
|
966
|
+
// note that policy still applies
|
|
836
967
|
const localPath = join(dependencyName, exportPath);
|
|
837
|
-
if
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
968
|
+
// if we have policy, this has already been vetted
|
|
969
|
+
moduleDescriptors[localPath] = {
|
|
970
|
+
compartment: packageLocation,
|
|
971
|
+
module: targetPath,
|
|
972
|
+
};
|
|
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
|
+
}
|
|
852
990
|
}
|
|
853
991
|
}
|
|
854
992
|
// if the exports field is not present, then all modules must be accessible
|
|
@@ -864,7 +1002,6 @@ const translateGraph = (
|
|
|
864
1002
|
for (const dependencyName of keys(dependencyLocations).sort()) {
|
|
865
1003
|
const dependencyLocation = dependencyLocations[dependencyName];
|
|
866
1004
|
digestExternalAliases(dependencyName, dependencyLocation);
|
|
867
|
-
compartmentNames.add(dependencyLocation);
|
|
868
1005
|
}
|
|
869
1006
|
// digest own internal aliases
|
|
870
1007
|
for (const modulePath of keys(internalAliases).sort()) {
|
|
@@ -881,17 +1018,17 @@ const translateGraph = (
|
|
|
881
1018
|
}
|
|
882
1019
|
|
|
883
1020
|
compartments[dependeeLocation] = {
|
|
1021
|
+
version: packageDescriptor.version ? packageDescriptor.version : '',
|
|
884
1022
|
label,
|
|
885
1023
|
name,
|
|
886
|
-
path,
|
|
887
1024
|
location: dependeeLocation,
|
|
888
1025
|
sourceDirname,
|
|
889
1026
|
modules: moduleDescriptors,
|
|
890
1027
|
scopes,
|
|
1028
|
+
...(patterns.length > 0 ? { patterns } : {}),
|
|
891
1029
|
parsers,
|
|
892
1030
|
types,
|
|
893
1031
|
policy: /** @type {SomePackagePolicy} */ (packagePolicy),
|
|
894
|
-
compartments: compartmentNames,
|
|
895
1032
|
};
|
|
896
1033
|
}
|
|
897
1034
|
|
|
@@ -900,7 +1037,7 @@ const translateGraph = (
|
|
|
900
1037
|
// https://github.com/endojs/endo/issues/2388
|
|
901
1038
|
tags: [...conditions],
|
|
902
1039
|
entry: {
|
|
903
|
-
compartment: entryPackageLocation,
|
|
1040
|
+
compartment: /** @type {FileUrlString} */ (entryPackageLocation),
|
|
904
1041
|
module: entryModuleSpecifier,
|
|
905
1042
|
},
|
|
906
1043
|
compartments,
|
|
@@ -974,23 +1111,200 @@ const makeLanguageOptions = ({
|
|
|
974
1111
|
workspaceModuleLanguageForExtension,
|
|
975
1112
|
};
|
|
976
1113
|
};
|
|
1114
|
+
/**
|
|
1115
|
+
* Creates a `Node` in `graph` corresponding to the "attenuators" Compartment.
|
|
1116
|
+
*
|
|
1117
|
+
* Only does so if `policy` is provided.
|
|
1118
|
+
*
|
|
1119
|
+
* @param {Graph} graph Graph
|
|
1120
|
+
* @param {Node} entryNode Entry node of the grpah
|
|
1121
|
+
* @param {SomePolicy} [policy]
|
|
1122
|
+
* @throws If there's already a `Node` in `graph` for the "attenuators"
|
|
1123
|
+
* Compartment
|
|
1124
|
+
* @returns {void}
|
|
1125
|
+
*/
|
|
1126
|
+
const makeAttenuatorsNode = (graph, entryNode, policy) => {
|
|
1127
|
+
if (policy) {
|
|
1128
|
+
assertPolicy(policy);
|
|
1129
|
+
|
|
1130
|
+
assert(
|
|
1131
|
+
graph[ATTENUATORS_COMPARTMENT] === undefined,
|
|
1132
|
+
`${q(ATTENUATORS_COMPARTMENT)} is a reserved compartment name`,
|
|
1133
|
+
);
|
|
1134
|
+
|
|
1135
|
+
graph[ATTENUATORS_COMPARTMENT] = {
|
|
1136
|
+
...entryNode,
|
|
1137
|
+
internalAliases: {},
|
|
1138
|
+
externalAliases: {},
|
|
1139
|
+
packageDescriptor: { name: ATTENUATORS_COMPARTMENT },
|
|
1140
|
+
name: ATTENUATORS_COMPARTMENT,
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* Transforms a `Graph` into a readonly `FinalGraph`, in preparation for
|
|
1147
|
+
* conversion to a `CompartmentDescriptor`.
|
|
1148
|
+
*
|
|
1149
|
+
* @param {Graph} graph Graph
|
|
1150
|
+
* @param {LogicalPathGraph} logicalPathGraph Logical path graph
|
|
1151
|
+
* @param {FileUrlString} entryPackageLocation Entry package location
|
|
1152
|
+
* @param {CanonicalNameMap} canonicalNameMap Mapping of canonical names to `Node` names (keys in `graph`)
|
|
1153
|
+
* @returns {Readonly<FinalGraph>}
|
|
1154
|
+
*/
|
|
1155
|
+
const finalizeGraph = (
|
|
1156
|
+
graph,
|
|
1157
|
+
logicalPathGraph,
|
|
1158
|
+
entryPackageLocation,
|
|
1159
|
+
canonicalNameMap,
|
|
1160
|
+
) => {
|
|
1161
|
+
const shortestPath = makeShortestPath(logicalPathGraph);
|
|
1162
|
+
|
|
1163
|
+
// neither the entry package nor the attenuators compartment have a path; omit
|
|
1164
|
+
const {
|
|
1165
|
+
[ATTENUATORS_COMPARTMENT]: attenuatorsNode,
|
|
1166
|
+
[entryPackageLocation]: entryNode,
|
|
1167
|
+
...subgraph
|
|
1168
|
+
} = graph;
|
|
1169
|
+
|
|
1170
|
+
/** @type {FinalGraph} */
|
|
1171
|
+
const finalGraph = create(null);
|
|
1172
|
+
|
|
1173
|
+
/** @type {Readonly<FinalNode>} */
|
|
1174
|
+
finalGraph[entryPackageLocation] = freeze({
|
|
1175
|
+
...entryNode,
|
|
1176
|
+
label: generateCanonicalName({
|
|
1177
|
+
isEntry: true,
|
|
1178
|
+
path: [],
|
|
1179
|
+
}),
|
|
1180
|
+
});
|
|
1181
|
+
|
|
1182
|
+
canonicalNameMap.set(ENTRY_COMPARTMENT, entryPackageLocation);
|
|
1183
|
+
|
|
1184
|
+
if (attenuatorsNode) {
|
|
1185
|
+
/** @type {Readonly<FinalNode>} */
|
|
1186
|
+
finalGraph[ATTENUATORS_COMPARTMENT] = freeze({
|
|
1187
|
+
...attenuatorsNode,
|
|
1188
|
+
label: generateCanonicalName({
|
|
1189
|
+
name: ATTENUATORS_COMPARTMENT,
|
|
1190
|
+
path: [],
|
|
1191
|
+
}),
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
const subgraphEntries = /** @type {[FileUrlString, Node][]} */ (
|
|
1196
|
+
entries(subgraph)
|
|
1197
|
+
);
|
|
1198
|
+
|
|
1199
|
+
for (const [location, node] of subgraphEntries) {
|
|
1200
|
+
const shortestLogicalPath = shortestPath(entryPackageLocation, location);
|
|
1201
|
+
|
|
1202
|
+
// the first element will always be the root package location; this is omitted from the path.
|
|
1203
|
+
shortestLogicalPath.shift();
|
|
1204
|
+
|
|
1205
|
+
const path = shortestLogicalPath.map(location => graph[location].name);
|
|
1206
|
+
const canonicalName = generateCanonicalName({ path });
|
|
1207
|
+
|
|
1208
|
+
/** @type {Readonly<FinalNode>} */
|
|
1209
|
+
const finalNode = freeze({
|
|
1210
|
+
...node,
|
|
1211
|
+
label: canonicalName,
|
|
1212
|
+
});
|
|
1213
|
+
|
|
1214
|
+
canonicalNameMap.set(canonicalName, location);
|
|
1215
|
+
|
|
1216
|
+
finalGraph[location] = finalNode;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
for (const node of values(finalGraph)) {
|
|
1220
|
+
Object.freeze(node);
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
return freeze(finalGraph);
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* Returns an array of "issue" objects if any resources referenced in `policy`
|
|
1228
|
+
* are unknown.
|
|
1229
|
+
*
|
|
1230
|
+
* @param {Set<CanonicalName>} canonicalNames Set of all known canonical names
|
|
1231
|
+
* @param {SomePolicy} policy Policy to validate
|
|
1232
|
+
* @returns {Array<{canonicalName: CanonicalName, message: string, path:
|
|
1233
|
+
* string[], suggestion?: CanonicalName}>} Array of issue objects, or `undefined` if no issues were
|
|
1234
|
+
* found
|
|
1235
|
+
*/
|
|
1236
|
+
const validatePolicyResources = (canonicalNames, policy) => {
|
|
1237
|
+
/**
|
|
1238
|
+
* Finds a suggestion for `badName` if it is a suffix of any
|
|
1239
|
+
* canonical name in `canonicalNames`.
|
|
1240
|
+
*
|
|
1241
|
+
* @param {string} badName Unknown canonical name
|
|
1242
|
+
* @returns {CanonicalName | undefined}
|
|
1243
|
+
*/
|
|
1244
|
+
const findSuggestion = badName => {
|
|
1245
|
+
for (const canonicalName of canonicalNames) {
|
|
1246
|
+
if (canonicalName.endsWith(`>${badName}`)) {
|
|
1247
|
+
return canonicalName;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
return undefined;
|
|
1251
|
+
};
|
|
1252
|
+
|
|
1253
|
+
/** @type {Array<{canonicalName: CanonicalName, message: string, path: string[], suggestion?: CanonicalName}>} */
|
|
1254
|
+
const issues = [];
|
|
1255
|
+
for (const [resourceName, resourcePolicy] of entries(
|
|
1256
|
+
policy.resources ?? {},
|
|
1257
|
+
)) {
|
|
1258
|
+
if (!canonicalNames.has(resourceName)) {
|
|
1259
|
+
const issueMessage = `Resource ${q(resourceName)} was not found`;
|
|
1260
|
+
const suggestion = findSuggestion(resourceName);
|
|
1261
|
+
const issue = {
|
|
1262
|
+
canonicalName: resourceName,
|
|
1263
|
+
message: issueMessage,
|
|
1264
|
+
path: ['resources', resourceName],
|
|
1265
|
+
};
|
|
1266
|
+
if (suggestion) {
|
|
1267
|
+
issue.suggestion = suggestion;
|
|
1268
|
+
}
|
|
1269
|
+
issues.push(issue);
|
|
1270
|
+
}
|
|
1271
|
+
if (typeof resourcePolicy?.packages === 'object') {
|
|
1272
|
+
for (const packageName of keys(resourcePolicy.packages)) {
|
|
1273
|
+
if (!canonicalNames.has(packageName)) {
|
|
1274
|
+
const issueMessage = `Resource ${q(packageName)} from resource ${q(resourceName)} was not found`;
|
|
1275
|
+
const suggestion = findSuggestion(packageName);
|
|
1276
|
+
const issue = {
|
|
1277
|
+
canonicalName: packageName,
|
|
1278
|
+
message: issueMessage,
|
|
1279
|
+
path: ['resources', resourceName, 'packages', packageName],
|
|
1280
|
+
};
|
|
1281
|
+
if (suggestion) {
|
|
1282
|
+
issue.suggestion = suggestion;
|
|
1283
|
+
}
|
|
1284
|
+
issues.push(issue);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
return issues;
|
|
1291
|
+
};
|
|
977
1292
|
|
|
978
1293
|
/**
|
|
979
1294
|
* @param {ReadFn | ReadPowers<FileUrlString> | MaybeReadPowers<FileUrlString>} readPowers
|
|
980
|
-
* @param {FileUrlString}
|
|
1295
|
+
* @param {FileUrlString} entryPackageLocation
|
|
981
1296
|
* @param {Set<string>} conditionsOption
|
|
982
1297
|
* @param {PackageDescriptor} packageDescriptor
|
|
983
|
-
* @param {string}
|
|
1298
|
+
* @param {string} entryModuleSpecifier
|
|
984
1299
|
* @param {CompartmentMapForNodeModulesOptions} [options]
|
|
985
|
-
* @returns {Promise<
|
|
986
|
-
* @deprecated Use {@link mapNodeModules} instead.
|
|
1300
|
+
* @returns {Promise<PackageCompartmentMapDescriptor>}
|
|
987
1301
|
*/
|
|
988
|
-
export const
|
|
1302
|
+
export const compartmentMapForNodeModules_ = async (
|
|
989
1303
|
readPowers,
|
|
990
|
-
|
|
1304
|
+
entryPackageLocation,
|
|
991
1305
|
conditionsOption,
|
|
992
1306
|
packageDescriptor,
|
|
993
|
-
|
|
1307
|
+
entryModuleSpecifier,
|
|
994
1308
|
options = {},
|
|
995
1309
|
) => {
|
|
996
1310
|
const {
|
|
@@ -999,6 +1313,9 @@ export const compartmentMapForNodeModules = async (
|
|
|
999
1313
|
policy,
|
|
1000
1314
|
strict = false,
|
|
1001
1315
|
log = noop,
|
|
1316
|
+
unknownCanonicalNameHook,
|
|
1317
|
+
packageDataHook,
|
|
1318
|
+
packageDependenciesHook,
|
|
1002
1319
|
} = options;
|
|
1003
1320
|
const { maybeRead, canonical } = unpackReadPowers(readPowers);
|
|
1004
1321
|
const languageOptions = makeLanguageOptions(options);
|
|
@@ -1021,7 +1338,7 @@ export const compartmentMapForNodeModules = async (
|
|
|
1021
1338
|
const graph = await graphPackages(
|
|
1022
1339
|
maybeRead,
|
|
1023
1340
|
canonical,
|
|
1024
|
-
|
|
1341
|
+
entryPackageLocation,
|
|
1025
1342
|
conditions,
|
|
1026
1343
|
packageDescriptor,
|
|
1027
1344
|
dev || (conditions && conditions.has('development')),
|
|
@@ -1029,52 +1346,76 @@ export const compartmentMapForNodeModules = async (
|
|
|
1029
1346
|
languageOptions,
|
|
1030
1347
|
strict,
|
|
1031
1348
|
logicalPathGraph,
|
|
1032
|
-
{ log },
|
|
1349
|
+
{ log, policy, packageDependenciesHook },
|
|
1033
1350
|
);
|
|
1034
1351
|
|
|
1035
|
-
|
|
1036
|
-
assertPolicy(policy);
|
|
1037
|
-
|
|
1038
|
-
assert(
|
|
1039
|
-
graph[ATTENUATORS_COMPARTMENT] === undefined,
|
|
1040
|
-
`${q(ATTENUATORS_COMPARTMENT)} is a reserved compartment name`,
|
|
1041
|
-
);
|
|
1352
|
+
makeAttenuatorsNode(graph, graph[entryPackageLocation], policy);
|
|
1042
1353
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
name: ATTENUATORS_COMPARTMENT,
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1354
|
+
/**
|
|
1355
|
+
* @type {CanonicalNameMap}
|
|
1356
|
+
*/
|
|
1357
|
+
const canonicalNameMap = new Map();
|
|
1050
1358
|
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
} = graph;
|
|
1359
|
+
const finalGraph = finalizeGraph(
|
|
1360
|
+
graph,
|
|
1361
|
+
logicalPathGraph,
|
|
1362
|
+
entryPackageLocation,
|
|
1363
|
+
canonicalNameMap,
|
|
1364
|
+
);
|
|
1058
1365
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
);
|
|
1366
|
+
// if policy exists, cross-reference the policy "resources" against the list
|
|
1367
|
+
// of known canonical names and fire the `unknownCanonicalName` hook for each
|
|
1368
|
+
// unknown resource, if found
|
|
1369
|
+
if (policy) {
|
|
1370
|
+
const canonicalNames = new Set(canonicalNameMap.keys());
|
|
1371
|
+
const issues = validatePolicyResources(canonicalNames, policy) ?? [];
|
|
1372
|
+
// Call default handler first if policy exists
|
|
1373
|
+
for (const { message, canonicalName, path, suggestion } of issues) {
|
|
1374
|
+
const hookInput = {
|
|
1375
|
+
canonicalName,
|
|
1376
|
+
message,
|
|
1377
|
+
path,
|
|
1378
|
+
log,
|
|
1379
|
+
};
|
|
1380
|
+
if (suggestion) {
|
|
1381
|
+
hookInput.suggestion = suggestion;
|
|
1382
|
+
}
|
|
1383
|
+
defaultUnknownCanonicalNameHandler(hookInput);
|
|
1384
|
+
// Then call user-provided hook if it exists
|
|
1385
|
+
if (unknownCanonicalNameHook) {
|
|
1386
|
+
unknownCanonicalNameHook(hookInput);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1065
1390
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1391
|
+
// Fire packageData hook with all package data before translateGraph
|
|
1392
|
+
if (packageDataHook) {
|
|
1393
|
+
const packageData =
|
|
1394
|
+
/** @type {Map<PackageCompartmentDescriptorName, PackageData>} */ (
|
|
1395
|
+
new Map(
|
|
1396
|
+
values(finalGraph).map(node => [
|
|
1397
|
+
node.label,
|
|
1398
|
+
{
|
|
1399
|
+
name: node.name,
|
|
1400
|
+
packageDescriptor: node.packageDescriptor,
|
|
1401
|
+
location: node.location,
|
|
1402
|
+
canonicalName: node.label,
|
|
1403
|
+
},
|
|
1404
|
+
]),
|
|
1405
|
+
)
|
|
1406
|
+
);
|
|
1407
|
+
packageDataHook({
|
|
1408
|
+
packageData,
|
|
1409
|
+
log,
|
|
1410
|
+
});
|
|
1070
1411
|
}
|
|
1071
1412
|
|
|
1072
1413
|
const compartmentMap = translateGraph(
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1414
|
+
entryPackageLocation,
|
|
1415
|
+
entryModuleSpecifier,
|
|
1416
|
+
finalGraph,
|
|
1076
1417
|
conditions,
|
|
1077
|
-
policy,
|
|
1418
|
+
{ policy, log, packageDependenciesHook },
|
|
1078
1419
|
);
|
|
1079
1420
|
|
|
1080
1421
|
return compartmentMap;
|
|
@@ -1089,12 +1430,21 @@ export const compartmentMapForNodeModules = async (
|
|
|
1089
1430
|
* @param {ReadFn | ReadPowers<FileUrlString> | MaybeReadPowers<FileUrlString>} readPowers
|
|
1090
1431
|
* @param {string} moduleLocation
|
|
1091
1432
|
* @param {MapNodeModulesOptions} [options]
|
|
1092
|
-
* @returns {Promise<
|
|
1433
|
+
* @returns {Promise<PackageCompartmentMapDescriptor>}
|
|
1093
1434
|
*/
|
|
1094
1435
|
export const mapNodeModules = async (
|
|
1095
1436
|
readPowers,
|
|
1096
1437
|
moduleLocation,
|
|
1097
|
-
{
|
|
1438
|
+
{
|
|
1439
|
+
tags = new Set(),
|
|
1440
|
+
conditions = tags,
|
|
1441
|
+
log = noop,
|
|
1442
|
+
unknownCanonicalNameHook,
|
|
1443
|
+
packageDataHook,
|
|
1444
|
+
packageDependenciesHook,
|
|
1445
|
+
policy,
|
|
1446
|
+
...otherOptions
|
|
1447
|
+
} = {},
|
|
1098
1448
|
) => {
|
|
1099
1449
|
const {
|
|
1100
1450
|
packageLocation,
|
|
@@ -1110,12 +1460,24 @@ export const mapNodeModules = async (
|
|
|
1110
1460
|
assertPackageDescriptor(packageDescriptor);
|
|
1111
1461
|
assertFileUrlString(packageLocation);
|
|
1112
1462
|
|
|
1113
|
-
return
|
|
1463
|
+
return compartmentMapForNodeModules_(
|
|
1114
1464
|
readPowers,
|
|
1115
1465
|
packageLocation,
|
|
1116
1466
|
conditions,
|
|
1117
1467
|
packageDescriptor,
|
|
1118
1468
|
moduleSpecifier,
|
|
1119
|
-
{
|
|
1469
|
+
{
|
|
1470
|
+
log,
|
|
1471
|
+
policy,
|
|
1472
|
+
unknownCanonicalNameHook,
|
|
1473
|
+
packageDependenciesHook,
|
|
1474
|
+
packageDataHook,
|
|
1475
|
+
...otherOptions,
|
|
1476
|
+
},
|
|
1120
1477
|
);
|
|
1121
1478
|
};
|
|
1479
|
+
|
|
1480
|
+
/**
|
|
1481
|
+
* @deprecated Use {@link mapNodeModules} instead.
|
|
1482
|
+
*/
|
|
1483
|
+
export const compartmentMapForNodeModules = compartmentMapForNodeModules_;
|