@nmnmcc/ability 2.0.6 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +56 -32
  2. package/dist/Authorizer.d.ts +21 -12
  3. package/dist/Authorizer.d.ts.map +1 -1
  4. package/dist/Authorizer.js.map +1 -1
  5. package/dist/Condition.d.ts +118 -18
  6. package/dist/Condition.d.ts.map +1 -1
  7. package/dist/Condition.js +27 -18
  8. package/dist/Condition.js.map +1 -1
  9. package/dist/Domain.d.ts +9 -0
  10. package/dist/Domain.d.ts.map +1 -1
  11. package/dist/Domain.js +5 -0
  12. package/dist/Domain.js.map +1 -1
  13. package/dist/Limits.d.ts +44 -13
  14. package/dist/Limits.d.ts.map +1 -1
  15. package/dist/Limits.js +52 -22
  16. package/dist/Limits.js.map +1 -1
  17. package/dist/Policy.d.ts +95 -12
  18. package/dist/Policy.d.ts.map +1 -1
  19. package/dist/Policy.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/internal/algebra.js +101 -74
  22. package/dist/internal/algebra.js.map +1 -1
  23. package/dist/internal/analysis.js +81 -75
  24. package/dist/internal/analysis.js.map +1 -1
  25. package/dist/internal/authorizer.d.ts.map +1 -1
  26. package/dist/internal/authorizer.js +16 -11
  27. package/dist/internal/authorizer.js.map +1 -1
  28. package/dist/internal/bind.js +119 -80
  29. package/dist/internal/bind.js.map +1 -1
  30. package/dist/internal/catalog.d.ts +33 -10
  31. package/dist/internal/catalog.d.ts.map +1 -1
  32. package/dist/internal/catalog.js +153 -78
  33. package/dist/internal/catalog.js.map +1 -1
  34. package/dist/internal/decide.js +25 -29
  35. package/dist/internal/decide.js.map +1 -1
  36. package/dist/internal/domain.js +19 -5
  37. package/dist/internal/domain.js.map +1 -1
  38. package/dist/internal/json.js +120 -76
  39. package/dist/internal/json.js.map +1 -1
  40. package/dist/internal/limits.d.ts +28 -0
  41. package/dist/internal/limits.d.ts.map +1 -1
  42. package/dist/internal/limits.js +75 -16
  43. package/dist/internal/limits.js.map +1 -1
  44. package/dist/internal/nodes.d.ts +7 -0
  45. package/dist/internal/nodes.d.ts.map +1 -1
  46. package/dist/internal/nodes.js +86 -47
  47. package/dist/internal/nodes.js.map +1 -1
  48. package/dist/internal/patterns.js +50 -15
  49. package/dist/internal/patterns.js.map +1 -1
  50. package/dist/internal/policy-json.js +169 -127
  51. package/dist/internal/policy-json.js.map +1 -1
  52. package/dist/internal/policy-nodes.d.ts.map +1 -1
  53. package/dist/internal/policy-nodes.js +17 -14
  54. package/dist/internal/policy-nodes.js.map +1 -1
  55. package/dist/internal/policy.d.ts.map +1 -1
  56. package/dist/internal/policy.js +38 -22
  57. package/dist/internal/policy.js.map +1 -1
  58. package/dist/internal/resource.js +1 -1
  59. package/dist/internal/rule.d.ts.map +1 -1
  60. package/dist/internal/rule.js +6 -5
  61. package/dist/internal/rule.js.map +1 -1
  62. package/dist/internal/search.d.ts.map +1 -1
  63. package/dist/internal/search.js +106 -92
  64. package/dist/internal/search.js.map +1 -1
  65. package/dist/internal/trampoline.js +89 -0
  66. package/dist/internal/trampoline.js.map +1 -0
  67. package/package.json +1 -1
  68. package/src/Authorizer.ts +30 -20
  69. package/src/Condition.ts +308 -83
  70. package/src/Domain.ts +9 -0
  71. package/src/Limits.ts +69 -29
  72. package/src/Policy.ts +131 -15
  73. package/src/internal/algebra.ts +218 -135
  74. package/src/internal/analysis.ts +154 -122
  75. package/src/internal/authorizer.ts +34 -16
  76. package/src/internal/bind.ts +279 -148
  77. package/src/internal/catalog.ts +307 -133
  78. package/src/internal/decide.ts +58 -49
  79. package/src/internal/domain.ts +39 -3
  80. package/src/internal/json.ts +212 -117
  81. package/src/internal/limits.ts +101 -31
  82. package/src/internal/nodes.ts +101 -59
  83. package/src/internal/patterns.ts +72 -26
  84. package/src/internal/policy-json.ts +266 -197
  85. package/src/internal/policy-nodes.ts +33 -24
  86. package/src/internal/policy.ts +63 -23
  87. package/src/internal/rule.ts +16 -3
  88. package/src/internal/search.ts +186 -136
  89. package/src/internal/trampoline.ts +194 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Walks that do not fill the stack.
3
+ *
4
+ * A walk is written one time, with the steps of a {@link Runner}, and a
5
+ * runner runs it:
6
+ * - {@link direct} runs each step at once, as a plain call does. It is fast,
7
+ * and it is for an input with few levels.
8
+ * - {@link loop} puts each step into the run loop of an Effect. A step gives
9
+ * the next step in place of calling it, and the loop runs one step after
10
+ * the other, so the stack does not grow with the levels of the input. This
11
+ * is a trampoline.
12
+ *
13
+ * {@link run} takes `direct` for an input with at most `directDepth` levels,
14
+ * and `loop` for a deeper one. A walk makes each call for a child through
15
+ * `suspend`, so the loop makes the step of the child only when it runs it.
16
+ */
17
+ import * as Arr from "effect/Array"
18
+ import * as Cause from "effect/Cause"
19
+ import * as Effect from "effect/Effect"
20
+ import * as Exit from "effect/Exit"
21
+ import * as Option from "effect/Option"
22
+
23
+ /**
24
+ * A step of a walk that gives an `A`. A runner of steps knows what a step
25
+ * is: the value itself for `direct`, and an Effect for `loop`. The type is
26
+ * only in the types.
27
+ */
28
+ export interface Step<A> {
29
+ readonly "~Step": (_: never) => A
30
+ }
31
+
32
+ /** The steps that a walk may take. */
33
+ export interface Runner {
34
+ readonly succeed: <A>(value: A) => Step<A>
35
+ /** The step that `step` makes, when the runner runs it. */
36
+ readonly suspend: <A>(step: () => Step<A>) => Step<A>
37
+ readonly map: <A, B>(step: Step<A>, f: (value: A) => B) => Step<B>
38
+ readonly flatMap: <A, B>(step: Step<A>, f: (value: A) => Step<B>) => Step<B>
39
+ /** Runs a step for each item, in order, and gives their values. */
40
+ readonly forEach: <A, B>(
41
+ items: ReadonlyArray<A>,
42
+ f: (item: A, index: number) => Step<B>,
43
+ ) => Step<ReadonlyArray<B>>
44
+ /**
45
+ * Runs a step for each item, in order, with the value of the step before.
46
+ * It does not grow the stack with the number of items.
47
+ */
48
+ readonly reduce: <A, B>(
49
+ items: ReadonlyArray<A>,
50
+ initial: B,
51
+ f: (before: B, item: A) => Step<B>,
52
+ ) => Step<B>
53
+ /** Runs a step for each item, in order, up to the first `true`. */
54
+ readonly some: <A>(
55
+ items: ReadonlyArray<A>,
56
+ f: (item: A) => Step<boolean>,
57
+ ) => Step<boolean>
58
+ /** Runs a step for each item, in order, up to the first `false`. */
59
+ readonly every: <A>(
60
+ items: ReadonlyArray<A>,
61
+ f: (item: A) => Step<boolean>,
62
+ ) => Step<boolean>
63
+ }
64
+
65
+ // A step of `direct` is its value. The casts below only change the type.
66
+ const value = <A>(step: Step<A>): A => step as unknown as A
67
+ const step = <A>(value: A): Step<A> => value as unknown as Step<A>
68
+
69
+ /** Runs each step at once, on the stack. */
70
+ // A step of `direct` is its value, so a function that gives a step gives a
71
+ // value too. The runner passes such a function on with no wrap: a wrap for
72
+ // each item would be a call more for each node of a walk.
73
+ export const direct: Runner = {
74
+ succeed: step,
75
+ suspend: (make) => make(),
76
+ map: (from, f) => step(f(value(from))),
77
+ flatMap: (from, f) => f(value(from)),
78
+ forEach: (items, f) => step(Arr.map(items, f as never)),
79
+ reduce: (items, initial, f) => step(Arr.reduce(items, initial, f as never)),
80
+ some: (items, f) => step(Arr.some(items, f as never)),
81
+ every: (items, f) => step(Arr.every(items, f as never)),
82
+ }
83
+
84
+ // A step of `loop` is an Effect with no error and no services. A failure of a
85
+ // walk is a thrown error, which `run` gives back as it was.
86
+ type Loop<A> = Effect.Effect<A>
87
+ const effect = <A>(step: Step<A>): Loop<A> => step as unknown as Loop<A>
88
+ const fromEffect = <A>(effect: Loop<A>): Step<A> => effect as unknown as Step<A>
89
+
90
+ /** Runs each step in the run loop of an Effect, so a deep walk does not fill the stack. */
91
+ export const loop: Runner = {
92
+ succeed: (value) => fromEffect(Effect.succeed(value)),
93
+ suspend: (make) => fromEffect(Effect.suspend(() => effect(make()))),
94
+ map: (from, f) => fromEffect(Effect.map(effect(from), f)),
95
+ flatMap: (from, f) =>
96
+ fromEffect(Effect.flatMap(effect(from), (value) => effect(f(value)))),
97
+ forEach: (items, f) =>
98
+ fromEffect(Effect.forEach(items, (item, index) => effect(f(item, index)))),
99
+ reduce: (items, initial, f) =>
100
+ fromEffect(
101
+ Effect.reduce(
102
+ items,
103
+ () => initial,
104
+ (before, item) => effect(f(before, item)),
105
+ ),
106
+ ),
107
+ some: (items, f) =>
108
+ fromEffect(
109
+ Effect.map(
110
+ Effect.findFirst(items, (item) => effect(f(item))),
111
+ Option.isSome,
112
+ ),
113
+ ),
114
+ every: (items, f) =>
115
+ fromEffect(
116
+ Effect.map(
117
+ Effect.findFirst(items, (item) =>
118
+ Effect.map(effect(f(item)), (value) => !value),
119
+ ),
120
+ Option.isNone,
121
+ ),
122
+ ),
123
+ }
124
+
125
+ /**
126
+ * The most levels of an input that `run` walks with `direct`. A level takes
127
+ * a few calls of the walk and of the runner on the stack, so this keeps the
128
+ * stack far from full, and most inputs take the fast way.
129
+ */
130
+ export const directDepth = 200
131
+
132
+ /**
133
+ * Gives the runner for an input with `depth` levels. The walks of a condition
134
+ * or a policy tree know the depth of the input from its node. A walk of an
135
+ * input with an unknown depth, as a decoder, takes `loop`.
136
+ */
137
+ export const runnerFor = (depth: number): Runner =>
138
+ depth <= directDepth ? direct : loop
139
+
140
+ /**
141
+ * Runs a walk at once, with the runner for `depth` levels, and gives its
142
+ * value. An error that a step throws comes out as it was, also from `loop`.
143
+ */
144
+ export const run = <A>(depth: number, walk: (runner: Runner) => Step<A>): A =>
145
+ runWith(runnerFor(depth), walk)
146
+
147
+ /** Runs a walk at once with a runner, as {@link run} does. */
148
+ export const runWith = <A>(
149
+ runner: Runner,
150
+ walk: (runner: Runner) => Step<A>,
151
+ ): A => {
152
+ if (runner === direct) {
153
+ return value(walk(direct))
154
+ }
155
+ return Exit.match(Effect.runSyncExit(effect(walk(loop))), {
156
+ onSuccess: (result) => result,
157
+ onFailure: (cause) => {
158
+ throw Cause.squash(cause)
159
+ },
160
+ })
161
+ }
162
+
163
+ /**
164
+ * Makes a walk of an input with an unknown depth, as the input of a decoder.
165
+ * It runs with `direct` while the input is low. A part more than
166
+ * `directDepth` levels down runs with `loop`, and the walk stays in the loop
167
+ * below it, so it goes into the loop one time on each path. `walk` gets the
168
+ * runner, and the call for a child at the next level: `child(item, depth)`.
169
+ */
170
+ export const adaptive = <I, A>(
171
+ walk: (
172
+ R: Runner,
173
+ child: (item: I, depth: number) => Step<A>,
174
+ ) => (item: I, depth: number) => Step<A>,
175
+ ): ((item: I) => A) => {
176
+ const inLoop: (item: I, depth: number) => Step<A> = walk(
177
+ loop,
178
+ (item, depth) => loop.suspend(() => inLoop(item, depth)),
179
+ )
180
+ const onStack: (item: I, depth: number) => Step<A> = walk(
181
+ direct,
182
+ (item, depth) =>
183
+ depth > directDepth
184
+ ? step(runWith(loop, () => inLoop(item, depth)))
185
+ : onStack(item, depth),
186
+ )
187
+ return (item) => value(onStack(item, 1))
188
+ }
189
+
190
+ /**
191
+ * Gives the Effect of a step of `loop`, so a walk can go on in an Effect
192
+ * that runs a predicate.
193
+ */
194
+ export const toEffect = <A>(step: Step<A>): Effect.Effect<A> => effect(step)