@endo/compartment-mapper 1.6.3 → 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.map +1 -1
- package/src/generic-graph.js +8 -3
- 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 +138 -69
- 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/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 +4 -3
- package/src/node-modules.d.ts.map +1 -1
- package/src/node-modules.js +482 -114
- 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 +168 -28
- package/src/types/external.d.ts.map +1 -1
- package/src/types/external.ts +215 -26
- package/src/types/internal.d.ts +23 -42
- package/src/types/internal.d.ts.map +1 -1
- package/src/types/internal.ts +51 -50
- package/src/types/node-modules.d.ts +71 -10
- package/src/types/node-modules.d.ts.map +1 -1
- package/src/types/node-modules.ts +107 -9
- 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/typescript.d.ts +28 -0
- package/src/types/typescript.d.ts.map +1 -1
- package/src/types/typescript.ts +37 -1
package/src/compartment-map.js
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
1
|
/* Validates a compartment map against its schema. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
assertPackagePolicy,
|
|
5
|
+
ATTENUATORS_COMPARTMENT,
|
|
6
|
+
ENTRY_COMPARTMENT,
|
|
7
|
+
} from './policy-format.js';
|
|
4
8
|
|
|
5
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* @import {
|
|
11
|
+
* FileCompartmentDescriptor,
|
|
12
|
+
* FileCompartmentMapDescriptor,
|
|
13
|
+
* FileModuleConfiguration,
|
|
14
|
+
* CompartmentMapDescriptor,
|
|
15
|
+
* EntryDescriptor,
|
|
16
|
+
* ModuleConfiguration,
|
|
17
|
+
* ExitModuleConfiguration,
|
|
18
|
+
* CompartmentModuleConfiguration,
|
|
19
|
+
* CompartmentDescriptor,
|
|
20
|
+
* ScopeDescriptor,
|
|
21
|
+
* BaseModuleConfiguration,
|
|
22
|
+
* DigestedCompartmentMapDescriptor,
|
|
23
|
+
* PackageCompartmentMapDescriptor,
|
|
24
|
+
* PackageCompartmentDescriptor,
|
|
25
|
+
* FileUrlString,
|
|
26
|
+
* LanguageForExtension,
|
|
27
|
+
* LanguageForModuleSpecifier,
|
|
28
|
+
* ModuleConfigurationKind,
|
|
29
|
+
* ModuleConfigurationKindToType,
|
|
30
|
+
* ErrorModuleConfiguration,
|
|
31
|
+
* DigestedCompartmentDescriptor} from './types.js'
|
|
32
|
+
*/
|
|
6
33
|
|
|
7
34
|
// TODO convert to the new `||` assert style.
|
|
8
35
|
// Deferred because this file pervasively uses simple template strings rather than
|
|
9
36
|
// template strings tagged with `assert.details` (aka `X`), and uses
|
|
10
37
|
// this definition of `q` rather than `assert.quote`
|
|
11
38
|
const q = JSON.stringify;
|
|
39
|
+
const { keys, entries } = Object;
|
|
40
|
+
const { isArray } = Array;
|
|
12
41
|
|
|
13
42
|
/** @type {(a: string, b: string) => number} */
|
|
14
43
|
// eslint-disable-next-line no-nested-ternary
|
|
@@ -26,432 +55,886 @@ function* enumerate(iterable) {
|
|
|
26
55
|
}
|
|
27
56
|
}
|
|
28
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Type guard for a string value.
|
|
60
|
+
*
|
|
61
|
+
* @overload
|
|
62
|
+
* @param {unknown} value
|
|
63
|
+
* @param {string} keypath
|
|
64
|
+
* @param {string} url
|
|
65
|
+
* @returns {asserts value is string}
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Type guard for a string value with a custom assertion failure message.
|
|
70
|
+
*
|
|
71
|
+
* @overload
|
|
72
|
+
* @param {unknown} value
|
|
73
|
+
* @param {string} message
|
|
74
|
+
* @returns {asserts value is string}
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Type guard for a string value.
|
|
79
|
+
*
|
|
80
|
+
* @param {unknown} value
|
|
81
|
+
* @param {string} pathOrMessage
|
|
82
|
+
* @param {string} url
|
|
83
|
+
* @returns {asserts value is string}
|
|
84
|
+
*/
|
|
85
|
+
const assertString = (value, pathOrMessage, url) => {
|
|
86
|
+
const keypath = pathOrMessage;
|
|
87
|
+
assert.typeof(
|
|
88
|
+
value,
|
|
89
|
+
'string',
|
|
90
|
+
`${keypath} in ${q(url)} must be a string; got ${q(value)}`,
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Asserts the `label` field valid
|
|
96
|
+
*
|
|
97
|
+
* @param {unknown} allegedLabel
|
|
98
|
+
* @param {string} keypath
|
|
99
|
+
* @param {string} url
|
|
100
|
+
* @returns {asserts alleged is string}
|
|
101
|
+
*/
|
|
102
|
+
const assertLabel = (allegedLabel, keypath, url) => {
|
|
103
|
+
assertString(allegedLabel, keypath, url);
|
|
104
|
+
if (allegedLabel === ATTENUATORS_COMPARTMENT) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (allegedLabel === ENTRY_COMPARTMENT) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
assert(
|
|
111
|
+
/^(?:@[a-z][a-z0-9-.]*\/)?[a-z][a-z0-9-.]*(?:>(?:@[a-z][a-z0-9-.]*\/)?[a-z][a-z0-9-.]*)*$/.test(
|
|
112
|
+
allegedLabel,
|
|
113
|
+
),
|
|
114
|
+
`${keypath} must be a canonical name in ${q(url)}; got ${q(allegedLabel)}`,
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param {unknown} allegedObject
|
|
120
|
+
* @param {string} keypath
|
|
121
|
+
* @param {string} url
|
|
122
|
+
* @returns {asserts allegedObject is Record<PropertyKey, unknown>}
|
|
123
|
+
*/
|
|
124
|
+
const assertPlainObject = (allegedObject, keypath, url) => {
|
|
125
|
+
const object = Object(allegedObject);
|
|
126
|
+
assert(
|
|
127
|
+
object === allegedObject &&
|
|
128
|
+
!isArray(object) &&
|
|
129
|
+
!(typeof object === 'function'),
|
|
130
|
+
`${keypath} must be an object; got ${q(allegedObject)} of type ${q(typeof allegedObject)} in ${q(url)}`,
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
* @param {unknown} value
|
|
137
|
+
* @param {string} keypath
|
|
138
|
+
* @param {string} url
|
|
139
|
+
* @returns {asserts value is boolean}
|
|
140
|
+
*/
|
|
141
|
+
const assertBoolean = (value, keypath, url) => {
|
|
142
|
+
assert.typeof(
|
|
143
|
+
value,
|
|
144
|
+
'boolean',
|
|
145
|
+
`${keypath} in ${q(url)} must be a boolean; got ${q(value)}`,
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
29
149
|
/**
|
|
30
150
|
* @param {Record<string, unknown>} object
|
|
31
151
|
* @param {string} message
|
|
32
152
|
*/
|
|
33
153
|
const assertEmptyObject = (object, message) => {
|
|
34
|
-
assert(
|
|
154
|
+
assert(keys(object).length === 0, message);
|
|
35
155
|
};
|
|
36
156
|
|
|
37
157
|
/**
|
|
38
158
|
* @param {unknown} conditions
|
|
39
159
|
* @param {string} url
|
|
160
|
+
* @returns {asserts conditions is CompartmentMapDescriptor['tags']}
|
|
40
161
|
*/
|
|
41
162
|
const assertConditions = (conditions, url) => {
|
|
42
163
|
if (conditions === undefined) return;
|
|
43
164
|
assert(
|
|
44
|
-
|
|
45
|
-
`conditions must be an array
|
|
165
|
+
isArray(conditions),
|
|
166
|
+
`conditions must be an array; got ${conditions} in ${q(url)}`,
|
|
46
167
|
);
|
|
47
168
|
for (const [index, value] of enumerate(conditions)) {
|
|
48
|
-
|
|
49
|
-
value,
|
|
50
|
-
'string',
|
|
51
|
-
`conditions[${index}] must be a string, got ${value} in ${q(url)}`,
|
|
52
|
-
);
|
|
169
|
+
assertString(value, `conditions[${index}]`, url);
|
|
53
170
|
}
|
|
54
171
|
};
|
|
55
172
|
|
|
56
173
|
/**
|
|
57
|
-
* @
|
|
58
|
-
* @param {
|
|
174
|
+
* @template {Partial<ModuleConfiguration>} T
|
|
175
|
+
* @param {T} allegedModule
|
|
176
|
+
* @returns {Omit<T, keyof BaseModuleConfiguration>}
|
|
177
|
+
*/
|
|
178
|
+
const getModuleConfigurationSpecificProperties = allegedModule => {
|
|
179
|
+
const {
|
|
180
|
+
__createdBy: _createdBy,
|
|
181
|
+
retained: _retained,
|
|
182
|
+
deferredError: _deferredError,
|
|
183
|
+
...other
|
|
184
|
+
} = allegedModule;
|
|
185
|
+
return other;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
*
|
|
190
|
+
* @param {Record<PropertyKey, unknown>} allegedModule
|
|
191
|
+
* @param {string} keypath
|
|
59
192
|
* @param {string} url
|
|
193
|
+
* @returns {asserts allegedModule is ModuleConfiguration}
|
|
60
194
|
*/
|
|
61
|
-
const
|
|
62
|
-
const {
|
|
195
|
+
const assertBaseModuleConfiguration = (allegedModule, keypath, url) => {
|
|
196
|
+
const { deferredError, retained, createdBy } = allegedModule;
|
|
197
|
+
if (deferredError !== undefined) {
|
|
198
|
+
assertString(deferredError, `${keypath}.deferredError`, url);
|
|
199
|
+
}
|
|
200
|
+
if (retained !== undefined) {
|
|
201
|
+
assertBoolean(retained, `${keypath}.retained`, url);
|
|
202
|
+
}
|
|
203
|
+
if (createdBy !== undefined) {
|
|
204
|
+
assertString(createdBy, `${keypath}.createdBy`, url);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @param {ModuleConfiguration} moduleDescriptor
|
|
210
|
+
* @param {string} keypath
|
|
211
|
+
* @param {string} url
|
|
212
|
+
* @returns {asserts allegedModule is CompartmentModuleConfiguration}
|
|
213
|
+
*/
|
|
214
|
+
const assertCompartmentModuleConfiguration = (
|
|
215
|
+
moduleDescriptor,
|
|
216
|
+
keypath,
|
|
217
|
+
url,
|
|
218
|
+
) => {
|
|
219
|
+
const { compartment, module, ...extra } =
|
|
220
|
+
getModuleConfigurationSpecificProperties(
|
|
221
|
+
/** @type {CompartmentModuleConfiguration} */ (moduleDescriptor),
|
|
222
|
+
);
|
|
63
223
|
assertEmptyObject(
|
|
64
224
|
extra,
|
|
65
|
-
`${
|
|
66
|
-
extra,
|
|
67
|
-
compartment,
|
|
68
|
-
})} in ${q(url)}`,
|
|
225
|
+
`${keypath} must not have extra properties; got ${q(extra)} in ${q(url)}`,
|
|
69
226
|
);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`${path}.compartment must be a string, got ${q(compartment)} in ${q(url)}`,
|
|
74
|
-
);
|
|
75
|
-
assert.typeof(
|
|
76
|
-
module,
|
|
77
|
-
'string',
|
|
78
|
-
`${path}.module must be a string, got ${q(module)} in ${q(url)}`,
|
|
79
|
-
);
|
|
80
|
-
if (retained !== undefined) {
|
|
81
|
-
assert.typeof(
|
|
82
|
-
retained,
|
|
83
|
-
'boolean',
|
|
84
|
-
`${path}.retained must be a boolean, got ${q(retained)} in ${q(url)}`,
|
|
85
|
-
);
|
|
86
|
-
}
|
|
227
|
+
|
|
228
|
+
assertString(compartment, `${keypath}.compartment`, url);
|
|
229
|
+
assertString(module, `${keypath}.module`, url);
|
|
87
230
|
};
|
|
88
231
|
|
|
89
232
|
/**
|
|
90
|
-
* @param {
|
|
91
|
-
* @param {string}
|
|
233
|
+
* @param {ModuleConfiguration} moduleDescriptor
|
|
234
|
+
* @param {string} keypath
|
|
92
235
|
* @param {string} url
|
|
236
|
+
* @returns {asserts allegedModule is FileModuleConfiguration}
|
|
93
237
|
*/
|
|
94
|
-
const
|
|
95
|
-
const { location, parser, sha512, ...extra } =
|
|
238
|
+
const assertFileModuleConfiguration = (moduleDescriptor, keypath, url) => {
|
|
239
|
+
const { location, parser, sha512, ...extra } =
|
|
240
|
+
getModuleConfigurationSpecificProperties(
|
|
241
|
+
/** @type {FileModuleConfiguration} */ (moduleDescriptor),
|
|
242
|
+
);
|
|
96
243
|
assertEmptyObject(
|
|
97
244
|
extra,
|
|
98
|
-
`${
|
|
99
|
-
|
|
245
|
+
`${keypath} must not have extra properties; got ${q(
|
|
246
|
+
keys(extra),
|
|
100
247
|
)} in ${q(url)}`,
|
|
101
248
|
);
|
|
102
|
-
|
|
103
|
-
location,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
);
|
|
107
|
-
assert.typeof(
|
|
108
|
-
parser,
|
|
109
|
-
'string',
|
|
110
|
-
`${path}.parser must be a string, got ${q(parser)} in ${q(url)}`,
|
|
111
|
-
);
|
|
249
|
+
if (location !== undefined) {
|
|
250
|
+
assertString(location, `${keypath}.location`, url);
|
|
251
|
+
}
|
|
252
|
+
assertString(parser, `${keypath}.parser`, url);
|
|
112
253
|
|
|
113
254
|
if (sha512 !== undefined) {
|
|
114
|
-
|
|
115
|
-
sha512,
|
|
116
|
-
'string',
|
|
117
|
-
`${path}.sha512 must be a string, got ${q(sha512)} in ${q(url)}`,
|
|
118
|
-
);
|
|
255
|
+
assertString(sha512, `${keypath}.sha512`, url);
|
|
119
256
|
}
|
|
120
257
|
};
|
|
121
258
|
|
|
122
259
|
/**
|
|
123
|
-
* @param {
|
|
124
|
-
* @param {string}
|
|
260
|
+
* @param {ModuleConfiguration} moduleDescriptor
|
|
261
|
+
* @param {string} keypath
|
|
125
262
|
* @param {string} url
|
|
263
|
+
* @returns {asserts allegedModule is ExitModuleConfiguration}
|
|
126
264
|
*/
|
|
127
|
-
const
|
|
128
|
-
const { exit, ...extra } =
|
|
265
|
+
const assertExitModuleConfiguration = (moduleDescriptor, keypath, url) => {
|
|
266
|
+
const { exit, ...extra } = getModuleConfigurationSpecificProperties(
|
|
267
|
+
/** @type {ExitModuleConfiguration} */ (moduleDescriptor),
|
|
268
|
+
);
|
|
129
269
|
assertEmptyObject(
|
|
130
270
|
extra,
|
|
131
|
-
`${
|
|
132
|
-
|
|
271
|
+
`${keypath} must not have extra properties; got ${q(
|
|
272
|
+
keys(extra),
|
|
133
273
|
)} in ${q(url)}`,
|
|
134
274
|
);
|
|
135
|
-
|
|
136
|
-
exit,
|
|
137
|
-
'string',
|
|
138
|
-
`${path}.exit must be a string, got ${q(exit)} in ${q(url)}`,
|
|
139
|
-
);
|
|
275
|
+
assertString(exit, `${keypath}.exit`, url);
|
|
140
276
|
};
|
|
141
277
|
|
|
142
278
|
/**
|
|
279
|
+
*
|
|
280
|
+
* @param {ModuleConfiguration} moduleDescriptor
|
|
281
|
+
* @param {string} keypath
|
|
282
|
+
* @param {string} url
|
|
283
|
+
* @returns {asserts moduleDescriptor is ErrorModuleConfiguration}
|
|
284
|
+
*/
|
|
285
|
+
const assertErrorModuleConfiguration = (moduleDescriptor, keypath, url) => {
|
|
286
|
+
const { deferredError } = moduleDescriptor;
|
|
287
|
+
if (deferredError) {
|
|
288
|
+
assertString(deferredError, `${keypath}.deferredError`, url);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @template {ModuleConfigurationKind[]} Kinds
|
|
294
|
+
* @overload
|
|
143
295
|
* @param {unknown} allegedModule
|
|
144
|
-
* @param {string}
|
|
296
|
+
* @param {string} keypath
|
|
145
297
|
* @param {string} url
|
|
298
|
+
* @param {Kinds} kinds
|
|
299
|
+
* @returns {asserts allegedModule is ModuleConfigurationKindToType<Kinds>}
|
|
146
300
|
*/
|
|
147
|
-
|
|
148
|
-
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* @overload
|
|
304
|
+
* @param {unknown} allegedModule
|
|
305
|
+
* @param {string} keypath
|
|
306
|
+
* @param {string} url
|
|
307
|
+
* @returns {asserts allegedModule is ModuleConfiguration}
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @param {unknown} allegedModule
|
|
312
|
+
* @param {string} keypath
|
|
313
|
+
* @param {string} url
|
|
314
|
+
* @param {ModuleConfigurationKind[]} kinds
|
|
315
|
+
*/
|
|
316
|
+
function assertModuleConfiguration(allegedModule, keypath, url, kinds) {
|
|
317
|
+
assertPlainObject(allegedModule, keypath, url);
|
|
318
|
+
assertBaseModuleConfiguration(allegedModule, keypath, url);
|
|
319
|
+
|
|
320
|
+
const finalKinds =
|
|
321
|
+
kinds.length > 0
|
|
322
|
+
? kinds
|
|
323
|
+
: /** @type {ModuleConfigurationKind[]} */ ([
|
|
324
|
+
'compartment',
|
|
325
|
+
'file',
|
|
326
|
+
'exit',
|
|
327
|
+
'error',
|
|
328
|
+
]);
|
|
329
|
+
/** @type {Error[]} */
|
|
330
|
+
const errors = [];
|
|
331
|
+
for (const kind of finalKinds) {
|
|
332
|
+
switch (kind) {
|
|
333
|
+
case 'compartment': {
|
|
334
|
+
try {
|
|
335
|
+
assertCompartmentModuleConfiguration(allegedModule, keypath, url);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
errors.push(error);
|
|
338
|
+
}
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
case 'file': {
|
|
342
|
+
try {
|
|
343
|
+
assertFileModuleConfiguration(allegedModule, keypath, url);
|
|
344
|
+
} catch (error) {
|
|
345
|
+
errors.push(error);
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case 'exit': {
|
|
350
|
+
try {
|
|
351
|
+
assertExitModuleConfiguration(allegedModule, keypath, url);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
errors.push(error);
|
|
354
|
+
}
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
case 'error': {
|
|
358
|
+
try {
|
|
359
|
+
assertErrorModuleConfiguration(allegedModule, keypath, url);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
errors.push(error);
|
|
362
|
+
}
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
default:
|
|
366
|
+
throw new TypeError(
|
|
367
|
+
`Unknown module descriptor kind ${q(kind)} in ${q(url)}`,
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
149
372
|
assert(
|
|
150
|
-
|
|
151
|
-
|
|
373
|
+
errors.length < finalKinds.length,
|
|
374
|
+
`invalid module descriptor in ${q(url)} at ${q(keypath)}; expected to match one of ${q(kinds)}: ${errors.map(err => err.message).join('; ')}`,
|
|
152
375
|
);
|
|
376
|
+
}
|
|
153
377
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
`${path}.deferredError must be a string contaiing an error message`,
|
|
378
|
+
/**
|
|
379
|
+
* @param {unknown} allegedModules
|
|
380
|
+
* @param {string} keypath
|
|
381
|
+
* @param {string} url
|
|
382
|
+
* @returns {asserts allegedModules is Record<string, ModuleConfiguration>}
|
|
383
|
+
*/
|
|
384
|
+
const assertModuleConfigurations = (allegedModules, keypath, url) => {
|
|
385
|
+
assertPlainObject(allegedModules, keypath, url);
|
|
386
|
+
for (const [key, value] of entries(allegedModules)) {
|
|
387
|
+
assertString(
|
|
388
|
+
key,
|
|
389
|
+
`all keys of ${keypath}.modules must be strings; got ${key} in ${q(url)}`,
|
|
167
390
|
);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
391
|
+
assertModuleConfiguration(value, `${keypath}.modules[${q(key)}]`, url);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* @param {unknown} allegedModules
|
|
397
|
+
* @param {string} keypath
|
|
398
|
+
* @param {string} url
|
|
399
|
+
* @returns {asserts allegedModules is Record<string, FileModuleConfiguration|CompartmentModuleConfiguration>}
|
|
400
|
+
*/
|
|
401
|
+
const assertFileModuleConfigurations = (allegedModules, keypath, url) => {
|
|
402
|
+
assertPlainObject(allegedModules, keypath, url);
|
|
403
|
+
for (const [key, value] of entries(allegedModules)) {
|
|
404
|
+
assertString(
|
|
405
|
+
key,
|
|
406
|
+
`all keys of ${keypath}.modules must be strings; got ${key} in ${q(url)}`,
|
|
173
407
|
);
|
|
408
|
+
assertModuleConfiguration(value, `${keypath}.modules[${q(key)}]`, url, [
|
|
409
|
+
'file',
|
|
410
|
+
'compartment',
|
|
411
|
+
'error',
|
|
412
|
+
]);
|
|
174
413
|
}
|
|
175
414
|
};
|
|
176
415
|
|
|
177
416
|
/**
|
|
178
417
|
* @param {unknown} allegedModules
|
|
179
|
-
* @param {string}
|
|
418
|
+
* @param {string} keypath
|
|
180
419
|
* @param {string} url
|
|
420
|
+
* @returns {asserts allegedModules is Record<string, ModuleConfiguration>}
|
|
181
421
|
*/
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
422
|
+
const assertDigestedModuleConfigurations = (allegedModules, keypath, url) => {
|
|
423
|
+
assertPlainObject(allegedModules, keypath, url);
|
|
424
|
+
for (const [key, value] of entries(allegedModules)) {
|
|
425
|
+
assertString(
|
|
426
|
+
key,
|
|
427
|
+
`all keys of ${keypath}.modules must be strings; got ${key} in ${q(url)}`,
|
|
428
|
+
);
|
|
429
|
+
assertModuleConfiguration(value, `${keypath}.modules[${q(key)}]`, url, [
|
|
430
|
+
'file',
|
|
431
|
+
'exit',
|
|
432
|
+
'error',
|
|
433
|
+
]);
|
|
190
434
|
}
|
|
191
435
|
};
|
|
192
436
|
|
|
193
437
|
/**
|
|
194
438
|
* @param {unknown} allegedParsers
|
|
195
|
-
* @param {string}
|
|
439
|
+
* @param {string} keypath
|
|
196
440
|
* @param {string} url
|
|
441
|
+
* @returns {asserts allegedParsers is LanguageForExtension}
|
|
197
442
|
*/
|
|
198
|
-
const assertParsers = (allegedParsers,
|
|
199
|
-
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const parsers = Object(allegedParsers);
|
|
203
|
-
assert(
|
|
204
|
-
allegedParsers === parsers && !Array.isArray(parsers),
|
|
205
|
-
`${path}.parsers must be an object, got ${allegedParsers} in ${q(url)}`,
|
|
206
|
-
);
|
|
443
|
+
const assertParsers = (allegedParsers, keypath, url) => {
|
|
444
|
+
assertPlainObject(allegedParsers, `${keypath}.parsers`, url);
|
|
207
445
|
|
|
208
|
-
for (const [key, value] of
|
|
209
|
-
|
|
446
|
+
for (const [key, value] of entries(allegedParsers)) {
|
|
447
|
+
assertString(
|
|
210
448
|
key,
|
|
211
|
-
|
|
212
|
-
`all keys of ${path}.parsers must be strings, got ${key} in ${q(url)}`,
|
|
213
|
-
);
|
|
214
|
-
assert.typeof(
|
|
215
|
-
value,
|
|
216
|
-
'string',
|
|
217
|
-
`${path}.parsers[${q(key)}] must be a string, got ${value} in ${q(url)}`,
|
|
449
|
+
`all keys of ${keypath}.parsers must be strings; got ${key} in ${q(url)}`,
|
|
218
450
|
);
|
|
451
|
+
assertString(value, `${keypath}.parsers[${q(key)}]`, url);
|
|
219
452
|
}
|
|
220
453
|
};
|
|
221
454
|
|
|
222
455
|
/**
|
|
223
|
-
* @
|
|
224
|
-
* @param {
|
|
456
|
+
* @overload
|
|
457
|
+
* @param {unknown} allegedTruthyValue
|
|
458
|
+
* @param {string} keypath
|
|
225
459
|
* @param {string} url
|
|
460
|
+
* @returns {asserts allegedTruthyValue is NonNullable<unknown>}
|
|
226
461
|
*/
|
|
227
|
-
|
|
228
|
-
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
*
|
|
465
|
+
* @overload
|
|
466
|
+
* @param {unknown} allegedTruthyValue
|
|
467
|
+
* @param {string} message
|
|
468
|
+
* @returns {asserts allegedTruthyValue is NonNullable<unknown>}
|
|
469
|
+
*/
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
*
|
|
473
|
+
* @param {unknown} allegedTruthyValue
|
|
474
|
+
* @param {string} keypath
|
|
475
|
+
* @param {string} [url]
|
|
476
|
+
* @returns {asserts allegedTruthyValue is NonNullable<unknown>}
|
|
477
|
+
*/
|
|
478
|
+
const assertTruthy = (allegedTruthyValue, keypath, url) => {
|
|
229
479
|
assert(
|
|
230
|
-
|
|
231
|
-
|
|
480
|
+
allegedTruthyValue,
|
|
481
|
+
url
|
|
482
|
+
? `${keypath} in ${q(url)} must be truthy; got ${q(allegedTruthyValue)}`
|
|
483
|
+
: url,
|
|
232
484
|
);
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* @template [T=string]
|
|
489
|
+
* @typedef {(value: unknown, keypath: string, url: string) => void} AssertFn
|
|
490
|
+
*/
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* @template [T=string]
|
|
494
|
+
* @param {unknown} allegedScope
|
|
495
|
+
* @param {string} keypath
|
|
496
|
+
* @param {string} url
|
|
497
|
+
* @param {AssertFn<T>} [assertCompartmentValue]
|
|
498
|
+
* @returns {asserts allegedScope is ScopeDescriptor<T>}
|
|
499
|
+
*/
|
|
500
|
+
const assertScope = (allegedScope, keypath, url, assertCompartmentValue) => {
|
|
501
|
+
assertPlainObject(allegedScope, keypath, url);
|
|
233
502
|
|
|
234
|
-
const { compartment, ...extra } =
|
|
503
|
+
const { compartment, ...extra } = allegedScope;
|
|
235
504
|
assertEmptyObject(
|
|
236
505
|
extra,
|
|
237
|
-
`${
|
|
238
|
-
|
|
506
|
+
`${keypath} must not have extra properties; got ${q(
|
|
507
|
+
keys(extra),
|
|
239
508
|
)} in ${q(url)}`,
|
|
240
509
|
);
|
|
241
510
|
|
|
242
|
-
|
|
243
|
-
compartment,
|
|
244
|
-
|
|
245
|
-
`${
|
|
246
|
-
|
|
511
|
+
if (assertCompartmentValue) {
|
|
512
|
+
assertCompartmentValue(compartment, `${keypath}.compartment`, url);
|
|
513
|
+
} else {
|
|
514
|
+
assertString(compartment, `${keypath}.compartment`, url);
|
|
515
|
+
}
|
|
247
516
|
};
|
|
248
517
|
|
|
249
518
|
/**
|
|
519
|
+
* @template [T=string]
|
|
250
520
|
* @param {unknown} allegedScopes
|
|
251
|
-
* @param {string}
|
|
521
|
+
* @param {string} keypath
|
|
252
522
|
* @param {string} url
|
|
523
|
+
* @param {AssertFn<T>} [assertCompartmentValue]
|
|
524
|
+
* @returns {asserts allegedScopes is Record<string, ScopeDescriptor<T>>}
|
|
253
525
|
*/
|
|
254
|
-
const assertScopes = (
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
`${path}.scopes must be an object, got ${q(allegedScopes)} in ${q(url)}`,
|
|
262
|
-
);
|
|
526
|
+
const assertScopes = (
|
|
527
|
+
allegedScopes,
|
|
528
|
+
keypath,
|
|
529
|
+
url,
|
|
530
|
+
assertCompartmentValue = assertString,
|
|
531
|
+
) => {
|
|
532
|
+
assertPlainObject(allegedScopes, keypath, url);
|
|
263
533
|
|
|
264
|
-
for (const [key, value] of
|
|
265
|
-
|
|
534
|
+
for (const [key, value] of entries(allegedScopes)) {
|
|
535
|
+
assertString(
|
|
266
536
|
key,
|
|
267
|
-
|
|
268
|
-
|
|
537
|
+
`all keys of ${keypath}.scopes must be strings; got ${key} in ${q(url)}`,
|
|
538
|
+
);
|
|
539
|
+
assertScope(
|
|
540
|
+
value,
|
|
541
|
+
`${keypath}.scopes[${q(key)}]`,
|
|
542
|
+
url,
|
|
543
|
+
assertCompartmentValue,
|
|
269
544
|
);
|
|
270
|
-
assertScope(value, `${path}.scopes[${q(key)}]`, url);
|
|
271
545
|
}
|
|
272
546
|
};
|
|
273
547
|
|
|
274
548
|
/**
|
|
275
549
|
* @param {unknown} allegedTypes
|
|
276
|
-
* @param {string}
|
|
550
|
+
* @param {string} keypath
|
|
277
551
|
* @param {string} url
|
|
552
|
+
* @returns {asserts allegedTypes is LanguageForModuleSpecifier}
|
|
278
553
|
*/
|
|
279
|
-
const assertTypes = (allegedTypes,
|
|
280
|
-
|
|
281
|
-
|
|
554
|
+
const assertTypes = (allegedTypes, keypath, url) => {
|
|
555
|
+
assertPlainObject(allegedTypes, `${keypath}.types`, url);
|
|
556
|
+
|
|
557
|
+
for (const [key, value] of entries(allegedTypes)) {
|
|
558
|
+
assertString(
|
|
559
|
+
key,
|
|
560
|
+
`all keys of ${keypath}.types must be strings; got ${key} in ${q(url)}`,
|
|
561
|
+
);
|
|
562
|
+
assertString(value, `${keypath}.types[${q(key)}]`, url);
|
|
282
563
|
}
|
|
283
|
-
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* @template {Record<string, ModuleConfiguration>} [M=Record<string, ModuleConfiguration>]
|
|
568
|
+
* @param {unknown} allegedCompartment
|
|
569
|
+
* @param {string} keypath
|
|
570
|
+
* @param {string} url
|
|
571
|
+
* @param {AssertFn<M>} [moduleConfigurationAssertionFn]
|
|
572
|
+
* @returns {asserts allegedCompartment is CompartmentDescriptor}
|
|
573
|
+
*/
|
|
574
|
+
const assertCompartmentDescriptor = (
|
|
575
|
+
allegedCompartment,
|
|
576
|
+
keypath,
|
|
577
|
+
url,
|
|
578
|
+
moduleConfigurationAssertionFn = assertModuleConfigurations,
|
|
579
|
+
) => {
|
|
580
|
+
assertPlainObject(allegedCompartment, keypath, url);
|
|
581
|
+
|
|
582
|
+
const {
|
|
583
|
+
location,
|
|
584
|
+
name,
|
|
585
|
+
parsers,
|
|
586
|
+
types,
|
|
587
|
+
scopes,
|
|
588
|
+
modules,
|
|
589
|
+
policy,
|
|
590
|
+
sourceDirname,
|
|
591
|
+
retained,
|
|
592
|
+
} = allegedCompartment;
|
|
593
|
+
|
|
594
|
+
assertString(location, `${keypath}.location`, url);
|
|
595
|
+
assertString(name, `${keypath}.name`, url);
|
|
596
|
+
|
|
597
|
+
// TODO: It may be prudent to assert that there exists some module referring
|
|
598
|
+
// to its own compartment
|
|
599
|
+
|
|
600
|
+
moduleConfigurationAssertionFn(modules, keypath, url);
|
|
601
|
+
|
|
602
|
+
if (parsers !== undefined) {
|
|
603
|
+
assertParsers(parsers, keypath, url);
|
|
604
|
+
}
|
|
605
|
+
if (scopes !== undefined) {
|
|
606
|
+
assertScopes(scopes, keypath, url);
|
|
607
|
+
}
|
|
608
|
+
if (types !== undefined) {
|
|
609
|
+
assertTypes(types, keypath, url);
|
|
610
|
+
}
|
|
611
|
+
if (policy !== undefined) {
|
|
612
|
+
assertPackagePolicy(policy, keypath, url);
|
|
613
|
+
}
|
|
614
|
+
if (sourceDirname !== undefined) {
|
|
615
|
+
assertString(sourceDirname, `${keypath}.sourceDirname`, url);
|
|
616
|
+
}
|
|
617
|
+
if (retained !== undefined) {
|
|
618
|
+
assertBoolean(retained, `${keypath}.retained`, url);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Ensures a string is a file URL (a {@link FileUrlString})
|
|
624
|
+
*
|
|
625
|
+
* @param {unknown} allegedFileUrlString - a package location to assert
|
|
626
|
+
* @param {string} keypath
|
|
627
|
+
* @param {string} url
|
|
628
|
+
* @returns {asserts allegedFileUrlString is FileUrlString}
|
|
629
|
+
*/
|
|
630
|
+
const assertFileUrlString = (allegedFileUrlString, keypath, url) => {
|
|
631
|
+
assertString(allegedFileUrlString, keypath, url);
|
|
284
632
|
assert(
|
|
285
|
-
|
|
286
|
-
`${
|
|
633
|
+
allegedFileUrlString.startsWith('file://'),
|
|
634
|
+
`${keypath} must be a file URL in ${q(url)}; got ${q(allegedFileUrlString)}`,
|
|
287
635
|
);
|
|
636
|
+
assert(
|
|
637
|
+
allegedFileUrlString.length > 7,
|
|
638
|
+
`${keypath} must contain a non-empty path in ${q(url)}; got ${q(allegedFileUrlString)}`,
|
|
639
|
+
);
|
|
640
|
+
};
|
|
288
641
|
|
|
289
|
-
|
|
290
|
-
|
|
642
|
+
/**
|
|
643
|
+
* @param {unknown} allegedModules
|
|
644
|
+
* @param {string} keypath
|
|
645
|
+
* @param {string} url
|
|
646
|
+
* @returns {asserts allegedModules is Record<string, CompartmentModuleConfiguration>}
|
|
647
|
+
*/
|
|
648
|
+
const assertPackageModuleConfigurations = (allegedModules, keypath, url) => {
|
|
649
|
+
assertPlainObject(allegedModules, keypath, url);
|
|
650
|
+
for (const [key, value] of entries(allegedModules)) {
|
|
651
|
+
assertString(
|
|
291
652
|
key,
|
|
292
|
-
|
|
293
|
-
`all keys of ${path}.types must be strings, got ${key} in ${q(url)}`,
|
|
294
|
-
);
|
|
295
|
-
assert.typeof(
|
|
296
|
-
value,
|
|
297
|
-
'string',
|
|
298
|
-
`${path}.types[${q(key)}] must be a string, got ${value} in ${q(url)}`,
|
|
653
|
+
`all keys of ${keypath}.modules must be strings; got ${key} in ${q(url)}`,
|
|
299
654
|
);
|
|
655
|
+
assertModuleConfiguration(value, `${keypath}.modules[${q(key)}]`, url, [
|
|
656
|
+
'compartment',
|
|
657
|
+
]);
|
|
300
658
|
}
|
|
301
659
|
};
|
|
302
660
|
|
|
303
661
|
/**
|
|
304
|
-
*
|
|
305
|
-
* @param {
|
|
306
|
-
* @param {string}
|
|
662
|
+
*
|
|
663
|
+
* @param {unknown} allegedLocation
|
|
664
|
+
* @param {string} keypath
|
|
665
|
+
* @param {string} url
|
|
666
|
+
* @returns {asserts allegedLocation is PackageCompartmentDescriptor['location']}
|
|
307
667
|
*/
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
) => {
|
|
314
|
-
assertPackagePolicy(allegedPolicy, `${path}.policy`, url);
|
|
668
|
+
const assertPackageLocation = (allegedLocation, keypath, url) => {
|
|
669
|
+
if (allegedLocation === ATTENUATORS_COMPARTMENT) {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
assertFileUrlString(allegedLocation, keypath, url);
|
|
315
673
|
};
|
|
316
674
|
|
|
317
675
|
/**
|
|
318
676
|
* @param {unknown} allegedCompartment
|
|
319
|
-
* @param {string}
|
|
677
|
+
* @param {string} keypath
|
|
320
678
|
* @param {string} url
|
|
679
|
+
* @returns {asserts allegedCompartment is PackageCompartmentDescriptor}
|
|
321
680
|
*/
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
681
|
+
const assertPackageCompartmentDescriptor = (
|
|
682
|
+
allegedCompartment,
|
|
683
|
+
keypath,
|
|
684
|
+
url,
|
|
685
|
+
) => {
|
|
686
|
+
assertCompartmentDescriptor(
|
|
687
|
+
allegedCompartment,
|
|
688
|
+
keypath,
|
|
689
|
+
url,
|
|
690
|
+
assertPackageModuleConfigurations,
|
|
327
691
|
);
|
|
328
692
|
|
|
329
693
|
const {
|
|
330
694
|
location,
|
|
331
|
-
name,
|
|
332
|
-
label,
|
|
333
|
-
parsers,
|
|
334
|
-
types,
|
|
335
695
|
scopes,
|
|
336
|
-
|
|
337
|
-
|
|
696
|
+
label,
|
|
697
|
+
// these unused vars already validated by assertPackageModuleConfigurations
|
|
698
|
+
name: _name,
|
|
699
|
+
sourceDirname: _sourceDirname,
|
|
700
|
+
modules: _modules,
|
|
701
|
+
parsers: _parsers,
|
|
702
|
+
types: _types,
|
|
703
|
+
policy: _policy,
|
|
704
|
+
version: _version,
|
|
338
705
|
...extra
|
|
339
|
-
} =
|
|
706
|
+
} = /** @type {PackageCompartmentDescriptor} */ (allegedCompartment);
|
|
340
707
|
|
|
341
708
|
assertEmptyObject(
|
|
342
709
|
extra,
|
|
343
|
-
`${
|
|
344
|
-
|
|
710
|
+
`${keypath} must not have extra properties; got ${q(
|
|
711
|
+
keys(extra),
|
|
345
712
|
)} in ${q(url)}`,
|
|
346
713
|
);
|
|
347
714
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
715
|
+
assertPackageLocation(location, `${keypath}.location`, url);
|
|
716
|
+
assertLabel(label, `${keypath}.label`, url);
|
|
717
|
+
assertScopes(scopes, `${keypath}.scopes`, url, assertFileUrlString);
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
*
|
|
722
|
+
* @param {unknown} allegedCompartment
|
|
723
|
+
* @param {string} keypath
|
|
724
|
+
* @param {string} url
|
|
725
|
+
* @returns {asserts allegedCompartment is DigestedCompartmentDescriptor}
|
|
726
|
+
*/
|
|
727
|
+
const assertDigestedCompartmentDescriptor = (
|
|
728
|
+
allegedCompartment,
|
|
729
|
+
keypath,
|
|
730
|
+
url,
|
|
731
|
+
) => {
|
|
732
|
+
assertCompartmentDescriptor(
|
|
733
|
+
allegedCompartment,
|
|
734
|
+
keypath,
|
|
735
|
+
url,
|
|
736
|
+
assertDigestedModuleConfigurations,
|
|
352
737
|
);
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
738
|
+
|
|
739
|
+
const {
|
|
740
|
+
name: _name,
|
|
741
|
+
label: _label,
|
|
742
|
+
modules: _modules,
|
|
743
|
+
policy: _policy,
|
|
744
|
+
location: _location,
|
|
745
|
+
...extra
|
|
746
|
+
} = allegedCompartment;
|
|
747
|
+
|
|
748
|
+
assertEmptyObject(
|
|
749
|
+
extra,
|
|
750
|
+
`${keypath} must not have extra properties; got ${q(
|
|
751
|
+
keys(extra),
|
|
752
|
+
)} in ${q(url)}`,
|
|
357
753
|
);
|
|
358
|
-
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* @param {unknown} allegedCompartment
|
|
758
|
+
* @param {string} keypath
|
|
759
|
+
* @param {string} url
|
|
760
|
+
* @returns {asserts allegedCompartment is FileCompartmentDescriptor}
|
|
761
|
+
*/
|
|
762
|
+
const assertFileCompartmentDescriptor = (allegedCompartment, keypath, url) => {
|
|
763
|
+
assertCompartmentDescriptor(
|
|
764
|
+
allegedCompartment,
|
|
765
|
+
keypath,
|
|
766
|
+
url,
|
|
767
|
+
assertFileModuleConfigurations,
|
|
768
|
+
);
|
|
769
|
+
|
|
770
|
+
const {
|
|
771
|
+
location: _location,
|
|
772
|
+
name: _name,
|
|
359
773
|
label,
|
|
360
|
-
|
|
361
|
-
|
|
774
|
+
modules: _modules,
|
|
775
|
+
policy: _policy,
|
|
776
|
+
...extra
|
|
777
|
+
} = /** @type {FileCompartmentDescriptor} */ (allegedCompartment);
|
|
778
|
+
|
|
779
|
+
assertEmptyObject(
|
|
780
|
+
extra,
|
|
781
|
+
`${keypath} must not have extra properties; got ${q(
|
|
782
|
+
keys(extra),
|
|
783
|
+
)} in ${q(url)}`,
|
|
362
784
|
);
|
|
363
785
|
|
|
364
|
-
|
|
365
|
-
assertParsers(parsers, path, url);
|
|
366
|
-
assertScopes(scopes, path, url);
|
|
367
|
-
assertTypes(types, path, url);
|
|
368
|
-
assertPolicy(policy, path, url);
|
|
786
|
+
assertString(label, `${keypath}.label`, url);
|
|
369
787
|
};
|
|
370
788
|
|
|
371
789
|
/**
|
|
372
790
|
* @param {unknown} allegedCompartments
|
|
373
791
|
* @param {string} url
|
|
792
|
+
* @returns {asserts allegedCompartments is Record<string, unknown>}
|
|
374
793
|
*/
|
|
375
|
-
const
|
|
376
|
-
|
|
794
|
+
const assertCompartmentDescriptors = (allegedCompartments, url) => {
|
|
795
|
+
assertPlainObject(allegedCompartments, 'compartments', url);
|
|
796
|
+
const compartmentNames = keys(allegedCompartments);
|
|
377
797
|
assert(
|
|
378
|
-
|
|
379
|
-
`compartments must be
|
|
380
|
-
url,
|
|
381
|
-
)}`,
|
|
798
|
+
compartmentNames.length > 0,
|
|
799
|
+
`compartments must not be empty in ${q(url)}`,
|
|
382
800
|
);
|
|
383
|
-
for (const
|
|
384
|
-
|
|
801
|
+
for (const key of keys(allegedCompartments)) {
|
|
802
|
+
assertString(
|
|
803
|
+
key,
|
|
804
|
+
`all keys of compartments must be strings; got ${key} in ${q(url)}`,
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
assert(
|
|
808
|
+
compartmentNames.every(name => typeof name === 'string'),
|
|
809
|
+
`all keys of compartments must be strings; got ${q(compartmentNames)} in ${q(url)}`,
|
|
810
|
+
);
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* @param {unknown} allegedCompartments
|
|
815
|
+
* @param {string} url
|
|
816
|
+
* @returns {asserts allegedCompartments is Record<string, FileCompartmentDescriptor>}
|
|
817
|
+
*/
|
|
818
|
+
const assertFileCompartmentDescriptors = (allegedCompartments, url) => {
|
|
819
|
+
assertCompartmentDescriptors(allegedCompartments, url);
|
|
820
|
+
for (const [key, value] of entries(allegedCompartments)) {
|
|
821
|
+
assertFileCompartmentDescriptor(value, `compartments[${q(key)}]`, url);
|
|
385
822
|
}
|
|
386
823
|
};
|
|
387
824
|
|
|
825
|
+
/**
|
|
826
|
+
* @param {unknown} allegedCompartments
|
|
827
|
+
* @param {string} url
|
|
828
|
+
* @returns {asserts allegedCompartments is Record<string, PackageCompartmentDescriptor>}
|
|
829
|
+
*/
|
|
830
|
+
const assertPackageCompartmentDescriptors = (allegedCompartments, url) => {
|
|
831
|
+
assertCompartmentDescriptors(allegedCompartments, url);
|
|
832
|
+
for (const [key, value] of entries(allegedCompartments)) {
|
|
833
|
+
assertPackageCompartmentDescriptor(value, `compartments[${q(key)}]`, url);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
388
836
|
/**
|
|
389
837
|
* @param {unknown} allegedEntry
|
|
390
838
|
* @param {string} url
|
|
839
|
+
* @returns {asserts allegedEntry is EntryDescriptor}
|
|
391
840
|
*/
|
|
392
841
|
const assertEntry = (allegedEntry, url) => {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
allegedEntry === entry && !Array.isArray(entry),
|
|
396
|
-
`"entry" must be an object in compartment map, got ${allegedEntry} in ${q(
|
|
397
|
-
url,
|
|
398
|
-
)}`,
|
|
399
|
-
);
|
|
400
|
-
const { compartment, module, ...extra } = entry;
|
|
842
|
+
assertPlainObject(allegedEntry, 'entry', url);
|
|
843
|
+
const { compartment, module, ...extra } = allegedEntry;
|
|
401
844
|
assertEmptyObject(
|
|
402
845
|
extra,
|
|
403
|
-
`"entry" must not have extra properties in compartment map
|
|
404
|
-
|
|
846
|
+
`"entry" must not have extra properties in compartment map; got ${q(
|
|
847
|
+
keys(extra),
|
|
405
848
|
)} in ${q(url)}`,
|
|
406
849
|
);
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
'string',
|
|
410
|
-
`entry.compartment must be a string in compartment map, got ${compartment} in ${q(
|
|
411
|
-
url,
|
|
412
|
-
)}`,
|
|
413
|
-
);
|
|
414
|
-
assert.typeof(
|
|
415
|
-
module,
|
|
416
|
-
'string',
|
|
417
|
-
`entry.module must be a string in compartment map, got ${module} in ${q(
|
|
418
|
-
url,
|
|
419
|
-
)}`,
|
|
420
|
-
);
|
|
850
|
+
assertString(compartment, 'entry.compartment', url);
|
|
851
|
+
assertString(module, 'entry.module', url);
|
|
421
852
|
};
|
|
422
853
|
|
|
423
854
|
/**
|
|
424
855
|
* @param {unknown} allegedCompartmentMap
|
|
425
|
-
* @param {string}
|
|
856
|
+
* @param {string} url
|
|
426
857
|
* @returns {asserts allegedCompartmentMap is CompartmentMapDescriptor}
|
|
427
858
|
*/
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
allegedCompartmentMap,
|
|
431
|
-
url = '<unknown-compartment-map.json>',
|
|
432
|
-
) => {
|
|
433
|
-
const compartmentMap = Object(allegedCompartmentMap);
|
|
434
|
-
assert(
|
|
435
|
-
allegedCompartmentMap === compartmentMap && !Array.isArray(compartmentMap),
|
|
436
|
-
`Compartment map must be an object, got ${allegedCompartmentMap} in ${q(
|
|
437
|
-
url,
|
|
438
|
-
)}`,
|
|
439
|
-
);
|
|
859
|
+
const assertCompartmentMap = (allegedCompartmentMap, url) => {
|
|
860
|
+
assertPlainObject(allegedCompartmentMap, 'compartment map', url);
|
|
440
861
|
const {
|
|
441
862
|
// TODO migrate tags to conditions
|
|
442
863
|
// https://github.com/endojs/endo/issues/2388
|
|
443
864
|
tags: conditions,
|
|
444
865
|
entry,
|
|
445
|
-
compartments,
|
|
866
|
+
compartments: _compartments,
|
|
446
867
|
...extra
|
|
447
|
-
} =
|
|
868
|
+
} = allegedCompartmentMap;
|
|
448
869
|
assertEmptyObject(
|
|
449
870
|
extra,
|
|
450
|
-
`Compartment map must not have extra properties
|
|
451
|
-
|
|
871
|
+
`Compartment map must not have extra properties; got ${q(
|
|
872
|
+
keys(extra),
|
|
452
873
|
)} in ${q(url)}`,
|
|
453
874
|
);
|
|
454
875
|
assertConditions(conditions, url);
|
|
455
876
|
assertEntry(entry, url);
|
|
456
|
-
|
|
877
|
+
assertTruthy(
|
|
878
|
+
allegedCompartmentMap.compartments?.[entry.compartment],
|
|
879
|
+
`compartments must contain entry compartment "${entry.compartment}" in ${q(url)}`,
|
|
880
|
+
);
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* @param {unknown} allegedCompartmentMap
|
|
885
|
+
* @param {string} [url]
|
|
886
|
+
* @returns {asserts allegedCompartmentMap is FileCompartmentMapDescriptor}
|
|
887
|
+
*/
|
|
888
|
+
export const assertFileCompartmentMap = (
|
|
889
|
+
allegedCompartmentMap,
|
|
890
|
+
url = '<unknown-compartment-map.json>',
|
|
891
|
+
) => {
|
|
892
|
+
assertCompartmentMap(allegedCompartmentMap, url);
|
|
893
|
+
const { compartments } = allegedCompartmentMap;
|
|
894
|
+
assertFileCompartmentDescriptors(compartments, url);
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
*
|
|
899
|
+
* @param {unknown} allegedCompartments
|
|
900
|
+
* @param {string} url
|
|
901
|
+
* @returns {asserts allegedCompartments is Record<string, DigestedCompartmentDescriptor>}
|
|
902
|
+
*/
|
|
903
|
+
export const assertDigestedCompartmentDescriptors = (
|
|
904
|
+
allegedCompartments,
|
|
905
|
+
url = '<unknown-compartment-map.json>',
|
|
906
|
+
) => {
|
|
907
|
+
assertCompartmentDescriptors(allegedCompartments, url);
|
|
908
|
+
for (const [key, value] of entries(allegedCompartments)) {
|
|
909
|
+
assertDigestedCompartmentDescriptor(value, `compartments[${q(key)}]`, url);
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
*
|
|
915
|
+
* @param {unknown} allegedCompartmentMap
|
|
916
|
+
* @param {string} [url]
|
|
917
|
+
* @returns {asserts allegedCompartmentMap is DigestedCompartmentMapDescriptor}
|
|
918
|
+
*/
|
|
919
|
+
export const assertDigestedCompartmentMap = (
|
|
920
|
+
allegedCompartmentMap,
|
|
921
|
+
url = '<unknown-compartment-map.json>',
|
|
922
|
+
) => {
|
|
923
|
+
assertCompartmentMap(allegedCompartmentMap, url);
|
|
924
|
+
const { compartments } = allegedCompartmentMap;
|
|
925
|
+
assertDigestedCompartmentDescriptors(compartments, url);
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* @param {unknown} allegedCompartmentMap
|
|
930
|
+
* @param {string} [url]
|
|
931
|
+
* @returns {asserts allegedCompartmentMap is PackageCompartmentMapDescriptor}
|
|
932
|
+
*/
|
|
933
|
+
export const assertPackageCompartmentMap = (
|
|
934
|
+
allegedCompartmentMap,
|
|
935
|
+
url = '<unknown-compartment-map.json>',
|
|
936
|
+
) => {
|
|
937
|
+
assertCompartmentMap(allegedCompartmentMap, url);
|
|
938
|
+
const { compartments } = allegedCompartmentMap;
|
|
939
|
+
assertPackageCompartmentDescriptors(compartments, url);
|
|
457
940
|
};
|