@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.
Files changed (95) hide show
  1. package/package.json +24 -14
  2. package/src/archive-lite.d.ts +7 -7
  3. package/src/archive-lite.d.ts.map +1 -1
  4. package/src/archive-lite.js +81 -30
  5. package/src/archive.d.ts.map +1 -1
  6. package/src/archive.js +7 -0
  7. package/src/bundle-lite.d.ts +3 -3
  8. package/src/bundle-lite.d.ts.map +1 -1
  9. package/src/bundle-lite.js +19 -24
  10. package/src/bundle.d.ts +3 -3
  11. package/src/bundle.d.ts.map +1 -1
  12. package/src/bundle.js +19 -24
  13. package/src/capture-lite.d.ts +2 -2
  14. package/src/capture-lite.d.ts.map +1 -1
  15. package/src/capture-lite.js +243 -25
  16. package/src/compartment-map.d.ts +9 -2
  17. package/src/compartment-map.d.ts.map +1 -1
  18. package/src/compartment-map.js +738 -254
  19. package/src/digest.d.ts +22 -2
  20. package/src/digest.d.ts.map +1 -1
  21. package/src/digest.js +180 -57
  22. package/src/generic-graph.d.ts +7 -25
  23. package/src/generic-graph.d.ts.map +1 -1
  24. package/src/generic-graph.js +83 -108
  25. package/src/guards.d.ts +18 -0
  26. package/src/guards.d.ts.map +1 -0
  27. package/src/guards.js +109 -0
  28. package/src/hooks.md +124 -0
  29. package/src/import-archive-lite.d.ts.map +1 -1
  30. package/src/import-archive-lite.js +15 -11
  31. package/src/import-archive.d.ts +5 -19
  32. package/src/import-archive.d.ts.map +1 -1
  33. package/src/import-archive.js +7 -27
  34. package/src/import-hook.d.ts +4 -3
  35. package/src/import-hook.d.ts.map +1 -1
  36. package/src/import-hook.js +140 -70
  37. package/src/import-lite.d.ts +6 -6
  38. package/src/import-lite.d.ts.map +1 -1
  39. package/src/import-lite.js +8 -5
  40. package/src/import.d.ts +3 -3
  41. package/src/import.d.ts.map +1 -1
  42. package/src/import.js +16 -6
  43. package/src/infer-exports.d.ts +4 -2
  44. package/src/infer-exports.d.ts.map +1 -1
  45. package/src/infer-exports.js +172 -23
  46. package/src/link.d.ts +4 -3
  47. package/src/link.d.ts.map +1 -1
  48. package/src/link.js +122 -52
  49. package/src/node-modules.d.ts +4 -3
  50. package/src/node-modules.d.ts.map +1 -1
  51. package/src/node-modules.js +513 -151
  52. package/src/parse-cjs-shared-export-wrapper.d.ts.map +1 -1
  53. package/src/parse-cjs-shared-export-wrapper.js +3 -1
  54. package/src/pattern-replacement.d.ts +6 -0
  55. package/src/pattern-replacement.d.ts.map +1 -0
  56. package/src/pattern-replacement.js +198 -0
  57. package/src/policy-format.d.ts +22 -5
  58. package/src/policy-format.d.ts.map +1 -1
  59. package/src/policy-format.js +342 -108
  60. package/src/policy.d.ts +13 -28
  61. package/src/policy.d.ts.map +1 -1
  62. package/src/policy.js +161 -106
  63. package/src/types/canonical-name.d.ts +97 -0
  64. package/src/types/canonical-name.d.ts.map +1 -0
  65. package/src/types/canonical-name.ts +151 -0
  66. package/src/types/compartment-map-schema.d.ts +121 -35
  67. package/src/types/compartment-map-schema.d.ts.map +1 -1
  68. package/src/types/compartment-map-schema.ts +211 -37
  69. package/src/types/external.d.ts +240 -76
  70. package/src/types/external.d.ts.map +1 -1
  71. package/src/types/external.ts +305 -74
  72. package/src/types/generic-graph.d.ts +8 -2
  73. package/src/types/generic-graph.d.ts.map +1 -1
  74. package/src/types/generic-graph.ts +7 -2
  75. package/src/types/internal.d.ts +31 -50
  76. package/src/types/internal.d.ts.map +1 -1
  77. package/src/types/internal.ts +60 -58
  78. package/src/types/node-modules.d.ts +112 -14
  79. package/src/types/node-modules.d.ts.map +1 -1
  80. package/src/types/node-modules.ts +152 -13
  81. package/src/types/pattern-replacement.d.ts +62 -0
  82. package/src/types/pattern-replacement.d.ts.map +1 -0
  83. package/src/types/pattern-replacement.ts +70 -0
  84. package/src/types/policy-schema.d.ts +26 -11
  85. package/src/types/policy-schema.d.ts.map +1 -1
  86. package/src/types/policy-schema.ts +29 -16
  87. package/src/types/policy.d.ts +6 -2
  88. package/src/types/policy.d.ts.map +1 -1
  89. package/src/types/policy.ts +7 -2
  90. package/src/types/powers.d.ts +11 -9
  91. package/src/types/powers.d.ts.map +1 -1
  92. package/src/types/powers.ts +11 -10
  93. package/src/types/typescript.d.ts +28 -0
  94. package/src/types/typescript.d.ts.map +1 -1
  95. package/src/types/typescript.ts +37 -1
package/src/link.js CHANGED
@@ -13,28 +13,39 @@
13
13
  /**
14
14
  * @import {ModuleMapHook} from 'ses'
15
15
  * @import {
16
- * CompartmentDescriptor,
17
- * CompartmentMapDescriptor,
18
16
  * ImportNowHookMaker,
19
17
  * LinkOptions,
20
18
  * LinkResult,
21
- * ModuleDescriptor,
22
19
  * ParseFn,
23
20
  * AsyncParseFn,
24
21
  * ParserForLanguage,
25
22
  * ParserImplementation,
26
23
  * ShouldDeferError,
24
+ * ScopeDescriptor,
25
+ * CompartmentModuleConfiguration,
26
+ * PackageCompartmentMapDescriptor,
27
+ * FileUrlString,
28
+ * PackageCompartmentDescriptor,
29
+ * FileCompartmentMapDescriptor,
30
+ * FileCompartmentDescriptor,
31
+ * FileModuleConfiguration,
27
32
  * } from './types.js'
33
+ * @import {SubpathReplacer} from './types/pattern-replacement.js'
28
34
  */
29
35
 
30
36
  import { makeMapParsers } from './map-parser.js';
31
37
  import { resolve as resolveFallback } from './node-module-specifier.js';
32
38
  import {
33
- ATTENUATORS_COMPARTMENT,
34
39
  attenuateGlobals,
35
- enforceModulePolicy,
40
+ enforcePolicyByModule,
36
41
  makeDeferredAttenuatorsProvider,
37
42
  } from './policy.js';
43
+ import { ATTENUATORS_COMPARTMENT } from './policy-format.js';
44
+ import {
45
+ isCompartmentModuleConfiguration,
46
+ isExitModuleConfiguration,
47
+ } from './guards.js';
48
+ import { makeMultiSubpathReplacer } from './pattern-replacement.js';
38
49
 
39
50
  const { assign, create, entries, freeze } = Object;
40
51
  const { hasOwnProperty } = Object.prototype;
@@ -47,17 +58,17 @@ const { allSettled } = Promise;
47
58
  */
48
59
  const promiseAllSettled = allSettled.bind(Promise);
49
60
 
50
- const defaultCompartment = Compartment;
51
-
52
- // q, as in quote, for strings in error messages.
53
- const q = JSON.stringify;
61
+ const DefaultCompartment = Compartment;
54
62
 
55
63
  /**
64
+ * TODO: can we just use `Object.hasOwn` instead?
56
65
  * @param {Record<string, unknown>} object
57
66
  * @param {string} key
58
67
  * @returns {boolean}
59
68
  */
60
69
  const has = (object, key) => apply(hasOwnProperty, object, [key]);
70
+ // q, as in quote, for strings in error messages.
71
+ const { quote: q } = assert;
61
72
 
62
73
  /**
63
74
  * For a full, absolute module specifier like "dependency",
@@ -89,11 +100,11 @@ const trimModuleSpecifierPrefix = (moduleSpecifier, prefix) => {
89
100
  * Any module specifier with an absolute prefix should be captured by
90
101
  * the `moduleMap` or `moduleMapHook`.
91
102
  *
92
- * @param {CompartmentDescriptor} compartmentDescriptor
103
+ * @param {FileCompartmentDescriptor|PackageCompartmentDescriptor} compartmentDescriptor
93
104
  * @param {Record<string, Compartment>} compartments
94
- * @param {string} compartmentName
95
- * @param {Record<string, ModuleDescriptor>} moduleDescriptors
96
- * @param {Record<string, ModuleDescriptor>} scopeDescriptors
105
+ * @param {FileUrlString} compartmentName
106
+ * @param {Record<string, FileModuleConfiguration|CompartmentModuleConfiguration>} moduleDescriptors
107
+ * @param {Record<string, ScopeDescriptor<FileUrlString>>} scopeDescriptors
97
108
  * @returns {ModuleMapHook | undefined}
98
109
  */
99
110
  const makeModuleMapHook = (
@@ -103,9 +114,16 @@ const makeModuleMapHook = (
103
114
  moduleDescriptors,
104
115
  scopeDescriptors,
105
116
  ) => {
117
+ // Build pattern matcher once per compartment if patterns exist.
118
+ const { patterns } = /** @type {Partial<PackageCompartmentDescriptor>} */ (
119
+ compartmentDescriptor
120
+ );
121
+ /** @type {SubpathReplacer | null} */
122
+ const matchPattern =
123
+ patterns && patterns.length > 0 ? makeMultiSubpathReplacer(patterns) : null;
124
+
106
125
  /**
107
- * @param {string} moduleSpecifier
108
- * @returns {string | object | undefined}
126
+ * @type {ModuleMapHook}
109
127
  */
110
128
  const moduleMapHook = moduleSpecifier => {
111
129
  compartmentDescriptor.retained = true;
@@ -114,39 +132,90 @@ const makeModuleMapHook = (
114
132
  if (moduleDescriptor !== undefined) {
115
133
  moduleDescriptor.retained = true;
116
134
 
135
+ if (isExitModuleConfiguration(moduleDescriptor)) {
136
+ return undefined;
137
+ }
117
138
  // "foreignCompartmentName" refers to the compartment which
118
139
  // may differ from the current compartment
119
- const {
120
- compartment: foreignCompartmentName = compartmentName,
121
- module: foreignModuleSpecifier,
122
- exit,
123
- } = moduleDescriptor;
124
- if (exit !== undefined) {
125
- return undefined; // fall through to import hook
140
+ if (isCompartmentModuleConfiguration(moduleDescriptor)) {
141
+ const {
142
+ compartment: foreignCompartmentName = compartmentName,
143
+ module: foreignModuleSpecifier,
144
+ } = moduleDescriptor;
145
+ if (foreignModuleSpecifier !== undefined) {
146
+ // archive goes through foreignModuleSpecifier for local modules too
147
+ if (!moduleSpecifier.startsWith('./')) {
148
+ // This code path seems to only be reached on subsequent imports of the same specifier in the same compartment.
149
+ // The check should be redundant and is only left here out of abundance of caution.
150
+ enforcePolicyByModule(moduleSpecifier, compartmentDescriptor, {
151
+ exit: false,
152
+ errorHint:
153
+ 'This check should not be reachable. If you see this error, please file an issue.',
154
+ });
155
+ }
156
+
157
+ const foreignCompartment = compartments[foreignCompartmentName];
158
+ if (foreignCompartment === undefined) {
159
+ throw Error(
160
+ `Cannot import from missing compartment ${q(
161
+ foreignCompartmentName,
162
+ )}}`,
163
+ );
164
+ }
165
+ // actual module descriptor
166
+ return {
167
+ compartment: foreignCompartment,
168
+ namespace: foreignModuleSpecifier,
169
+ };
170
+ }
126
171
  }
127
- if (foreignModuleSpecifier !== undefined) {
128
- // archive goes through foreignModuleSpecifier for local modules too
129
- if (!moduleSpecifier.startsWith('./')) {
130
- // This code path seems to only be reached on subsequent imports of the same specifier in the same compartment.
131
- // The check should be redundant and is only left here out of abundance of caution.
132
- enforceModulePolicy(moduleSpecifier, compartmentDescriptor, {
133
- exit: false,
134
- errorHint:
135
- 'This check should not be reachable. If you see this error, please file an issue.',
136
- });
172
+ }
173
+
174
+ // Check patterns for wildcard matches (before scopes).
175
+ // Patterns may resolve within the same compartment (internal patterns)
176
+ // or to a foreign compartment (dependency export patterns).
177
+ if (matchPattern) {
178
+ const match = matchPattern(moduleSpecifier);
179
+ if (match !== null) {
180
+ const { result: resolvedPath, compartment: foreignCompartmentName } =
181
+ match;
182
+
183
+ // Null result means the specifier is explicitly excluded.
184
+ if (resolvedPath === null) {
185
+ throw Error(
186
+ `Cannot find module ${q(moduleSpecifier)} — excluded by null target pattern in ${q(compartmentName)}`,
187
+ );
137
188
  }
189
+ const targetCompartmentName =
190
+ /** @type {FileUrlString} */
191
+ (foreignCompartmentName || compartmentName);
192
+
193
+ // Write back to moduleDescriptors for caching, archival, and
194
+ // policy enforcement. The write-back must precede the policy
195
+ // check because enforcePolicyByModule verifies the specifier
196
+ // exists in compartmentDescriptor.modules (the same object).
197
+ moduleDescriptors[moduleSpecifier] = {
198
+ retained: true,
199
+ compartment: targetCompartmentName,
200
+ module: resolvedPath,
201
+ __createdBy: 'link-pattern',
202
+ };
138
203
 
139
- const foreignCompartment = compartments[foreignCompartmentName];
140
- if (foreignCompartment === undefined) {
204
+ // Policy enforcement for pattern-matched modules
205
+ enforcePolicyByModule(moduleSpecifier, compartmentDescriptor, {
206
+ exit: false,
207
+ errorHint: `Pattern matched in compartment ${q(compartmentName)}: module specifier ${q(moduleSpecifier)} mapped to ${q(resolvedPath)}`,
208
+ });
209
+
210
+ const targetCompartment = compartments[targetCompartmentName];
211
+ if (targetCompartment === undefined) {
141
212
  throw Error(
142
- `Cannot import from missing compartment ${q(
143
- foreignCompartmentName,
144
- )}}`,
213
+ `Cannot import module specifier ${q(moduleSpecifier)} from missing compartment ${q(targetCompartmentName)}`,
145
214
  );
146
215
  }
147
216
  return {
148
- compartment: foreignCompartment,
149
- namespace: foreignModuleSpecifier,
217
+ compartment: targetCompartment,
218
+ namespace: resolvedPath,
150
219
  };
151
220
  }
152
221
  }
@@ -178,7 +247,7 @@ const makeModuleMapHook = (
178
247
  );
179
248
  }
180
249
 
181
- enforceModulePolicy(scopePrefix, compartmentDescriptor, {
250
+ enforcePolicyByModule(scopePrefix, compartmentDescriptor, {
182
251
  exit: false,
183
252
  errorHint: `Blocked in linking. ${q(
184
253
  moduleSpecifier,
@@ -198,7 +267,9 @@ const makeModuleMapHook = (
198
267
  retained: true,
199
268
  compartment: foreignCompartmentName,
200
269
  module: foreignModuleSpecifier,
270
+ __createdBy: 'link',
201
271
  };
272
+ // actual module descriptor
202
273
  return {
203
274
  compartment: foreignCompartment,
204
275
  namespace: foreignModuleSpecifier,
@@ -236,16 +307,10 @@ const impossibleImportNowHookMaker = () => {
236
307
  * - Passes the given globals and external modules into the root compartment
237
308
  * only.
238
309
  *
239
- * @param {CompartmentMapDescriptor} compartmentMap
310
+ * @param {PackageCompartmentMapDescriptor|FileCompartmentMapDescriptor} compartmentMap
240
311
  * @param {LinkOptions} options
241
312
  * @returns {LinkResult} the root compartment of the compartment DAG
242
313
  */
243
-
244
- /**
245
- * @param {CompartmentMapDescriptor} compartmentMap
246
- * @param {LinkOptions} options
247
- * @returns {LinkResult}
248
- */
249
314
  export const link = (
250
315
  { entry, compartments: compartmentDescriptors },
251
316
  options,
@@ -262,7 +327,7 @@ export const link = (
262
327
  __shimTransforms__ = [],
263
328
  __native__ = false,
264
329
  archiveOnly = false,
265
- Compartment = defaultCompartment,
330
+ Compartment = DefaultCompartment,
266
331
  } = options;
267
332
 
268
333
  const { compartment: entryCompartmentName } = entry;
@@ -291,9 +356,14 @@ export const link = (
291
356
  syncModuleTransforms,
292
357
  });
293
358
 
294
- for (const [compartmentName, compartmentDescriptor] of entries(
295
- compartmentDescriptors,
296
- )) {
359
+ const compartmentDescriptorEntries =
360
+ /** @type {[FileUrlString, PackageCompartmentDescriptor|FileCompartmentDescriptor][]} */ (
361
+ entries(compartmentDescriptors)
362
+ );
363
+ for (const [
364
+ compartmentName,
365
+ compartmentDescriptor,
366
+ ] of compartmentDescriptorEntries) {
297
367
  const {
298
368
  location,
299
369
  name,
@@ -418,7 +488,7 @@ export const link = (
418
488
  };
419
489
 
420
490
  /**
421
- * @param {CompartmentMapDescriptor} compartmentMap
491
+ * @param {PackageCompartmentMapDescriptor} compartmentMap
422
492
  * @param {LinkOptions} options
423
493
  * @deprecated Use {@link link}.
424
494
  */
@@ -1,12 +1,13 @@
1
1
  export function basename(location: string): string;
2
- export function compartmentMapForNodeModules(readPowers: ReadFn | ReadPowers<FileUrlString> | MaybeReadPowers<FileUrlString>, packageLocation: FileUrlString, conditionsOption: Set<string>, packageDescriptor: PackageDescriptor, moduleSpecifier: string, options?: CompartmentMapForNodeModulesOptions): Promise<CompartmentMapDescriptor>;
3
- export function mapNodeModules(readPowers: ReadFn | ReadPowers<FileUrlString> | MaybeReadPowers<FileUrlString>, moduleLocation: string, { tags, conditions, log, ...otherOptions }?: MapNodeModulesOptions): Promise<CompartmentMapDescriptor>;
2
+ export function compartmentMapForNodeModules_(readPowers: ReadFn | ReadPowers<FileUrlString> | MaybeReadPowers<FileUrlString>, entryPackageLocation: FileUrlString, conditionsOption: Set<string>, packageDescriptor: PackageDescriptor, entryModuleSpecifier: string, options?: CompartmentMapForNodeModulesOptions): Promise<PackageCompartmentMapDescriptor>;
3
+ export function mapNodeModules(readPowers: ReadFn | ReadPowers<FileUrlString> | MaybeReadPowers<FileUrlString>, moduleLocation: string, { tags, conditions, log, unknownCanonicalNameHook, packageDataHook, packageDependenciesHook, policy, ...otherOptions }?: MapNodeModulesOptions): Promise<PackageCompartmentMapDescriptor>;
4
+ export function compartmentMapForNodeModules(readPowers: ReadFn | ReadPowers<FileUrlString> | MaybeReadPowers<FileUrlString>, entryPackageLocation: FileUrlString, conditionsOption: Set<string>, packageDescriptor: PackageDescriptor, entryModuleSpecifier: string, options?: CompartmentMapForNodeModulesOptions): Promise<PackageCompartmentMapDescriptor>;
4
5
  import type { ReadFn } from './types.js';
5
6
  import type { FileUrlString } from './types.js';
6
7
  import type { ReadPowers } from './types.js';
7
8
  import type { MaybeReadPowers } from './types.js';
8
9
  import type { PackageDescriptor } from './types.js';
9
10
  import type { CompartmentMapForNodeModulesOptions } from './types.js';
10
- import type { CompartmentMapDescriptor } from './types.js';
11
+ import type { PackageCompartmentMapDescriptor } from './types.js';
11
12
  import type { MapNodeModulesOptions } from './types.js';
12
13
  //# sourceMappingURL=node-modules.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node-modules.d.ts","sourceRoot":"","sources":["node-modules.js"],"names":[],"mappings":"AAyHO,mCAHI,MAAM,GACJ,MAAM,CAYlB;AAw1BM,yDATI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,mBACnE,aAAa,oBACb,GAAG,CAAC,MAAM,CAAC,qBACX,iBAAiB,mBACjB,MAAM,YACN,mCAAmC,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAgG7C;AAaM,2CALI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,kBACnE,MAAM,+CACN,qBAAqB,GACnB,OAAO,CAAC,wBAAwB,CAAC,CA6B7C;4BAnjCS,YAAY;mCAAZ,YAAY;gCAAZ,YAAY;qCAAZ,YAAY;uCAAZ,YAAY;yDAAZ,YAAY;8CAAZ,YAAY;2CAAZ,YAAY"}
1
+ {"version":3,"file":"node-modules.d.ts","sourceRoot":"","sources":["node-modules.js"],"names":[],"mappings":"AA4LO,mCAHI,MAAM,GACJ,MAAM,CAYlB;AA+kCM,0DARI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,wBACnE,aAAa,oBACb,GAAG,CAAC,MAAM,CAAC,qBACX,iBAAiB,wBACjB,MAAM,YACN,mCAAmC,GACjC,OAAO,CAAC,+BAA+B,CAAC,CA0HpD;AAaM,2CALI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,kBACnE,MAAM,2HACN,qBAAqB,GACnB,OAAO,CAAC,+BAA+B,CAAC,CA6CpD;AAhLM,yDARI,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,gBAAgB,aAAa,CAAC,wBACnE,aAAa,oBACb,GAAG,CAAC,MAAM,CAAC,qBACX,iBAAiB,wBACjB,MAAM,YACN,mCAAmC,GACjC,OAAO,CAAC,+BAA+B,CAAC,CA0HpD;4BAt1CS,YAAY;mCAAZ,YAAY;gCAAZ,YAAY;qCAAZ,YAAY;uCAAZ,YAAY;yDAAZ,YAAY;qDAAZ,YAAY;2CAAZ,YAAY"}