@nmnmcc/ability 2.0.5 → 2.0.7
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/README.md +6 -5
- package/dist/Condition.d.ts +6 -6
- package/dist/Condition.d.ts.map +1 -1
- package/dist/Condition.js.map +1 -1
- package/dist/Domain.d.ts +1 -1
- package/dist/Policy.d.ts +2 -2
- package/dist/Policy.d.ts.map +1 -1
- package/dist/Policy.js.map +1 -1
- package/dist/internal/algebra.js +128 -79
- package/dist/internal/algebra.js.map +1 -1
- package/dist/internal/analysis.js +1 -1
- package/dist/internal/analysis.js.map +1 -1
- package/dist/internal/authorizer.d.ts.map +1 -1
- package/dist/internal/authorizer.js +38 -14
- package/dist/internal/authorizer.js.map +1 -1
- package/dist/internal/bind.js +59 -43
- package/dist/internal/bind.js.map +1 -1
- package/dist/internal/catalog.d.ts +6 -0
- package/dist/internal/catalog.d.ts.map +1 -1
- package/dist/internal/catalog.js +17 -14
- package/dist/internal/catalog.js.map +1 -1
- package/dist/internal/decide.js +1 -1
- package/dist/internal/domain.js +1 -1
- package/dist/internal/json.js +2 -10
- package/dist/internal/json.js.map +1 -1
- package/dist/internal/nodes.d.ts +11 -1
- package/dist/internal/nodes.d.ts.map +1 -1
- package/dist/internal/nodes.js +51 -11
- package/dist/internal/nodes.js.map +1 -1
- package/dist/internal/patterns.js +1 -1
- package/dist/internal/patterns.js.map +1 -1
- package/dist/internal/policy-json.js +2 -8
- package/dist/internal/policy-json.js.map +1 -1
- package/dist/internal/policy-nodes.d.ts +4 -1
- package/dist/internal/policy-nodes.d.ts.map +1 -1
- package/dist/internal/policy-nodes.js +14 -5
- package/dist/internal/policy-nodes.js.map +1 -1
- package/dist/internal/search.js +4 -4
- package/dist/internal/search.js.map +1 -1
- package/dist/internal/trampoline.js +75 -0
- package/dist/internal/trampoline.js.map +1 -0
- package/package.json +1 -1
- package/src/Condition.ts +5 -2
- package/src/Policy.ts +1 -2
- package/src/internal/algebra.ts +262 -143
- package/src/internal/analysis.ts +3 -1
- package/src/internal/authorizer.ts +59 -14
- package/src/internal/bind.ts +149 -71
- package/src/internal/catalog.ts +54 -50
- package/src/internal/json.ts +2 -11
- package/src/internal/nodes.ts +58 -24
- package/src/internal/patterns.ts +7 -3
- package/src/internal/policy-json.ts +2 -9
- package/src/internal/policy-nodes.ts +16 -7
- package/src/internal/search.ts +13 -10
- package/src/internal/trampoline.ts +147 -0
package/dist/internal/algebra.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { And, Compare, In, Not, Or, Predicate, isScalar, literal, nodes_exports, runOf } from "./nodes.js";
|
|
2
2
|
import { readPath } from "./read.js";
|
|
3
|
+
import { loop, run, toEffect } from "./trampoline.js";
|
|
3
4
|
import * as Effect from "effect/Effect";
|
|
4
5
|
import * as Arr from "effect/Array";
|
|
5
6
|
import * as Option from "effect/Option";
|
|
@@ -8,9 +9,10 @@ import * as Option from "effect/Option";
|
|
|
8
9
|
* The work on condition nodes: smart constructors, simplification, the step
|
|
9
10
|
* that puts the principal in, tests on a value, and folds.
|
|
10
11
|
*
|
|
11
|
-
* The constructors of the nodes keep each condition small
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* The constructors of the nodes keep each condition small, so each walk here
|
|
13
|
+
* has no memo. A shared child is walked again for each place, and the limits
|
|
14
|
+
* of the nodes keep that work small. A walk takes the steps of a trampoline,
|
|
15
|
+
* so a deep condition does not fill the stack: see `Trampoline`.
|
|
14
16
|
*/
|
|
15
17
|
const { always, never } = nodes_exports;
|
|
16
18
|
/** The text of an operand. The type is in it, so `"1"` is not `1`. */
|
|
@@ -46,10 +48,31 @@ const shapeOf = (node) => {
|
|
|
46
48
|
*/
|
|
47
49
|
const structureText = (node) => JSON.stringify(shapeOf(node));
|
|
48
50
|
/**
|
|
49
|
-
* The
|
|
50
|
-
*
|
|
51
|
+
* The work of the text of the structure of a condition: each node, and each
|
|
52
|
+
* value of an `In` test or an `Under` test. A node counts as one in `size`,
|
|
53
|
+
* also an `In` test with very many values. This walk reads the nodes only,
|
|
54
|
+
* so it takes `size` steps.
|
|
55
|
+
*/
|
|
56
|
+
const weightOf = (node) => {
|
|
57
|
+
switch (node._tag) {
|
|
58
|
+
case "In": return 1 + node.values.length;
|
|
59
|
+
case "Under": return 1 + node.prefix.length;
|
|
60
|
+
case "And":
|
|
61
|
+
case "Or": return Arr.reduce(node.conditions, 1, (total, child) => total + weightOf(child));
|
|
62
|
+
case "Not": return 1 + weightOf(node.condition);
|
|
63
|
+
default: return 1;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* The most nodes of a condition that a smart constructor reads for its key,
|
|
68
|
+
* and the most children of a child that it puts into a node. A larger child
|
|
69
|
+
* is its own key, and it stays one child, so the work of a constructor stays
|
|
70
|
+
* small. A deep chain of `And` nodes, for one, does not copy all its leaves
|
|
71
|
+
* at each level.
|
|
51
72
|
*/
|
|
52
73
|
const keyNodes = 64;
|
|
74
|
+
/** The most work of a key, with the values of its tests: see {@link weightOf}. */
|
|
75
|
+
const keyWeight = 256;
|
|
53
76
|
/**
|
|
54
77
|
* The key of a child in a smart constructor: the text of its structure, or
|
|
55
78
|
* the node itself when it is large. The keys go into a native `Set`, not a
|
|
@@ -58,7 +81,7 @@ const keyNodes = 64;
|
|
|
58
81
|
* set would read all of them. A native `Set` finds a node by the node itself,
|
|
59
82
|
* and it hashes a string with the random seed of the engine.
|
|
60
83
|
*/
|
|
61
|
-
const keyOf = (node) => node.size > keyNodes ? node : structureText(node);
|
|
84
|
+
const keyOf = (node) => node.size > keyNodes || weightOf(node) > keyWeight ? node : structureText(node);
|
|
62
85
|
/**
|
|
63
86
|
* Keeps the first node of each structure, in order. A large node is a copy
|
|
64
87
|
* only of itself.
|
|
@@ -96,7 +119,8 @@ const shortCircuit = (tag, children, index) => {
|
|
|
96
119
|
/**
|
|
97
120
|
* Makes an `And` or an `Or` of simple children, and makes it simple. It looks
|
|
98
121
|
* one level down only:
|
|
99
|
-
* - it puts the children of a child of the same kind into the node
|
|
122
|
+
* - it puts the children of a child of the same kind into the node, when
|
|
123
|
+
* the child has at most `keyNodes` of them;
|
|
100
124
|
* - it stops at a `False` in an `And`, or at a `True` in an `Or`;
|
|
101
125
|
* - it removes `True` from an `And`, `False` from an `Or`, copies, and the
|
|
102
126
|
* children that other children make useless.
|
|
@@ -108,7 +132,7 @@ const shortCircuit = (tag, children, index) => {
|
|
|
108
132
|
const junction = (tag, children) => {
|
|
109
133
|
const constant = tag === "And" ? "False" : "True";
|
|
110
134
|
const neutral = tag === "And" ? "True" : "False";
|
|
111
|
-
const flat = Arr.flatMap(children, (child) => child._tag === tag && !child.opaque ? child.conditions : [child]);
|
|
135
|
+
const flat = Arr.flatMap(children, (child) => child._tag === tag && !child.opaque && child.conditions.length <= keyNodes ? child.conditions : [child]);
|
|
112
136
|
return Option.match(Arr.findFirstIndex(flat, (child) => child._tag === constant), {
|
|
113
137
|
onSome: (stop) => shortCircuit(tag, flat, stop),
|
|
114
138
|
onNone: () => {
|
|
@@ -136,16 +160,24 @@ const not = (child) => {
|
|
|
136
160
|
default: return new Not(child);
|
|
137
161
|
}
|
|
138
162
|
};
|
|
163
|
+
/** The children of a node, each walked by `go` as a step of `R`. */
|
|
164
|
+
const eachChild = (R, children, go) => R.forEach(children, (child) => R.suspend(() => go(child)));
|
|
139
165
|
/** Makes a condition simple, from its leaves up. */
|
|
140
|
-
const simplify = (node) => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
166
|
+
const simplify = (node) => run(node.depth, (R) => {
|
|
167
|
+
const go = (current) => {
|
|
168
|
+
switch (current._tag) {
|
|
169
|
+
case "And":
|
|
170
|
+
case "Or": {
|
|
171
|
+
const tag = current._tag;
|
|
172
|
+
return R.map(eachChild(R, current.conditions, go), (children) => junction(tag, children));
|
|
173
|
+
}
|
|
174
|
+
case "Not": return R.map(R.suspend(() => go(current.condition)), not);
|
|
175
|
+
case "In": return R.succeed(current.values.length === 0 ? never : current);
|
|
176
|
+
default: return R.succeed(current);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return go(node);
|
|
180
|
+
});
|
|
149
181
|
/**
|
|
150
182
|
* Gets a field of a value by a path with dots. It reads only plain data: see
|
|
151
183
|
* `readPart`. A missing field, or a field under a value that is not an object,
|
|
@@ -191,35 +223,46 @@ const testUnder = (prefix, input) => {
|
|
|
191
223
|
return value !== void 0 && value === values[index];
|
|
192
224
|
});
|
|
193
225
|
};
|
|
194
|
-
/**
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return
|
|
226
|
+
/**
|
|
227
|
+
* The test of a simple condition with no predicate on a value, as a walk.
|
|
228
|
+
* The children of `And` and `Or` run in order, and they stop at the first
|
|
229
|
+
* child that gives the answer.
|
|
230
|
+
*/
|
|
231
|
+
const testWith = (input) => (R) => {
|
|
232
|
+
const go = (node) => {
|
|
233
|
+
switch (node._tag) {
|
|
234
|
+
case "True": return R.succeed(true);
|
|
235
|
+
case "False": return R.succeed(false);
|
|
236
|
+
case "Compare": return R.succeed(testCompare(node.op, getField(input.value, node.field), resolve(node.value, input.principal)));
|
|
237
|
+
case "In": {
|
|
238
|
+
const field = getField(input.value, node.field);
|
|
239
|
+
return R.succeed(node.values.some((operand) => resolve(operand, input.principal) === field));
|
|
240
|
+
}
|
|
241
|
+
case "Exists": return R.succeed(getField(input.value, node.field) !== null);
|
|
242
|
+
case "Under": return R.succeed(testUnder(node.prefix, input));
|
|
243
|
+
case "And": return R.every(node.conditions, (child) => R.suspend(() => go(child)));
|
|
244
|
+
case "Or": return R.some(node.conditions, (child) => R.suspend(() => go(child)));
|
|
245
|
+
case "Not": return R.map(R.suspend(() => go(node.condition)), (value) => !value);
|
|
246
|
+
case "Predicate": throw new Error(`The predicate "${node.name}" needs an Effect. Use Condition.evaluate.`);
|
|
203
247
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
case "And": return Arr.every(node.conditions, (child) => testSync(child, input));
|
|
207
|
-
case "Or": return Arr.some(node.conditions, (child) => testSync(child, input));
|
|
208
|
-
case "Not": return !testSync(node.condition, input);
|
|
209
|
-
case "Predicate": throw new Error(`The predicate "${node.name}" needs an Effect. Use Condition.evaluate.`);
|
|
210
|
-
}
|
|
248
|
+
};
|
|
249
|
+
return go;
|
|
211
250
|
};
|
|
251
|
+
/** Tests a simple condition with no predicate on a value. */
|
|
252
|
+
const testSync = (node, input) => run(node.depth, (R) => testWith(input)(R)(node));
|
|
212
253
|
/**
|
|
213
254
|
* Tests a simple condition on a value. The children of `And` and `Or` run in
|
|
214
|
-
* order, and they stop at the first child that gives the answer.
|
|
255
|
+
* order, and they stop at the first child that gives the answer. Each call
|
|
256
|
+
* for a child is a step of the Effect, so a deep condition does not fill the
|
|
257
|
+
* stack. A part with no predicate runs as a walk in the same loop.
|
|
215
258
|
*/
|
|
216
259
|
const test = (node, input) => {
|
|
217
|
-
if (!node.opaque) return Effect.sync(() => testSync(node, input));
|
|
260
|
+
if (!node.opaque) return node.depth <= 200 ? Effect.sync(() => testSync(node, input)) : node.pipe(testWith(input)(loop), toEffect);
|
|
218
261
|
switch (node._tag) {
|
|
219
262
|
case "Predicate": return runOf(node)(input.value, input.principal);
|
|
220
|
-
case "Not": return Effect.map(test(node.condition, input), (value) => !value);
|
|
221
|
-
case "And": return Effect.map(Effect.findFirst(node.conditions, (child) => Effect.map(test(child, input), (value) => !value)), Option.isNone);
|
|
222
|
-
case "Or": return Effect.map(Effect.findFirst(node.conditions, (child) => test(child, input)), Option.isSome);
|
|
263
|
+
case "Not": return Effect.map(Effect.suspend(() => test(node.condition, input)), (value) => !value);
|
|
264
|
+
case "And": return Effect.map(Effect.findFirst(node.conditions, (child) => Effect.map(Effect.suspend(() => test(child, input)), (value) => !value)), Option.isNone);
|
|
265
|
+
case "Or": return Effect.map(Effect.findFirst(node.conditions, (child) => Effect.suspend(() => test(child, input))), Option.isSome);
|
|
223
266
|
default: return Effect.sync(() => testSync(node, input));
|
|
224
267
|
}
|
|
225
268
|
};
|
|
@@ -259,72 +302,78 @@ const expandUnder = (prefix, principal, path) => {
|
|
|
259
302
|
* resource. The result is simple. It has no principal fields and no `Under`
|
|
260
303
|
* nodes. A predicate keeps the principal.
|
|
261
304
|
*/
|
|
262
|
-
const partial = (node, input) => {
|
|
305
|
+
const partial = (node, input) => run(node.depth, (R) => {
|
|
263
306
|
const bind = (current) => {
|
|
264
307
|
switch (current._tag) {
|
|
265
308
|
case "Compare": {
|
|
266
309
|
const value = bindOperand(current.value, input.principal);
|
|
267
|
-
return value === void 0 ? never : value === current.value ? current : new Compare({
|
|
310
|
+
return R.succeed(value === void 0 ? never : value === current.value ? current : new Compare({
|
|
268
311
|
op: current.op,
|
|
269
312
|
field: current.field,
|
|
270
313
|
value
|
|
271
|
-
});
|
|
314
|
+
}));
|
|
272
315
|
}
|
|
273
316
|
case "In": {
|
|
274
317
|
const values = Arr.flatMap(current.values, (operand) => Option.toArray(Option.fromUndefinedOr(bindOperand(operand, input.principal))));
|
|
275
|
-
return values.length === 0 ? never : new In({
|
|
318
|
+
return R.succeed(values.length === 0 ? never : new In({
|
|
276
319
|
field: current.field,
|
|
277
320
|
values
|
|
278
|
-
});
|
|
321
|
+
}));
|
|
279
322
|
}
|
|
280
|
-
case "Under": return expandUnder(current.prefix, input.principal, input.path);
|
|
281
|
-
case "And": return
|
|
282
|
-
case "Or": return
|
|
283
|
-
case "Not": return
|
|
323
|
+
case "Under": return R.succeed(expandUnder(current.prefix, input.principal, input.path));
|
|
324
|
+
case "And": return R.map(eachChild(R, current.conditions, bind), and);
|
|
325
|
+
case "Or": return R.map(eachChild(R, current.conditions, bind), or);
|
|
326
|
+
case "Not": return R.map(R.suspend(() => bind(current.condition)), not);
|
|
284
327
|
case "Predicate": {
|
|
285
328
|
const run = runOf(current);
|
|
286
|
-
return new Predicate({
|
|
329
|
+
return R.succeed(new Predicate({
|
|
287
330
|
name: current.name,
|
|
288
331
|
run: (value) => run(value, input.principal)
|
|
289
|
-
});
|
|
332
|
+
}));
|
|
290
333
|
}
|
|
291
|
-
default: return current;
|
|
334
|
+
default: return R.succeed(current);
|
|
292
335
|
}
|
|
293
336
|
};
|
|
294
337
|
return bind(node);
|
|
295
|
-
};
|
|
338
|
+
});
|
|
296
339
|
/** Gives the services in `context` to every predicate of a condition. */
|
|
297
|
-
const provide = (node, context) => {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
case "Predicate": {
|
|
301
|
-
const run = runOf(node);
|
|
302
|
-
return new Predicate({
|
|
303
|
-
name: node.name,
|
|
304
|
-
run: (value, principal) => Effect.provideContext(run(value, principal), context)
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
case "And": return new And(Arr.map(node.conditions, (child) => provide(child, context)));
|
|
308
|
-
case "Or": return new Or(Arr.map(node.conditions, (child) => provide(child, context)));
|
|
309
|
-
case "Not": return new Not(provide(node.condition, context));
|
|
310
|
-
default: return node;
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
/** The fields that a condition tests, in the order that they first come. */
|
|
314
|
-
const fields = (node) => {
|
|
315
|
-
const all = (current) => {
|
|
340
|
+
const provide = (node, context) => run(node.depth, (R) => {
|
|
341
|
+
const go = (current) => {
|
|
342
|
+
if (!current.opaque) return R.succeed(current);
|
|
316
343
|
switch (current._tag) {
|
|
317
|
-
case "
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
344
|
+
case "Predicate": {
|
|
345
|
+
const run = runOf(current);
|
|
346
|
+
return R.succeed(new Predicate({
|
|
347
|
+
name: current.name,
|
|
348
|
+
run: (value, principal) => Effect.provideContext(run(value, principal), context)
|
|
349
|
+
}));
|
|
350
|
+
}
|
|
351
|
+
case "And": return R.map(eachChild(R, current.conditions, go), (children) => new And(children));
|
|
352
|
+
case "Or": return R.map(eachChild(R, current.conditions, go), (children) => new Or(children));
|
|
353
|
+
case "Not": return R.map(R.suspend(() => go(current.condition)), (child) => new Not(child));
|
|
354
|
+
default: return R.succeed(current);
|
|
324
355
|
}
|
|
325
356
|
};
|
|
326
|
-
return
|
|
357
|
+
return go(node);
|
|
358
|
+
});
|
|
359
|
+
/** The fields that a condition tests, in the order that they first come. */
|
|
360
|
+
const fields = (node) => {
|
|
361
|
+
const all = run(node.depth, (R) => {
|
|
362
|
+
const go = (current) => {
|
|
363
|
+
switch (current._tag) {
|
|
364
|
+
case "Compare":
|
|
365
|
+
case "In":
|
|
366
|
+
case "Exists": return R.succeed([current.field]);
|
|
367
|
+
case "And":
|
|
368
|
+
case "Or": return R.map(eachChild(R, current.conditions, go), Arr.flatten);
|
|
369
|
+
case "Not": return R.suspend(() => go(current.condition));
|
|
370
|
+
default: return R.succeed([]);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
return go(node);
|
|
374
|
+
});
|
|
375
|
+
return Array.from(new Set(all));
|
|
327
376
|
};
|
|
328
|
-
export { and, evaluate, evaluateSync, fields, not, or, partial, provide, simplify,
|
|
377
|
+
export { and, evaluate, evaluateSync, fields, keyOf, not, or, partial, provide, simplify, testCompare };
|
|
329
378
|
|
|
330
379
|
//# sourceMappingURL=algebra.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"algebra.js","names":["Nodes","Nodes.And","Nodes.Or","Nodes.Compare","Nodes.Not","Nodes.isScalar","Nodes.runOf","Nodes.literal","Nodes.In","Nodes.Predicate"],"sources":["../../src/internal/algebra.ts"],"sourcesContent":["/**\n * The work on condition nodes: smart constructors, simplification, the step\n * that puts the principal in, tests on a value, and folds.\n *\n * The constructors of the nodes keep each condition small and low, so each\n * walk here is a plain walk with no memo. A shared child is walked again for\n * each place, and the limits of the nodes keep that work small.\n */\n// A predicate gives an Effect with an error type and a service type that this\n// code does not know, so they are `unknown` here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Arr from \"effect/Array\"\nimport type * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Option from \"effect/Option\"\nimport type * as Resource from \"../Resource.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport { readPath } from \"./read.ts\"\n\ntype Node = Nodes.Node\n\nconst { always, never } = Nodes\n\n// Keys of structure\n\n/** The text of an operand. The type is in it, so `\"1\"` is not `1`. */\nconst operandText = (operand: Nodes.Operand): ReadonlyArray<string> =>\n\toperand._tag === \"Literal\"\n\t\t? [typeof operand.value, String(operand.value)]\n\t\t: [\"principal\", operand.path]\n\n/** The parts of the text of a condition with no predicate. */\nconst shapeOf = (node: Node): unknown => {\n\tswitch (node._tag) {\n\t\tcase \"True\":\n\t\tcase \"False\":\n\t\t\treturn [node._tag]\n\t\tcase \"Compare\":\n\t\t\treturn [node._tag, node.op, node.field, operandText(node.value)]\n\t\tcase \"In\":\n\t\t\treturn [node._tag, node.field, Arr.map(node.values, operandText)]\n\t\tcase \"Exists\":\n\t\t\treturn [node._tag, node.field]\n\t\tcase \"Under\":\n\t\t\treturn [node._tag, Arr.map(node.prefix, operandText)]\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn [node._tag, Arr.map(node.conditions, shapeOf)]\n\t\tcase \"Not\":\n\t\t\treturn [node._tag, shapeOf(node.condition)]\n\t\tcase \"Predicate\":\n\t\t\t// A smart constructor and a search do not ask for the text of a\n\t\t\t// predicate: it is equal only to itself.\n\t\t\tthrow new Error(\"A predicate has no text of structure\")\n\t}\n}\n\n/**\n * The text of the structure of a condition with no predicate. Two conditions\n * with one text give the same answer for every value. It reads all of the\n * condition, so a search counts its size in the budget.\n */\nexport const structureText = (node: Node): string =>\n\tJSON.stringify(shapeOf(node))\n\n/**\n * The most nodes of a condition that a smart constructor reads for its key.\n * A larger child is its own key, so the work of a constructor stays small.\n */\nconst keyNodes = 64\n\n/**\n * The key of a child in a smart constructor: the text of its structure, or\n * the node itself when it is large. The keys go into a native `Set`, not a\n * `HashSet` of Effect. The hash of a string in Effect has no random seed, so\n * a policy could hold very many strings with one hash, and each test of the\n * set would read all of them. A native `Set` finds a node by the node itself,\n * and it hashes a string with the random seed of the engine.\n */\nconst keyOf = (node: Node): string | Node =>\n\tnode.size > keyNodes ? node : structureText(node)\n\n/**\n * Keeps the first node of each structure, in order. A large node is a copy\n * only of itself.\n */\nconst dedupe = (nodes: ReadonlyArray<Node>): ReadonlyArray<Node> => {\n\t// The set belongs to this call.\n\tconst seen = new Set<string | Node>()\n\treturn Arr.filter(nodes, (node) => {\n\t\tconst key = keyOf(node)\n\t\tif (seen.has(key)) {\n\t\t\treturn false\n\t\t}\n\t\tseen.add(key)\n\t\treturn true\n\t})\n}\n\n/**\n * Removes the children that the other children make useless. In an `Or`,\n * `a OR (a AND b)` is `a`. In an `And`, `a AND (a OR b)` is `a`.\n */\nconst absorb = (\n\tinner: \"And\" | \"Or\",\n\tnodes: ReadonlyArray<Node>,\n): ReadonlyArray<Node> => {\n\t// A native `Set`, as in `dedupe`.\n\tconst all = new Set(Arr.map(nodes, keyOf))\n\treturn Arr.filter(\n\t\tnodes,\n\t\t(node) =>\n\t\t\tnode._tag !== inner ||\n\t\t\t!Arr.some(node.conditions, (part) => all.has(keyOf(part))),\n\t)\n}\n\n// Smart constructors\n\n/**\n * Gives the result of an `And` with a `False` child, or of an `Or` with a\n * `True` child. The children are tested in order, so a predicate before the\n * constant still runs, and it may fail. When there is such a predicate, the\n * children before the constant stay, so the failure is not lost.\n */\nconst shortCircuit = (\n\ttag: \"And\" | \"Or\",\n\tchildren: ReadonlyArray<Node>,\n\tindex: number,\n): Node => {\n\tconst constant = tag === \"And\" ? never : always\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst before = Arr.filter(\n\t\tArr.take(children, index),\n\t\t(child) => child._tag !== neutral,\n\t)\n\tif (!Arr.some(before, (child) => child.opaque)) {\n\t\treturn constant\n\t}\n\treturn tag === \"And\"\n\t\t? new Nodes.And([...before, constant])\n\t\t: new Nodes.Or([...before, constant])\n}\n\n/**\n * Makes an `And` or an `Or` of simple children, and makes it simple. It looks\n * one level down only:\n * - it puts the children of a child of the same kind into the node;\n * - it stops at a `False` in an `And`, or at a `True` in an `Or`;\n * - it removes `True` from an `And`, `False` from an `Or`, copies, and the\n * children that other children make useless.\n *\n * A predicate may fail, and it may give another answer when it runs again. So\n * when a child has a predicate, the children stay as they are, and each one\n * runs in its place. A child with a predicate is not put into the node either.\n */\nconst junction = (tag: \"And\" | \"Or\", children: ReadonlyArray<Node>): Node => {\n\tconst constant = tag === \"And\" ? \"False\" : \"True\"\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst flat = Arr.flatMap(children, (child) =>\n\t\tchild._tag === tag && !child.opaque ? child.conditions : [child],\n\t)\n\treturn Option.match(\n\t\tArr.findFirstIndex(flat, (child) => child._tag === constant),\n\t\t{\n\t\t\tonSome: (stop) => shortCircuit(tag, flat, stop),\n\t\t\tonNone: () => {\n\t\t\t\tconst kept = Arr.filter(flat, (child) => child._tag !== neutral)\n\t\t\t\tconst unique = Arr.some(kept, (child) => child.opaque)\n\t\t\t\t\t? kept\n\t\t\t\t\t: absorb(tag === \"And\" ? \"Or\" : \"And\", dedupe(kept))\n\t\t\t\treturn unique.length === 0\n\t\t\t\t\t? tag === \"And\"\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: unique.length === 1\n\t\t\t\t\t\t? unique[0]!\n\t\t\t\t\t\t: tag === \"And\"\n\t\t\t\t\t\t\t? new Nodes.And(unique)\n\t\t\t\t\t\t\t: new Nodes.Or(unique)\n\t\t\t},\n\t\t},\n\t)\n}\n\n/** An `And` of simple children, made simple. */\nexport const and = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"And\", children)\n\n/** An `Or` of simple children, made simple. */\nexport const or = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"Or\", children)\n\n/** A `Not` of a simple child, made simple. */\nexport const not = (child: Node): Node => {\n\tswitch (child._tag) {\n\t\tcase \"True\":\n\t\t\treturn never\n\t\tcase \"False\":\n\t\t\treturn always\n\t\tcase \"Not\":\n\t\t\treturn child.condition\n\t\tcase \"Compare\":\n\t\t\t// A principal field with no value makes `eq` and `ne` both false, so\n\t\t\t// only a fixed value lets `not eq` become `ne`.\n\t\t\treturn child.value._tag === \"Literal\" &&\n\t\t\t\t(child.op === \"eq\" || child.op === \"ne\")\n\t\t\t\t? new Nodes.Compare({\n\t\t\t\t\t\top: child.op === \"eq\" ? \"ne\" : \"eq\",\n\t\t\t\t\t\tfield: child.field,\n\t\t\t\t\t\tvalue: child.value,\n\t\t\t\t\t})\n\t\t\t\t: new Nodes.Not(child)\n\t\tdefault:\n\t\t\treturn new Nodes.Not(child)\n\t}\n}\n\n/** Makes a condition simple, from its leaves up. */\nexport const simplify = (node: Node): Node => {\n\tswitch (node._tag) {\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn junction(node._tag, Arr.map(node.conditions, simplify))\n\t\tcase \"Not\":\n\t\t\treturn node.condition.pipe(simplify, not)\n\t\tcase \"In\":\n\t\t\treturn node.values.length === 0 ? never : node\n\t\tdefault:\n\t\t\treturn node\n\t}\n}\n\n// Tests on a value\n\n/** The data that a condition needs for a test. */\nexport interface Input {\n\treadonly value: object\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Gets a field of a value by a path with dots. It reads only plain data: see\n * `readPart`. A missing field, or a field under a value that is not an object,\n * gives `null`.\n */\nconst getField = (value: unknown, path: string): unknown =>\n\treadPath(value, path.split(\".\"))\n\n/**\n * Gives the value of an operand. A principal field that is `null`, missing, or\n * not a scalar gives `undefined`. No field of a resource is `undefined`, so a\n * test with it is never true. This keeps the check closed: a principal with no\n * id never matches a resource with no owner.\n */\nconst resolve = (operand: Nodes.Operand, principal: unknown): unknown => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand.value\n\t}\n\tconst value = getField(principal, operand.path)\n\treturn value !== null && Nodes.isScalar(value) ? value : undefined\n}\n\nexport const testCompare = (\n\top: Nodes.CompareOperator,\n\tleft: unknown,\n\tright: unknown,\n): boolean => {\n\tif (right === undefined) {\n\t\treturn false\n\t}\n\tswitch (op) {\n\t\tcase \"eq\":\n\t\t\treturn left === right\n\t\tcase \"ne\":\n\t\t\treturn left !== right\n\t\tdefault: {\n\t\t\tconst ordered =\n\t\t\t\t(typeof left === \"number\" && typeof right === \"number\") ||\n\t\t\t\t(typeof left === \"string\" && typeof right === \"string\")\n\t\t\tif (!ordered) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst a = left as number | string\n\t\t\tconst b = right as number | string\n\t\t\tswitch (op) {\n\t\t\t\tcase \"lt\":\n\t\t\t\t\treturn a < b\n\t\t\t\tcase \"lte\":\n\t\t\t\t\treturn a <= b\n\t\t\t\tcase \"gt\":\n\t\t\t\t\treturn a > b\n\t\t\t\tcase \"gte\":\n\t\t\t\t\treturn a >= b\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Gives the values of the path of a resource, or `undefined` for no path. */\nconst pathValues = (\n\tvalue: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): ReadonlyArray<unknown> | undefined =>\n\tpath?.map((segment) =>\n\t\ttypeof segment === \"string\" ? segment : getField(value, segment.field),\n\t)\n\nconst testUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tinput: Input,\n): boolean => {\n\tconst values = pathValues(input.value, input.path)\n\tif (values === undefined || prefix.length > values.length) {\n\t\treturn false\n\t}\n\t// An operand with no value never matches, also a hole in a path that gives\n\t// `undefined` too.\n\treturn prefix.every((operand, index) => {\n\t\tconst value = resolve(operand, input.principal)\n\t\treturn value !== undefined && value === values[index]\n\t})\n}\n\n/** Tests a simple condition with no predicate on a value. */\nconst testSync = (node: Node, input: Input): boolean => {\n\tswitch (node._tag) {\n\t\tcase \"True\":\n\t\t\treturn true\n\t\tcase \"False\":\n\t\t\treturn false\n\t\tcase \"Compare\":\n\t\t\treturn testCompare(\n\t\t\t\tnode.op,\n\t\t\t\tgetField(input.value, node.field),\n\t\t\t\tresolve(node.value, input.principal),\n\t\t\t)\n\t\tcase \"In\": {\n\t\t\tconst field = getField(input.value, node.field)\n\t\t\treturn node.values.some(\n\t\t\t\t(operand) => resolve(operand, input.principal) === field,\n\t\t\t)\n\t\t}\n\t\tcase \"Exists\":\n\t\t\treturn getField(input.value, node.field) !== null\n\t\tcase \"Under\":\n\t\t\treturn testUnder(node.prefix, input)\n\t\tcase \"And\":\n\t\t\treturn Arr.every(node.conditions, (child) => testSync(child, input))\n\t\tcase \"Or\":\n\t\t\treturn Arr.some(node.conditions, (child) => testSync(child, input))\n\t\tcase \"Not\":\n\t\t\treturn !testSync(node.condition, input)\n\t\tcase \"Predicate\":\n\t\t\t// The types stop this. A predicate needs `evaluate`.\n\t\t\tthrow new Error(\n\t\t\t\t`The predicate \"${node.name}\" needs an Effect. Use Condition.evaluate.`,\n\t\t\t)\n\t}\n}\n\n/**\n * Tests a simple condition on a value. The children of `And` and `Or` run in\n * order, and they stop at the first child that gives the answer.\n */\nconst test = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> => {\n\tif (!node.opaque) {\n\t\treturn Effect.sync(() => testSync(node, input))\n\t}\n\tswitch (node._tag) {\n\t\tcase \"Predicate\":\n\t\t\treturn Nodes.runOf(node)(input.value, input.principal)\n\t\tcase \"Not\":\n\t\t\treturn Effect.map(test(node.condition, input), (value) => !value)\n\t\tcase \"And\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) =>\n\t\t\t\t\tEffect.map(test(child, input), (value) => !value),\n\t\t\t\t),\n\t\t\t\tOption.isNone,\n\t\t\t)\n\t\tcase \"Or\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) => test(child, input)),\n\t\t\t\tOption.isSome,\n\t\t\t)\n\t\tdefault:\n\t\t\treturn Effect.sync(() => testSync(node, input))\n\t}\n}\n\n/**\n * Tests a condition with no predicate on a value. The test runs on the\n * simple form of the condition with the principal in it, as a residual does.\n * So a test reads only the fields that the residual reads: a read of a field\n * that is not plain data is a defect, and a field that the answer does not\n * need, as in `x AND False`, is not read.\n */\nexport const evaluateSync = (node: Node, input: Input): boolean =>\n\ttestSync(partial(node, input), input)\n\n/** Tests a condition on a value, as {@link evaluateSync} does. */\nexport const evaluate = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> =>\n\tEffect.suspend(() => test(partial(node, input), input))\n\n// The principal and the path\n\n/**\n * Puts the value of the principal into an operand. It gives `undefined` for a\n * principal field with no value. See {@link resolve}.\n */\nconst bindOperand = (\n\toperand: Nodes.Operand,\n\tprincipal: unknown,\n): Nodes.Literal | undefined => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand\n\t}\n\tconst value = resolve(operand, principal)\n\treturn value === undefined ? undefined : Nodes.literal(value as Nodes.Scalar)\n}\n\nconst expandUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tprincipal: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): Node => {\n\tif (path === undefined || prefix.length > path.length) {\n\t\treturn never\n\t}\n\treturn and(\n\t\tArr.map(prefix, (operand, index): Node => {\n\t\t\tconst value = resolve(operand, principal)\n\t\t\tconst segment = path[index]!\n\t\t\treturn value === undefined\n\t\t\t\t? never\n\t\t\t\t: typeof segment === \"string\"\n\t\t\t\t\t? segment === value\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: new Nodes.Compare({\n\t\t\t\t\t\t\top: \"eq\",\n\t\t\t\t\t\t\tfield: segment.field,\n\t\t\t\t\t\t\tvalue: Nodes.literal(value as Nodes.Scalar),\n\t\t\t\t\t\t})\n\t\t}),\n\t)\n}\n\n/** The principal and the path of the resource, for {@link partial}. */\nexport interface PartialInput {\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Puts the principal into a condition and expands `Under` with the path of the\n * resource. The result is simple. It has no principal fields and no `Under`\n * nodes. A predicate keeps the principal.\n */\nexport const partial = (node: Node, input: PartialInput): Node => {\n\tconst bind = (current: Node): Node => {\n\t\tswitch (current._tag) {\n\t\t\tcase \"Compare\": {\n\t\t\t\tconst value = bindOperand(current.value, input.principal)\n\t\t\t\treturn value === undefined\n\t\t\t\t\t? never\n\t\t\t\t\t: value === current.value\n\t\t\t\t\t\t? current\n\t\t\t\t\t\t: new Nodes.Compare({ op: current.op, field: current.field, value })\n\t\t\t}\n\t\t\tcase \"In\": {\n\t\t\t\tconst values = Arr.flatMap(current.values, (operand) =>\n\t\t\t\t\tOption.toArray(\n\t\t\t\t\t\tOption.fromUndefinedOr(bindOperand(operand, input.principal)),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\treturn values.length === 0\n\t\t\t\t\t? never\n\t\t\t\t\t: new Nodes.In({ field: current.field, values })\n\t\t\t}\n\t\t\tcase \"Under\":\n\t\t\t\treturn expandUnder(current.prefix, input.principal, input.path)\n\t\t\tcase \"And\":\n\t\t\t\treturn and(Arr.map(current.conditions, bind))\n\t\t\tcase \"Or\":\n\t\t\t\treturn or(Arr.map(current.conditions, bind))\n\t\t\tcase \"Not\":\n\t\t\t\treturn current.condition.pipe(bind, not)\n\t\t\tcase \"Predicate\": {\n\t\t\t\tconst run = Nodes.runOf(current)\n\t\t\t\treturn new Nodes.Predicate({\n\t\t\t\t\tname: current.name,\n\t\t\t\t\trun: (value) => run(value, input.principal),\n\t\t\t\t})\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn current\n\t\t}\n\t}\n\treturn bind(node)\n}\n\n/** Gives the services in `context` to every predicate of a condition. */\nexport const provide = (node: Node, context: Context.Context<never>): Node => {\n\tif (!node.opaque) {\n\t\treturn node\n\t}\n\tswitch (node._tag) {\n\t\tcase \"Predicate\": {\n\t\t\tconst run = Nodes.runOf(node)\n\t\t\treturn new Nodes.Predicate({\n\t\t\t\tname: node.name,\n\t\t\t\trun: (value, principal) =>\n\t\t\t\t\tEffect.provideContext(run(value, principal), context),\n\t\t\t})\n\t\t}\n\t\tcase \"And\":\n\t\t\treturn new Nodes.And(\n\t\t\t\tArr.map(node.conditions, (child) => provide(child, context)),\n\t\t\t)\n\t\tcase \"Or\":\n\t\t\treturn new Nodes.Or(\n\t\t\t\tArr.map(node.conditions, (child) => provide(child, context)),\n\t\t\t)\n\t\tcase \"Not\":\n\t\t\treturn new Nodes.Not(provide(node.condition, context))\n\t\tdefault:\n\t\t\treturn node\n\t}\n}\n\n/** The fields that a condition tests, in the order that they first come. */\nexport const fields = (node: Node): ReadonlyArray<string> => {\n\tconst all = (current: Node): ReadonlyArray<string> => {\n\t\tswitch (current._tag) {\n\t\t\tcase \"Compare\":\n\t\t\tcase \"In\":\n\t\t\tcase \"Exists\":\n\t\t\t\treturn [current.field]\n\t\t\tcase \"And\":\n\t\t\tcase \"Or\":\n\t\t\t\treturn Arr.flatMap(current.conditions, all)\n\t\t\tcase \"Not\":\n\t\t\t\treturn all(current.condition)\n\t\t\tdefault:\n\t\t\t\treturn []\n\t\t}\n\t}\n\t// A native `Set`, as in `dedupe`: a field of a condition that is not bound\n\t// to a domain may be any string.\n\treturn Array.from(new Set(all(node)))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"algebra.js","names":["Nodes","Nodes.And","Nodes.Or","Nodes.Compare","Nodes.Not","Trampoline.run","Nodes.isScalar","Trampoline.loop","Trampoline.toEffect","Nodes.runOf","Nodes.literal","Nodes.In","Nodes.Predicate"],"sources":["../../src/internal/algebra.ts"],"sourcesContent":["/**\n * The work on condition nodes: smart constructors, simplification, the step\n * that puts the principal in, tests on a value, and folds.\n *\n * The constructors of the nodes keep each condition small, so each walk here\n * has no memo. A shared child is walked again for each place, and the limits\n * of the nodes keep that work small. A walk takes the steps of a trampoline,\n * so a deep condition does not fill the stack: see `Trampoline`.\n */\n// A predicate gives an Effect with an error type and a service type that this\n// code does not know, so they are `unknown` here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Arr from \"effect/Array\"\nimport type * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Option from \"effect/Option\"\nimport type * as Resource from \"../Resource.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport { readPath } from \"./read.ts\"\nimport * as Trampoline from \"./trampoline.ts\"\n\ntype Node = Nodes.Node\n\nconst { always, never } = Nodes\n\n// Keys of structure\n\n/** The text of an operand. The type is in it, so `\"1\"` is not `1`. */\nconst operandText = (operand: Nodes.Operand): ReadonlyArray<string> =>\n\toperand._tag === \"Literal\"\n\t\t? [typeof operand.value, String(operand.value)]\n\t\t: [\"principal\", operand.path]\n\n/** The parts of the text of a condition with no predicate. */\nconst shapeOf = (node: Node): unknown => {\n\tswitch (node._tag) {\n\t\tcase \"True\":\n\t\tcase \"False\":\n\t\t\treturn [node._tag]\n\t\tcase \"Compare\":\n\t\t\treturn [node._tag, node.op, node.field, operandText(node.value)]\n\t\tcase \"In\":\n\t\t\treturn [node._tag, node.field, Arr.map(node.values, operandText)]\n\t\tcase \"Exists\":\n\t\t\treturn [node._tag, node.field]\n\t\tcase \"Under\":\n\t\t\treturn [node._tag, Arr.map(node.prefix, operandText)]\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn [node._tag, Arr.map(node.conditions, shapeOf)]\n\t\tcase \"Not\":\n\t\t\treturn [node._tag, shapeOf(node.condition)]\n\t\tcase \"Predicate\":\n\t\t\t// A smart constructor and a search do not ask for the text of a\n\t\t\t// predicate: it is equal only to itself.\n\t\t\tthrow new Error(\"A predicate has no text of structure\")\n\t}\n}\n\n/**\n * The text of the structure of a condition with no predicate. Two conditions\n * with one text give the same answer for every value. It reads all of the\n * condition, so a search counts its size in the budget.\n */\nconst structureText = (node: Node): string => JSON.stringify(shapeOf(node))\n\n/**\n * The work of the text of the structure of a condition: each node, and each\n * value of an `In` test or an `Under` test. A node counts as one in `size`,\n * also an `In` test with very many values. This walk reads the nodes only,\n * so it takes `size` steps.\n */\nconst weightOf = (node: Node): number => {\n\tswitch (node._tag) {\n\t\tcase \"In\":\n\t\t\treturn 1 + node.values.length\n\t\tcase \"Under\":\n\t\t\treturn 1 + node.prefix.length\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn Arr.reduce(\n\t\t\t\tnode.conditions,\n\t\t\t\t1,\n\t\t\t\t(total, child) => total + weightOf(child),\n\t\t\t)\n\t\tcase \"Not\":\n\t\t\treturn 1 + weightOf(node.condition)\n\t\tdefault:\n\t\t\treturn 1\n\t}\n}\n\n/**\n * The most nodes of a condition that a smart constructor reads for its key,\n * and the most children of a child that it puts into a node. A larger child\n * is its own key, and it stays one child, so the work of a constructor stays\n * small. A deep chain of `And` nodes, for one, does not copy all its leaves\n * at each level.\n */\nconst keyNodes = 64\n\n/** The most work of a key, with the values of its tests: see {@link weightOf}. */\nconst keyWeight = 256\n\n/**\n * The key of a child in a smart constructor: the text of its structure, or\n * the node itself when it is large. The keys go into a native `Set`, not a\n * `HashSet` of Effect. The hash of a string in Effect has no random seed, so\n * a policy could hold very many strings with one hash, and each test of the\n * set would read all of them. A native `Set` finds a node by the node itself,\n * and it hashes a string with the random seed of the engine.\n */\nexport const keyOf = (node: Node): string | Node =>\n\tnode.size > keyNodes || weightOf(node) > keyWeight\n\t\t? node\n\t\t: structureText(node)\n\n/**\n * Keeps the first node of each structure, in order. A large node is a copy\n * only of itself.\n */\nconst dedupe = (nodes: ReadonlyArray<Node>): ReadonlyArray<Node> => {\n\t// The set belongs to this call.\n\tconst seen = new Set<string | Node>()\n\treturn Arr.filter(nodes, (node) => {\n\t\tconst key = keyOf(node)\n\t\tif (seen.has(key)) {\n\t\t\treturn false\n\t\t}\n\t\tseen.add(key)\n\t\treturn true\n\t})\n}\n\n/**\n * Removes the children that the other children make useless. In an `Or`,\n * `a OR (a AND b)` is `a`. In an `And`, `a AND (a OR b)` is `a`.\n */\nconst absorb = (\n\tinner: \"And\" | \"Or\",\n\tnodes: ReadonlyArray<Node>,\n): ReadonlyArray<Node> => {\n\t// A native `Set`, as in `dedupe`.\n\tconst all = new Set(Arr.map(nodes, keyOf))\n\treturn Arr.filter(\n\t\tnodes,\n\t\t(node) =>\n\t\t\tnode._tag !== inner ||\n\t\t\t!Arr.some(node.conditions, (part) => all.has(keyOf(part))),\n\t)\n}\n\n// Smart constructors\n\n/**\n * Gives the result of an `And` with a `False` child, or of an `Or` with a\n * `True` child. The children are tested in order, so a predicate before the\n * constant still runs, and it may fail. When there is such a predicate, the\n * children before the constant stay, so the failure is not lost.\n */\nconst shortCircuit = (\n\ttag: \"And\" | \"Or\",\n\tchildren: ReadonlyArray<Node>,\n\tindex: number,\n): Node => {\n\tconst constant = tag === \"And\" ? never : always\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst before = Arr.filter(\n\t\tArr.take(children, index),\n\t\t(child) => child._tag !== neutral,\n\t)\n\tif (!Arr.some(before, (child) => child.opaque)) {\n\t\treturn constant\n\t}\n\treturn tag === \"And\"\n\t\t? new Nodes.And([...before, constant])\n\t\t: new Nodes.Or([...before, constant])\n}\n\n/**\n * Makes an `And` or an `Or` of simple children, and makes it simple. It looks\n * one level down only:\n * - it puts the children of a child of the same kind into the node, when\n * the child has at most `keyNodes` of them;\n * - it stops at a `False` in an `And`, or at a `True` in an `Or`;\n * - it removes `True` from an `And`, `False` from an `Or`, copies, and the\n * children that other children make useless.\n *\n * A predicate may fail, and it may give another answer when it runs again. So\n * when a child has a predicate, the children stay as they are, and each one\n * runs in its place. A child with a predicate is not put into the node either.\n */\nconst junction = (tag: \"And\" | \"Or\", children: ReadonlyArray<Node>): Node => {\n\tconst constant = tag === \"And\" ? \"False\" : \"True\"\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst flat = Arr.flatMap(children, (child) =>\n\t\tchild._tag === tag && !child.opaque && child.conditions.length <= keyNodes\n\t\t\t? child.conditions\n\t\t\t: [child],\n\t)\n\treturn Option.match(\n\t\tArr.findFirstIndex(flat, (child) => child._tag === constant),\n\t\t{\n\t\t\tonSome: (stop) => shortCircuit(tag, flat, stop),\n\t\t\tonNone: () => {\n\t\t\t\tconst kept = Arr.filter(flat, (child) => child._tag !== neutral)\n\t\t\t\tconst unique = Arr.some(kept, (child) => child.opaque)\n\t\t\t\t\t? kept\n\t\t\t\t\t: absorb(tag === \"And\" ? \"Or\" : \"And\", dedupe(kept))\n\t\t\t\treturn unique.length === 0\n\t\t\t\t\t? tag === \"And\"\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: unique.length === 1\n\t\t\t\t\t\t? unique[0]!\n\t\t\t\t\t\t: tag === \"And\"\n\t\t\t\t\t\t\t? new Nodes.And(unique)\n\t\t\t\t\t\t\t: new Nodes.Or(unique)\n\t\t\t},\n\t\t},\n\t)\n}\n\n/** An `And` of simple children, made simple. */\nexport const and = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"And\", children)\n\n/** An `Or` of simple children, made simple. */\nexport const or = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"Or\", children)\n\n/** A `Not` of a simple child, made simple. */\nexport const not = (child: Node): Node => {\n\tswitch (child._tag) {\n\t\tcase \"True\":\n\t\t\treturn never\n\t\tcase \"False\":\n\t\t\treturn always\n\t\tcase \"Not\":\n\t\t\treturn child.condition\n\t\tcase \"Compare\":\n\t\t\t// A principal field with no value makes `eq` and `ne` both false, so\n\t\t\t// only a fixed value lets `not eq` become `ne`.\n\t\t\treturn child.value._tag === \"Literal\" &&\n\t\t\t\t(child.op === \"eq\" || child.op === \"ne\")\n\t\t\t\t? new Nodes.Compare({\n\t\t\t\t\t\top: child.op === \"eq\" ? \"ne\" : \"eq\",\n\t\t\t\t\t\tfield: child.field,\n\t\t\t\t\t\tvalue: child.value,\n\t\t\t\t\t})\n\t\t\t\t: new Nodes.Not(child)\n\t\tdefault:\n\t\t\treturn new Nodes.Not(child)\n\t}\n}\n\ntype Step<A> = Trampoline.Step<A>\n\n/** The children of a node, each walked by `go` as a step of `R`. */\nconst eachChild = <A>(\n\tR: Trampoline.Runner,\n\tchildren: ReadonlyArray<Node>,\n\tgo: (child: Node) => Step<A>,\n): Step<ReadonlyArray<A>> =>\n\tR.forEach(children, (child) => R.suspend(() => go(child)))\n\n/** Makes a condition simple, from its leaves up. */\nexport const simplify = (node: Node): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<Node> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"And\":\n\t\t\t\tcase \"Or\": {\n\t\t\t\t\tconst tag = current._tag\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, go), (children) =>\n\t\t\t\t\t\tjunction(tag, children),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => go(current.condition)),\n\t\t\t\t\t\tnot,\n\t\t\t\t\t)\n\t\t\t\tcase \"In\":\n\t\t\t\t\treturn R.succeed(current.values.length === 0 ? never : current)\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\n// Tests on a value\n\n/** The data that a condition needs for a test. */\nexport interface Input {\n\treadonly value: object\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Gets a field of a value by a path with dots. It reads only plain data: see\n * `readPart`. A missing field, or a field under a value that is not an object,\n * gives `null`.\n */\nconst getField = (value: unknown, path: string): unknown =>\n\treadPath(value, path.split(\".\"))\n\n/**\n * Gives the value of an operand. A principal field that is `null`, missing, or\n * not a scalar gives `undefined`. No field of a resource is `undefined`, so a\n * test with it is never true. This keeps the check closed: a principal with no\n * id never matches a resource with no owner.\n */\nconst resolve = (operand: Nodes.Operand, principal: unknown): unknown => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand.value\n\t}\n\tconst value = getField(principal, operand.path)\n\treturn value !== null && Nodes.isScalar(value) ? value : undefined\n}\n\nexport const testCompare = (\n\top: Nodes.CompareOperator,\n\tleft: unknown,\n\tright: unknown,\n): boolean => {\n\tif (right === undefined) {\n\t\treturn false\n\t}\n\tswitch (op) {\n\t\tcase \"eq\":\n\t\t\treturn left === right\n\t\tcase \"ne\":\n\t\t\treturn left !== right\n\t\tdefault: {\n\t\t\tconst ordered =\n\t\t\t\t(typeof left === \"number\" && typeof right === \"number\") ||\n\t\t\t\t(typeof left === \"string\" && typeof right === \"string\")\n\t\t\tif (!ordered) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst a = left as number | string\n\t\t\tconst b = right as number | string\n\t\t\tswitch (op) {\n\t\t\t\tcase \"lt\":\n\t\t\t\t\treturn a < b\n\t\t\t\tcase \"lte\":\n\t\t\t\t\treturn a <= b\n\t\t\t\tcase \"gt\":\n\t\t\t\t\treturn a > b\n\t\t\t\tcase \"gte\":\n\t\t\t\t\treturn a >= b\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Gives the values of the path of a resource, or `undefined` for no path. */\nconst pathValues = (\n\tvalue: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): ReadonlyArray<unknown> | undefined =>\n\tpath?.map((segment) =>\n\t\ttypeof segment === \"string\" ? segment : getField(value, segment.field),\n\t)\n\nconst testUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tinput: Input,\n): boolean => {\n\tconst values = pathValues(input.value, input.path)\n\tif (values === undefined || prefix.length > values.length) {\n\t\treturn false\n\t}\n\t// An operand with no value never matches, also a hole in a path that gives\n\t// `undefined` too.\n\treturn prefix.every((operand, index) => {\n\t\tconst value = resolve(operand, input.principal)\n\t\treturn value !== undefined && value === values[index]\n\t})\n}\n\n/**\n * The test of a simple condition with no predicate on a value, as a walk.\n * The children of `And` and `Or` run in order, and they stop at the first\n * child that gives the answer.\n */\nconst testWith = (input: Input) => (R: Trampoline.Runner) => {\n\tconst go = (node: Node): Step<boolean> => {\n\t\tswitch (node._tag) {\n\t\t\tcase \"True\":\n\t\t\t\treturn R.succeed(true)\n\t\t\tcase \"False\":\n\t\t\t\treturn R.succeed(false)\n\t\t\tcase \"Compare\":\n\t\t\t\treturn R.succeed(\n\t\t\t\t\ttestCompare(\n\t\t\t\t\t\tnode.op,\n\t\t\t\t\t\tgetField(input.value, node.field),\n\t\t\t\t\t\tresolve(node.value, input.principal),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\tcase \"In\": {\n\t\t\t\tconst field = getField(input.value, node.field)\n\t\t\t\treturn R.succeed(\n\t\t\t\t\tnode.values.some(\n\t\t\t\t\t\t(operand) => resolve(operand, input.principal) === field,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t\tcase \"Exists\":\n\t\t\t\treturn R.succeed(getField(input.value, node.field) !== null)\n\t\t\tcase \"Under\":\n\t\t\t\treturn R.succeed(testUnder(node.prefix, input))\n\t\t\tcase \"And\":\n\t\t\t\treturn R.every(node.conditions, (child) => R.suspend(() => go(child)))\n\t\t\tcase \"Or\":\n\t\t\t\treturn R.some(node.conditions, (child) => R.suspend(() => go(child)))\n\t\t\tcase \"Not\":\n\t\t\t\treturn R.map(\n\t\t\t\t\tR.suspend(() => go(node.condition)),\n\t\t\t\t\t(value) => !value,\n\t\t\t\t)\n\t\t\tcase \"Predicate\":\n\t\t\t\t// The types stop this. A predicate needs `evaluate`.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The predicate \"${node.name}\" needs an Effect. Use Condition.evaluate.`,\n\t\t\t\t)\n\t\t}\n\t}\n\treturn go\n}\n\n/** Tests a simple condition with no predicate on a value. */\nconst testSync = (node: Node, input: Input): boolean =>\n\tTrampoline.run(node.depth, (R) => testWith(input)(R)(node))\n\n/**\n * Tests a simple condition on a value. The children of `And` and `Or` run in\n * order, and they stop at the first child that gives the answer. Each call\n * for a child is a step of the Effect, so a deep condition does not fill the\n * stack. A part with no predicate runs as a walk in the same loop.\n */\nconst test = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> => {\n\tif (!node.opaque) {\n\t\treturn node.depth <= Trampoline.directDepth\n\t\t\t? Effect.sync(() => testSync(node, input))\n\t\t\t: node.pipe(testWith(input)(Trampoline.loop), Trampoline.toEffect)\n\t}\n\tswitch (node._tag) {\n\t\tcase \"Predicate\":\n\t\t\treturn Nodes.runOf(node)(input.value, input.principal)\n\t\tcase \"Not\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.suspend(() => test(node.condition, input)),\n\t\t\t\t(value) => !value,\n\t\t\t)\n\t\tcase \"And\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) =>\n\t\t\t\t\tEffect.map(\n\t\t\t\t\t\tEffect.suspend(() => test(child, input)),\n\t\t\t\t\t\t(value) => !value,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tOption.isNone,\n\t\t\t)\n\t\tcase \"Or\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) =>\n\t\t\t\t\tEffect.suspend(() => test(child, input)),\n\t\t\t\t),\n\t\t\t\tOption.isSome,\n\t\t\t)\n\t\tdefault:\n\t\t\treturn Effect.sync(() => testSync(node, input))\n\t}\n}\n\n/**\n * Tests a condition with no predicate on a value. The test runs on the\n * simple form of the condition with the principal in it, as a residual does.\n * So a test reads only the fields that the residual reads: a read of a field\n * that is not plain data is a defect, and a field that the answer does not\n * need, as in `x AND False`, is not read.\n */\nexport const evaluateSync = (node: Node, input: Input): boolean =>\n\ttestSync(partial(node, input), input)\n\n/** Tests a condition on a value, as {@link evaluateSync} does. */\nexport const evaluate = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> =>\n\tEffect.suspend(() => test(partial(node, input), input))\n\n// The principal and the path\n\n/**\n * Puts the value of the principal into an operand. It gives `undefined` for a\n * principal field with no value. See {@link resolve}.\n */\nconst bindOperand = (\n\toperand: Nodes.Operand,\n\tprincipal: unknown,\n): Nodes.Literal | undefined => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand\n\t}\n\tconst value = resolve(operand, principal)\n\treturn value === undefined ? undefined : Nodes.literal(value as Nodes.Scalar)\n}\n\nconst expandUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tprincipal: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): Node => {\n\tif (path === undefined || prefix.length > path.length) {\n\t\treturn never\n\t}\n\treturn and(\n\t\tArr.map(prefix, (operand, index): Node => {\n\t\t\tconst value = resolve(operand, principal)\n\t\t\tconst segment = path[index]!\n\t\t\treturn value === undefined\n\t\t\t\t? never\n\t\t\t\t: typeof segment === \"string\"\n\t\t\t\t\t? segment === value\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: new Nodes.Compare({\n\t\t\t\t\t\t\top: \"eq\",\n\t\t\t\t\t\t\tfield: segment.field,\n\t\t\t\t\t\t\tvalue: Nodes.literal(value as Nodes.Scalar),\n\t\t\t\t\t\t})\n\t\t}),\n\t)\n}\n\n/** The principal and the path of the resource, for {@link partial}. */\nexport interface PartialInput {\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Puts the principal into a condition and expands `Under` with the path of the\n * resource. The result is simple. It has no principal fields and no `Under`\n * nodes. A predicate keeps the principal.\n */\nexport const partial = (node: Node, input: PartialInput): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst bind = (current: Node): Step<Node> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Compare\": {\n\t\t\t\t\tconst value = bindOperand(current.value, input.principal)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tvalue === undefined\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: value === current.value\n\t\t\t\t\t\t\t\t? current\n\t\t\t\t\t\t\t\t: new Nodes.Compare({\n\t\t\t\t\t\t\t\t\t\top: current.op,\n\t\t\t\t\t\t\t\t\t\tfield: current.field,\n\t\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"In\": {\n\t\t\t\t\tconst values = Arr.flatMap(current.values, (operand) =>\n\t\t\t\t\t\tOption.toArray(\n\t\t\t\t\t\t\tOption.fromUndefinedOr(bindOperand(operand, input.principal)),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tvalues.length === 0\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: new Nodes.In({ field: current.field, values }),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"Under\":\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\texpandUnder(current.prefix, input.principal, input.path),\n\t\t\t\t\t)\n\t\t\t\tcase \"And\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, bind), and)\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, bind), or)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => bind(current.condition)),\n\t\t\t\t\t\tnot,\n\t\t\t\t\t)\n\t\t\t\tcase \"Predicate\": {\n\t\t\t\t\tconst run = Nodes.runOf(current)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tnew Nodes.Predicate({\n\t\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\t\trun: (value) => run(value, input.principal),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn bind(node)\n\t})\n\n/** Gives the services in `context` to every predicate of a condition. */\nexport const provide = (node: Node, context: Context.Context<never>): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<Node> => {\n\t\t\tif (!current.opaque) {\n\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Predicate\": {\n\t\t\t\t\tconst run = Nodes.runOf(current)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tnew Nodes.Predicate({\n\t\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\t\trun: (value, principal) =>\n\t\t\t\t\t\t\t\tEffect.provideContext(run(value, principal), context),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"And\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\teachChild(R, current.conditions, go),\n\t\t\t\t\t\t(children) => new Nodes.And(children),\n\t\t\t\t\t)\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\teachChild(R, current.conditions, go),\n\t\t\t\t\t\t(children) => new Nodes.Or(children),\n\t\t\t\t\t)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => go(current.condition)),\n\t\t\t\t\t\t(child) => new Nodes.Not(child),\n\t\t\t\t\t)\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\n/** The fields that a condition tests, in the order that they first come. */\nexport const fields = (node: Node): ReadonlyArray<string> => {\n\tconst all = Trampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<ReadonlyArray<string>> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Compare\":\n\t\t\t\tcase \"In\":\n\t\t\t\tcase \"Exists\":\n\t\t\t\t\treturn R.succeed([current.field])\n\t\t\t\tcase \"And\":\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, go), Arr.flatten)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.suspend(() => go(current.condition))\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed([])\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\t// A native `Set`, as in `dedupe`: a field of a condition that is not bound\n\t// to a domain may be any string.\n\treturn Array.from(new Set(all))\n}\n"],"mappings":"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"}
|
|
@@ -144,7 +144,7 @@ const scopeOf = (request, domain, input) => {
|
|
|
144
144
|
actions: [request.action],
|
|
145
145
|
resources: [request.kind],
|
|
146
146
|
when: ast
|
|
147
|
-
}, ["within"]);
|
|
147
|
+
}, () => ["within"]);
|
|
148
148
|
if (issues.length > 0) throw new globalThis.Error(`A scope does not fit the domain: ${issues.map((issue) => issue.issue).join("; ")}`);
|
|
149
149
|
return partial(ast, input);
|
|
150
150
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis.js","names":["Condition.always","Condition.never","Limits.exceeded","Limits.residualNodes","Algebra.and","Algebra.or","Algebra.not","RuleData.matchesTarget","Condition.partial","Nodes.toNode","Condition.builder","Bind.ruleIssues","DomainData.descriptorOf","RuleData.fitsOf","PolicyNodes.rulesOf","ResourceData.kindOf","Search.satisfiable","Search.kindsIn","Decision.Deny","Decision.Allow","Decision.NotApplicable"],"sources":["../../src/internal/analysis.ts"],"sourcesContent":["/**\n * The residual conditions and the coverage of a policy. The types are in\n * `Policy.ts`.\n */\n// A policy keeps the error type and the service type of its predicates in the\n// public types. The code below works on the nodes with no types, where they\n// are `unknown`, so the language service check for `unknown` in an Effect is\n// off here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Data from \"effect/Data\"\nimport * as Arr from \"effect/Array\"\nimport * as Effect from \"effect/Effect\"\nimport * as Condition from \"../Condition.ts\"\nimport * as Decision from \"../Decision.ts\"\nimport type * as Domain from \"../Domain.ts\"\nimport type * as Policy from \"../Policy.ts\"\nimport type * as Resource from \"../Resource.ts\"\nimport * as Algebra from \"./algebra.ts\"\nimport * as Bind from \"./bind.ts\"\nimport type * as Catalog from \"./catalog.ts\"\nimport { decideNode, fitsKind } from \"./decide.ts\"\nimport * as DomainData from \"./domain.ts\"\nimport * as Limits from \"./limits.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport * as PolicyNodes from \"./policy-nodes.ts\"\nimport { nodeOf } from \"./policy.ts\"\nimport * as ResourceData from \"./resource.ts\"\nimport * as RuleData from \"./rule.ts\"\nimport * as Search from \"./search.ts\"\n\ntype Any = Policy.Any\n\ntype Ast = Condition.Ast\n\nconst always: Ast = Condition.always\nconst never: Ast = Condition.never\n\n/**\n * Makes conditions for one residual, with no types. Each step makes the\n * condition simple, and it stops the work when the condition has more nodes\n * than `residualNodes`. A policy tree may use a condition of a child two\n * times, in its allow condition and in its deny condition, so a small policy\n * may give a very large condition.\n */\ninterface Build {\n\t// A list goes in as an array, not as arguments: a call may take only so\n\t// many arguments, and a policy may have more rules.\n\treadonly and: (values: ReadonlyArray<Ast>) => Ast\n\treadonly or: (values: ReadonlyArray<Ast>) => Ast\n\treadonly not: (value: Ast) => Ast\n}\n\nconst limit = (node: Nodes.Node): Ast => {\n\tif (node.size > Limits.residualNodes) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A residual condition\",\n\t\t\t\"residualNodes\",\n\t\t\t\"nodes\",\n\t\t\tnode.size,\n\t\t\tLimits.residualNodes,\n\t\t)\n\t}\n\treturn node\n}\n\nconst build: Build = {\n\tand: (values) => limit(Algebra.and(values as ReadonlyArray<Nodes.Node>)),\n\tor: (values) => limit(Algebra.or(values as ReadonlyArray<Nodes.Node>)),\n\tnot: (value) => (value as Nodes.Node).pipe(Algebra.not, limit),\n}\n\n/** The two residual conditions of a node, with no types. */\ninterface Pair {\n\treadonly allow: Ast\n\treadonly deny: Ast\n}\n\ninterface ResidualContext {\n\treadonly action: string\n\treadonly kind: string\n\treadonly field: string | undefined\n\treadonly input: {\n\t\treadonly principal: object\n\t\treadonly path: Condition.Input[\"path\"]\n\t}\n\t/** The resource of the kind, for the fields that a rule may grant. */\n\treadonly descriptor: Resource.Descriptor\n\t/** The test of `RuleData.fitsOf` for the catalog, for this request. */\n\treadonly fits: (pattern: string) => boolean\n\t/**\n\t * The condition of each rule, with the principal in it. They are made\n\t * first, from a flat list of the rules, so the walk does not go down the\n\t * levels of the tree and of a condition at once. It is a native map,\n\t * because it must find a rule by the rule itself: two rules with the same\n\t * data are `Equal`.\n\t */\n\treadonly conditions: Map<RuleData.Rule, Ast>\n}\n\nconst makeCondition = (\n\tvalue: RuleData.Rule,\n\tcontext: Omit<ResidualContext, \"conditions\">,\n): Ast =>\n\t!RuleData.matchesTarget(value, context)\n\t\t? never\n\t\t: value.when === undefined\n\t\t\t? always\n\t\t\t: Condition.partial(value.when as Condition.Any, context.input)\n\nconst ruleCondition = (value: RuleData.Rule, context: ResidualContext): Ast =>\n\tcontext.conditions.get(value) ?? makeCondition(value, context)\n\n/**\n * Gives the conditions for \"the first rule that applies is an allow rule\" and\n * \"the first rule that applies is a deny rule\".\n */\nconst firstApplicableResidual = (\n\tvalues: ReadonlyArray<RuleData.Rule>,\n\tcontext: ResidualContext,\n): Pair => {\n\tconst { and, not, or } = build\n\t// The rules go in runs of one tag, from the last run to the first. The\n\t// conditions of a run go into one node at once. With one node for each\n\t// rule, each step would flatten the whole condition again.\n\tconst runs = Arr.isReadonlyArrayNonEmpty(values)\n\t\t? Arr.groupWith(values, (a, b) => a._tag === b._tag)\n\t\t: []\n\treturn Arr.reduceRight(\n\t\truns,\n\t\t{ allow: never, deny: never },\n\t\t(rest: Pair, run): Pair => {\n\t\t\tconst applies = or(Arr.map(run, (value) => ruleCondition(value, context)))\n\t\t\treturn run[0]._tag === \"Allow\"\n\t\t\t\t? {\n\t\t\t\t\t\tallow: or([applies, rest.allow]),\n\t\t\t\t\t\tdeny: and([not(applies), rest.deny]),\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tallow: and([not(applies), rest.allow]),\n\t\t\t\t\t\tdeny: or([applies, rest.deny]),\n\t\t\t\t\t}\n\t\t},\n\t)\n}\n\n/**\n * Gives the residual pair of a node. A shared child is worked again for each\n * place. The limits of the nodes and of a residual keep this work small.\n */\nconst residualNode = (\n\tnode: PolicyNodes.Node,\n\tcontext: ResidualContext,\n): Pair => {\n\tconst { and, not, or } = build\n\tswitch (node._tag) {\n\t\tcase \"Rules\": {\n\t\t\tswitch (node.algorithm) {\n\t\t\t\tcase \"denyOverrides\": {\n\t\t\t\t\tconst deny = or(\n\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t.filter((value) => value._tag === \"Deny\")\n\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t)\n\t\t\t\t\tconst allow = and([\n\t\t\t\t\t\tnot(deny),\n\t\t\t\t\t\tor(\n\t\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t\t.filter((value) => value._tag === \"Allow\")\n\t\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t\t),\n\t\t\t\t\t])\n\t\t\t\t\treturn { allow, deny }\n\t\t\t\t}\n\t\t\t\tcase \"permitOverrides\": {\n\t\t\t\t\tconst allow = or(\n\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t.filter((value) => value._tag === \"Allow\")\n\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t)\n\t\t\t\t\tconst deny = and([\n\t\t\t\t\t\tnot(allow),\n\t\t\t\t\t\tor(\n\t\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t\t.filter((value) => value._tag === \"Deny\")\n\t\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t\t),\n\t\t\t\t\t])\n\t\t\t\t\treturn { allow, deny }\n\t\t\t\t}\n\t\t\t\tcase \"firstApplicable\":\n\t\t\t\t\treturn firstApplicableResidual(node.rules, context)\n\t\t\t\tcase \"lastApplicable\":\n\t\t\t\t\treturn firstApplicableResidual(node.rules.slice().reverse(), context)\n\t\t\t}\n\t\t}\n\t\t// falls through: every algorithm returns above\n\t\tcase \"All\": {\n\t\t\tif (node.policies.length === 0) {\n\t\t\t\treturn { allow: never, deny: never }\n\t\t\t}\n\t\t\tconst pairs = node.policies.map((child) => residualNode(child, context))\n\t\t\tconst deny = or(pairs.map((pair) => pair.deny))\n\t\t\tconst allow = and([...pairs.map((pair) => pair.allow), not(deny)])\n\t\t\treturn { allow, deny }\n\t\t}\n\t\tcase \"Any\": {\n\t\t\tconst pairs = node.policies.map((child) => residualNode(child, context))\n\t\t\tconst allow = or(pairs.map((pair) => pair.allow))\n\t\t\tconst deny = and([not(allow), or(pairs.map((pair) => pair.deny))])\n\t\t\treturn { allow, deny }\n\t\t}\n\t\tcase \"FirstOf\": {\n\t\t\t// The first child that gives an answer wins.\n\t\t\treturn Arr.reduceRight(\n\t\t\t\tnode.policies,\n\t\t\t\t{ allow: never, deny: never },\n\t\t\t\t(rest: Pair, child): Pair => {\n\t\t\t\t\tconst pair = residualNode(child, context)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tallow: or([pair.allow, and([not(pair.deny), rest.allow])]),\n\t\t\t\t\t\tdeny: or([pair.deny, and([not(pair.allow), rest.deny])]),\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t\tcase \"Ceiling\": {\n\t\t\tconst cap = residualNode(node.cap, context)\n\t\t\tconst inner = residualNode(node.policy, context)\n\t\t\treturn {\n\t\t\t\tallow: and([not(cap.deny), inner.allow]),\n\t\t\t\tdeny: or([cap.deny, inner.deny]),\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** The name of the predicate of a residual condition that runs `decide`. */\nconst policyPredicate = \"policy\"\n\n/** What {@link usesPredicate} needs: the request. */\ninterface PredicateContext {\n\treadonly action: string\n\treadonly kind: string\n\treadonly field: string | undefined\n\treadonly descriptor: Resource.Descriptor\n\treadonly fits: (pattern: string) => boolean\n}\n\n/** Tests if a rule that the request may use has a predicate. */\nconst usesPredicate = (\n\tnode: PolicyNodes.Node,\n\tcontext: PredicateContext,\n): boolean => {\n\tif (!node.opaque) {\n\t\treturn false\n\t}\n\tswitch (node._tag) {\n\t\tcase \"Rules\":\n\t\t\treturn node.rules.some(\n\t\t\t\t(value) =>\n\t\t\t\t\tvalue.when !== undefined &&\n\t\t\t\t\tNodes.toNode(value.when).opaque &&\n\t\t\t\t\tRuleData.matchesTarget(value, context),\n\t\t\t)\n\t\tcase \"All\":\n\t\tcase \"Any\":\n\t\tcase \"FirstOf\":\n\t\t\treturn node.policies.some((child) => usesPredicate(child, context))\n\t\tcase \"Ceiling\":\n\t\t\treturn (\n\t\t\t\tusesPredicate(node.cap, context) || usesPredicate(node.policy, context)\n\t\t\t)\n\t}\n}\n\n/**\n * Makes the scope of a request, with the principal in it. A scope comes from\n * code, so a scope that does not fit the domain is a defect. It is bound as a\n * rule for the kind and the action of the request is.\n */\nconst scopeOf = (\n\trequest: ScopedRequest,\n\tdomain: Domain.Any,\n\tinput: ResidualContext[\"input\"],\n): Ast => {\n\tif (request.within === undefined) {\n\t\treturn always\n\t}\n\t// The builder stops a value that a condition can not hold, such as\n\t// `undefined` from a route parameter. A predicate could make a check pass\n\t// on the wrong values, so a scope with one is a defect too.\n\tconst ast = (request.within as (builder: unknown) => Ast)(Condition.builder())\n\tif (Nodes.toNode(ast).opaque) {\n\t\tthrow new globalThis.Error(\"A scope can not have a predicate\")\n\t}\n\tconst issues = Bind.ruleIssues(\n\t\tdomain,\n\t\t{ actions: [request.action], resources: [request.kind], when: ast },\n\t\t[\"within\"],\n\t)\n\tif (issues.length > 0) {\n\t\tthrow new globalThis.Error(\n\t\t\t`A scope does not fit the domain: ${issues.map((issue) => issue.issue).join(\"; \")}`,\n\t\t)\n\t}\n\treturn Condition.partial(ast as Condition.Condition, input)\n}\n\n/** A request about a kind with no types, with the scope of a target. */\nexport interface ScopedRequest {\n\treadonly principal: object\n\treadonly action: string\n\treadonly kind: string\n\treadonly field?: string | undefined\n\treadonly within?: unknown\n}\n\n/** The scope of a request, and the residual conditions inside it. */\ninterface Scoped extends Pair {\n\treadonly scope: Ast\n\t/** The catalog of the kind, when the request fits the kind. */\n\treadonly catalog: Catalog.Catalog | undefined\n}\n\nexport const residualsAny = (policy: Any, request: ScopedRequest): Pair =>\n\tscopedResiduals(policy, request)\n\nconst scopedResiduals = (policy: Any, request: ScopedRequest): Scoped => {\n\tconst descriptor = DomainData.descriptorOf(policy.domain, request.kind)\n\tif (descriptor === undefined || !fitsKind(descriptor, request)) {\n\t\treturn { scope: never, allow: never, deny: never, catalog: undefined }\n\t}\n\tconst input = { principal: request.principal, path: descriptor.path }\n\tconst scope = scopeOf(request, policy.domain, input)\n\tconst and = build.and\n\tconst inScope = (pair: Pair): Scoped => ({\n\t\tscope,\n\t\tallow: and([scope, pair.allow]),\n\t\tdeny: and([scope, pair.deny]),\n\t\tcatalog: descriptor.catalog,\n\t})\n\tif (scope._tag === \"False\") {\n\t\treturn inScope({ allow: never, deny: never })\n\t}\n\tconst target = {\n\t\taction: request.action,\n\t\tkind: request.kind,\n\t\tfield: request.field,\n\t\tinput,\n\t\tdescriptor,\n\t\tfits: RuleData.fitsOf(descriptor.catalog),\n\t}\n\tconst context: ResidualContext = {\n\t\t...target,\n\t\tconditions: new Map(\n\t\t\tArr.map(policy.pipe(nodeOf, PolicyNodes.rulesOf), (value) => [\n\t\t\t\tvalue,\n\t\t\t\tmakeCondition(value, target),\n\t\t\t]),\n\t\t),\n\t}\n\t// The type of the residual of a plain policy says that it has no\n\t// predicate, so it can not be the predicate below. A residual past the\n\t// limit is a defect.\n\tif (!usesPredicate(nodeOf(policy), context)) {\n\t\treturn inScope(residualNode(nodeOf(policy), context))\n\t}\n\t// A predicate may fail, and it may give another answer each time it runs.\n\t// A tree of `And` and `Or` nodes can not run the predicates in the same\n\t// order and the same number of times as `decide`. So the residual is one\n\t// predicate that runs `decide` for each value.\n\tconst decision = (value: object) =>\n\t\tdecideNode(\n\t\t\tnodeOf(policy),\n\t\t\t{\n\t\t\t\taction: request.action,\n\t\t\t\tkind: request.kind,\n\t\t\t\tfield: request.field,\n\t\t\t\tinput: {\n\t\t\t\t\tvalue,\n\t\t\t\t\tprincipal: request.principal,\n\t\t\t\t\tpath: descriptor.path,\n\t\t\t\t},\n\t\t\t\tdescriptor,\n\t\t\t\tfits: RuleData.fitsOf(descriptor.catalog),\n\t\t\t\ttrace: undefined,\n\t\t\t},\n\t\t\t[],\n\t\t)\n\t// A value of another kind is not a value that the residual is about, so\n\t// the rules of this kind must not run on it.\n\tconst test = (tag: Decision.Decision[\"_tag\"]): Ast =>\n\t\tCondition.builder<any, any, any>().predicate(policyPredicate, (value) =>\n\t\t\tResourceData.kindOf(value) === request.kind\n\t\t\t\t? Effect.map(decision(value), (result) => result._tag === tag)\n\t\t\t\t: Effect.succeed(false),\n\t\t)\n\t// The scope comes first in each `And`, so the policy runs only on values\n\t// in the scope.\n\treturn inScope({ allow: test(\"Allow\"), deny: test(\"Deny\") })\n}\n\n/** Gives the condition on resource values for which the policy allows. */\nexport const residual = (policy: Any, request: ScopedRequest): Ast =>\n\tresidualsAny(policy, request).allow\n\n/** A {@link Policy.Coverage} with no types. */\nexport type AnyCoverage = Data.TaggedEnum<{\n\tAll: { readonly condition: Ast }\n\tNone: { readonly condition: Ast }\n\tSome: {\n\t\treadonly condition: Ast\n\t\treadonly allowed: Condition.Example\n\t\treadonly refused: Condition.Example\n\t}\n\tUnknown: {\n\t\treadonly condition: Ast\n\t\treadonly reason: \"predicate\" | \"budget\"\n\t}\n}>\n\nconst coverages = Data.taggedEnum<AnyCoverage>()\n\n/** Searches for a value of the kind of a scope that makes a condition true. */\nconst search = (scoped: Scoped, ast: Ast): Condition.Satisfiability =>\n\tSearch.satisfiable(ast as Nodes.Node, Search.kindsIn(scoped.catalog))\n\n/** The values in the scope that the policy does not allow. */\nconst refusedOf = (scoped: Scoped): Ast =>\n\t// Only two nodes more than the residual, so it needs no size limit.\n\tAlgebra.and([\n\t\tscoped.scope as Nodes.Node,\n\t\tAlgebra.not(scoped.allow as Nodes.Node),\n\t])\n\nexport const coverageAny = (\n\tpolicy: Any,\n\trequest: ScopedRequest,\n): AnyCoverage => {\n\tconst scoped = scopedResiduals(policy, request)\n\tconst allowed = scoped.allow\n\tconst some = search(scoped, allowed)\n\tif (some._tag === \"Unsatisfiable\") {\n\t\treturn coverages.None({ condition: never })\n\t}\n\tif (some._tag === \"Unknown\") {\n\t\treturn coverages.Unknown({ condition: allowed, reason: some.reason })\n\t}\n\tconst missing = search(scoped, refusedOf(scoped))\n\tif (missing._tag === \"Unsatisfiable\") {\n\t\treturn coverages.All({ condition: scoped.scope })\n\t}\n\tif (missing._tag === \"Unknown\") {\n\t\treturn coverages.Unknown({ condition: allowed, reason: missing.reason })\n\t}\n\treturn coverages.Some({\n\t\tcondition: allowed,\n\t\tallowed: some.example,\n\t\trefused: missing.example,\n\t})\n}\n\n/** Decides a request about every value in a scope. */\nexport const decideKind = (\n\tpolicy: Any,\n\trequest: ScopedRequest,\n): Decision.Decision => {\n\tconst scoped = scopedResiduals(policy, request)\n\tconst missing = search(scoped, refusedOf(scoped))\n\tswitch (missing._tag) {\n\t\tcase \"Unknown\":\n\t\t\treturn Decision.Deny({})\n\t\tcase \"Unsatisfiable\":\n\t\t\treturn search(scoped, scoped.scope)._tag === \"Satisfiable\"\n\t\t\t\t? Decision.Allow({})\n\t\t\t\t: Decision.Deny({})\n\t\tcase \"Satisfiable\":\n\t\t\t// A refused value is in the scope, so the scope has a value.\n\t\t\treturn search(scoped, scoped.deny)._tag === \"Unsatisfiable\"\n\t\t\t\t? Decision.NotApplicable\n\t\t\t\t: Decision.Deny({})\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analysis.js","names":["Condition.always","Condition.never","Limits.exceeded","Limits.residualNodes","Algebra.and","Algebra.or","Algebra.not","RuleData.matchesTarget","Condition.partial","Nodes.toNode","Condition.builder","Bind.ruleIssues","DomainData.descriptorOf","RuleData.fitsOf","PolicyNodes.rulesOf","ResourceData.kindOf","Search.satisfiable","Search.kindsIn","Decision.Deny","Decision.Allow","Decision.NotApplicable"],"sources":["../../src/internal/analysis.ts"],"sourcesContent":["/**\n * The residual conditions and the coverage of a policy. The types are in\n * `Policy.ts`.\n */\n// A policy keeps the error type and the service type of its predicates in the\n// public types. The code below works on the nodes with no types, where they\n// are `unknown`, so the language service check for `unknown` in an Effect is\n// off here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Data from \"effect/Data\"\nimport * as Arr from \"effect/Array\"\nimport * as Effect from \"effect/Effect\"\nimport * as Condition from \"../Condition.ts\"\nimport * as Decision from \"../Decision.ts\"\nimport type * as Domain from \"../Domain.ts\"\nimport type * as Policy from \"../Policy.ts\"\nimport type * as Resource from \"../Resource.ts\"\nimport * as Algebra from \"./algebra.ts\"\nimport * as Bind from \"./bind.ts\"\nimport type * as Catalog from \"./catalog.ts\"\nimport { decideNode, fitsKind } from \"./decide.ts\"\nimport * as DomainData from \"./domain.ts\"\nimport * as Limits from \"./limits.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport * as PolicyNodes from \"./policy-nodes.ts\"\nimport { nodeOf } from \"./policy.ts\"\nimport * as ResourceData from \"./resource.ts\"\nimport * as RuleData from \"./rule.ts\"\nimport * as Search from \"./search.ts\"\n\ntype Any = Policy.Any\n\ntype Ast = Condition.Ast\n\nconst always: Ast = Condition.always\nconst never: Ast = Condition.never\n\n/**\n * Makes conditions for one residual, with no types. Each step makes the\n * condition simple, and it stops the work when the condition has more nodes\n * than `residualNodes`. A policy tree may use a condition of a child two\n * times, in its allow condition and in its deny condition, so a small policy\n * may give a very large condition.\n */\ninterface Build {\n\t// A list goes in as an array, not as arguments: a call may take only so\n\t// many arguments, and a policy may have more rules.\n\treadonly and: (values: ReadonlyArray<Ast>) => Ast\n\treadonly or: (values: ReadonlyArray<Ast>) => Ast\n\treadonly not: (value: Ast) => Ast\n}\n\nconst limit = (node: Nodes.Node): Ast => {\n\t// A residual grows by its nodes, as the conditions of the rules come\n\t// together. Its values come from the policy, which has a limit of them.\n\tif (node.size > Limits.residualNodes) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A residual condition\",\n\t\t\t\"residualNodes\",\n\t\t\t\"nodes\",\n\t\t\tnode.size,\n\t\t\tLimits.residualNodes,\n\t\t)\n\t}\n\treturn node\n}\n\nconst build: Build = {\n\tand: (values) => limit(Algebra.and(values as ReadonlyArray<Nodes.Node>)),\n\tor: (values) => limit(Algebra.or(values as ReadonlyArray<Nodes.Node>)),\n\tnot: (value) => (value as Nodes.Node).pipe(Algebra.not, limit),\n}\n\n/** The two residual conditions of a node, with no types. */\ninterface Pair {\n\treadonly allow: Ast\n\treadonly deny: Ast\n}\n\ninterface ResidualContext {\n\treadonly action: string\n\treadonly kind: string\n\treadonly field: string | undefined\n\treadonly input: {\n\t\treadonly principal: object\n\t\treadonly path: Condition.Input[\"path\"]\n\t}\n\t/** The resource of the kind, for the fields that a rule may grant. */\n\treadonly descriptor: Resource.Descriptor\n\t/** The test of `RuleData.fitsOf` for the catalog, for this request. */\n\treadonly fits: (pattern: string) => boolean\n\t/**\n\t * The condition of each rule, with the principal in it. They are made\n\t * first, from a flat list of the rules, so the walk does not go down the\n\t * levels of the tree and of a condition at once. It is a native map,\n\t * because it must find a rule by the rule itself: two rules with the same\n\t * data are `Equal`.\n\t */\n\treadonly conditions: Map<RuleData.Rule, Ast>\n}\n\nconst makeCondition = (\n\tvalue: RuleData.Rule,\n\tcontext: Omit<ResidualContext, \"conditions\">,\n): Ast =>\n\t!RuleData.matchesTarget(value, context)\n\t\t? never\n\t\t: value.when === undefined\n\t\t\t? always\n\t\t\t: Condition.partial(value.when as Condition.Any, context.input)\n\nconst ruleCondition = (value: RuleData.Rule, context: ResidualContext): Ast =>\n\tcontext.conditions.get(value) ?? makeCondition(value, context)\n\n/**\n * Gives the conditions for \"the first rule that applies is an allow rule\" and\n * \"the first rule that applies is a deny rule\".\n */\nconst firstApplicableResidual = (\n\tvalues: ReadonlyArray<RuleData.Rule>,\n\tcontext: ResidualContext,\n): Pair => {\n\tconst { and, not, or } = build\n\t// The rules go in runs of one tag, from the last run to the first. The\n\t// conditions of a run go into one node at once. With one node for each\n\t// rule, each step would flatten the whole condition again.\n\tconst runs = Arr.isReadonlyArrayNonEmpty(values)\n\t\t? Arr.groupWith(values, (a, b) => a._tag === b._tag)\n\t\t: []\n\treturn Arr.reduceRight(\n\t\truns,\n\t\t{ allow: never, deny: never },\n\t\t(rest: Pair, run): Pair => {\n\t\t\tconst applies = or(Arr.map(run, (value) => ruleCondition(value, context)))\n\t\t\treturn run[0]._tag === \"Allow\"\n\t\t\t\t? {\n\t\t\t\t\t\tallow: or([applies, rest.allow]),\n\t\t\t\t\t\tdeny: and([not(applies), rest.deny]),\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tallow: and([not(applies), rest.allow]),\n\t\t\t\t\t\tdeny: or([applies, rest.deny]),\n\t\t\t\t\t}\n\t\t},\n\t)\n}\n\n/**\n * Gives the residual pair of a node. A shared child is worked again for each\n * place. The limits of the nodes and of a residual keep this work small.\n */\nconst residualNode = (\n\tnode: PolicyNodes.Node,\n\tcontext: ResidualContext,\n): Pair => {\n\tconst { and, not, or } = build\n\tswitch (node._tag) {\n\t\tcase \"Rules\": {\n\t\t\tswitch (node.algorithm) {\n\t\t\t\tcase \"denyOverrides\": {\n\t\t\t\t\tconst deny = or(\n\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t.filter((value) => value._tag === \"Deny\")\n\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t)\n\t\t\t\t\tconst allow = and([\n\t\t\t\t\t\tnot(deny),\n\t\t\t\t\t\tor(\n\t\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t\t.filter((value) => value._tag === \"Allow\")\n\t\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t\t),\n\t\t\t\t\t])\n\t\t\t\t\treturn { allow, deny }\n\t\t\t\t}\n\t\t\t\tcase \"permitOverrides\": {\n\t\t\t\t\tconst allow = or(\n\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t.filter((value) => value._tag === \"Allow\")\n\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t)\n\t\t\t\t\tconst deny = and([\n\t\t\t\t\t\tnot(allow),\n\t\t\t\t\t\tor(\n\t\t\t\t\t\t\tnode.rules\n\t\t\t\t\t\t\t\t.filter((value) => value._tag === \"Deny\")\n\t\t\t\t\t\t\t\t.map((value) => ruleCondition(value, context)),\n\t\t\t\t\t\t),\n\t\t\t\t\t])\n\t\t\t\t\treturn { allow, deny }\n\t\t\t\t}\n\t\t\t\tcase \"firstApplicable\":\n\t\t\t\t\treturn firstApplicableResidual(node.rules, context)\n\t\t\t\tcase \"lastApplicable\":\n\t\t\t\t\treturn firstApplicableResidual(node.rules.slice().reverse(), context)\n\t\t\t}\n\t\t}\n\t\t// falls through: every algorithm returns above\n\t\tcase \"All\": {\n\t\t\tif (node.policies.length === 0) {\n\t\t\t\treturn { allow: never, deny: never }\n\t\t\t}\n\t\t\tconst pairs = node.policies.map((child) => residualNode(child, context))\n\t\t\tconst deny = or(pairs.map((pair) => pair.deny))\n\t\t\tconst allow = and([...pairs.map((pair) => pair.allow), not(deny)])\n\t\t\treturn { allow, deny }\n\t\t}\n\t\tcase \"Any\": {\n\t\t\tconst pairs = node.policies.map((child) => residualNode(child, context))\n\t\t\tconst allow = or(pairs.map((pair) => pair.allow))\n\t\t\tconst deny = and([not(allow), or(pairs.map((pair) => pair.deny))])\n\t\t\treturn { allow, deny }\n\t\t}\n\t\tcase \"FirstOf\": {\n\t\t\t// The first child that gives an answer wins.\n\t\t\treturn Arr.reduceRight(\n\t\t\t\tnode.policies,\n\t\t\t\t{ allow: never, deny: never },\n\t\t\t\t(rest: Pair, child): Pair => {\n\t\t\t\t\tconst pair = residualNode(child, context)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tallow: or([pair.allow, and([not(pair.deny), rest.allow])]),\n\t\t\t\t\t\tdeny: or([pair.deny, and([not(pair.allow), rest.deny])]),\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t\tcase \"Ceiling\": {\n\t\t\tconst cap = residualNode(node.cap, context)\n\t\t\tconst inner = residualNode(node.policy, context)\n\t\t\treturn {\n\t\t\t\tallow: and([not(cap.deny), inner.allow]),\n\t\t\t\tdeny: or([cap.deny, inner.deny]),\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** The name of the predicate of a residual condition that runs `decide`. */\nconst policyPredicate = \"policy\"\n\n/** What {@link usesPredicate} needs: the request. */\ninterface PredicateContext {\n\treadonly action: string\n\treadonly kind: string\n\treadonly field: string | undefined\n\treadonly descriptor: Resource.Descriptor\n\treadonly fits: (pattern: string) => boolean\n}\n\n/** Tests if a rule that the request may use has a predicate. */\nconst usesPredicate = (\n\tnode: PolicyNodes.Node,\n\tcontext: PredicateContext,\n): boolean => {\n\tif (!node.opaque) {\n\t\treturn false\n\t}\n\tswitch (node._tag) {\n\t\tcase \"Rules\":\n\t\t\treturn node.rules.some(\n\t\t\t\t(value) =>\n\t\t\t\t\tvalue.when !== undefined &&\n\t\t\t\t\tNodes.toNode(value.when).opaque &&\n\t\t\t\t\tRuleData.matchesTarget(value, context),\n\t\t\t)\n\t\tcase \"All\":\n\t\tcase \"Any\":\n\t\tcase \"FirstOf\":\n\t\t\treturn node.policies.some((child) => usesPredicate(child, context))\n\t\tcase \"Ceiling\":\n\t\t\treturn (\n\t\t\t\tusesPredicate(node.cap, context) || usesPredicate(node.policy, context)\n\t\t\t)\n\t}\n}\n\n/**\n * Makes the scope of a request, with the principal in it. A scope comes from\n * code, so a scope that does not fit the domain is a defect. It is bound as a\n * rule for the kind and the action of the request is.\n */\nconst scopeOf = (\n\trequest: ScopedRequest,\n\tdomain: Domain.Any,\n\tinput: ResidualContext[\"input\"],\n): Ast => {\n\tif (request.within === undefined) {\n\t\treturn always\n\t}\n\t// The builder stops a value that a condition can not hold, such as\n\t// `undefined` from a route parameter. A predicate could make a check pass\n\t// on the wrong values, so a scope with one is a defect too.\n\tconst ast = (request.within as (builder: unknown) => Ast)(Condition.builder())\n\tif (Nodes.toNode(ast).opaque) {\n\t\tthrow new globalThis.Error(\"A scope can not have a predicate\")\n\t}\n\tconst issues = Bind.ruleIssues(\n\t\tdomain,\n\t\t{ actions: [request.action], resources: [request.kind], when: ast },\n\t\t() => [\"within\"],\n\t)\n\tif (issues.length > 0) {\n\t\tthrow new globalThis.Error(\n\t\t\t`A scope does not fit the domain: ${issues.map((issue) => issue.issue).join(\"; \")}`,\n\t\t)\n\t}\n\treturn Condition.partial(ast as Condition.Condition, input)\n}\n\n/** A request about a kind with no types, with the scope of a target. */\nexport interface ScopedRequest {\n\treadonly principal: object\n\treadonly action: string\n\treadonly kind: string\n\treadonly field?: string | undefined\n\treadonly within?: unknown\n}\n\n/** The scope of a request, and the residual conditions inside it. */\ninterface Scoped extends Pair {\n\treadonly scope: Ast\n\t/** The catalog of the kind, when the request fits the kind. */\n\treadonly catalog: Catalog.Catalog | undefined\n}\n\nexport const residualsAny = (policy: Any, request: ScopedRequest): Pair =>\n\tscopedResiduals(policy, request)\n\nconst scopedResiduals = (policy: Any, request: ScopedRequest): Scoped => {\n\tconst descriptor = DomainData.descriptorOf(policy.domain, request.kind)\n\tif (descriptor === undefined || !fitsKind(descriptor, request)) {\n\t\treturn { scope: never, allow: never, deny: never, catalog: undefined }\n\t}\n\tconst input = { principal: request.principal, path: descriptor.path }\n\tconst scope = scopeOf(request, policy.domain, input)\n\tconst and = build.and\n\tconst inScope = (pair: Pair): Scoped => ({\n\t\tscope,\n\t\tallow: and([scope, pair.allow]),\n\t\tdeny: and([scope, pair.deny]),\n\t\tcatalog: descriptor.catalog,\n\t})\n\tif (scope._tag === \"False\") {\n\t\treturn inScope({ allow: never, deny: never })\n\t}\n\tconst target = {\n\t\taction: request.action,\n\t\tkind: request.kind,\n\t\tfield: request.field,\n\t\tinput,\n\t\tdescriptor,\n\t\tfits: RuleData.fitsOf(descriptor.catalog),\n\t}\n\tconst context: ResidualContext = {\n\t\t...target,\n\t\tconditions: new Map(\n\t\t\tArr.map(policy.pipe(nodeOf, PolicyNodes.rulesOf), (value) => [\n\t\t\t\tvalue,\n\t\t\t\tmakeCondition(value, target),\n\t\t\t]),\n\t\t),\n\t}\n\t// The type of the residual of a plain policy says that it has no\n\t// predicate, so it can not be the predicate below. A residual past the\n\t// limit is a defect.\n\tif (!usesPredicate(nodeOf(policy), context)) {\n\t\treturn inScope(residualNode(nodeOf(policy), context))\n\t}\n\t// A predicate may fail, and it may give another answer each time it runs.\n\t// A tree of `And` and `Or` nodes can not run the predicates in the same\n\t// order and the same number of times as `decide`. So the residual is one\n\t// predicate that runs `decide` for each value.\n\tconst decision = (value: object) =>\n\t\tdecideNode(\n\t\t\tnodeOf(policy),\n\t\t\t{\n\t\t\t\taction: request.action,\n\t\t\t\tkind: request.kind,\n\t\t\t\tfield: request.field,\n\t\t\t\tinput: {\n\t\t\t\t\tvalue,\n\t\t\t\t\tprincipal: request.principal,\n\t\t\t\t\tpath: descriptor.path,\n\t\t\t\t},\n\t\t\t\tdescriptor,\n\t\t\t\tfits: RuleData.fitsOf(descriptor.catalog),\n\t\t\t\ttrace: undefined,\n\t\t\t},\n\t\t\t[],\n\t\t)\n\t// A value of another kind is not a value that the residual is about, so\n\t// the rules of this kind must not run on it.\n\tconst test = (tag: Decision.Decision[\"_tag\"]): Ast =>\n\t\tCondition.builder<any, any, any>().predicate(policyPredicate, (value) =>\n\t\t\tResourceData.kindOf(value) === request.kind\n\t\t\t\t? Effect.map(decision(value), (result) => result._tag === tag)\n\t\t\t\t: Effect.succeed(false),\n\t\t)\n\t// The scope comes first in each `And`, so the policy runs only on values\n\t// in the scope.\n\treturn inScope({ allow: test(\"Allow\"), deny: test(\"Deny\") })\n}\n\n/** Gives the condition on resource values for which the policy allows. */\nexport const residual = (policy: Any, request: ScopedRequest): Ast =>\n\tresidualsAny(policy, request).allow\n\n/** A {@link Policy.Coverage} with no types. */\nexport type AnyCoverage = Data.TaggedEnum<{\n\tAll: { readonly condition: Ast }\n\tNone: { readonly condition: Ast }\n\tSome: {\n\t\treadonly condition: Ast\n\t\treadonly allowed: Condition.Example\n\t\treadonly refused: Condition.Example\n\t}\n\tUnknown: {\n\t\treadonly condition: Ast\n\t\treadonly reason: \"predicate\" | \"budget\"\n\t}\n}>\n\nconst coverages = Data.taggedEnum<AnyCoverage>()\n\n/** Searches for a value of the kind of a scope that makes a condition true. */\nconst search = (scoped: Scoped, ast: Ast): Condition.Satisfiability =>\n\tSearch.satisfiable(ast as Nodes.Node, Search.kindsIn(scoped.catalog))\n\n/** The values in the scope that the policy does not allow. */\nconst refusedOf = (scoped: Scoped): Ast =>\n\t// Only two nodes more than the residual, so it needs no size limit.\n\tAlgebra.and([\n\t\tscoped.scope as Nodes.Node,\n\t\tAlgebra.not(scoped.allow as Nodes.Node),\n\t])\n\nexport const coverageAny = (\n\tpolicy: Any,\n\trequest: ScopedRequest,\n): AnyCoverage => {\n\tconst scoped = scopedResiduals(policy, request)\n\tconst allowed = scoped.allow\n\tconst some = search(scoped, allowed)\n\tif (some._tag === \"Unsatisfiable\") {\n\t\treturn coverages.None({ condition: never })\n\t}\n\tif (some._tag === \"Unknown\") {\n\t\treturn coverages.Unknown({ condition: allowed, reason: some.reason })\n\t}\n\tconst missing = search(scoped, refusedOf(scoped))\n\tif (missing._tag === \"Unsatisfiable\") {\n\t\treturn coverages.All({ condition: scoped.scope })\n\t}\n\tif (missing._tag === \"Unknown\") {\n\t\treturn coverages.Unknown({ condition: allowed, reason: missing.reason })\n\t}\n\treturn coverages.Some({\n\t\tcondition: allowed,\n\t\tallowed: some.example,\n\t\trefused: missing.example,\n\t})\n}\n\n/** Decides a request about every value in a scope. */\nexport const decideKind = (\n\tpolicy: Any,\n\trequest: ScopedRequest,\n): Decision.Decision => {\n\tconst scoped = scopedResiduals(policy, request)\n\tconst missing = search(scoped, refusedOf(scoped))\n\tswitch (missing._tag) {\n\t\tcase \"Unknown\":\n\t\t\treturn Decision.Deny({})\n\t\tcase \"Unsatisfiable\":\n\t\t\treturn search(scoped, scoped.scope)._tag === \"Satisfiable\"\n\t\t\t\t? Decision.Allow({})\n\t\t\t\t: Decision.Deny({})\n\t\tcase \"Satisfiable\":\n\t\t\t// A refused value is in the scope, so the scope has a value.\n\t\t\treturn search(scoped, scoped.deny)._tag === \"Unsatisfiable\"\n\t\t\t\t? Decision.NotApplicable\n\t\t\t\t: Decision.Deny({})\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorizer.d.ts","names":[],"sources":["../../src/internal/authorizer.ts"],"mappings":";;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"authorizer.d.ts","names":[],"sources":["../../src/internal/authorizer.ts"],"mappings":";;;;;;;;;;;;;;;;qBAkCa,kBAAkB;;;;;qBAUlB,0BAA0B;;;;;;qBAK1B,gBAAgB"}
|