@fieldia/core 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/package.json +1 -1
  2. package/schema/page.schema.json +1128 -89
  3. package/src/lib/expression/evaluator.d.mts +6 -5
  4. package/src/lib/expression/evaluator.d.ts +6 -5
  5. package/src/lib/expression/evaluator.js +37 -22
  6. package/src/lib/expression/evaluator.js.map +1 -1
  7. package/src/lib/expression/evaluator.mjs +32 -18
  8. package/src/lib/expression/evaluator.mjs.map +1 -1
  9. package/src/lib/expression/expression.d.mts +21 -0
  10. package/src/lib/expression/expression.d.ts +21 -0
  11. package/src/lib/expression/expression.js +29 -0
  12. package/src/lib/expression/expression.js.map +1 -0
  13. package/src/lib/expression/expression.mjs +26 -0
  14. package/src/lib/expression/expression.mjs.map +1 -0
  15. package/src/lib/expression/extractFieldNames.js +6 -1
  16. package/src/lib/expression/extractFieldNames.js.map +1 -1
  17. package/src/lib/expression/extractFieldNames.mjs +6 -1
  18. package/src/lib/expression/extractFieldNames.mjs.map +1 -1
  19. package/src/lib/expression/functions.d.mts +35 -0
  20. package/src/lib/expression/functions.d.ts +35 -0
  21. package/src/lib/expression/functions.js +129 -0
  22. package/src/lib/expression/functions.js.map +1 -0
  23. package/src/lib/expression/functions.mjs +124 -0
  24. package/src/lib/expression/functions.mjs.map +1 -0
  25. package/src/lib/expression/modifier.d.mts +3 -1
  26. package/src/lib/expression/modifier.d.ts +3 -1
  27. package/src/lib/expression/modifier.js +4 -27
  28. package/src/lib/expression/modifier.js.map +1 -1
  29. package/src/lib/expression/modifier.mjs +3 -26
  30. package/src/lib/expression/modifier.mjs.map +1 -1
  31. package/src/lib/expression/operations.d.mts +25 -0
  32. package/src/lib/expression/operations.d.ts +25 -0
  33. package/src/lib/expression/operations.js +81 -0
  34. package/src/lib/expression/operations.js.map +1 -0
  35. package/src/lib/expression/operations.mjs +72 -0
  36. package/src/lib/expression/operations.mjs.map +1 -0
  37. package/src/lib/expression/order.d.mts +11 -0
  38. package/src/lib/expression/order.d.ts +11 -0
  39. package/src/lib/expression/order.js +36 -0
  40. package/src/lib/expression/order.js.map +1 -0
  41. package/src/lib/expression/order.mjs +33 -0
  42. package/src/lib/expression/order.mjs.map +1 -0
  43. package/src/lib/expression/parser.d.mts +34 -4
  44. package/src/lib/expression/parser.d.ts +34 -4
  45. package/src/lib/expression/parser.js +72 -6
  46. package/src/lib/expression/parser.js.map +1 -1
  47. package/src/lib/expression/parser.mjs +72 -6
  48. package/src/lib/expression/parser.mjs.map +1 -1
  49. package/src/lib/expression/reads.d.mts +8 -0
  50. package/src/lib/expression/reads.d.ts +8 -0
  51. package/src/lib/expression/reads.js +48 -0
  52. package/src/lib/expression/reads.js.map +1 -0
  53. package/src/lib/expression/reads.mjs +44 -0
  54. package/src/lib/expression/reads.mjs.map +1 -0
  55. package/src/lib/expression/tokenizer.d.mts +7 -6
  56. package/src/lib/expression/tokenizer.d.ts +7 -6
  57. package/src/lib/expression/tokenizer.js +28 -18
  58. package/src/lib/expression/tokenizer.js.map +1 -1
  59. package/src/lib/expression/tokenizer.mjs +28 -18
  60. package/src/lib/expression/tokenizer.mjs.map +1 -1
  61. package/src/lib/format/field.d.mts +686 -5
  62. package/src/lib/format/field.d.ts +686 -5
  63. package/src/lib/format/field.js +115 -13
  64. package/src/lib/format/field.js.map +1 -1
  65. package/src/lib/format/field.mjs +114 -12
  66. package/src/lib/format/field.mjs.map +1 -1
  67. package/src/lib/format/layout.d.mts +388 -10
  68. package/src/lib/format/layout.d.ts +388 -10
  69. package/src/lib/format/layout.js +50 -3
  70. package/src/lib/format/layout.js.map +1 -1
  71. package/src/lib/format/layout.mjs +49 -2
  72. package/src/lib/format/layout.mjs.map +1 -1
  73. package/src/lib/format/names.d.mts +1 -1
  74. package/src/lib/format/names.d.ts +1 -1
  75. package/src/lib/format/names.js +1 -0
  76. package/src/lib/format/names.js.map +1 -1
  77. package/src/lib/format/names.mjs +1 -0
  78. package/src/lib/format/names.mjs.map +1 -1
  79. package/src/lib/format/page.d.mts +391 -4
  80. package/src/lib/format/page.d.ts +391 -4
  81. package/src/lib/format/page.js +13 -0
  82. package/src/lib/format/page.js.map +1 -1
  83. package/src/lib/format/page.mjs +13 -0
  84. package/src/lib/format/page.mjs.map +1 -1
  85. package/src/lib/format/references.d.mts +14 -1
  86. package/src/lib/format/references.d.ts +14 -1
  87. package/src/lib/format/references.js +96 -8
  88. package/src/lib/format/references.js.map +1 -1
  89. package/src/lib/format/references.mjs +96 -8
  90. package/src/lib/format/references.mjs.map +1 -1
  91. package/src/lib/format/translate.d.mts +20 -0
  92. package/src/lib/format/translate.d.ts +20 -0
  93. package/src/lib/format/translate.js +79 -21
  94. package/src/lib/format/translate.js.map +1 -1
  95. package/src/lib/format/translate.mjs +76 -21
  96. package/src/lib/format/translate.mjs.map +1 -1
  97. package/src/lib/record/check.d.mts +19 -1
  98. package/src/lib/record/check.d.ts +19 -1
  99. package/src/lib/record/check.js +84 -21
  100. package/src/lib/record/check.js.map +1 -1
  101. package/src/lib/record/check.mjs +82 -21
  102. package/src/lib/record/check.mjs.map +1 -1
  103. package/src/lib/record/compute.d.mts +24 -0
  104. package/src/lib/record/compute.d.ts +24 -0
  105. package/src/lib/record/compute.js +107 -0
  106. package/src/lib/record/compute.js.map +1 -0
  107. package/src/lib/record/compute.mjs +103 -0
  108. package/src/lib/record/compute.mjs.map +1 -0
  109. package/src/lib/record/data-source.d.mts +9 -1
  110. package/src/lib/record/data-source.d.ts +9 -1
  111. package/src/lib/record/data-source.js.map +1 -1
  112. package/src/lib/record/data-source.mjs.map +1 -1
  113. package/src/lib/record/env.d.mts +9 -0
  114. package/src/lib/record/env.d.ts +9 -0
  115. package/src/lib/record/env.js +28 -0
  116. package/src/lib/record/env.js.map +1 -0
  117. package/src/lib/record/env.mjs +25 -0
  118. package/src/lib/record/env.mjs.map +1 -0
  119. package/src/lib/record/form.d.mts +24 -0
  120. package/src/lib/record/form.d.ts +24 -0
  121. package/src/lib/record/form.js +160 -32
  122. package/src/lib/record/form.js.map +1 -1
  123. package/src/lib/record/form.mjs +160 -32
  124. package/src/lib/record/form.mjs.map +1 -1
  125. package/src/lib/record/inputs.d.mts +5 -0
  126. package/src/lib/record/inputs.d.ts +5 -0
  127. package/src/lib/record/inputs.js +47 -0
  128. package/src/lib/record/inputs.js.map +1 -0
  129. package/src/lib/record/inputs.mjs +44 -0
  130. package/src/lib/record/inputs.mjs.map +1 -0
  131. package/src/lib/record/limits.d.mts +13 -0
  132. package/src/lib/record/limits.d.ts +13 -0
  133. package/src/lib/record/limits.js +45 -0
  134. package/src/lib/record/limits.js.map +1 -0
  135. package/src/lib/record/limits.mjs +41 -0
  136. package/src/lib/record/limits.mjs.map +1 -0
  137. package/src/lib/record/locales/all.d.mts +7 -0
  138. package/src/lib/record/locales/all.d.ts +7 -0
  139. package/src/lib/record/locales/all.js +13 -0
  140. package/src/lib/record/locales/all.js.map +1 -0
  141. package/src/lib/record/locales/all.mjs +10 -0
  142. package/src/lib/record/locales/all.mjs.map +1 -0
  143. package/src/lib/record/locales/ar.d.mts +3 -0
  144. package/src/lib/record/locales/ar.d.ts +3 -0
  145. package/src/lib/record/locales/ar.js +55 -0
  146. package/src/lib/record/locales/ar.js.map +1 -0
  147. package/src/lib/record/locales/ar.mjs +52 -0
  148. package/src/lib/record/locales/ar.mjs.map +1 -0
  149. package/src/lib/record/locales/de.d.mts +3 -0
  150. package/src/lib/record/locales/de.d.ts +3 -0
  151. package/src/lib/record/locales/de.js +55 -0
  152. package/src/lib/record/locales/de.js.map +1 -0
  153. package/src/lib/record/locales/de.mjs +52 -0
  154. package/src/lib/record/locales/de.mjs.map +1 -0
  155. package/src/lib/record/locales/fr.d.mts +3 -0
  156. package/src/lib/record/locales/fr.d.ts +3 -0
  157. package/src/lib/record/locales/fr.js +55 -0
  158. package/src/lib/record/locales/fr.js.map +1 -0
  159. package/src/lib/record/locales/fr.mjs +52 -0
  160. package/src/lib/record/locales/fr.mjs.map +1 -0
  161. package/src/lib/record/memory-data-source.d.mts +3 -0
  162. package/src/lib/record/memory-data-source.d.ts +3 -0
  163. package/src/lib/record/memory-data-source.js +8 -0
  164. package/src/lib/record/memory-data-source.js.map +1 -1
  165. package/src/lib/record/memory-data-source.mjs +8 -0
  166. package/src/lib/record/memory-data-source.mjs.map +1 -1
  167. package/src/lib/record/messages.d.mts +46 -0
  168. package/src/lib/record/messages.d.ts +46 -0
  169. package/src/lib/record/messages.js +58 -101
  170. package/src/lib/record/messages.js.map +1 -1
  171. package/src/lib/record/messages.mjs +58 -101
  172. package/src/lib/record/messages.mjs.map +1 -1
  173. package/src/lib/record/rules.d.mts +33 -0
  174. package/src/lib/record/rules.d.ts +33 -0
  175. package/src/lib/record/rules.js +83 -0
  176. package/src/lib/record/rules.js.map +1 -0
  177. package/src/lib/record/rules.mjs +79 -0
  178. package/src/lib/record/rules.mjs.map +1 -0
  179. package/src/lib/record/score.d.mts +16 -0
  180. package/src/lib/record/score.d.ts +16 -0
  181. package/src/lib/record/score.js +35 -0
  182. package/src/lib/record/score.js.map +1 -0
  183. package/src/lib/record/score.mjs +32 -0
  184. package/src/lib/record/score.mjs.map +1 -0
  185. package/src/lib/record/set-when.d.mts +24 -0
  186. package/src/lib/record/set-when.d.ts +24 -0
  187. package/src/lib/record/set-when.js +68 -0
  188. package/src/lib/record/set-when.js.map +1 -0
  189. package/src/lib/record/set-when.mjs +65 -0
  190. package/src/lib/record/set-when.mjs.map +1 -0
  191. package/src/lib/record/structures.d.mts +14 -0
  192. package/src/lib/record/structures.d.ts +14 -0
  193. package/src/lib/record/structures.js +32 -0
  194. package/src/lib/record/structures.js.map +1 -0
  195. package/src/lib/record/structures.mjs +28 -0
  196. package/src/lib/record/structures.mjs.map +1 -0
  197. package/src/lib/record/values.d.mts +10 -5
  198. package/src/lib/record/values.d.ts +10 -5
  199. package/src/lib/record/values.js +20 -6
  200. package/src/lib/record/values.js.map +1 -1
  201. package/src/lib/record/values.mjs +19 -6
  202. package/src/lib/record/values.mjs.map +1 -1
  203. package/src/runtime.d.mts +10 -7
  204. package/src/runtime.d.ts +10 -7
  205. package/src/runtime.js +12 -1
  206. package/src/runtime.js.map +1 -1
  207. package/src/runtime.mjs +5 -2
  208. package/src/runtime.mjs.map +1 -1
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FUNCTIONS = void 0;
4
+ exports.localDay = localDay;
5
+ exports.takesInWords = takesInWords;
6
+ const operations_1 = require("./operations");
7
+ /** A day as YYYY-MM-DD, in the computer's own time zone. */
8
+ function localDay(date) {
9
+ const pad = (n) => String(n).padStart(2, '0');
10
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
11
+ }
12
+ /** The list a function counts or adds up: the rows of a one2many named by its field, or any list. */
13
+ function listOf(call) {
14
+ const first = call.args[0];
15
+ const rows = first.type === 'Identifier' ? call.env.lines?.(first.name) : undefined;
16
+ return rows ?? call.value(first);
17
+ }
18
+ /** The smallest or largest of the values, lists opened: empty ones left out, numbers or text but not both. */
19
+ function extreme(call, smaller) {
20
+ const items = call.args
21
+ .flatMap((arg) => {
22
+ const value = call.value(arg);
23
+ return Array.isArray(value) ? value : [value];
24
+ })
25
+ .filter((value) => value !== null && value !== undefined);
26
+ if (!items.length)
27
+ return null;
28
+ if (!items.every(operations_1.isNumber) && !items.every((value) => typeof value === 'string'))
29
+ return null;
30
+ const ordered = items;
31
+ return ordered.reduce((best, value) => ((smaller ? value < best : value > best) ? value : best));
32
+ }
33
+ exports.FUNCTIONS = new Map([
34
+ [
35
+ 'round',
36
+ {
37
+ takes: [1, 2],
38
+ call({ args, value }) {
39
+ const x = value(args[0]);
40
+ const digits = args.length > 1 ? value(args[1]) : 0;
41
+ return (0, operations_1.isNumber)(x) && (0, operations_1.isNumber)(digits) ? (0, operations_1.roundTo)(x, digits) : null;
42
+ },
43
+ },
44
+ ],
45
+ [
46
+ 'abs',
47
+ {
48
+ takes: [1, 1],
49
+ call({ args, value }) {
50
+ const x = value(args[0]);
51
+ return (0, operations_1.isNumber)(x) ? Math.abs(x) : null;
52
+ },
53
+ },
54
+ ],
55
+ ['min', { takes: [1, Infinity], call: (call) => extreme(call, true) }],
56
+ ['max', { takes: [1, Infinity], call: (call) => extreme(call, false) }],
57
+ [
58
+ 'len',
59
+ {
60
+ takes: [1, 1],
61
+ call({ args, value }) {
62
+ const x = value(args[0]);
63
+ if (x === null || x === undefined)
64
+ return 0;
65
+ return typeof x === 'string' || Array.isArray(x) ? x.length : null;
66
+ },
67
+ },
68
+ ],
69
+ ['today', { takes: [0, 0], call: ({ env }) => env.today?.() ?? localDay(new Date()) }],
70
+ [
71
+ 'sum',
72
+ {
73
+ takes: [1, 2],
74
+ check(args) {
75
+ const field = args[1];
76
+ if (field && !(field.type === 'Literal' && typeof field.value === 'string')) {
77
+ return "sum takes the name of a field, in quotes, after the lines: sum(lines, 'subtotal')";
78
+ }
79
+ return undefined;
80
+ },
81
+ call(call) {
82
+ const list = listOf(call);
83
+ if (list === null || list === undefined)
84
+ return 0;
85
+ if (!Array.isArray(list))
86
+ return null;
87
+ const field = call.args[1]?.type === 'Literal' ? call.args[1].value : undefined;
88
+ let total = 0;
89
+ for (const item of list) {
90
+ const n = field === undefined ? item : item?.[field];
91
+ if ((0, operations_1.isNumber)(n))
92
+ total += n;
93
+ }
94
+ return (0, operations_1.tidy)(total);
95
+ },
96
+ },
97
+ ],
98
+ [
99
+ 'count',
100
+ {
101
+ takes: [1, 1],
102
+ call(call) {
103
+ const list = listOf(call);
104
+ if (list === null || list === undefined)
105
+ return 0;
106
+ return Array.isArray(list) ? list.length : null;
107
+ },
108
+ },
109
+ ],
110
+ [
111
+ 'if',
112
+ {
113
+ takes: [3, 3],
114
+ // Only the branch chosen is worked out.
115
+ call: ({ args, value }) => ((0, operations_1.truthy)(value(args[0])) ? value(args[1]) : value(args[2])),
116
+ },
117
+ ],
118
+ ]);
119
+ /** How many values a function takes, in words: "round takes 1 or 2 values". */
120
+ function takesInWords(name, [least, most]) {
121
+ if (most === 0)
122
+ return `${name} takes no values`;
123
+ if (least === most)
124
+ return `${name} takes ${least} value${least === 1 ? '' : 's'}`;
125
+ if (most === Infinity)
126
+ return `${name} takes ${least} or more values`;
127
+ return `${name} takes ${least} or ${most} values`;
128
+ }
129
+ //# sourceMappingURL=functions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/functions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ import { isNumber, roundTo, tidy, truthy } from './operations.mjs';
2
+ /** A day as YYYY-MM-DD, in the computer's own time zone. */
3
+ export function localDay(date) {
4
+ const pad = (n) => String(n).padStart(2, '0');
5
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
6
+ }
7
+ /** The list a function counts or adds up: the rows of a one2many named by its field, or any list. */
8
+ function listOf(call) {
9
+ const first = call.args[0];
10
+ const rows = first.type === 'Identifier' ? call.env.lines?.(first.name) : undefined;
11
+ return rows ?? call.value(first);
12
+ }
13
+ /** The smallest or largest of the values, lists opened: empty ones left out, numbers or text but not both. */
14
+ function extreme(call, smaller) {
15
+ const items = call.args
16
+ .flatMap((arg) => {
17
+ const value = call.value(arg);
18
+ return Array.isArray(value) ? value : [value];
19
+ })
20
+ .filter((value) => value !== null && value !== undefined);
21
+ if (!items.length)
22
+ return null;
23
+ if (!items.every(isNumber) && !items.every((value) => typeof value === 'string'))
24
+ return null;
25
+ const ordered = items;
26
+ return ordered.reduce((best, value) => ((smaller ? value < best : value > best) ? value : best));
27
+ }
28
+ export const FUNCTIONS = new Map([
29
+ [
30
+ 'round',
31
+ {
32
+ takes: [1, 2],
33
+ call({ args, value }) {
34
+ const x = value(args[0]);
35
+ const digits = args.length > 1 ? value(args[1]) : 0;
36
+ return isNumber(x) && isNumber(digits) ? roundTo(x, digits) : null;
37
+ },
38
+ },
39
+ ],
40
+ [
41
+ 'abs',
42
+ {
43
+ takes: [1, 1],
44
+ call({ args, value }) {
45
+ const x = value(args[0]);
46
+ return isNumber(x) ? Math.abs(x) : null;
47
+ },
48
+ },
49
+ ],
50
+ ['min', { takes: [1, Infinity], call: (call) => extreme(call, true) }],
51
+ ['max', { takes: [1, Infinity], call: (call) => extreme(call, false) }],
52
+ [
53
+ 'len',
54
+ {
55
+ takes: [1, 1],
56
+ call({ args, value }) {
57
+ const x = value(args[0]);
58
+ if (x === null || x === undefined)
59
+ return 0;
60
+ return typeof x === 'string' || Array.isArray(x) ? x.length : null;
61
+ },
62
+ },
63
+ ],
64
+ ['today', { takes: [0, 0], call: ({ env }) => env.today?.() ?? localDay(new Date()) }],
65
+ [
66
+ 'sum',
67
+ {
68
+ takes: [1, 2],
69
+ check(args) {
70
+ const field = args[1];
71
+ if (field && !(field.type === 'Literal' && typeof field.value === 'string')) {
72
+ return "sum takes the name of a field, in quotes, after the lines: sum(lines, 'subtotal')";
73
+ }
74
+ return undefined;
75
+ },
76
+ call(call) {
77
+ const list = listOf(call);
78
+ if (list === null || list === undefined)
79
+ return 0;
80
+ if (!Array.isArray(list))
81
+ return null;
82
+ const field = call.args[1]?.type === 'Literal' ? call.args[1].value : undefined;
83
+ let total = 0;
84
+ for (const item of list) {
85
+ const n = field === undefined ? item : item?.[field];
86
+ if (isNumber(n))
87
+ total += n;
88
+ }
89
+ return tidy(total);
90
+ },
91
+ },
92
+ ],
93
+ [
94
+ 'count',
95
+ {
96
+ takes: [1, 1],
97
+ call(call) {
98
+ const list = listOf(call);
99
+ if (list === null || list === undefined)
100
+ return 0;
101
+ return Array.isArray(list) ? list.length : null;
102
+ },
103
+ },
104
+ ],
105
+ [
106
+ 'if',
107
+ {
108
+ takes: [3, 3],
109
+ // Only the branch chosen is worked out.
110
+ call: ({ args, value }) => (truthy(value(args[0])) ? value(args[1]) : value(args[2])),
111
+ },
112
+ ],
113
+ ]);
114
+ /** How many values a function takes, in words: "round takes 1 or 2 values". */
115
+ export function takesInWords(name, [least, most]) {
116
+ if (most === 0)
117
+ return `${name} takes no values`;
118
+ if (least === most)
119
+ return `${name} takes ${least} value${least === 1 ? '' : 's'}`;
120
+ if (most === Infinity)
121
+ return `${name} takes ${least} or more values`;
122
+ return `${name} takes ${least} or ${most} values`;
123
+ }
124
+ //# sourceMappingURL=functions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/functions.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  import type { Modifier } from '../format/layout.mjs';
2
+ import type { ExpressionEnv } from './functions.mjs';
2
3
  /** A modifier read once, ready to evaluate against a record's values. */
3
4
  export interface CompiledModifier {
4
5
  readonly source: Modifier | undefined;
5
6
  /** The fields it reads, by their first name, in order of appearance. */
6
7
  readonly fields: readonly string[];
7
- evaluate(values: Readonly<Record<string, unknown>>): boolean;
8
+ /** Whether it holds for these values; `env` gives `sum` and `count` the lines, and `today()` its day. */
9
+ evaluate(values: Readonly<Record<string, unknown>>, env?: ExpressionEnv): boolean;
8
10
  }
9
11
  /**
10
12
  * Read a modifier. `true`, `false` and a missing modifier become constants;
@@ -1,10 +1,12 @@
1
1
  import type { Modifier } from '../format/layout';
2
+ import type { ExpressionEnv } from './functions';
2
3
  /** A modifier read once, ready to evaluate against a record's values. */
3
4
  export interface CompiledModifier {
4
5
  readonly source: Modifier | undefined;
5
6
  /** The fields it reads, by their first name, in order of appearance. */
6
7
  readonly fields: readonly string[];
7
- evaluate(values: Readonly<Record<string, unknown>>): boolean;
8
+ /** Whether it holds for these values; `env` gives `sum` and `count` the lines, and `today()` its day. */
9
+ evaluate(values: Readonly<Record<string, unknown>>, env?: ExpressionEnv): boolean;
8
10
  }
9
11
  /**
10
12
  * Read a modifier. `true`, `false` and a missing modifier become constants;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compileModifier = compileModifier;
4
4
  const evaluator_1 = require("./evaluator");
5
5
  const parser_1 = require("./parser");
6
+ const reads_1 = require("./reads");
6
7
  const tokenizer_1 = require("./tokenizer");
7
8
  /**
8
9
  * Read a modifier. `true`, `false` and a missing modifier become constants;
@@ -17,10 +18,10 @@ function compileModifier(modifier) {
17
18
  const ast = new parser_1.ExpressionParser((0, tokenizer_1.tokenize)(modifier)).parse();
18
19
  return {
19
20
  source: modifier,
20
- fields: fieldsRead(ast),
21
- evaluate(values) {
21
+ fields: (0, reads_1.fieldsRead)(ast),
22
+ evaluate(values, env) {
22
23
  try {
23
- return (0, evaluator_1.truthy)((0, evaluator_1.evaluate)(ast, values));
24
+ return (0, evaluator_1.truthy)((0, evaluator_1.evaluate)(ast, values, env));
24
25
  }
25
26
  catch {
26
27
  return false;
@@ -28,28 +29,4 @@ function compileModifier(modifier) {
28
29
  },
29
30
  };
30
31
  }
31
- function fieldsRead(ast) {
32
- const names = [];
33
- const visit = (node) => {
34
- switch (node.type) {
35
- case 'Identifier': {
36
- const root = node.name.split('.')[0];
37
- if (!names.includes(root))
38
- names.push(root);
39
- return;
40
- }
41
- case 'BinaryOp':
42
- visit(node.left);
43
- visit(node.right);
44
- return;
45
- case 'UnaryOp':
46
- visit(node.operand);
47
- return;
48
- default:
49
- return;
50
- }
51
- };
52
- visit(ast);
53
- return names;
54
- }
55
32
  //# sourceMappingURL=modifier.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"modifier.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/modifier.ts"],"names":[],"mappings":";;AAkBA,0CAiBC;AAlCD,2CAA+C;AAC/C,qCAA0D;AAC1D,2CAAuC;AAUvC;;;;GAIG;AACH,SAAgB,eAAe,CAAC,QAA8B;IAC5D,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IACjE,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,yBAAgB,CAAC,IAAA,oBAAQ,EAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC7D,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC;QACvB,QAAQ,CAAC,MAAM;YACb,IAAI,CAAC;gBACH,OAAO,IAAA,kBAAM,EAAC,IAAA,oBAAQ,EAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,CAAC,IAAa,EAAQ,EAAE;QACpC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YACD,KAAK,UAAU;gBACb,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAClB,OAAO;YACT,KAAK,SAAS;gBACZ,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACpB,OAAO;YACT;gBACE,OAAO;QACX,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,CAAC;IACX,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"modifier.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/modifier.ts"],"names":[],"mappings":";;AAqBA,0CAiBC;AArCD,2CAA+C;AAE/C,qCAA4C;AAC5C,mCAAqC;AACrC,2CAAuC;AAWvC;;;;GAIG;AACH,SAAgB,eAAe,CAAC,QAA8B;IAC5D,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IACjE,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,yBAAgB,CAAC,IAAA,oBAAQ,EAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC7D,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,IAAA,kBAAU,EAAC,GAAG,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,GAAG;YAClB,IAAI,CAAC;gBACH,OAAO,IAAA,kBAAM,EAAC,IAAA,oBAAQ,EAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { evaluate, truthy } from './evaluator.mjs';
2
2
  import { ExpressionParser } from './parser.mjs';
3
+ import { fieldsRead } from './reads.mjs';
3
4
  import { tokenize } from './tokenizer.mjs';
4
5
  /**
5
6
  * Read a modifier. `true`, `false` and a missing modifier become constants;
@@ -15,9 +16,9 @@ export function compileModifier(modifier) {
15
16
  return {
16
17
  source: modifier,
17
18
  fields: fieldsRead(ast),
18
- evaluate(values) {
19
+ evaluate(values, env) {
19
20
  try {
20
- return truthy(evaluate(ast, values));
21
+ return truthy(evaluate(ast, values, env));
21
22
  }
22
23
  catch {
23
24
  return false;
@@ -25,28 +26,4 @@ export function compileModifier(modifier) {
25
26
  },
26
27
  };
27
28
  }
28
- function fieldsRead(ast) {
29
- const names = [];
30
- const visit = (node) => {
31
- switch (node.type) {
32
- case 'Identifier': {
33
- const root = node.name.split('.')[0];
34
- if (!names.includes(root))
35
- names.push(root);
36
- return;
37
- }
38
- case 'BinaryOp':
39
- visit(node.left);
40
- visit(node.right);
41
- return;
42
- case 'UnaryOp':
43
- visit(node.operand);
44
- return;
45
- default:
46
- return;
47
- }
48
- };
49
- visit(ast);
50
- return names;
51
- }
52
29
  //# sourceMappingURL=modifier.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"modifier.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/modifier.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAgB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAUvC;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAA8B;IAC5D,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IACjE,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC7D,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC;QACvB,QAAQ,CAAC,MAAM;YACb,IAAI,CAAC;gBACH,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,CAAC,IAAa,EAAQ,EAAE;QACpC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YACD,KAAK,UAAU;gBACb,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAClB,OAAO;YACT,KAAK,SAAS;gBACZ,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACpB,OAAO;YACT;gBACE,OAAO;QACX,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,CAAC;IACX,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"modifier.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/modifier.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAWvC;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAA8B;IAC5D,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IACjE,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC7D,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,GAAG;YAClB,IAAI,CAAC;gBACH,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * What the language's operators do to values, the way a form needs it:
3
+ * arithmetic on numbers only, text joined with +, and null — never an error —
4
+ * for what cannot be worked out, such as a sum with an empty field in it or a
5
+ * division by zero.
6
+ */
7
+ /** A number that can be counted with: not NaN, not infinite. */
8
+ export declare const isNumber: (value: unknown) => value is number;
9
+ /**
10
+ * A result without the noise of binary fractions, so 0.1 + 0.2 is 0.3 and
11
+ * money adds up; null when it is not a finite number (a division by zero).
12
+ */
13
+ export declare function tidy(value: number): number | null;
14
+ /** `+ - * / %` on two values. `+` joins text when either side is text; an empty value joins as nothing. */
15
+ export declare function arithmetic(operator: string, left: unknown, right: unknown): unknown;
16
+ /** A number with its sign turned, or null for anything else. */
17
+ export declare function negate(value: unknown): number | null;
18
+ /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
19
+ export declare function truthy(value: unknown): boolean;
20
+ /**
21
+ * A number rounded to so many digits after the point (before it, when
22
+ * negative), half away from zero as people and invoices round: 2.5 is 3,
23
+ * -2.5 is -3, and 1.005 to two digits is 1.01.
24
+ */
25
+ export declare function roundTo(value: number, digits: number): number | null;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * What the language's operators do to values, the way a form needs it:
3
+ * arithmetic on numbers only, text joined with +, and null — never an error —
4
+ * for what cannot be worked out, such as a sum with an empty field in it or a
5
+ * division by zero.
6
+ */
7
+ /** A number that can be counted with: not NaN, not infinite. */
8
+ export declare const isNumber: (value: unknown) => value is number;
9
+ /**
10
+ * A result without the noise of binary fractions, so 0.1 + 0.2 is 0.3 and
11
+ * money adds up; null when it is not a finite number (a division by zero).
12
+ */
13
+ export declare function tidy(value: number): number | null;
14
+ /** `+ - * / %` on two values. `+` joins text when either side is text; an empty value joins as nothing. */
15
+ export declare function arithmetic(operator: string, left: unknown, right: unknown): unknown;
16
+ /** A number with its sign turned, or null for anything else. */
17
+ export declare function negate(value: unknown): number | null;
18
+ /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
19
+ export declare function truthy(value: unknown): boolean;
20
+ /**
21
+ * A number rounded to so many digits after the point (before it, when
22
+ * negative), half away from zero as people and invoices round: 2.5 is 3,
23
+ * -2.5 is -3, and 1.005 to two digits is 1.01.
24
+ */
25
+ export declare function roundTo(value: number, digits: number): number | null;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * What the language's operators do to values, the way a form needs it:
4
+ * arithmetic on numbers only, text joined with +, and null — never an error —
5
+ * for what cannot be worked out, such as a sum with an empty field in it or a
6
+ * division by zero.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isNumber = void 0;
10
+ exports.tidy = tidy;
11
+ exports.arithmetic = arithmetic;
12
+ exports.negate = negate;
13
+ exports.truthy = truthy;
14
+ exports.roundTo = roundTo;
15
+ /** A number that can be counted with: not NaN, not infinite. */
16
+ const isNumber = (value) => typeof value === 'number' && Number.isFinite(value);
17
+ exports.isNumber = isNumber;
18
+ /**
19
+ * A result without the noise of binary fractions, so 0.1 + 0.2 is 0.3 and
20
+ * money adds up; null when it is not a finite number (a division by zero).
21
+ */
22
+ function tidy(value) {
23
+ return Number.isFinite(value) ? Number(value.toPrecision(15)) : null;
24
+ }
25
+ /** `+ - * / %` on two values. `+` joins text when either side is text; an empty value joins as nothing. */
26
+ function arithmetic(operator, left, right) {
27
+ if (operator === '+' && (typeof left === 'string' || typeof right === 'string')) {
28
+ const l = joinable(left);
29
+ const r = joinable(right);
30
+ return l === null || r === null ? null : l + r;
31
+ }
32
+ if (!(0, exports.isNumber)(left) || !(0, exports.isNumber)(right))
33
+ return null;
34
+ switch (operator) {
35
+ case '+':
36
+ return tidy(left + right);
37
+ case '-':
38
+ return tidy(left - right);
39
+ case '*':
40
+ return tidy(left * right);
41
+ case '/':
42
+ return tidy(left / right);
43
+ case '%':
44
+ // Python's remainder takes the divisor's sign: -7 % 3 is 2.
45
+ return tidy(left - right * Math.floor(left / right));
46
+ default:
47
+ return null;
48
+ }
49
+ }
50
+ /** A value as it reads inside joined text: text and numbers as written, an empty value as nothing. */
51
+ function joinable(value) {
52
+ if (value === null || value === undefined)
53
+ return '';
54
+ if (typeof value === 'string')
55
+ return value;
56
+ return (0, exports.isNumber)(value) ? String(value) : null;
57
+ }
58
+ /** A number with its sign turned, or null for anything else. */
59
+ function negate(value) {
60
+ return (0, exports.isNumber)(value) ? tidy(-value) : null;
61
+ }
62
+ /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
63
+ function truthy(value) {
64
+ if (Array.isArray(value))
65
+ return value.length > 0;
66
+ if (value !== null && typeof value === 'object')
67
+ return Object.keys(value).length > 0;
68
+ return Boolean(value);
69
+ }
70
+ /**
71
+ * A number rounded to so many digits after the point (before it, when
72
+ * negative), half away from zero as people and invoices round: 2.5 is 3,
73
+ * -2.5 is -3, and 1.005 to two digits is 1.01.
74
+ */
75
+ function roundTo(value, digits) {
76
+ const scale = 10 ** Math.trunc(digits);
77
+ // Tidied first, so 1.005 × 100 is 100.5 and not 100.49999999999999.
78
+ const scaled = Number((Math.abs(value) * scale).toPrecision(15));
79
+ return tidy((Math.sign(value) * Math.round(scaled)) / scale);
80
+ }
81
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * What the language's operators do to values, the way a form needs it:
3
+ * arithmetic on numbers only, text joined with +, and null — never an error —
4
+ * for what cannot be worked out, such as a sum with an empty field in it or a
5
+ * division by zero.
6
+ */
7
+ /** A number that can be counted with: not NaN, not infinite. */
8
+ export const isNumber = (value) => typeof value === 'number' && Number.isFinite(value);
9
+ /**
10
+ * A result without the noise of binary fractions, so 0.1 + 0.2 is 0.3 and
11
+ * money adds up; null when it is not a finite number (a division by zero).
12
+ */
13
+ export function tidy(value) {
14
+ return Number.isFinite(value) ? Number(value.toPrecision(15)) : null;
15
+ }
16
+ /** `+ - * / %` on two values. `+` joins text when either side is text; an empty value joins as nothing. */
17
+ export function arithmetic(operator, left, right) {
18
+ if (operator === '+' && (typeof left === 'string' || typeof right === 'string')) {
19
+ const l = joinable(left);
20
+ const r = joinable(right);
21
+ return l === null || r === null ? null : l + r;
22
+ }
23
+ if (!isNumber(left) || !isNumber(right))
24
+ return null;
25
+ switch (operator) {
26
+ case '+':
27
+ return tidy(left + right);
28
+ case '-':
29
+ return tidy(left - right);
30
+ case '*':
31
+ return tidy(left * right);
32
+ case '/':
33
+ return tidy(left / right);
34
+ case '%':
35
+ // Python's remainder takes the divisor's sign: -7 % 3 is 2.
36
+ return tidy(left - right * Math.floor(left / right));
37
+ default:
38
+ return null;
39
+ }
40
+ }
41
+ /** A value as it reads inside joined text: text and numbers as written, an empty value as nothing. */
42
+ function joinable(value) {
43
+ if (value === null || value === undefined)
44
+ return '';
45
+ if (typeof value === 'string')
46
+ return value;
47
+ return isNumber(value) ? String(value) : null;
48
+ }
49
+ /** A number with its sign turned, or null for anything else. */
50
+ export function negate(value) {
51
+ return isNumber(value) ? tidy(-value) : null;
52
+ }
53
+ /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
54
+ export function truthy(value) {
55
+ if (Array.isArray(value))
56
+ return value.length > 0;
57
+ if (value !== null && typeof value === 'object')
58
+ return Object.keys(value).length > 0;
59
+ return Boolean(value);
60
+ }
61
+ /**
62
+ * A number rounded to so many digits after the point (before it, when
63
+ * negative), half away from zero as people and invoices round: 2.5 is 3,
64
+ * -2.5 is -3, and 1.005 to two digits is 1.01.
65
+ */
66
+ export function roundTo(value, digits) {
67
+ const scale = 10 ** Math.trunc(digits);
68
+ // Tidied first, so 1.005 × 100 is 100.5 and not 100.49999999999999.
69
+ const scaled = Number((Math.abs(value) * scale).toPrecision(15));
70
+ return tidy((Math.sign(value) * Math.round(scaled)) / scale);
71
+ }
72
+ //# sourceMappingURL=operations.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/operations.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAEjH;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,KAAa;IAChC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,IAAa,EAAE,KAAc;IACxE,IAAI,QAAQ,KAAK,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,EAAE,CAAC;QAChF,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,GAAG;YACN,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;QAC5B,KAAK,GAAG;YACN,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;QAC5B,KAAK,GAAG;YACN,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;QAC5B,KAAK,GAAG;YACN,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;QAC5B,KAAK,GAAG;YACN,4DAA4D;YAC5D,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;QACvD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,sGAAsG;AACtG,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAClD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACtF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,MAAc;IACnD,MAAM,KAAK,GAAG,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,oEAAoE;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The order to work fields out in: each after the fields it reads. `reads`
3
+ * maps each worked-out field to the fields its expression reads; names not in
4
+ * the map are plain values and need no order. A circle — a field read, at
5
+ * some remove, by itself — has no order: it is listed among the cycles, as
6
+ * the fields around it (`a → b → a`), and its fields still come out once each.
7
+ */
8
+ export declare function dependencyOrder(reads: ReadonlyMap<string, readonly string[]>): {
9
+ order: string[];
10
+ cycles: string[][];
11
+ };