@elaraai/east 1.0.83 → 1.0.85

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 (252) hide show
  1. package/dist/src/analyze.d.ts.map +1 -1
  2. package/dist/src/analyze.js +48 -0
  3. package/dist/src/analyze.js.map +1 -1
  4. package/dist/src/ast_to_ir.coerce_to.spec.js +4 -4
  5. package/dist/src/ast_to_ir.coerce_to.spec.js.map +1 -1
  6. package/dist/src/ast_to_ir.d.ts +6 -1
  7. package/dist/src/ast_to_ir.d.ts.map +1 -1
  8. package/dist/src/ast_to_ir.js +20 -7
  9. package/dist/src/ast_to_ir.js.map +1 -1
  10. package/dist/src/builtins.d.ts +1 -1
  11. package/dist/src/builtins.d.ts.map +1 -1
  12. package/dist/src/builtins.js +52 -0
  13. package/dist/src/builtins.js.map +1 -1
  14. package/dist/src/codegen/canonical.d.ts +37 -0
  15. package/dist/src/codegen/canonical.d.ts.map +1 -0
  16. package/dist/src/codegen/canonical.js +208 -0
  17. package/dist/src/codegen/canonical.js.map +1 -0
  18. package/dist/src/codegen/codegen.spec.js +132 -201
  19. package/dist/src/codegen/codegen.spec.js.map +1 -1
  20. package/dist/src/codegen/printer.d.ts.map +1 -1
  21. package/dist/src/codegen/printer.js +142 -24
  22. package/dist/src/codegen/printer.js.map +1 -1
  23. package/dist/src/codegen/spellings.d.ts +4 -1
  24. package/dist/src/codegen/spellings.d.ts.map +1 -1
  25. package/dist/src/codegen/spellings.js +5 -1
  26. package/dist/src/codegen/spellings.js.map +1 -1
  27. package/dist/src/compile/builtins/index.d.ts.map +1 -1
  28. package/dist/src/compile/builtins/index.js +2 -0
  29. package/dist/src/compile/builtins/index.js.map +1 -1
  30. package/dist/src/compile/builtins/primitives.d.ts.map +1 -1
  31. package/dist/src/compile/builtins/primitives.js +2 -1
  32. package/dist/src/compile/builtins/primitives.js.map +1 -1
  33. package/dist/src/compile/builtins/query.d.ts +10 -0
  34. package/dist/src/compile/builtins/query.d.ts.map +1 -0
  35. package/dist/src/compile/builtins/query.js +5 -0
  36. package/dist/src/compile/builtins/query.js.map +1 -0
  37. package/dist/src/expr/block.d.ts.map +1 -1
  38. package/dist/src/expr/block.js +2 -1
  39. package/dist/src/expr/block.js.map +1 -1
  40. package/dist/src/expr/index.d.ts +75 -47
  41. package/dist/src/expr/index.d.ts.map +1 -1
  42. package/dist/src/expr/index.js +31 -0
  43. package/dist/src/expr/index.js.map +1 -1
  44. package/dist/src/expr/libs/datetime.d.ts +20 -20
  45. package/dist/src/expr/libs/datetime.d.ts.map +1 -1
  46. package/dist/src/expr/libs/datetime.js +208 -167
  47. package/dist/src/expr/libs/datetime.js.map +1 -1
  48. package/dist/src/expr/libs/float.d.ts +15 -15
  49. package/dist/src/expr/libs/float.d.ts.map +1 -1
  50. package/dist/src/expr/libs/float.js +298 -267
  51. package/dist/src/expr/libs/float.js.map +1 -1
  52. package/dist/src/expr/libs/integer.d.ts +12 -12
  53. package/dist/src/expr/libs/integer.d.ts.map +1 -1
  54. package/dist/src/expr/libs/integer.js +219 -194
  55. package/dist/src/expr/libs/integer.js.map +1 -1
  56. package/dist/src/expr/libs/lazy.d.ts +28 -0
  57. package/dist/src/expr/libs/lazy.d.ts.map +1 -0
  58. package/dist/src/expr/libs/lazy.js +55 -0
  59. package/dist/src/expr/libs/lazy.js.map +1 -0
  60. package/dist/src/expr/libs/lazy.spec.d.ts +6 -0
  61. package/dist/src/expr/libs/lazy.spec.d.ts.map +1 -0
  62. package/dist/src/expr/libs/lazy.spec.js +102 -0
  63. package/dist/src/expr/libs/lazy.spec.js.map +1 -0
  64. package/dist/src/expr/query.d.ts +60 -0
  65. package/dist/src/expr/query.d.ts.map +1 -0
  66. package/dist/src/expr/query.js +84 -0
  67. package/dist/src/expr/query.js.map +1 -0
  68. package/dist/src/index.d.ts +3 -0
  69. package/dist/src/index.d.ts.map +1 -1
  70. package/dist/src/index.js +3 -0
  71. package/dist/src/index.js.map +1 -1
  72. package/dist/src/internal.d.ts +4 -0
  73. package/dist/src/internal.d.ts.map +1 -1
  74. package/dist/src/internal.js +9 -0
  75. package/dist/src/internal.js.map +1 -1
  76. package/dist/src/location.d.ts +22 -0
  77. package/dist/src/location.d.ts.map +1 -1
  78. package/dist/src/location.js +31 -0
  79. package/dist/src/location.js.map +1 -1
  80. package/dist/src/naming.d.ts +12 -7
  81. package/dist/src/naming.d.ts.map +1 -1
  82. package/dist/src/naming.js +30 -13
  83. package/dist/src/naming.js.map +1 -1
  84. package/dist/src/naming.spec.js +49 -0
  85. package/dist/src/naming.spec.js.map +1 -1
  86. package/dist/src/portable.spec.d.ts +6 -0
  87. package/dist/src/portable.spec.d.ts.map +1 -0
  88. package/dist/src/portable.spec.js +181 -0
  89. package/dist/src/portable.spec.js.map +1 -0
  90. package/dist/src/query/evaluate.d.ts +98 -0
  91. package/dist/src/query/evaluate.d.ts.map +1 -0
  92. package/dist/src/query/evaluate.js +193 -0
  93. package/dist/src/query/evaluate.js.map +1 -0
  94. package/dist/src/query/index.d.ts +17 -0
  95. package/dist/src/query/index.d.ts.map +1 -0
  96. package/dist/src/query/index.js +17 -0
  97. package/dist/src/query/index.js.map +1 -0
  98. package/dist/src/query/jq/catalog.d.ts +174 -0
  99. package/dist/src/query/jq/catalog.d.ts.map +1 -0
  100. package/dist/src/query/jq/catalog.js +1740 -0
  101. package/dist/src/query/jq/catalog.js.map +1 -0
  102. package/dist/src/query/jq/check.d.ts +210 -0
  103. package/dist/src/query/jq/check.d.ts.map +1 -0
  104. package/dist/src/query/jq/check.js +2261 -0
  105. package/dist/src/query/jq/check.js.map +1 -0
  106. package/dist/src/query/jq/complete.d.ts +89 -0
  107. package/dist/src/query/jq/complete.d.ts.map +1 -0
  108. package/dist/src/query/jq/complete.js +320 -0
  109. package/dist/src/query/jq/complete.js.map +1 -0
  110. package/dist/src/query/jq/describe.d.ts +53 -0
  111. package/dist/src/query/jq/describe.d.ts.map +1 -0
  112. package/dist/src/query/jq/describe.js +149 -0
  113. package/dist/src/query/jq/describe.js.map +1 -0
  114. package/dist/src/query/jq/lex.d.ts +118 -0
  115. package/dist/src/query/jq/lex.d.ts.map +1 -0
  116. package/dist/src/query/jq/lex.js +371 -0
  117. package/dist/src/query/jq/lex.js.map +1 -0
  118. package/dist/src/query/jq/literals.d.ts +49 -0
  119. package/dist/src/query/jq/literals.d.ts.map +1 -0
  120. package/dist/src/query/jq/literals.js +78 -0
  121. package/dist/src/query/jq/literals.js.map +1 -0
  122. package/dist/src/query/jq/messages.d.ts +126 -0
  123. package/dist/src/query/jq/messages.d.ts.map +1 -0
  124. package/dist/src/query/jq/messages.js +172 -0
  125. package/dist/src/query/jq/messages.js.map +1 -0
  126. package/dist/src/query/jq/parse.d.ts +70 -0
  127. package/dist/src/query/jq/parse.d.ts.map +1 -0
  128. package/dist/src/query/jq/parse.js +1013 -0
  129. package/dist/src/query/jq/parse.js.map +1 -0
  130. package/dist/src/query/jq/print.d.ts +59 -0
  131. package/dist/src/query/jq/print.d.ts.map +1 -0
  132. package/dist/src/query/jq/print.js +587 -0
  133. package/dist/src/query/jq/print.js.map +1 -0
  134. package/dist/src/query/jq/shapes.d.ts +345 -0
  135. package/dist/src/query/jq/shapes.d.ts.map +1 -0
  136. package/dist/src/query/jq/shapes.js +584 -0
  137. package/dist/src/query/jq/shapes.js.map +1 -0
  138. package/dist/src/query/jq/spans.d.ts +133 -0
  139. package/dist/src/query/jq/spans.d.ts.map +1 -0
  140. package/dist/src/query/jq/spans.js +195 -0
  141. package/dist/src/query/jq/spans.js.map +1 -0
  142. package/dist/src/query/jq/split.d.ts +334 -0
  143. package/dist/src/query/jq/split.d.ts.map +1 -0
  144. package/dist/src/query/jq/split.js +2108 -0
  145. package/dist/src/query/jq/split.js.map +1 -0
  146. package/dist/src/query/jq/strftime.d.ts +20 -0
  147. package/dist/src/query/jq/strftime.d.ts.map +1 -0
  148. package/dist/src/query/jq/strftime.js +65 -0
  149. package/dist/src/query/jq/strftime.js.map +1 -0
  150. package/dist/src/query/jq/summary.d.ts +139 -0
  151. package/dist/src/query/jq/summary.d.ts.map +1 -0
  152. package/dist/src/query/jq/summary.js +222 -0
  153. package/dist/src/query/jq/summary.js.map +1 -0
  154. package/dist/src/query/jq/translate-builtins.d.ts +21 -0
  155. package/dist/src/query/jq/translate-builtins.d.ts.map +1 -0
  156. package/dist/src/query/jq/translate-builtins.js +1873 -0
  157. package/dist/src/query/jq/translate-builtins.js.map +1 -0
  158. package/dist/src/query/jq/translate.d.ts +627 -0
  159. package/dist/src/query/jq/translate.d.ts.map +1 -0
  160. package/dist/src/query/jq/translate.js +3364 -0
  161. package/dist/src/query/jq/translate.js.map +1 -0
  162. package/dist/src/query/types.d.ts +505 -0
  163. package/dist/src/query/types.d.ts.map +1 -0
  164. package/dist/src/query/types.js +231 -0
  165. package/dist/src/query/types.js.map +1 -0
  166. package/dist/src/runner_exec.d.ts +134 -0
  167. package/dist/src/runner_exec.d.ts.map +1 -0
  168. package/dist/src/runner_exec.js +371 -0
  169. package/dist/src/runner_exec.js.map +1 -0
  170. package/dist/src/runner_exec.spec.d.ts +6 -0
  171. package/dist/src/runner_exec.spec.d.ts.map +1 -0
  172. package/dist/src/runner_exec.spec.js +198 -0
  173. package/dist/src/runner_exec.spec.js.map +1 -0
  174. package/dist/src/runner_io.d.ts +370 -0
  175. package/dist/src/runner_io.d.ts.map +1 -0
  176. package/dist/src/runner_io.js +563 -0
  177. package/dist/src/runner_io.js.map +1 -0
  178. package/dist/src/runner_io.spec.d.ts +6 -0
  179. package/dist/src/runner_io.spec.d.ts.map +1 -0
  180. package/dist/src/runner_io.spec.js +224 -0
  181. package/dist/src/runner_io.spec.js.map +1 -0
  182. package/dist/src/runner_merge.d.ts +95 -0
  183. package/dist/src/runner_merge.d.ts.map +1 -0
  184. package/dist/src/runner_merge.js +238 -0
  185. package/dist/src/runner_merge.js.map +1 -0
  186. package/dist/src/runner_protocol.d.ts +60 -6
  187. package/dist/src/runner_protocol.d.ts.map +1 -1
  188. package/dist/src/runner_protocol.js +48 -6
  189. package/dist/src/runner_protocol.js.map +1 -1
  190. package/dist/src/serialization/beast2/index.d.ts +2 -2
  191. package/dist/src/serialization/beast2/index.d.ts.map +1 -1
  192. package/dist/src/serialization/beast2/index.js +1 -1
  193. package/dist/src/serialization/beast2/index.js.map +1 -1
  194. package/dist/src/serialization/beast2/v5/frames.d.ts +10 -6
  195. package/dist/src/serialization/beast2/v5/frames.d.ts.map +1 -1
  196. package/dist/src/serialization/beast2/v5/frames.js +10 -6
  197. package/dist/src/serialization/beast2/v5/frames.js.map +1 -1
  198. package/dist/src/serialization/beast2/v5/frames.spec.d.ts +6 -0
  199. package/dist/src/serialization/beast2/v5/frames.spec.d.ts.map +1 -0
  200. package/dist/src/serialization/beast2/v5/frames.spec.js +42 -0
  201. package/dist/src/serialization/beast2/v5/frames.spec.js.map +1 -0
  202. package/dist/src/serialization/beast2/v5/index.spec.js +108 -0
  203. package/dist/src/serialization/beast2/v5/index.spec.js.map +1 -1
  204. package/dist/src/serialization/beast2/v5/lazy.d.ts +74 -7
  205. package/dist/src/serialization/beast2/v5/lazy.d.ts.map +1 -1
  206. package/dist/src/serialization/beast2/v5/lazy.js +129 -27
  207. package/dist/src/serialization/beast2/v5/lazy.js.map +1 -1
  208. package/dist/src/serialization/beast2/v5/lazy.spec.js +251 -16
  209. package/dist/src/serialization/beast2/v5/lazy.spec.js.map +1 -1
  210. package/dist/src/serialization/beast2/v5/stream.d.ts +139 -23
  211. package/dist/src/serialization/beast2/v5/stream.d.ts.map +1 -1
  212. package/dist/src/serialization/beast2/v5/stream.js +196 -44
  213. package/dist/src/serialization/beast2/v5/stream.js.map +1 -1
  214. package/dist/src/serialization/beast2/v5/type-section.d.ts.map +1 -1
  215. package/dist/src/serialization/beast2/v5/type-section.js +25 -12
  216. package/dist/src/serialization/beast2/v5/type-section.js.map +1 -1
  217. package/dist/src/serialization/beast2/v5/type-section.spec.d.ts +6 -0
  218. package/dist/src/serialization/beast2/v5/type-section.spec.d.ts.map +1 -0
  219. package/dist/src/serialization/beast2/v5/type-section.spec.js +41 -0
  220. package/dist/src/serialization/beast2/v5/type-section.spec.js.map +1 -0
  221. package/dist/src/serialization/beast2/v5/weight.d.ts +36 -0
  222. package/dist/src/serialization/beast2/v5/weight.d.ts.map +1 -0
  223. package/dist/src/serialization/beast2/v5/weight.js +238 -0
  224. package/dist/src/serialization/beast2/v5/weight.js.map +1 -0
  225. package/dist/src/serialization/crc32.d.ts +38 -0
  226. package/dist/src/serialization/crc32.d.ts.map +1 -0
  227. package/dist/src/serialization/crc32.js +70 -0
  228. package/dist/src/serialization/crc32.js.map +1 -0
  229. package/dist/src/serialization/crc32.spec.d.ts +6 -0
  230. package/dist/src/serialization/crc32.spec.d.ts.map +1 -0
  231. package/dist/src/serialization/crc32.spec.js +92 -0
  232. package/dist/src/serialization/crc32.spec.js.map +1 -0
  233. package/dist/src/serialization/east-inferred.spec.js +4 -0
  234. package/dist/src/serialization/east-inferred.spec.js.map +1 -1
  235. package/dist/src/serialization/east.d.ts.map +1 -1
  236. package/dist/src/serialization/east.js +134 -110
  237. package/dist/src/serialization/east.js.map +1 -1
  238. package/dist/src/serialization/east.spec.js +185 -4
  239. package/dist/src/serialization/east.spec.js.map +1 -1
  240. package/dist/src/serialization/east_text.d.ts +25 -0
  241. package/dist/src/serialization/east_text.d.ts.map +1 -0
  242. package/dist/src/serialization/east_text.js +29 -0
  243. package/dist/src/serialization/east_text.js.map +1 -0
  244. package/dist/src/serialization/index.d.ts +1 -1
  245. package/dist/src/serialization/index.d.ts.map +1 -1
  246. package/dist/src/serialization/index.js +1 -1
  247. package/dist/src/serialization/index.js.map +1 -1
  248. package/dist/src/types.d.ts +1 -1
  249. package/dist/src/types.d.ts.map +1 -1
  250. package/dist/src/types.js +7 -6
  251. package/dist/src/types.js.map +1 -1
  252. package/package.json +7 -4
@@ -0,0 +1,1740 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The builtin catalog: every builtin of jq 1.8 and East's additions, with the
7
+ * checker's typing rule for each one a query may use, and the East builtin or
8
+ * library function the translator defines it by (`devdocs/QUERY.md` §10).
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import { validateCrossPlatformCompatible } from "../../expr/regex_validation.js";
13
+ import { ArrayType, BooleanType, DateTimeType, DictType, FloatType, IntegerType, NeverType, NullType, OptionType, StringType, StructType, VariantType, isImmutableType, isTypeEqual, } from "../../types.js";
14
+ import { jsonString } from "./literals.js";
15
+ import { MESSAGES, edit } from "./messages.js";
16
+ import { ERROR, MANY, MAYBE, ONE, ZERO, describeType, descendTypes, either, isOrdered, membersOf, nullablePayload, orNull, piped, typed, unify, union, unwrap, } from "./shapes.js";
17
+ import { formatTokens } from "./strftime.js";
18
+ // ─── Helpers ─────────────────────────────────────────────────────────────
19
+ const one = (type, mult = ONE) => ({ shape: typed(type), mult });
20
+ /** A result's members' types, read through options when `nullable`. */
21
+ function typesOf(result) {
22
+ return membersOf(result.shape).map(m => m.shape.type);
23
+ }
24
+ /** Applies a rule to each member of the call's input, and unions the outcomes. */
25
+ function perMember(ctx, input, each) {
26
+ if (input.shape.kind === "error")
27
+ return { shape: ERROR, mult: ONE };
28
+ const members = [];
29
+ let mult;
30
+ for (const member of membersOf(input.shape)) {
31
+ const out = each(member.shape);
32
+ if (out.shape.kind === "error")
33
+ return { shape: ERROR, mult: ONE };
34
+ members.push(...membersOf(out.shape));
35
+ mult = mult === undefined ? out.mult : either(mult, out.mult);
36
+ }
37
+ return { shape: union(members), mult: mult ?? ZERO };
38
+ }
39
+ /** Requires the input's members to be of some kind, typing each with `rule`. */
40
+ function onInput(ctx, expected, rule) {
41
+ return perMember(ctx, ctx.input, member => {
42
+ const t = unwrap(member.type);
43
+ const out = rule(t, member);
44
+ if (out !== undefined)
45
+ return out;
46
+ return inputMismatch(ctx, expected, member.type);
47
+ });
48
+ }
49
+ /**
50
+ * The diagnostic for an input of the wrong type: "Narrow first" when it is an
51
+ * option only because a variant is not narrowed; `array_builtin_on_element`
52
+ * when an array builtin runs on each element of a stream; for a string
53
+ * builtin on a DateTime, what to use instead.
54
+ */
55
+ function inputMismatch(ctx, expected, type) {
56
+ if (ctx.input.partial !== undefined && nullablePayload(unwrap(type)) !== undefined)
57
+ return ctx.narrowFirst(type);
58
+ if (ctx.input.stream !== undefined && expected.startsWith("an array"))
59
+ return ctx.onElement(type);
60
+ if (unwrap(type).type === "DateTime" && expected === "a string")
61
+ return ctx.mismatch("type_mismatch", MESSAGES.dateAsString(ctx.name));
62
+ // An input that can be null: the fix skips the nulls.
63
+ const skip = nullablePayload(unwrap(type)) !== undefined ? ctx.skipNulls() : undefined;
64
+ return ctx.mismatch("type_mismatch", MESSAGES.input(ctx.name, expected, describeType(type)), undefined, skip === undefined ? [] : [skip]);
65
+ }
66
+ /** The element type of an array-like value as jq sees it: arrays, sets, vectors; matrix rows. */
67
+ function elementOf(t) {
68
+ switch (t.type) {
69
+ case "Array": return t.value;
70
+ case "Set": return t.key;
71
+ case "Vector": return t.element;
72
+ case "Matrix": return ArrayType(t.element);
73
+ default: return undefined;
74
+ }
75
+ }
76
+ /** The elements of an array-like input, with their facts, for a builtin that runs a filter on each. */
77
+ function elements(member) {
78
+ const t = unwrap(member.type);
79
+ const element = elementOf(t);
80
+ if (element === undefined)
81
+ return undefined;
82
+ const facts = t.type === "Array" && member.facts?.kind === "elements" ? member.facts.element : undefined;
83
+ return { shape: typed(element, facts), mult: ONE };
84
+ }
85
+ /** The values `.[]` gives: array-like elements, dict values, struct fields. */
86
+ function valuesOf(member) {
87
+ const t = unwrap(member.type);
88
+ const direct = elements(member);
89
+ if (direct !== undefined)
90
+ return direct;
91
+ if (t.type === "Dict")
92
+ return { shape: typed(t.value, member.facts?.kind === "values" ? member.facts.value : undefined), mult: ONE };
93
+ if (t.type === "Struct") {
94
+ const facts = member.facts?.kind === "fields" ? member.facts.fields : undefined;
95
+ return { shape: union(Object.entries(t.fields).map(([name, f]) => ({ shape: typed(f, facts?.get(name)), case: undefined }))), mult: ONE };
96
+ }
97
+ return undefined;
98
+ }
99
+ /** A number type's promotion to Float. */
100
+ function isNumber(t) {
101
+ return t.type === "Integer" || t.type === "Float";
102
+ }
103
+ /** A literal argument that must be a non-negative Integer written in the query. */
104
+ function literalInteger(ctx, i, what) {
105
+ const literal = ctx.literal(i);
106
+ if (literal?.type.type !== "Integer" || literal.value < 0n) {
107
+ ctx.fail("type_mismatch", MESSAGES.literalArgument(ctx.name, what, "a non-negative Integer"), { arg: i });
108
+ return undefined;
109
+ }
110
+ return literal.value;
111
+ }
112
+ /** A literal argument that must be a String written in the query. */
113
+ function literalString(ctx, i, what) {
114
+ const literal = ctx.literal(i);
115
+ if (literal?.type.type !== "String") {
116
+ ctx.fail("type_mismatch", MESSAGES.literalArgument(ctx.name, what, "a string"), { arg: i });
117
+ return undefined;
118
+ }
119
+ return literal.value;
120
+ }
121
+ /** Checks an argument that must give values of one type among `allowed`. */
122
+ function argOf(ctx, i, expected, allowed, input, coerce) {
123
+ const result = ctx.arg(i, input);
124
+ if (result.shape.kind === "error")
125
+ return undefined;
126
+ const type = ctx.collect(result, i);
127
+ if (type === undefined)
128
+ return undefined;
129
+ if (!allowed(unwrap(type))) {
130
+ // A literal of another type the argument's type is written as: an ISO-8601 string for a DateTime.
131
+ const coerced = coerce === undefined ? undefined : coerceArgument(ctx, i, coerce, "value");
132
+ if (coerced === null)
133
+ return undefined;
134
+ if (coerced !== undefined)
135
+ return { result: one(coerced), type: coerced };
136
+ ctx.fail("type_mismatch", MESSAGES.argument(ctx.name, ordinal(i), expected, describeType(type)), { arg: i });
137
+ return undefined;
138
+ }
139
+ return { result, type };
140
+ }
141
+ /**
142
+ * Argument `i` read as `wanted` is written, when it is a literal of another
143
+ * type (`as: "value"`), or an array literal of them (`"elements"`, each
144
+ * element a `wanted`): an ISO-8601 string as a DateTime, an Integer as a
145
+ * Float.
146
+ *
147
+ * @returns the type the argument is read as; `undefined` when it is no such
148
+ * literal; or `null` when it is a string that is not an ISO-8601 date,
149
+ * which reading it has reported
150
+ */
151
+ function coerceArgument(ctx, i, wanted, as) {
152
+ const reported = ctx.problems();
153
+ const coerced = as === "value" ? ctx.coerceArg(i, wanted) : ctx.coerceArgElements(i, wanted);
154
+ if (coerced !== undefined)
155
+ return coerced;
156
+ return ctx.problems() > reported ? null : undefined;
157
+ }
158
+ function ordinal(i) {
159
+ return ["first", "second", "third", "fourth", "fifth"][i] ?? `${i + 1}th`;
160
+ }
161
+ /** The type `+` gives on values of one type, and whether adding nothing gives its identity (§13.15). */
162
+ function addType(t) {
163
+ const u = unwrap(t);
164
+ const payload = nullablePayload(u);
165
+ if (payload !== undefined)
166
+ return addType(payload);
167
+ switch (u.type) {
168
+ case "Integer":
169
+ case "Float":
170
+ case "String":
171
+ case "Array":
172
+ case "Dict": return u;
173
+ case "Null": return NullType;
174
+ case "Struct": return orNull(u);
175
+ default: return undefined;
176
+ }
177
+ }
178
+ /** Validates a regular expression written in the query as an East one. */
179
+ function checkRegex(ctx, i, flags) {
180
+ const literal = ctx.literal(i);
181
+ if (literal === undefined) {
182
+ const r = argOf(ctx, i, "a string", t => t.type === "String");
183
+ return r === undefined ? undefined : [];
184
+ }
185
+ if (literal.type.type !== "String") {
186
+ ctx.fail("type_mismatch", MESSAGES.argument(ctx.name, ordinal(i), "a string", describeType(literal.type)), { arg: i });
187
+ return undefined;
188
+ }
189
+ const pattern = literal.value;
190
+ let regex;
191
+ try {
192
+ regex = new RegExp(pattern, flags.replace(/g/g, ""));
193
+ }
194
+ catch (e) {
195
+ ctx.fail("type_mismatch", MESSAGES.regex(ctx.source(i), e instanceof Error ? e.message.replace(/^Invalid regular expression: /, "").replace(/\.$/, "") : "invalid"), { arg: i });
196
+ return undefined;
197
+ }
198
+ const validation = validateCrossPlatformCompatible(regex);
199
+ if (!validation.isValid) {
200
+ ctx.fail("type_mismatch", MESSAGES.regex(ctx.source(i), validation.errors[0].replace(/\.$/, "")), { arg: i });
201
+ return undefined;
202
+ }
203
+ return [...pattern.matchAll(/\(\?<([a-zA-Z_][a-zA-Z0-9_]*)>/g)].map(m => m[1]);
204
+ }
205
+ /** A regex's flags, written in the query: `g` and `i`. */
206
+ function checkFlags(ctx, i) {
207
+ if (i === undefined)
208
+ return "";
209
+ const flags = literalString(ctx, i, "flags");
210
+ if (flags === undefined)
211
+ return undefined;
212
+ for (const flag of flags) {
213
+ if (flag !== "g" && flag !== "i") {
214
+ ctx.fail("unsupported", MESSAGES.regexFlag(flag), { arg: i });
215
+ return undefined;
216
+ }
217
+ }
218
+ return flags;
219
+ }
220
+ /**
221
+ * Checks a strftime/strptime format argument: a literal string whose every
222
+ * code East has a token for. The translator makes the tokens from it.
223
+ */
224
+ function checkFormat(ctx) {
225
+ const format = literalString(ctx, 0, "format");
226
+ if (format === undefined)
227
+ return false;
228
+ const tokens = formatTokens(format);
229
+ if ("code" in tokens) {
230
+ ctx.fail("unsupported", MESSAGES.formatCode(tokens.code), { arg: 0 });
231
+ return false;
232
+ }
233
+ return true;
234
+ }
235
+ /** A DateTime input, or a number of epoch seconds as jq's date builtins take. */
236
+ function dateInput(ctx, then) {
237
+ return onInput(ctx, "a DateTime or epoch seconds", t => t.type === "DateTime" || isNumber(t) ? one(then) : undefined);
238
+ }
239
+ /** The typing of a builtin on numbers, promoting Integer to Float. */
240
+ function math(output) {
241
+ return ctx => onInput(ctx, "a number", t => {
242
+ if (!isNumber(t))
243
+ return undefined;
244
+ if (output === "same")
245
+ return one(t);
246
+ if (output === "Integer")
247
+ return one(IntegerType);
248
+ return one(FloatType);
249
+ });
250
+ }
251
+ /** The typing of a builtin of two number arguments. */
252
+ function math2(ctx) {
253
+ const a = argOf(ctx, 0, "a number", isNumber);
254
+ const b = argOf(ctx, 1, "a number", isNumber);
255
+ if (a === undefined || b === undefined)
256
+ return { shape: ERROR, mult: ONE };
257
+ return one(FloatType, piped(a.result.mult, b.result.mult));
258
+ }
259
+ /** A type selector (`numbers`, `strings`, …): each member is kept, dropped, or kept when present. */
260
+ function selector(keep) {
261
+ return ctx => perMember(ctx, ctx.input, member => {
262
+ const t = unwrap(member.type);
263
+ const payload = nullablePayload(t);
264
+ if (payload !== undefined) {
265
+ const inner = keep(unwrap(payload));
266
+ const nullKept = keep(NullType);
267
+ if (inner === "drop" && nullKept === "drop")
268
+ return { shape: typed(NeverType), mult: ZERO };
269
+ if (inner === "drop")
270
+ return { shape: typed(NullType), mult: MAYBE };
271
+ if (nullKept === "drop")
272
+ return { shape: typed(payload), mult: MAYBE };
273
+ return { shape: member, mult: ONE };
274
+ }
275
+ const k = keep(t);
276
+ if (k === "drop")
277
+ return { shape: typed(NeverType), mult: ZERO };
278
+ return { shape: member, mult: k === "keep" ? ONE : MAYBE };
279
+ });
280
+ }
281
+ /** Whether a type is a jq scalar: not an array, set, dict, struct, vector or matrix. */
282
+ function isScalar(t) {
283
+ const u = unwrap(t);
284
+ if (nullablePayload(u) !== undefined)
285
+ return isScalar(nullablePayload(u));
286
+ return !["Array", "Set", "Dict", "Struct", "Vector", "Matrix"].includes(u.type) && !(u.type === "Variant");
287
+ }
288
+ /**
289
+ * Runs a filter argument on each element of the input: for `map`, on the
290
+ * values `.[]` gives (an object's too); for the `*_by` builtins, on an
291
+ * array's elements.
292
+ */
293
+ function eachElement(ctx, i, expected, onEach, arraysOnly = false) {
294
+ return perMember(ctx, ctx.input, member => {
295
+ const element = arraysOnly ? elements(member) : valuesOf(member);
296
+ if (element === undefined)
297
+ return inputMismatch(ctx, expected, member.type);
298
+ const per = ctx.arg(i, element);
299
+ if (per.shape.kind === "error")
300
+ return { shape: ERROR, mult: ONE };
301
+ return onEach(element, per) ?? { shape: ERROR, mult: ONE };
302
+ });
303
+ }
304
+ /** An array of a result's outputs, carrying their facts. */
305
+ function arrayOf(ctx, per) {
306
+ const t = ctx.collect(per);
307
+ if (t === undefined)
308
+ return undefined;
309
+ const facts = per.shape.kind === "type" && per.shape.facts !== undefined ? { kind: "elements", element: per.shape.facts } : undefined;
310
+ return { shape: typed(ArrayType(t), facts), mult: ONE };
311
+ }
312
+ /** A filter that repeats: the one type its input and outputs settle on, by fixpoint. */
313
+ function settle(ctx, argument, start) {
314
+ let type = start;
315
+ for (let round = 0; round < 8; round++) {
316
+ const out = ctx.arg(argument, one(type));
317
+ if (out.shape.kind === "error")
318
+ return undefined;
319
+ const next = ctx.collect(out, argument);
320
+ if (next === undefined)
321
+ return undefined;
322
+ const merged = unify(type, next);
323
+ if (merged === undefined) {
324
+ ctx.fail("cannot_infer", MESSAGES.accumulator(ctx.name, describeType(type), describeType(next)));
325
+ return undefined;
326
+ }
327
+ if (isTypeEqual(merged, type))
328
+ return type;
329
+ type = merged;
330
+ }
331
+ ctx.fail("cannot_infer", MESSAGES.accumulator(ctx.name, describeType(start), describeType(type)));
332
+ return undefined;
333
+ }
334
+ /** The type of `.[]` taken `depth` times on arrays, for flatten. */
335
+ function flattened(t, depth) {
336
+ const u = unwrap(t);
337
+ if (depth === 0 || u.type !== "Array")
338
+ return t;
339
+ const inner = unwrap(u.value);
340
+ if (inner.type !== "Array")
341
+ return t;
342
+ return flattened(ArrayType(inner.value), depth - 1);
343
+ }
344
+ /** A struct without some fields. */
345
+ function withoutFields(t, names) {
346
+ const u = unwrap(t);
347
+ if (u.type !== "Struct")
348
+ return t;
349
+ const fields = {};
350
+ for (const [name, f] of Object.entries(u.fields))
351
+ if (!names.includes(name))
352
+ fields[name] = f;
353
+ return StructType(fields);
354
+ }
355
+ /**
356
+ * The paths `del`'s argument names, each as its steps from `.`.
357
+ *
358
+ * @param node - the argument
359
+ * @param path - its node path
360
+ * @returns the paths, or `undefined` when the argument is not made of field
361
+ * reads, indexes, slices, `.[]`, `select`, `|` and `,`
362
+ *
363
+ * @internal
364
+ */
365
+ export function delPaths(node, path) {
366
+ const at = (step) => path === "" ? step : `${path}.${step}`;
367
+ const extend = (target, step, last) => delPaths(target, at(step))?.map(steps => [...steps, last]);
368
+ switch (node.type) {
369
+ case "identity":
370
+ return [[]];
371
+ case "comma": {
372
+ const left = delPaths(node.value.left, at("comma.left"));
373
+ const right = delPaths(node.value.right, at("comma.right"));
374
+ return left === undefined || right === undefined ? undefined : [...left, ...right];
375
+ }
376
+ case "pipe": {
377
+ const left = delPaths(node.value.left, at("pipe.left"));
378
+ const right = delPaths(node.value.right, at("pipe.right"));
379
+ return left === undefined || right === undefined ? undefined : left.flatMap(l => right.map(r => [...l, ...r]));
380
+ }
381
+ case "field":
382
+ return extend(node.value.target, "field.target", { kind: "field", name: node.value.name });
383
+ case "index":
384
+ return extend(node.value.target, "index.target", { kind: "index", node: node.value.index, path: at("index.index") });
385
+ case "slice":
386
+ return extend(node.value.target, "slice.target", { kind: "slice", path });
387
+ case "iterate":
388
+ return extend(node.value.target, "iterate.target", { kind: "iterate" });
389
+ case "call":
390
+ if (node.value.name === "select" && node.value.args.length === 1)
391
+ return [[{ kind: "select", path: at("call.args[0]") }]];
392
+ if (node.value.name === "empty" && node.value.args.length === 0)
393
+ return [];
394
+ return undefined;
395
+ default:
396
+ return undefined;
397
+ }
398
+ }
399
+ /** Whether a step's remaining steps delete the element itself: none left, or only a `select`. */
400
+ function deletesElement(rest) {
401
+ return rest.length === 0 || (rest.length === 1 && rest[0].kind === "select");
402
+ }
403
+ /**
404
+ * The type a value has after `del` deletes at a path: a struct loses a field
405
+ * it deletes; an array or dict keeps its type when elements are deleted, and
406
+ * takes the new element type when every element changes alike.
407
+ *
408
+ * @returns the type, or `undefined` when the values left have no one type
409
+ * (one element of an array loses a field the others keep)
410
+ */
411
+ function afterDelete(ctx, type, steps) {
412
+ if (steps.length === 0)
413
+ return NullType;
414
+ const t = unwrap(type);
415
+ if (t.type === "Null")
416
+ return NullType;
417
+ const payload = nullablePayload(t);
418
+ if (payload !== undefined) {
419
+ const inner = afterDelete(ctx, payload, steps);
420
+ return inner === undefined ? undefined : orNull(inner);
421
+ }
422
+ const [step, ...rest] = steps;
423
+ // A change to some of a container's elements must leave their type as it was.
424
+ const same = (element) => {
425
+ if (deletesElement(rest))
426
+ return true;
427
+ const inner = afterDelete(ctx, element, rest);
428
+ return inner !== undefined && isTypeEqual(inner, element);
429
+ };
430
+ const literalName = step.kind === "index" && step.node.type === "literal" ? ctx.literalOf(step.node) : undefined;
431
+ const name = step.kind === "field" ? step.name : literalName?.type.type === "String" && t.type !== "Dict" ? literalName.value : undefined;
432
+ if (name !== undefined) {
433
+ if (t.type === "Struct") {
434
+ const fields = t.fields;
435
+ if (!(name in fields))
436
+ return t;
437
+ if (deletesElement(rest)) {
438
+ if (rest.length === 0)
439
+ return withoutFields(t, [name]);
440
+ return same(fields[name]) ? t : undefined;
441
+ }
442
+ const inner = afterDelete(ctx, fields[name], rest);
443
+ return inner === undefined ? undefined : StructType({ ...fields, [name]: inner });
444
+ }
445
+ if (t.type === "Dict")
446
+ return same(t.value) ? t : undefined;
447
+ return undefined;
448
+ }
449
+ switch (step.kind) {
450
+ case "index":
451
+ case "slice":
452
+ if (t.type === "Dict")
453
+ return same(t.value) ? t : undefined;
454
+ if (t.type === "Array")
455
+ return same(t.value) ? t : undefined;
456
+ if (t.type === "String" && step.kind === "slice" && rest.length === 0)
457
+ return t;
458
+ return undefined;
459
+ case "iterate": {
460
+ if (t.type === "Array" || t.type === "Dict") {
461
+ const element = t.value;
462
+ if (deletesElement(rest))
463
+ return t;
464
+ const inner = afterDelete(ctx, element, rest);
465
+ if (inner === undefined)
466
+ return undefined;
467
+ return t.type === "Array" ? ArrayType(inner) : DictType(t.key, inner);
468
+ }
469
+ if (t.type === "Struct") {
470
+ if (deletesElement(rest))
471
+ return rest.length === 0 ? StructType({}) : undefined;
472
+ const fields = {};
473
+ for (const [field, f] of Object.entries(t.fields)) {
474
+ const inner = afterDelete(ctx, f, rest);
475
+ if (inner === undefined)
476
+ return undefined;
477
+ fields[field] = inner;
478
+ }
479
+ return StructType(fields);
480
+ }
481
+ return undefined;
482
+ }
483
+ case "select":
484
+ // The value is deleted (it becomes null) where the condition holds, or
485
+ // what follows is; its type stays only when that leaves it as it was.
486
+ if (rest.length === 0)
487
+ return orNull(t);
488
+ return same(t) ? t : undefined;
489
+ default:
490
+ return undefined;
491
+ }
492
+ }
493
+ // ─── The catalog ─────────────────────────────────────────────────────────
494
+ const entries = [];
495
+ function supported(name, arities, east, typing) {
496
+ entries.push([name, { status: "supported", arities, east, typing }]);
497
+ }
498
+ function excluded(builtins) {
499
+ for (const [name, arities] of Object.entries(builtins))
500
+ entries.push([name, { status: "excluded", arities, east: "—" }]);
501
+ }
502
+ function unavailable(builtins, reason) {
503
+ for (const [name, arities] of Object.entries(builtins))
504
+ entries.push([name, { status: "unavailable", arities, east: "—", reason }]);
505
+ }
506
+ /** The same arities for each of some names. */
507
+ function each(names, arities) {
508
+ return Object.fromEntries(names.map(name => [name, arities]));
509
+ }
510
+ // Selection and streams.
511
+ supported("empty", [0], "no output", () => ({ shape: typed(NeverType), mult: ZERO }));
512
+ supported("error", [0, 1], "an East error whose message is the value's East text (§13.14)", ctx => {
513
+ if (ctx.args.length === 1) {
514
+ const message = ctx.arg(0);
515
+ if (message.shape.kind === "error")
516
+ return { shape: ERROR, mult: ONE };
517
+ }
518
+ return { shape: typed(NeverType), mult: ZERO };
519
+ });
520
+ supported("not", [0], "BooleanNot of jq's truthiness", () => one(BooleanType));
521
+ supported("select", [1], "a branch on jq's truthiness", ctx => {
522
+ const condition = ctx.arg(0);
523
+ if (condition.shape.kind === "error")
524
+ return { shape: ERROR, mult: ONE };
525
+ if (condition.mult.hi === 2)
526
+ duplicateOutputs(ctx);
527
+ const narrowed = condition.proves !== undefined ? ctx.narrow(ctx.input, condition.proves) : ctx.input;
528
+ return { shape: narrowed.shape, mult: { lo: 0, hi: condition.mult.hi }, access: [], stream: ctx.input.stream };
529
+ });
530
+ /**
531
+ * The `duplicate_outputs` lint: `select(f)` where `f` gives many values emits
532
+ * its input once for each true one. The fix tests the generator with `any`:
533
+ * `select(.x[] | cond)` and `select(.x[].y == v)` become
534
+ * `select(any(.x[]; cond))` and `select(any(.x[]; .y == v))`.
535
+ */
536
+ function duplicateOutputs(ctx) {
537
+ const argPath = ctx.argPaths[0];
538
+ const argRange = ctx.argRange(0);
539
+ const many = (path) => ctx.resultAt(path)?.mult.hi === 2;
540
+ let generator;
541
+ let rest;
542
+ const arg = ctx.args[0];
543
+ if (arg.type === "pipe" && many(`${argPath}.pipe.left`)) {
544
+ generator = ctx.rangeAt(`${argPath}.pipe.left`);
545
+ const right = ctx.rangeAt(`${argPath}.pipe.right`);
546
+ rest = right === undefined ? undefined : ctx.text.slice(right.from, right.to);
547
+ }
548
+ else {
549
+ // The first `[]` on the condition's leftmost path of reads and operators.
550
+ let node = arg;
551
+ let path = argPath;
552
+ for (;;) {
553
+ if (node.type === "iterate" && many(path)) {
554
+ generator = ctx.rangeAt(path);
555
+ break;
556
+ }
557
+ if (node.type === "binary") {
558
+ node = node.value.left;
559
+ path = `${path}.binary.left`;
560
+ continue;
561
+ }
562
+ if (node.type === "field" || node.type === "index" || node.type === "slice" || node.type === "iterate") {
563
+ path = `${path}.${node.type}.target`;
564
+ node = node.value.target;
565
+ continue;
566
+ }
567
+ break;
568
+ }
569
+ if (generator !== undefined && argRange !== undefined && generator.from === argRange.from) {
570
+ const after = ctx.text.slice(generator.to, argRange.to);
571
+ rest = `${after.startsWith(".") ? "" : "."}${after}`;
572
+ }
573
+ }
574
+ if (generator === undefined || rest === undefined || argRange === undefined) {
575
+ ctx.warn("duplicate_outputs", MESSAGES.duplicateOutputs(ctx.source(0)));
576
+ return;
577
+ }
578
+ const text = ctx.text.slice(generator.from, generator.to);
579
+ ctx.warn("duplicate_outputs", MESSAGES.duplicateOutputs(text), [
580
+ edit(`Use any(${text}; …)`, argRange.from, argRange.to, `any(${text}; ${rest.trim()})`),
581
+ ]);
582
+ }
583
+ supported("first", [0, 1], "ArrayTryGet(0); for first(f), the first output of f, then stop", ctx => {
584
+ if (ctx.args.length === 1) {
585
+ const f = ctx.arg(0);
586
+ return { shape: f.shape, mult: { lo: f.mult.lo, hi: f.mult.hi === 0 ? 0 : 1 } };
587
+ }
588
+ return onInput(ctx, "an array", t => {
589
+ if (t.type === "Null")
590
+ return one(NullType);
591
+ const e = elementOf(t);
592
+ const r = e === undefined ? undefined : orNull(e);
593
+ return r === undefined ? undefined : one(r);
594
+ });
595
+ });
596
+ supported("last", [0, 1], "ArrayTryGet(size − 1); for last(f), the last output of f", ctx => {
597
+ if (ctx.args.length === 1) {
598
+ const f = ctx.arg(0);
599
+ return { shape: f.shape, mult: { lo: f.mult.lo, hi: f.mult.hi === 0 ? 0 : 1 } };
600
+ }
601
+ return onInput(ctx, "an array", t => {
602
+ if (t.type === "Null")
603
+ return one(NullType);
604
+ const e = elementOf(t);
605
+ const r = e === undefined ? undefined : orNull(e);
606
+ return r === undefined ? undefined : one(r);
607
+ });
608
+ });
609
+ supported("nth", [1, 2], "ArrayTryGet(n); for nth(n; f), the nth output of f", ctx => {
610
+ const n = argOf(ctx, 0, "an Integer", t => t.type === "Integer");
611
+ if (n === undefined)
612
+ return { shape: ERROR, mult: ONE };
613
+ if (ctx.args.length === 2) {
614
+ const f = ctx.arg(1);
615
+ return { shape: f.shape, mult: { lo: 0, hi: f.mult.hi === 0 ? 0 : 1 } };
616
+ }
617
+ return onInput(ctx, "an array", t => {
618
+ const e = elementOf(t);
619
+ const r = e === undefined ? undefined : orNull(e);
620
+ return r === undefined ? undefined : one(r, n.result.mult);
621
+ });
622
+ });
623
+ supported("limit", [2], "the first n outputs of f, then stop", ctx => {
624
+ const n = argOf(ctx, 0, "an Integer", t => t.type === "Integer");
625
+ const f = ctx.arg(1);
626
+ if (n === undefined || f.shape.kind === "error")
627
+ return { shape: ERROR, mult: ONE };
628
+ return { shape: f.shape, mult: { lo: 0, hi: f.mult.hi } };
629
+ });
630
+ supported("skip", [2], "the outputs of f after the first n", ctx => {
631
+ const n = argOf(ctx, 0, "an Integer", t => t.type === "Integer");
632
+ const f = ctx.arg(1);
633
+ if (n === undefined || f.shape.kind === "error")
634
+ return { shape: ERROR, mult: ONE };
635
+ return { shape: f.shape, mult: { lo: 0, hi: f.mult.hi } };
636
+ });
637
+ supported("isempty", [1], "whether f gives no output, stopping at the first", ctx => {
638
+ const f = ctx.arg(0);
639
+ return f.shape.kind === "error" ? { shape: ERROR, mult: ONE } : one(BooleanType);
640
+ });
641
+ supported("range", [1, 2, 3], "ArrayRange, or a Float loop, streamed", ctx => {
642
+ const args = ctx.args.map((_, i) => argOf(ctx, i, "a number", isNumber));
643
+ if (args.some(a => a === undefined))
644
+ return { shape: ERROR, mult: ONE };
645
+ const float = args.some(a => unwrap(a.type).type === "Float");
646
+ const literals = ctx.args.map((_, i) => ctx.literal(i));
647
+ if (literals.every(l => l !== undefined && isNumber(l.type))) {
648
+ const nums = literals.map(l => Number(l.value));
649
+ const [from, upto, by] = nums.length === 1 ? [0, nums[0], 1] : nums.length === 2 ? [nums[0], nums[1], 1] : [nums[0], nums[1], nums[2]];
650
+ const count = by > 0 ? Math.max(0, Math.ceil((upto - from) / by)) : by < 0 ? Math.max(0, Math.ceil((from - upto) / -by)) : 0;
651
+ if (count === 0)
652
+ return ctx.fail("type_mismatch", MESSAGES.emptyRange(ctx.source()));
653
+ if (count > 1000)
654
+ ctx.warn("long_range", MESSAGES.longRange(ctx.source(), count.toLocaleString("en-US").replace(/,/g, " ")));
655
+ }
656
+ const mult = args.reduce((m, a) => piped(m, a.result.mult), ONE);
657
+ return { shape: typed(float ? FloatType : IntegerType), mult: piped(mult, MANY) };
658
+ });
659
+ supported("recurse", [0, 1, 2], "a depth-first walk with an explicit stack", ctx => {
660
+ if (ctx.args.length === 0) {
661
+ // `recurse` is `..`: jq defines both as `recurse(.[]?)`.
662
+ if (ctx.refuseRoot())
663
+ return { shape: ERROR, mult: ONE };
664
+ if (ctx.input.shape.kind === "error")
665
+ return { shape: ERROR, mult: ONE };
666
+ return { shape: union(descendTypes(typesOf(ctx.input)).map(t => ({ shape: typed(t), case: undefined }))), mult: MANY };
667
+ }
668
+ const start = ctx.collect(ctx.input);
669
+ if (start === undefined)
670
+ return { shape: ERROR, mult: ONE };
671
+ const type = settle(ctx, 0, start);
672
+ if (type === undefined)
673
+ return { shape: ERROR, mult: ONE };
674
+ if (ctx.args.length === 2) {
675
+ const cond = ctx.arg(1, one(type));
676
+ if (cond.shape.kind === "error")
677
+ return { shape: ERROR, mult: ONE };
678
+ }
679
+ return { shape: typed(type), mult: { lo: 1, hi: 2 } };
680
+ });
681
+ supported("until", [2], "a loop: update while cond is false", ctx => {
682
+ const start = ctx.collect(ctx.input);
683
+ if (start === undefined)
684
+ return { shape: ERROR, mult: ONE };
685
+ const type = settle(ctx, 1, start);
686
+ if (type === undefined)
687
+ return { shape: ERROR, mult: ONE };
688
+ const cond = ctx.arg(0, one(type));
689
+ if (cond.shape.kind === "error")
690
+ return { shape: ERROR, mult: ONE };
691
+ return one(type);
692
+ });
693
+ supported("while", [2], "a loop: each value while cond holds", ctx => {
694
+ const start = ctx.collect(ctx.input);
695
+ if (start === undefined)
696
+ return { shape: ERROR, mult: ONE };
697
+ const type = settle(ctx, 1, start);
698
+ if (type === undefined)
699
+ return { shape: ERROR, mult: ONE };
700
+ const cond = ctx.arg(0, one(type));
701
+ if (cond.shape.kind === "error")
702
+ return { shape: ERROR, mult: ONE };
703
+ return { shape: typed(type), mult: MANY };
704
+ });
705
+ supported("repeat", [1], "a loop: the value, then f of it, and so on", ctx => {
706
+ const start = ctx.collect(ctx.input);
707
+ if (start === undefined)
708
+ return { shape: ERROR, mult: ONE };
709
+ const type = settle(ctx, 0, start);
710
+ if (type === undefined)
711
+ return { shape: ERROR, mult: ONE };
712
+ return { shape: typed(type), mult: MANY };
713
+ });
714
+ supported("combinations", [0, 1], "nested loops over the arrays", ctx => {
715
+ if (ctx.args.length === 1) {
716
+ const n = argOf(ctx, 0, "an Integer", t => t.type === "Integer");
717
+ if (n === undefined)
718
+ return { shape: ERROR, mult: ONE };
719
+ return onInput(ctx, "an array", t => t.type === "Array" ? { shape: typed(t), mult: MANY } : undefined);
720
+ }
721
+ return onInput(ctx, "an array of arrays", t => {
722
+ if (t.type !== "Array")
723
+ return undefined;
724
+ const inner = unwrap(t.value);
725
+ return inner.type === "Array" ? { shape: typed(inner), mult: MANY } : undefined;
726
+ });
727
+ });
728
+ supported("walk", [1], "a bottom-up rebuild, applying f to each value", ctx => {
729
+ if (ctx.refuseRoot())
730
+ return { shape: ERROR, mult: ONE };
731
+ const start = ctx.collect(ctx.input);
732
+ if (start === undefined)
733
+ return { shape: ERROR, mult: ONE };
734
+ const memo = new Map();
735
+ // A value's parts, each walked: an option's value's, an array's elements, a
736
+ // dict's values, a struct's fields and a variant's payload (not its case's
737
+ // name, which is its type).
738
+ const rebuildParts = (t) => {
739
+ const u = unwrap(t);
740
+ const payload = nullablePayload(u);
741
+ if (payload !== undefined) {
742
+ const p = rebuildType(payload);
743
+ return p === undefined ? undefined : orNull(p) ?? OptionType(p);
744
+ }
745
+ if (u.type === "Array") {
746
+ const e = walkType(u.value);
747
+ return e === undefined ? undefined : ArrayType(e);
748
+ }
749
+ if (u.type === "Dict") {
750
+ const v = walkType(u.value);
751
+ return v === undefined ? undefined : DictType(u.key, v);
752
+ }
753
+ if (u.type === "Struct") {
754
+ const fields = {};
755
+ for (const [name, f] of Object.entries(u.fields)) {
756
+ const w = walkType(f);
757
+ if (w === undefined)
758
+ return undefined;
759
+ fields[name] = w;
760
+ }
761
+ return StructType(fields);
762
+ }
763
+ if (u.type === "Variant") {
764
+ const cases = {};
765
+ for (const [name, c] of Object.entries(u.cases)) {
766
+ const w = walkType(c);
767
+ if (w === undefined)
768
+ return undefined;
769
+ cases[name] = w;
770
+ }
771
+ return VariantType(cases);
772
+ }
773
+ return t;
774
+ };
775
+ // A recursive value rebuilt as its node keeps its recursive type.
776
+ const rebuildType = (t) => {
777
+ const rebuilt = rebuildParts(t);
778
+ return rebuilt !== undefined && t.type === "Recursive" && isTypeEqual(t.node, rebuilt) ? t : rebuilt;
779
+ };
780
+ const walkType = (t) => {
781
+ // A Never has no value to walk: an empty collection's elements.
782
+ if (t.type === "Never")
783
+ return t;
784
+ if (memo.has(t))
785
+ return memo.get(t);
786
+ memo.set(t, t);
787
+ const rebuilt = t.type === "Recursive" ? t : rebuildType(t);
788
+ if (rebuilt === undefined)
789
+ return undefined;
790
+ const out = ctx.arg(0, one(rebuilt));
791
+ if (out.shape.kind === "error")
792
+ return undefined;
793
+ if (out.mult.lo !== 1 || out.mult.hi !== 1) {
794
+ ctx.fail("unsupported", MESSAGES.unavailable("walk(f)", "f must give one output for each value"));
795
+ return undefined;
796
+ }
797
+ const result = ctx.collect(out);
798
+ if (result === undefined)
799
+ return undefined;
800
+ if (t.type === "Recursive" && !isTypeEqual(result, t)) {
801
+ ctx.fail("cannot_infer", MESSAGES.accumulator("walk", describeType(t), describeType(result)));
802
+ return undefined;
803
+ }
804
+ memo.set(t, result);
805
+ return result;
806
+ };
807
+ const type = walkType(start);
808
+ return type === undefined ? { shape: ERROR, mult: ONE } : one(type);
809
+ });
810
+ supported("IN", [1, 2], "Equal against each output, stopping at the first match", ctx => {
811
+ const parts = ctx.args.map((_, i) => ctx.arg(i));
812
+ if (parts.some(p => p.shape.kind === "error"))
813
+ return { shape: ERROR, mult: ONE };
814
+ return one(BooleanType);
815
+ });
816
+ supported("INDEX", [1, 2], "ArrayToDict keyed by the index filter (keys keep their type, §13.2)", ctx => {
817
+ const rows = ctx.args.length === 2 ? ctx.arg(0) : (() => {
818
+ const r = perMember(ctx, ctx.input, member => valuesOf(member) ?? inputMismatch(ctx, "an array", member.type));
819
+ return { ...r, mult: MANY };
820
+ })();
821
+ if (rows.shape.kind === "error")
822
+ return { shape: ERROR, mult: ONE };
823
+ const row = ctx.collect(rows);
824
+ if (row === undefined)
825
+ return { shape: ERROR, mult: ONE };
826
+ const key = argOf(ctx, ctx.args.length - 1, "an immutable value", t => isImmutableType(t), one(row));
827
+ if (key === undefined)
828
+ return { shape: ERROR, mult: ONE };
829
+ return one(DictType(key.type, row));
830
+ });
831
+ unavailable({ JOIN: [2, 3, 4] }, "its pairs [row, match] hold two types, which one East array cannot");
832
+ unavailable({ getpath: [1], setpath: [2], delpaths: [1] }, "a path array mixes strings and integers, which no one East type holds; write the path as field reads and indexes, .a.b[0]");
833
+ unavailable({ path: [1], paths: [0, 1], tostream: [0], fromstream: [1], truncate_stream: [1] }, "a path array mixes strings and integers, which no one East type holds");
834
+ supported("del", [1], "a rebuild without the positions the path names", ctx => {
835
+ const paths = delPaths(ctx.args[0], ctx.argPaths[0]);
836
+ if (paths === undefined)
837
+ return ctx.fail("unsupported", MESSAGES.unavailable(`del(${ctx.source(0)})`, "del takes field reads, indexes, slices, .[], select and ,"), { arg: 0 });
838
+ // The path reads what it deletes, so it is checked as a read first.
839
+ const read = ctx.arg(0);
840
+ if (read.shape.kind === "error")
841
+ return { shape: ERROR, mult: ONE };
842
+ return perMember(ctx, ctx.input, member => {
843
+ let type = member.type;
844
+ for (const steps of paths) {
845
+ const next = afterDelete(ctx, type, steps);
846
+ if (next === undefined)
847
+ return ctx.fail("ambiguous_output", MESSAGES.mixedDelete(`del(${ctx.source(0)})`), { arg: 0 });
848
+ type = next;
849
+ }
850
+ return one(type);
851
+ });
852
+ });
853
+ supported("to_entries", [0], "DictToArray / the struct's fields as {key, value}", ctx => {
854
+ if (ctx.refuseRoot())
855
+ return { shape: ERROR, mult: ONE };
856
+ return onInput(ctx, "a dict, a struct or an array", t => {
857
+ if (t.type === "Dict")
858
+ return one(ArrayType(StructType({ key: t.key, value: t.value })));
859
+ if (t.type === "Struct") {
860
+ let value = NeverType;
861
+ for (const f of Object.values(t.fields)) {
862
+ const next = unify(value, f);
863
+ if (next === undefined)
864
+ return ctx.fail("ambiguous_output", MESSAGES.noCommonType(describeType(value), describeType(f)));
865
+ value = next;
866
+ }
867
+ return one(ArrayType(StructType({ key: StringType, value })));
868
+ }
869
+ const e = elementOf(t);
870
+ return e === undefined ? undefined : one(ArrayType(StructType({ key: IntegerType, value: e })));
871
+ });
872
+ });
873
+ /** The key and value fields a from_entries entry can have, as jq accepts them. */
874
+ const KEY_FIELDS = ["key", "k", "name", "Name", "K", "Key"];
875
+ const VALUE_FIELDS = ["value", "v", "Value", "V"];
876
+ function fromEntries(ctx, entries) {
877
+ return perMember(ctx, entries, member => {
878
+ const t = unwrap(member.type);
879
+ if (t.type !== "Array")
880
+ return inputMismatch(ctx, "an array of {key, value}", member.type);
881
+ const entry = unwrap(t.value);
882
+ if (entry.type !== "Struct")
883
+ return inputMismatch(ctx, "an array of {key, value}", member.type);
884
+ const fields = entry.fields;
885
+ const key = KEY_FIELDS.find(k => k in fields);
886
+ const value = VALUE_FIELDS.find(v => v in fields);
887
+ if (key === undefined)
888
+ return inputMismatch(ctx, "an array of {key, value}", member.type);
889
+ const keyType = fields[key];
890
+ if (!isImmutableType(keyType))
891
+ return ctx.fail("type_mismatch", MESSAGES.mutableKey(`.${key}`, describeType(keyType)));
892
+ return one(DictType(keyType, value === undefined ? NullType : fields[value]));
893
+ });
894
+ }
895
+ supported("from_entries", [0], "ArrayToDict by the entries' key and value", ctx => fromEntries(ctx, ctx.input));
896
+ supported("with_entries", [1], "to_entries, map(f), from_entries", ctx => {
897
+ if (ctx.refuseRoot())
898
+ return { shape: ERROR, mult: ONE };
899
+ const entries = onInput(ctx, "a dict or a struct", t => {
900
+ if (t.type === "Dict")
901
+ return one(StructType({ key: t.key, value: t.value }));
902
+ if (t.type === "Struct") {
903
+ let value = NeverType;
904
+ for (const f of Object.values(t.fields)) {
905
+ const next = unify(value, f);
906
+ if (next === undefined)
907
+ return ctx.fail("ambiguous_output", MESSAGES.noCommonType(describeType(value), describeType(f)));
908
+ value = next;
909
+ }
910
+ return one(StructType({ key: StringType, value }));
911
+ }
912
+ return undefined;
913
+ });
914
+ if (entries.shape.kind === "error")
915
+ return entries;
916
+ const mapped = ctx.arg(0, { shape: entries.shape, mult: ONE });
917
+ const t = ctx.collect(mapped);
918
+ if (t === undefined)
919
+ return { shape: ERROR, mult: ONE };
920
+ return fromEntries(ctx, one(ArrayType(t)));
921
+ });
922
+ supported("pick", [1], "a struct of the picked fields", ctx => {
923
+ let node = ctx.args[0];
924
+ const fields = [];
925
+ while (node.type === "field") {
926
+ fields.unshift(node.value.name);
927
+ node = node.value.target;
928
+ }
929
+ if (node.type !== "identity" || fields.length === 0)
930
+ return ctx.fail("unsupported", MESSAGES.unavailable("pick of this path", "pick takes field reads: pick(.a.b)"), { arg: 0 });
931
+ return perMember(ctx, ctx.input, member => {
932
+ const build = (t, rest) => {
933
+ const u = unwrap(t);
934
+ // `null`'s fields are null, so picking from it builds the path, null at its end, as jq does.
935
+ if (u.type === "Null")
936
+ return StructType({ [rest[0]]: rest.length === 1 ? NullType : build(NullType, rest.slice(1)) });
937
+ if (u.type !== "Struct" || !(rest[0] in u.fields))
938
+ return undefined;
939
+ const inner = u.fields[rest[0]];
940
+ const picked = rest.length === 1 ? inner : build(inner, rest.slice(1));
941
+ return picked === undefined ? undefined : StructType({ [rest[0]]: picked });
942
+ };
943
+ const out = build(member.type, fields);
944
+ return out === undefined ? inputMismatch(ctx, `a struct with .${fields.join(".")}`, member.type) : one(out);
945
+ });
946
+ });
947
+ supported("transpose", [0], "nested loops, padding short rows with null", ctx => onInput(ctx, "an array of arrays", t => {
948
+ if (t.type !== "Array")
949
+ return undefined;
950
+ const row = unwrap(t.value);
951
+ if (row.type === "Never")
952
+ return one(ArrayType(ArrayType(NeverType)));
953
+ if (row.type !== "Array")
954
+ return undefined;
955
+ const cell = orNull(row.value);
956
+ return cell === undefined ? undefined : one(ArrayType(ArrayType(cell)));
957
+ }));
958
+ // Collections.
959
+ supported("length", [0], "StringLength, ArraySize, SetSize, DictSize, BlobSize, the field count, abs", ctx => onInput(ctx, "a value with a length", t => {
960
+ const payload = nullablePayload(t);
961
+ const u = payload === undefined ? t : unwrap(payload);
962
+ switch (u.type) {
963
+ case "Null":
964
+ case "String":
965
+ case "Array":
966
+ case "Set":
967
+ case "Dict":
968
+ case "Vector":
969
+ case "Matrix":
970
+ case "Struct":
971
+ case "Blob":
972
+ case "Integer":
973
+ return one(IntegerType);
974
+ case "Float": return one(FloatType);
975
+ case "Variant": return one(IntegerType);
976
+ default: return undefined;
977
+ }
978
+ }));
979
+ supported("utf8bytelength", [0], "BlobSize of StringEncodeUtf8", ctx => onInput(ctx, "a string", t => t.type === "String" ? one(IntegerType) : undefined));
980
+ supported("keys", [0], "DictKeys, the struct's field names sorted, the indices", keys);
981
+ supported("keys_unsorted", [0], "DictKeys, the struct's field names in declared order (§13.12), the indices", keys);
982
+ /** `keys` and `keys_unsorted`: a struct's names, a root's included, are its type's, which the translator gives. */
983
+ function keys(ctx) {
984
+ return onInput(ctx, "a dict, a struct or an array", t => {
985
+ if (t.type === "Dict")
986
+ return one(ArrayType(t.key));
987
+ if (t.type === "Struct")
988
+ return one(ArrayType(StringType));
989
+ if (t.type === "Variant" && nullablePayload(t) === undefined)
990
+ return one(ArrayType(StringType));
991
+ return elementOf(t) === undefined ? undefined : one(ArrayType(IntegerType));
992
+ });
993
+ }
994
+ supported("has", [1], "DictHas, the struct's field names, ArraySize", ctx => {
995
+ const key = ctx.arg(0);
996
+ if (key.shape.kind === "error")
997
+ return { shape: ERROR, mult: ONE };
998
+ const keyType = ctx.collect(key, 0);
999
+ if (keyType === undefined)
1000
+ return { shape: ERROR, mult: ONE };
1001
+ return onInput(ctx, "a dict, a struct or an array", t => {
1002
+ if (t.type === "Dict") {
1003
+ const dictKey = unwrap(t.key);
1004
+ if (isTypeEqual(unwrap(keyType), dictKey))
1005
+ return one(BooleanType, key.mult);
1006
+ // A literal written as the key type is: an ISO-8601 string for a DateTime, an Integer for a Float.
1007
+ const coerced = coerceArgument(ctx, 0, dictKey, "value");
1008
+ if (coerced === null)
1009
+ return { shape: ERROR, mult: ONE };
1010
+ if (coerced !== undefined)
1011
+ return one(BooleanType, key.mult);
1012
+ return ctx.fail("type_mismatch", MESSAGES.keyType("has", describeType(t.key), ctx.source(0), describeType(keyType)), { arg: 0 });
1013
+ }
1014
+ // A struct's names, a root's included, are its type's, which the translator answers from.
1015
+ if (t.type === "Struct") {
1016
+ if (unwrap(keyType).type !== "String")
1017
+ return ctx.fail("type_mismatch", MESSAGES.keyType("has", "String", ctx.source(0), describeType(keyType)), { arg: 0 });
1018
+ return one(BooleanType, key.mult);
1019
+ }
1020
+ if (elementOf(t) !== undefined) {
1021
+ return unwrap(keyType).type === "Integer" ? one(BooleanType, key.mult)
1022
+ : ctx.fail("type_mismatch", MESSAGES.keyType("has", "Integer", ctx.source(0), describeType(keyType)), { arg: 0 });
1023
+ }
1024
+ return undefined;
1025
+ });
1026
+ });
1027
+ supported("in", [1], "has, on the argument", ctx => {
1028
+ const container = ctx.arg(0);
1029
+ if (container.shape.kind === "error")
1030
+ return { shape: ERROR, mult: ONE };
1031
+ const keyType = ctx.collect(ctx.input);
1032
+ if (keyType === undefined)
1033
+ return { shape: ERROR, mult: ONE };
1034
+ const key = unwrap(keyType);
1035
+ // The input is a key of the argument: of a dict's key type, a struct's field name, an array's index.
1036
+ return perMember(ctx, container, member => {
1037
+ const t = unwrap(member.type);
1038
+ const wanted = t.type === "Dict" ? unwrap(t.key) : t.type === "Struct" ? StringType : elementOf(t) !== undefined ? IntegerType : undefined;
1039
+ if (wanted === undefined)
1040
+ return ctx.fail("type_mismatch", MESSAGES.argument("in", "first", "a dict, a struct or an array", describeType(member.type)), { arg: 0 });
1041
+ if (isTypeEqual(key, wanted) || (wanted.type === "Float" && key.type === "Integer"))
1042
+ return one(BooleanType, container.mult);
1043
+ return ctx.fail("type_mismatch", MESSAGES.keyType("in", describeType(wanted), "its input", describeType(keyType)));
1044
+ });
1045
+ });
1046
+ supported("map", [1], "ArrayMap / SetToArray / DictToArray of f (f's outputs collected)", ctx => {
1047
+ if (ctx.refuseRoot())
1048
+ return { shape: ERROR, mult: ONE };
1049
+ return eachElement(ctx, 0, "an array", (_element, per) => arrayOf(ctx, per));
1050
+ });
1051
+ supported("map_values", [1], "ArrayMap / DictMap / the struct rebuilt field by field, with f's first output", ctx => {
1052
+ if (ctx.refuseRoot())
1053
+ return { shape: ERROR, mult: ONE };
1054
+ return perMember(ctx, ctx.input, member => {
1055
+ const t = unwrap(member.type);
1056
+ if (t.type === "Array" || t.type === "Dict") {
1057
+ const per = ctx.arg(0, valuesOf(member));
1058
+ const v = ctx.collect(per);
1059
+ if (v === undefined)
1060
+ return { shape: ERROR, mult: ONE };
1061
+ return one(t.type === "Array" ? ArrayType(v) : DictType(t.key, v));
1062
+ }
1063
+ if (t.type === "Struct") {
1064
+ const fields = {};
1065
+ for (const [name, f] of Object.entries(t.fields)) {
1066
+ const per = ctx.arg(0, one(f));
1067
+ if (per.shape.kind === "error")
1068
+ return { shape: ERROR, mult: ONE };
1069
+ if (per.mult.lo !== 1)
1070
+ return ctx.fail("unsupported", MESSAGES.unavailable("map_values(f) on a struct", "f must give an output for every field, which a struct cannot lose"));
1071
+ const v = ctx.collect(per);
1072
+ if (v === undefined)
1073
+ return { shape: ERROR, mult: ONE };
1074
+ fields[name] = v;
1075
+ }
1076
+ return one(StructType(fields));
1077
+ }
1078
+ return inputMismatch(ctx, "an array, a dict or a struct", member.type);
1079
+ });
1080
+ });
1081
+ supported("add", [0, 1], "ArrayFold of the matching add builtin (adding nothing gives its identity, §13.15)", ctx => {
1082
+ if (ctx.refuseRoot())
1083
+ return { shape: ERROR, mult: ONE };
1084
+ const values = ctx.args.length === 1 ? ctx.arg(0) : perMember(ctx, ctx.input, member => valuesOf(member) ?? inputMismatch(ctx, "an array", member.type));
1085
+ if (values.shape.kind === "error")
1086
+ return { shape: ERROR, mult: ONE };
1087
+ const t = ctx.collect(values);
1088
+ if (t === undefined)
1089
+ return { shape: ERROR, mult: ONE };
1090
+ if (t.type === "Never")
1091
+ return one(NullType);
1092
+ const added = addType(t);
1093
+ if (added === undefined)
1094
+ return ctx.mismatch("type_mismatch", MESSAGES.input("add", "numbers, strings, arrays, structs or dicts", describeType(t)));
1095
+ return one(added);
1096
+ });
1097
+ for (const [name, arities] of [["any", [0, 1, 2]], ["all", [0, 1, 2]]]) {
1098
+ supported(name, arities, `a loop on jq's truthiness, stopping at the first ${name === "any" ? "true" : "false"}`, ctx => {
1099
+ if (ctx.args.length === 2) {
1100
+ const gen = ctx.arg(0);
1101
+ if (gen.shape.kind === "error")
1102
+ return { shape: ERROR, mult: ONE };
1103
+ const cond = ctx.arg(1, { shape: gen.shape, mult: ONE });
1104
+ return cond.shape.kind === "error" ? cond : one(BooleanType);
1105
+ }
1106
+ return eachElementOrSelf(ctx);
1107
+ });
1108
+ }
1109
+ function eachElementOrSelf(ctx) {
1110
+ return perMember(ctx, ctx.input, member => {
1111
+ const element = valuesOf(member);
1112
+ if (element === undefined)
1113
+ return inputMismatch(ctx, "an array", member.type);
1114
+ if (ctx.args.length === 1) {
1115
+ const cond = ctx.arg(0, element);
1116
+ if (cond.shape.kind === "error")
1117
+ return cond;
1118
+ }
1119
+ return one(BooleanType);
1120
+ });
1121
+ }
1122
+ supported("flatten", [0, 1], "ArrayFlattenToArray, depth times", ctx => {
1123
+ let depth = 1_000;
1124
+ if (ctx.args.length === 1) {
1125
+ const d = literalInteger(ctx, 0, "depth");
1126
+ if (d === undefined)
1127
+ return { shape: ERROR, mult: ONE };
1128
+ depth = Number(d);
1129
+ }
1130
+ return onInput(ctx, "an array", t => t.type === "Array" ? one(flattened(t, depth)) : undefined);
1131
+ });
1132
+ supported("sort", [0], "ArraySort by the value (East's total order, §11)", ctx => onInput(ctx, "an array of ordered values", t => {
1133
+ const e = elementOf(t);
1134
+ if (e === undefined || t.type === "Matrix")
1135
+ return undefined;
1136
+ return isOrdered(e) ? one(ArrayType(e)) : undefined;
1137
+ }));
1138
+ for (const [name, output] of [["sort_by", "array"], ["group_by", "groups"], ["unique_by", "array"], ["min_by", "element"], ["max_by", "element"]]) {
1139
+ supported(name, [1], output === "groups" ? "ArrayGroupFold by the key, in key order" : `${name === "sort_by" ? "ArraySort" : name === "unique_by" ? "ArrayToDict by the key" : "ArrayFold"} by the key f gives`, ctx => eachElement(ctx, 0, "an array", (element, per) => {
1140
+ const key = ctx.collect(per, 0);
1141
+ if (key === undefined)
1142
+ return undefined;
1143
+ if (!isOrdered(key))
1144
+ return ctx.fail("type_mismatch", MESSAGES.argument(ctx.name, "first", "an ordered key", describeType(key)), { arg: 0 });
1145
+ const e = element.shape.kind === "type" ? element.shape.type : NeverType;
1146
+ const facts = element.shape.kind === "type" && element.shape.facts !== undefined ? { kind: "elements", element: element.shape.facts } : undefined;
1147
+ if (output === "groups")
1148
+ return { shape: typed(ArrayType(ArrayType(e)), facts !== undefined ? { kind: "elements", element: facts } : undefined), mult: ONE };
1149
+ if (output === "element")
1150
+ return one(orNull(e) ?? e);
1151
+ return { shape: typed(ArrayType(e), facts), mult: ONE };
1152
+ }, true));
1153
+ }
1154
+ supported("unique", [0], "ArrayToSet, as an array", ctx => onInput(ctx, "an array of ordered values", t => {
1155
+ const e = elementOf(t);
1156
+ return e !== undefined && isOrdered(e) ? one(ArrayType(e)) : undefined;
1157
+ }));
1158
+ for (const name of ["min", "max"]) {
1159
+ supported(name, [0], `ArrayFold keeping the ${name === "min" ? "least" : "greatest"} (null for an empty array)`, ctx => onInput(ctx, "an array of ordered values", t => {
1160
+ const e = elementOf(t);
1161
+ if (e === undefined || !isOrdered(e))
1162
+ return undefined;
1163
+ const r = orNull(e);
1164
+ return r === undefined ? undefined : one(r);
1165
+ }));
1166
+ }
1167
+ supported("reverse", [0], "ArrayReverse; a string's code points reversed", ctx => onInput(ctx, "an array or a string", t => {
1168
+ if (t.type === "String")
1169
+ return one(StringType);
1170
+ if (t.type === "Null")
1171
+ return one(ArrayType(NeverType));
1172
+ const e = elementOf(t);
1173
+ return e === undefined ? undefined : one(ArrayType(e));
1174
+ }));
1175
+ supported("contains", [1], "StringContains for strings; loops of it for arrays, structs and dicts; Equal for other values", containment);
1176
+ supported("inside", [1], "contains, the other way round", containment);
1177
+ /**
1178
+ * `contains` and `inside`: whether one value holds another, as jq's
1179
+ * `contains` decides it. A string holds its substrings; an array holds an
1180
+ * array whose every element some element of it holds; a struct or a dict
1181
+ * holds one whose every field or key it has, holding its value; other
1182
+ * values hold only an equal one.
1183
+ */
1184
+ function containment(ctx) {
1185
+ const other = ctx.arg(0);
1186
+ if (other.shape.kind === "error")
1187
+ return { shape: ERROR, mult: ONE };
1188
+ const ot = ctx.collect(other, 0);
1189
+ if (ot === undefined)
1190
+ return { shape: ERROR, mult: ONE };
1191
+ return perMember(ctx, ctx.input, member => {
1192
+ const holds = (arg) => ctx.name === "contains" ? containable(member.type, arg) : containable(arg, member.type);
1193
+ if (holds(ot))
1194
+ return one(BooleanType, other.mult);
1195
+ // Literals written as the input's type is: ISO-8601 strings for DateTimes, alone or in an array.
1196
+ const element = elementOf(unwrap(member.type));
1197
+ const coerced = element !== undefined && unwrap(ot).type === "Array"
1198
+ ? coerceArgument(ctx, 0, element, "elements")
1199
+ : coerceArgument(ctx, 0, unwrap(member.type), "value");
1200
+ if (coerced === null)
1201
+ return { shape: ERROR, mult: ONE };
1202
+ if (coerced !== undefined && holds(coerced))
1203
+ return one(BooleanType, other.mult);
1204
+ // An input that can be null holds only null (§13.16): skip the nulls.
1205
+ if (nullablePayload(unwrap(member.type)) !== undefined)
1206
+ return inputMismatch(ctx, "a value", member.type);
1207
+ // jq raises for values whose containment it cannot check: in a lenient place, at run time.
1208
+ return ctx.mismatch("type_mismatch", MESSAGES.argument(ctx.name, "first", `a value ${ctx.name === "contains" ? "held in" : "holding"} ${describeType(member.type)}`, describeType(ot)), 0);
1209
+ });
1210
+ }
1211
+ /** Whether values of type `inner` can be held in values of type `outer`, as `contains` compares them. */
1212
+ function containable(outer, inner) {
1213
+ const a = unwrap(outer);
1214
+ const b = unwrap(inner);
1215
+ if (b.type === "Never")
1216
+ return true;
1217
+ if (a.type === "String" && b.type === "String")
1218
+ return true;
1219
+ // Arrays, sets, vectors and matrices are all arrays to jq.
1220
+ const ea = elementOf(a);
1221
+ const eb = elementOf(b);
1222
+ if (ea !== undefined && eb !== undefined)
1223
+ return containable(ea, eb);
1224
+ if (a.type === "Struct" && b.type === "Struct") {
1225
+ const fields = a.fields;
1226
+ // A field the outer struct lacks is never held: the answer is false, not an error.
1227
+ return Object.entries(b.fields).every(([name, f]) => !(name in fields) || containable(fields[name], f));
1228
+ }
1229
+ if (a.type === "Dict" && b.type === "Dict")
1230
+ return isTypeEqual(unwrap(a.key), unwrap(b.key)) && containable(a.value, b.value);
1231
+ if (a.type === "Dict" && b.type === "Struct" && Object.keys(b.fields).length === 0)
1232
+ return true;
1233
+ return isScalar(a) && isScalar(b) && unify(a, b) !== undefined;
1234
+ }
1235
+ for (const [name, output] of [["index", "first"], ["rindex", "last"], ["indices", "all"]]) {
1236
+ supported(name, [1], `StringIndexOf${output === "first" ? "" : " in a loop"} (strings); Equal in a loop (arrays)`, ctx => {
1237
+ const x = ctx.arg(0);
1238
+ if (x.shape.kind === "error")
1239
+ return { shape: ERROR, mult: ONE };
1240
+ const xt = ctx.collect(x, 0);
1241
+ if (xt === undefined)
1242
+ return { shape: ERROR, mult: ONE };
1243
+ const found = () => one(output === "all" ? ArrayType(IntegerType) : orNull(IntegerType), x.mult);
1244
+ return onInput(ctx, "a string or an array", t => {
1245
+ const u = unwrap(xt);
1246
+ if (t.type === "String")
1247
+ return u.type === "String" ? found() : ctx.fail("type_mismatch", MESSAGES.argument(ctx.name, "first", "a string", describeType(xt)), { arg: 0 });
1248
+ const element = elementOf(t);
1249
+ if (element === undefined)
1250
+ return undefined;
1251
+ // An element, or an array: a run of elements.
1252
+ const fits = (given) => {
1253
+ const g = unwrap(given);
1254
+ const wanted = g.type === "Array" ? g.value : given;
1255
+ return wanted.type === "Never" || unify(element, wanted) !== undefined;
1256
+ };
1257
+ if (fits(xt))
1258
+ return found();
1259
+ // Literals written as the elements' type is: an ISO-8601 string for a DateTime, alone or in an array.
1260
+ const coerced = coerceArgument(ctx, 0, element, u.type === "Array" ? "elements" : "value");
1261
+ if (coerced === null)
1262
+ return { shape: ERROR, mult: ONE };
1263
+ if (coerced !== undefined && fits(coerced))
1264
+ return found();
1265
+ // An array that is itself an element: jq reads an array as a run of elements.
1266
+ if (u.type === "Array" && unify(element, u) !== undefined) {
1267
+ return ctx.fail("type_mismatch", MESSAGES.runArgument(ctx.name, describeType(element), describeType(u.value), `${ctx.name}([${ctx.source(0)}])`), { arg: 0 });
1268
+ }
1269
+ return ctx.fail("type_mismatch", MESSAGES.argument(ctx.name, "first", `${describeType(element)}, or an array of it`, describeType(xt)), { arg: 0 });
1270
+ });
1271
+ });
1272
+ }
1273
+ supported("bsearch", [1], "ArrayFindSortedFirst, with jq's −1 − insertion point when absent", ctx => {
1274
+ const x = ctx.arg(0);
1275
+ if (x.shape.kind === "error")
1276
+ return { shape: ERROR, mult: ONE };
1277
+ return onInput(ctx, "a sorted array", t => {
1278
+ const e = elementOf(t);
1279
+ const xt = ctx.collect(x, 0);
1280
+ if (e === undefined || xt === undefined)
1281
+ return undefined;
1282
+ if (unify(e, xt) !== undefined)
1283
+ return one(IntegerType, x.mult);
1284
+ // A literal written as the elements' type is: an ISO-8601 string for a DateTime.
1285
+ const coerced = coerceArgument(ctx, 0, e, "value");
1286
+ if (coerced === null)
1287
+ return { shape: ERROR, mult: ONE };
1288
+ if (coerced !== undefined && unify(e, coerced) !== undefined)
1289
+ return one(IntegerType, x.mult);
1290
+ return ctx.fail("type_mismatch", MESSAGES.argument("bsearch", "first", describeType(e), describeType(xt)), { arg: 0 });
1291
+ });
1292
+ });
1293
+ supported("join", [1], "ArrayStringJoin of the elements as text (null as \"\")", ctx => {
1294
+ const sep = argOf(ctx, 0, "a string", t => t.type === "String");
1295
+ if (sep === undefined)
1296
+ return { shape: ERROR, mult: ONE };
1297
+ return onInput(ctx, "an array of strings, numbers, booleans or nulls", t => {
1298
+ const e = elementOf(t);
1299
+ if (e === undefined)
1300
+ return undefined;
1301
+ const u = unwrap(nullablePayload(unwrap(e)) ?? e);
1302
+ return ["String", "Integer", "Float", "Boolean", "Null"].includes(u.type) ? one(StringType, sep.result.mult) : undefined;
1303
+ });
1304
+ });
1305
+ // Types and conversion.
1306
+ supported("type", [0], "the jq type name of the value's East type, as a literal or by the option's case (§2)", () => ({ shape: typed(StringType), mult: ONE, typeOf: [] }));
1307
+ supported("arrays", [0], "a type test", selector(t => elementOf(t) !== undefined ? "keep" : "drop"));
1308
+ supported("objects", [0], "a type test", selector(t => t.type === "Struct" || t.type === "Dict" || t.type === "Variant" ? "keep" : "drop"));
1309
+ supported("iterables", [0], "a type test", selector(t => elementOf(t) !== undefined || t.type === "Struct" || t.type === "Dict" ? "keep" : "drop"));
1310
+ supported("booleans", [0], "a type test", selector(t => t.type === "Boolean" ? "keep" : "drop"));
1311
+ supported("numbers", [0], "a type test", selector(t => isNumber(t) ? "keep" : "drop"));
1312
+ supported("strings", [0], "a type test", selector(t => t.type === "String" ? "keep" : "drop"));
1313
+ supported("nulls", [0], "a type test", selector(t => t.type === "Null" ? "keep" : "drop"));
1314
+ supported("values", [0], "a type test", selector(t => t.type === "Null" ? "drop" : "keep"));
1315
+ supported("scalars", [0], "a type test", selector(t => isScalar(t) ? "keep" : "drop"));
1316
+ supported("normals", [0], "a type test and FloatAbs ≥ 2⁻¹⁰²²", selector(t => isNumber(t) ? "maybe" : "drop"));
1317
+ supported("finites", [0], "a type test and a comparison with ±Infinity", selector(t => t.type === "Integer" ? "keep" : t.type === "Float" ? "maybe" : "drop"));
1318
+ supported("tostring", [0], "the string, or Print (East text, §13.9)", ctx => {
1319
+ if (ctx.refuseRoot())
1320
+ return { shape: ERROR, mult: ONE };
1321
+ return onInput(ctx, "a data value", t => t.type === "Function" || t.type === "AsyncFunction" ? undefined : one(StringType));
1322
+ });
1323
+ supported("tojson", [0], "StringPrintJSON (East's JSON codec, §13.9)", ctx => {
1324
+ if (ctx.refuseRoot())
1325
+ return { shape: ERROR, mult: ONE };
1326
+ return onInput(ctx, "a data value", t => t.type === "Function" || t.type === "AsyncFunction" ? undefined : one(StringType));
1327
+ });
1328
+ supported("tonumber", [0], "Parse as a Float; numbers as they are", ctx => onInput(ctx, "a string or a number", t => {
1329
+ if (isNumber(t))
1330
+ return one(t);
1331
+ return t.type === "String" ? one(FloatType) : undefined;
1332
+ }));
1333
+ supported("toboolean", [0], "Parse as a Boolean; booleans as they are", ctx => onInput(ctx, "a string or a boolean", t => t.type === "String" || t.type === "Boolean" ? one(BooleanType) : undefined));
1334
+ supported("builtins", [0], "the catalog's names, as a literal", () => one(ArrayType(StringType)));
1335
+ supported("infinite", [0], "the Float Infinity", () => one(FloatType));
1336
+ supported("nan", [0], "the Float NaN", () => one(FloatType));
1337
+ for (const name of ["isfinite", "isinfinite", "isnan", "isnormal"]) {
1338
+ supported(name, [0], "FloatAbs and comparisons", ctx => onInput(ctx, "a number", t => isNumber(t) ? one(BooleanType) : undefined));
1339
+ }
1340
+ // jq's `if . < 0 then -. else . end`: null and booleans, below every number, raise as they are negated.
1341
+ supported("abs", [0], "IntegerAbs / FloatAbs; other values as they are", ctx => onInput(ctx, "a number, or a value above every number", t => {
1342
+ if (t.type === "Null" || t.type === "Boolean" || nullablePayload(t) !== undefined)
1343
+ return undefined;
1344
+ return one(t);
1345
+ }));
1346
+ unavailable({ fromjson: [0] }, "its result has no static type; parse into a known type in the program that runs the query");
1347
+ unavailable(each(["implode", "explode"], [0]), "East has no builtin between a string and its code points");
1348
+ unavailable(each(["have_decnum", "have_literal_numbers"], [0]), "it describes jq's build, not the data");
1349
+ unavailable({ splits: [1, 2] }, "East regular expressions have no regex split");
1350
+ unavailable(each(["match", "capture", "scan"], [1, 2]), "East regular expressions have no capture groups (§13.8)");
1351
+ unavailable(each(["@base64d", "@urid"], [0]), "no East builtin makes a Blob from bytes");
1352
+ // Strings.
1353
+ for (const name of ["startswith", "endswith"]) {
1354
+ supported(name, [1], name === "startswith" ? "StringStartsWith" : "StringEndsWith", ctx => {
1355
+ const s = argOf(ctx, 0, "a string", t => t.type === "String");
1356
+ if (s === undefined)
1357
+ return { shape: ERROR, mult: ONE };
1358
+ return onInput(ctx, "a string", t => t.type === "String" ? one(BooleanType, s.result.mult) : undefined);
1359
+ });
1360
+ }
1361
+ for (const name of ["ltrimstr", "rtrimstr", "trimstr"]) {
1362
+ // jq 1.8 raises for an input or an affix that is not a string (jq #2969).
1363
+ supported(name, [1], "StringStartsWith / StringEndsWith and StringSubstring", ctx => {
1364
+ const s = argOf(ctx, 0, "a string", t => t.type === "String");
1365
+ if (s === undefined)
1366
+ return { shape: ERROR, mult: ONE };
1367
+ return onInput(ctx, "a string", t => t.type === "String" ? one(StringType, s.result.mult) : undefined);
1368
+ });
1369
+ }
1370
+ for (const [name, east] of [["trim", "StringTrim"], ["ltrim", "StringTrimStart"], ["rtrim", "StringTrimEnd"], ["ascii_downcase", "StringLowerCase"], ["ascii_upcase", "StringUpperCase"]]) {
1371
+ supported(name, [0], east, ctx => onInput(ctx, "a string", t => t.type === "String" ? one(StringType) : undefined));
1372
+ }
1373
+ supported("split", [1, 2], "StringSplit (a literal separator)", ctx => {
1374
+ if (ctx.args.length === 2)
1375
+ return ctx.fail("unsupported", MESSAGES.unavailable("split(re; flags)", "East regular expressions have no regex split"));
1376
+ const sep = argOf(ctx, 0, "a string", t => t.type === "String");
1377
+ if (sep === undefined)
1378
+ return { shape: ERROR, mult: ONE };
1379
+ return onInput(ctx, "a string", t => t.type === "String" ? one(ArrayType(StringType), sep.result.mult) : undefined);
1380
+ });
1381
+ supported("test", [1, 2], "RegexContains", ctx => {
1382
+ const flags = checkFlags(ctx, ctx.args.length === 2 ? 1 : undefined);
1383
+ if (flags === undefined || checkRegex(ctx, 0, flags) === undefined)
1384
+ return { shape: ERROR, mult: ONE };
1385
+ return onInput(ctx, "a string", t => t.type === "String" ? one(BooleanType) : undefined);
1386
+ });
1387
+ for (const name of ["sub", "gsub"]) {
1388
+ supported(name, [2, 3], name === "gsub" ? "RegexReplace, captures as $<name>" : "RegexReplace of ^([\\s\\S]*?)(?:re), captures as $<name>", ctx => {
1389
+ const flags = checkFlags(ctx, ctx.args.length === 3 ? 2 : undefined);
1390
+ if (flags === undefined)
1391
+ return { shape: ERROR, mult: ONE };
1392
+ const groups = checkRegex(ctx, 0, flags);
1393
+ if (groups === undefined)
1394
+ return { shape: ERROR, mult: ONE };
1395
+ const replacement = ctx.args[1];
1396
+ const capture = (n) => (n.type === "field" && n.value.target.type === "identity" && groups.includes(n.value.name)) || n.type === "variable";
1397
+ const ok = (replacement.type === "literal" && ctx.literal(1)?.type.type === "String") || capture(replacement)
1398
+ || (replacement.type === "string" && replacement.value.every(part => part.type === "text" || capture(part.value)));
1399
+ if (!ok)
1400
+ return ctx.fail("type_mismatch", MESSAGES.replacement(name), { arg: 1 });
1401
+ // The replacement reads the named groups: check it on them, as strings.
1402
+ const r = ctx.arg(1, one(StructType(Object.fromEntries(groups.map(g => [g, StringType])))));
1403
+ if (r.shape.kind === "error")
1404
+ return r;
1405
+ return onInput(ctx, "a string", t => t.type === "String" ? one(StringType) : undefined);
1406
+ });
1407
+ }
1408
+ supported("format", [1], "the format of that name", ctx => {
1409
+ const name = literalString(ctx, 0, "format name");
1410
+ if (name === undefined)
1411
+ return { shape: ERROR, mult: ONE };
1412
+ const format = BUILTINS.get(`@${name}`);
1413
+ if (format === undefined || format.status !== "supported")
1414
+ return ctx.fail("unsupported", MESSAGES.unavailable(`format("${name}")`, "it is not a format a query can use"), { arg: 0 });
1415
+ return format.typing(ctx);
1416
+ });
1417
+ // Formats.
1418
+ supported("@text", [0], "tostring", ctx => onInput(ctx, "a data value", () => one(StringType)));
1419
+ supported("@json", [0], "StringPrintJSON", ctx => onInput(ctx, "a data value", () => one(StringType)));
1420
+ supported("@html", [0], "tostring, then StringReplace of < > & ' \"", ctx => onInput(ctx, "a data value", () => one(StringType)));
1421
+ supported("@uri", [0], "tostring, then each code point kept or percent-encoded from StringEncodeUtf8", ctx => onInput(ctx, "a data value", () => one(StringType)));
1422
+ supported("@base64", [0], "a Blob's bytes, or tostring's StringEncodeUtf8, then RFC 4648 over BlobGetUint8", ctx => onInput(ctx, "a data value", () => one(StringType)));
1423
+ for (const name of ["@csv", "@tsv"]) {
1424
+ supported(name, [0], "ArrayStringJoin of the quoted cells", ctx => onInput(ctx, "an array of scalars", t => {
1425
+ const e = elementOf(t);
1426
+ return e !== undefined && isScalar(e) ? one(StringType) : undefined;
1427
+ }));
1428
+ }
1429
+ supported("@sh", [0], "StringReplace of ' and ArrayStringJoin", ctx => onInput(ctx, "a string or an array of scalars", t => {
1430
+ if (isScalar(t))
1431
+ return one(StringType);
1432
+ const e = elementOf(t);
1433
+ return e !== undefined && isScalar(e) ? one(StringType) : undefined;
1434
+ }));
1435
+ // Math.
1436
+ for (const [name, east] of [["floor", "East.Float.roundFloor"], ["ceil", "East.Float.roundCeil"], ["round", "East.Float.roundHalf"], ["trunc", "East.Float.roundTrunc"]]) {
1437
+ supported(name, [0], east, math("Integer"));
1438
+ }
1439
+ for (const [name, east] of [
1440
+ ["sqrt", "FloatSqrt"], ["log", "FloatLog"], ["log2", "FloatLog / FloatLog(2)"], ["log10", "FloatLog / FloatLog(10)"],
1441
+ ["exp", "FloatExp"], ["exp2", "FloatPow(2, x)"], ["exp10", "FloatPow(10, x)"], ["sin", "FloatSin"], ["cos", "FloatCos"],
1442
+ ["tan", "FloatTan"], ["fabs", "FloatAbs"],
1443
+ ]) {
1444
+ supported(name, [0], east, math("Float"));
1445
+ }
1446
+ supported("pow", [2], "FloatPow", math2);
1447
+ supported("fmin", [2], "a comparison, as C's fmin", math2);
1448
+ supported("fmax", [2], "a comparison, as C's fmax", math2);
1449
+ supported("fmod", [2], "FloatRemainder", math2);
1450
+ unavailable({
1451
+ ...each([
1452
+ "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "cosh", "erf", "erfc", "expm1", "frexp", "gamma", "j0", "j1",
1453
+ "lgamma", "lgamma_r", "log1p", "logb", "modf", "nearbyint", "rint", "significand", "sinh", "tanh", "tgamma", "y0", "y1",
1454
+ ], [0]),
1455
+ ...each(["atan2", "copysign", "drem", "fdim", "hypot", "jn", "ldexp", "nextafter", "nexttoward", "remainder", "scalb", "scalbln", "yn"], [2]),
1456
+ fma: [3],
1457
+ }, "East has no builtin for it");
1458
+ // DateTime.
1459
+ for (const name of ["todate", "todateiso8601"]) {
1460
+ supported(name, [0], "DateTimePrintFormat as RFC 3339 (East JSON's form); epoch seconds via DateTimeFromEpochMilliseconds", ctx => dateInput(ctx, StringType));
1461
+ }
1462
+ for (const name of ["fromdate", "fromdateiso8601"]) {
1463
+ supported(name, [0], "StringParseJSON as a DateTime: RFC 3339 with milliseconds and offsets (§13.4)", ctx => onInput(ctx, "a string", t => t.type === "String" ? one(DateTimeType) : undefined));
1464
+ }
1465
+ supported("strftime", [1], "DateTimePrintFormat with the format's tokens, made when the query is translated", ctx => {
1466
+ if (!checkFormat(ctx))
1467
+ return { shape: ERROR, mult: ONE };
1468
+ return dateInput(ctx, StringType);
1469
+ });
1470
+ supported("strptime", [1], "DateTimeParseFormat with the format's tokens (gives a DateTime, §13.4)", ctx => {
1471
+ if (!checkFormat(ctx))
1472
+ return { shape: ERROR, mult: ONE };
1473
+ return onInput(ctx, "a string", t => t.type === "String" ? one(DateTimeType) : undefined);
1474
+ });
1475
+ for (const [name, east] of [
1476
+ ["year", "DateTimeGetYear"], ["month", "DateTimeGetMonth"], ["day", "DateTimeGetDayOfMonth"], ["hour", "DateTimeGetHour"],
1477
+ ["minute", "DateTimeGetMinute"], ["second", "DateTimeGetSecond"], ["millisecond", "DateTimeGetMillisecond"],
1478
+ ["weekday", "DateTimeGetDayOfWeek"], ["epoch_ms", "DateTimeToEpochMilliseconds"],
1479
+ ]) {
1480
+ supported(name, [0], east, ctx => onInput(ctx, "a DateTime", t => t.type === "DateTime" ? one(IntegerType) : undefined));
1481
+ }
1482
+ const UNITS = ["millisecond", "second", "minute", "hour", "day", "week"];
1483
+ function unit(ctx, i) {
1484
+ const u = literalString(ctx, i, "unit");
1485
+ if (u === undefined)
1486
+ return false;
1487
+ if (!UNITS.includes(u)) {
1488
+ ctx.fail("type_mismatch", MESSAGES.argument(ctx.name, ordinal(i), `one of ${UNITS.join(", ")}`, jsonString(u)), { arg: i });
1489
+ return false;
1490
+ }
1491
+ return true;
1492
+ }
1493
+ supported("datetime_add", [2], "DateTimeAddMilliseconds of n units", ctx => {
1494
+ const n = argOf(ctx, 0, "an Integer", t => t.type === "Integer");
1495
+ if (n === undefined || !unit(ctx, 1))
1496
+ return { shape: ERROR, mult: ONE };
1497
+ return onInput(ctx, "a DateTime", t => t.type === "DateTime" ? one(DateTimeType, n.result.mult) : undefined);
1498
+ });
1499
+ supported("datetime_diff", [2], "DateTimeDurationMilliseconds in units, truncated", ctx => {
1500
+ const other = argOf(ctx, 0, "a DateTime", t => t.type === "DateTime", undefined, DateTimeType);
1501
+ if (other === undefined || !unit(ctx, 1))
1502
+ return { shape: ERROR, mult: ONE };
1503
+ return onInput(ctx, "a DateTime", t => t.type === "DateTime" ? one(IntegerType, other.result.mult) : undefined);
1504
+ });
1505
+ entries.push(["gmtime", { status: "not_yet", arities: [0], east: "—" }]);
1506
+ entries.push(["mktime", { status: "not_yet", arities: [0], east: "—" }]);
1507
+ excluded({ now: [0], localtime: [0], strflocaltime: [1] });
1508
+ // Host access and modules (§11).
1509
+ excluded({
1510
+ ...each(["env", "input", "inputs", "input_filename", "input_line_number", "stderr", "halt", "get_search_list", "get_prog_origin",
1511
+ "get_jq_origin", "modulemeta"], [0]),
1512
+ debug: [0, 1],
1513
+ halt_error: [0, 1],
1514
+ });
1515
+ // Function values (§9).
1516
+ supported("call", [1, 2, 3, 4, 5, 6, 7, 8], "a call of the function value", ctx => {
1517
+ const f = ctx.arg(0);
1518
+ if (f.shape.kind === "error")
1519
+ return { shape: ERROR, mult: ONE };
1520
+ const ft = ctx.collect(f, 0);
1521
+ if (ft === undefined)
1522
+ return { shape: ERROR, mult: ONE };
1523
+ const fn = unwrap(ft);
1524
+ if (fn.type === "AsyncFunction")
1525
+ return ctx.fail("unsupported", MESSAGES.asyncCall(), { arg: 0 });
1526
+ if (fn.type !== "Function")
1527
+ return ctx.fail("type_mismatch", MESSAGES.input("call", "a function value", describeType(ft)), { arg: 0 });
1528
+ const inputs = fn.inputs;
1529
+ if (inputs.length !== ctx.args.length - 1)
1530
+ return ctx.fail("arity", MESSAGES.arity("the function value", [inputs.length], ctx.args.length - 1));
1531
+ let mult = f.mult;
1532
+ for (let i = 1; i < ctx.args.length; i++) {
1533
+ const want = inputs[i - 1];
1534
+ const a = ctx.arg(i);
1535
+ if (a.shape.kind === "error")
1536
+ return { shape: ERROR, mult: ONE };
1537
+ const got = ctx.collect(a, i);
1538
+ if (got === undefined)
1539
+ return { shape: ERROR, mult: ONE };
1540
+ const fits = isTypeEqual(unwrap(got), unwrap(want)) || (unwrap(want).type === "Float" && unwrap(got).type === "Integer") || callStructFits(got, want);
1541
+ if (!fits)
1542
+ return ctx.fail("type_mismatch", MESSAGES.argument("call", ordinal(i), describeType(want), describeType(got)), { arg: i });
1543
+ mult = piped(mult, a.mult);
1544
+ }
1545
+ return one(fn.output, mult);
1546
+ });
1547
+ /** A struct argument fits a struct input field by field, with Integer → Float. */
1548
+ function callStructFits(got, want) {
1549
+ const g = unwrap(got);
1550
+ const w = unwrap(want);
1551
+ if (g.type !== "Struct" || w.type !== "Struct")
1552
+ return false;
1553
+ const gf = g.fields;
1554
+ const wf = w.fields;
1555
+ const names = Object.keys(wf);
1556
+ if (names.length !== Object.keys(gf).length || !names.every(n => n in gf))
1557
+ return false;
1558
+ return names.every(n => isTypeEqual(unwrap(gf[n]), unwrap(wf[n])) || (unwrap(wf[n]).type === "Float" && unwrap(gf[n]).type === "Integer") || callStructFits(gf[n], wf[n]));
1559
+ }
1560
+ for (const [name, output] of [["signature", StringType], ["source", StringType], ["calls", ArrayType(StringType)], ["captures", ArrayType(StringType)]]) {
1561
+ entries.push([name, {
1562
+ status: "tooling", arities: [0], east: `the host platform function jq_${name}`,
1563
+ typing: ctx => onInput(ctx, "a function value", t => t.type === "Function" || t.type === "AsyncFunction" ? one(output) : undefined),
1564
+ }]);
1565
+ }
1566
+ /**
1567
+ * What each builtin a query may call takes and gives, and how many outputs it
1568
+ * gives for one input: `QUERY.md` §10's columns.
1569
+ */
1570
+ const RULES = {
1571
+ empty: ["any → nothing", "none"],
1572
+ error: ["any; `error(v)` of any type (§13.14) → a runtime error", "none"],
1573
+ not: ["any → Boolean, by jq's truthiness", "one"],
1574
+ select: ["`select(f)` → its input, narrowed by what `f` proves", "maybe; many when `f` is"],
1575
+ first: ["Array<T> → Option<T>; `first(f)` → f's first output", "one; maybe"],
1576
+ last: ["Array<T> → Option<T>; `last(f)` → f's last output", "one; maybe"],
1577
+ nth: ["`nth(n)`: Array<T> → Option<T>; `nth(n; f)` → f's nth output", "one; maybe"],
1578
+ limit: ["`limit(n; f)` → f's first n outputs", "as `f`'s"],
1579
+ skip: ["`skip(n; f)` → f's outputs after the first n", "as `f`'s"],
1580
+ isempty: ["`isempty(f)` → Boolean", "one"],
1581
+ range: ["Integer bounds → Integer; a Float bound → Float", "many"],
1582
+ recurse: ["every value nested in the input; `recurse(f[; c])` → the input, then f again, of the one type a fixpoint settles on", "many"],
1583
+ until: ["`until(c; u)` → u applied until c holds, of one type by fixpoint", "one"],
1584
+ while: ["`while(c; u)` → each value while c holds, of one type by fixpoint", "many"],
1585
+ repeat: ["`repeat(f)` → the input, f of it, and so on", "many"],
1586
+ combinations: ["Array<Array<T>> → Array<T>; `combinations(n)`: Array<T> → Array<T>", "many"],
1587
+ walk: ["any → rebuilt bottom-up with `f`, which gives one output of a type each value's place can hold", "one"],
1588
+ IN: ["`IN(s)`, `IN(src; s)` → Boolean", "one"],
1589
+ INDEX: ["`INDEX(f)`: Array<T> → Dict<K, T> for f's key K; `INDEX(src; f)`", "one"],
1590
+ del: ["`del(p)` → the input without what `p` names; a struct loses the field", "one"],
1591
+ to_entries: ["Dict<K, V> → Array<Struct{key: K, value: V}>; a struct's fields, keyed by name; an array's elements, by index", "one"],
1592
+ from_entries: ["Array of `{key, value}` (or `k`, `name`, `v`, …) → Dict<K, V>", "one"],
1593
+ with_entries: ["`to_entries | map(f) | from_entries`", "one"],
1594
+ pick: ["`pick(.a.b)` → Struct{a: Struct{b: T}}", "one"],
1595
+ transpose: ["Array<Array<T>> → Array<Array<Option<T>>>", "one"],
1596
+ length: ["String, Array, Set, Dict, Blob → Integer; a struct's field count; a number's absolute value; null → 0", "one"],
1597
+ utf8bytelength: ["String → Integer", "one"],
1598
+ keys: ["Dict<K, V> → Array<K>; a struct's field names, sorted; an array's indices", "one"],
1599
+ keys_unsorted: ["as `keys`, with a struct's fields in declared order (§13.12)", "one"],
1600
+ has: ["`has(k)` → Boolean: a Dict's key of its key type, a struct's field name, an array's index", "one"],
1601
+ in: ["`in(o)` → `o | has(.)`", "one"],
1602
+ map: ["`map(f)`: Array<T>, Set<T>, or a Dict's or struct's values → Array of f's outputs", "one"],
1603
+ map_values: ["`map_values(f)`: Array, Dict or struct → the same with f's first output in each place", "one"],
1604
+ add: ["Array<T> → T for numbers, strings, arrays and dicts (their identity when empty, §13.15), Option<T> for structs; `add(f)` over f's outputs", "one"],
1605
+ any: ["`any`, `any(f)`, `any(g; c)` → Boolean", "one"],
1606
+ all: ["`all`, `all(f)`, `all(g; c)` → Boolean", "one"],
1607
+ flatten: ["Array<Array<…T>> → Array<T>; `flatten(d)` d levels deep", "one"],
1608
+ sort: ["Array<T> → Array<T>", "one"],
1609
+ sort_by: ["`sort_by(f)`: Array<T>, f giving an ordered key → Array<T>", "one"],
1610
+ group_by: ["`group_by(f)`: Array<T> → Array<Array<T>>, in key order", "one"],
1611
+ unique_by: ["`unique_by(f)`: Array<T> → Array<T>", "one"],
1612
+ min_by: ["`min_by(f)`: Array<T> → Option<T>", "one"],
1613
+ max_by: ["`max_by(f)`: Array<T> → Option<T>", "one"],
1614
+ unique: ["Array<T> → Array<T>, sorted", "one"],
1615
+ min: ["Array<T> → Option<T>", "one"],
1616
+ max: ["Array<T> → Option<T>", "one"],
1617
+ reverse: ["Array<T> → Array<T>; String → String; null → []", "one"],
1618
+ contains: ["two strings, arrays, structs or dicts, or equal values → Boolean", "one"],
1619
+ inside: ["two strings, arrays, structs or dicts, or equal values → Boolean", "one"],
1620
+ index: ["String, String → Option<Integer>; Array<T> and a T or an Array<T> → Option<Integer>", "one"],
1621
+ rindex: ["String, String → Option<Integer>; Array<T> and a T or an Array<T> → Option<Integer>", "one"],
1622
+ indices: ["String, String → Array<Integer>; Array<T> and a T or an Array<T> → Array<Integer>", "one"],
1623
+ bsearch: ["Array<T>, T → Integer", "one"],
1624
+ join: ["Array of strings, numbers, booleans or nulls; String → String", "one"],
1625
+ type: ["any → String: `null`, `boolean`, `number`, `string`, `array`, `object`, `datetime`, `blob` or `function`; `type == \"…\"` narrows", "one"],
1626
+ arrays: ["the input when it is an array; narrows", "maybe"],
1627
+ objects: ["the input when it is a struct, dict or variant; narrows", "maybe"],
1628
+ iterables: ["the input when it is an array, struct or dict; narrows", "maybe"],
1629
+ booleans: ["the input when it is a Boolean; narrows", "maybe"],
1630
+ numbers: ["the input when it is a number; narrows", "maybe"],
1631
+ strings: ["the input when it is a String; narrows", "maybe"],
1632
+ nulls: ["the input when it is null; narrows", "maybe"],
1633
+ values: ["the input when it is not null: Option<T> → T", "maybe"],
1634
+ scalars: ["the input when it is not an array, struct or dict; narrows", "maybe"],
1635
+ normals: ["a number, when normal", "maybe"],
1636
+ finites: ["a number, when finite", "maybe"],
1637
+ tostring: ["any → String: a string as it is, anything else as East text (§13.9)", "one"],
1638
+ tojson: ["any → String, East's JSON (§13.9)", "one"],
1639
+ tonumber: ["String → Float (§13.19); a number as it is", "one"],
1640
+ toboolean: ["String or Boolean → Boolean", "one"],
1641
+ builtins: ["→ Array<String>", "one"],
1642
+ infinite: ["→ Float", "one"],
1643
+ nan: ["→ Float", "one"],
1644
+ isfinite: ["a number → Boolean", "one"],
1645
+ isinfinite: ["a number → Boolean", "one"],
1646
+ isnan: ["a number → Boolean", "one"],
1647
+ isnormal: ["a number → Boolean", "one"],
1648
+ abs: ["Integer → Integer; Float → Float; strings, arrays, objects as they are", "one"],
1649
+ startswith: ["String, String → Boolean", "one"],
1650
+ endswith: ["String, String → Boolean", "one"],
1651
+ ltrimstr: ["String, String → String", "one"],
1652
+ rtrimstr: ["String, String → String", "one"],
1653
+ trimstr: ["String, String → String", "one"],
1654
+ trim: ["String → String", "one"],
1655
+ ltrim: ["String → String", "one"],
1656
+ rtrim: ["String → String", "one"],
1657
+ ascii_downcase: ["String → String (§13.18)", "one"],
1658
+ ascii_upcase: ["String → String (§13.18)", "one"],
1659
+ split: ["`split(s)`: String → Array<String>", "one"],
1660
+ test: ["String, a literal regex, flags `g` `i` → Boolean", "one"],
1661
+ sub: ["String, a literal regex, a replacement of text and named groups `\\(.name)` → String", "one"],
1662
+ gsub: ["String, a literal regex, a replacement of text and named groups `\\(.name)` → String", "one"],
1663
+ format: ["`format(\"name\")` → as `@name`", "one"],
1664
+ "@text": ["any → String, as `tostring`", "one"],
1665
+ "@json": ["any → String, as `tojson`", "one"],
1666
+ "@html": ["any → String, HTML-escaped", "one"],
1667
+ "@uri": ["any → String, percent-encoded", "one"],
1668
+ "@base64": ["any → String", "one"],
1669
+ "@csv": ["Array of scalars → String", "one"],
1670
+ "@tsv": ["Array of scalars → String", "one"],
1671
+ "@sh": ["a scalar or an array of scalars → String", "one"],
1672
+ floor: ["a number → Integer", "one"],
1673
+ ceil: ["a number → Integer", "one"],
1674
+ round: ["a number → Integer", "one"],
1675
+ trunc: ["a number → Integer", "one"],
1676
+ sqrt: ["a number → Float", "one"],
1677
+ log: ["a number → Float", "one"],
1678
+ log2: ["a number → Float", "one"],
1679
+ log10: ["a number → Float", "one"],
1680
+ exp: ["a number → Float", "one"],
1681
+ exp2: ["a number → Float", "one"],
1682
+ exp10: ["a number → Float", "one"],
1683
+ sin: ["a number → Float", "one"],
1684
+ cos: ["a number → Float", "one"],
1685
+ tan: ["a number → Float", "one"],
1686
+ fabs: ["a number → Float", "one"],
1687
+ pow: ["two numbers → Float", "one"],
1688
+ fmin: ["two numbers → Float", "one"],
1689
+ fmax: ["two numbers → Float", "one"],
1690
+ fmod: ["two numbers → Float", "one"],
1691
+ todate: ["DateTime or epoch seconds → String, RFC 3339", "one"],
1692
+ todateiso8601: ["DateTime or epoch seconds → String, RFC 3339", "one"],
1693
+ fromdate: ["String → DateTime (§13.4)", "one"],
1694
+ fromdateiso8601: ["String → DateTime (§13.4)", "one"],
1695
+ strftime: ["DateTime or epoch seconds, a literal format → String", "one"],
1696
+ strptime: ["String, a literal format → DateTime (§13.4)", "one"],
1697
+ year: ["DateTime → Integer", "one"],
1698
+ month: ["DateTime → Integer", "one"],
1699
+ day: ["DateTime → Integer", "one"],
1700
+ hour: ["DateTime → Integer", "one"],
1701
+ minute: ["DateTime → Integer", "one"],
1702
+ second: ["DateTime → Integer", "one"],
1703
+ millisecond: ["DateTime → Integer", "one"],
1704
+ weekday: ["DateTime → Integer", "one"],
1705
+ epoch_ms: ["DateTime → Integer", "one"],
1706
+ datetime_add: ["`datetime_add(n; unit)`: DateTime, Integer, a literal unit → DateTime", "one"],
1707
+ datetime_diff: ["`datetime_diff(other; unit)`: DateTime, DateTime, a literal unit → Integer", "one"],
1708
+ call: ["`call(f; a…)`: Function([I…], O), arguments of I (Integer → Float) → O", "one"],
1709
+ signature: ["a function value → String (tooling)", "one"],
1710
+ source: ["a function value → String (tooling)", "one"],
1711
+ calls: ["a function value → Array<String> (tooling)", "one"],
1712
+ captures: ["a function value → Array<String> (tooling)", "one"],
1713
+ };
1714
+ /**
1715
+ * The catalog: every builtin of jq 1.8 and East's additions, by name, and
1716
+ * each format by `@name`.
1717
+ *
1718
+ * @internal
1719
+ */
1720
+ export const BUILTINS = new Map(entries.map(([name, builtin]) => {
1721
+ const rule = RULES[name];
1722
+ return [name, rule === undefined ? builtin : { ...builtin, rule: rule[0], outputs: rule[1] }];
1723
+ }));
1724
+ /**
1725
+ * Whether a name is a builtin a jq query can call: one of jq 1.8's, or one of
1726
+ * East's additions, whether or not a query may use it.
1727
+ *
1728
+ * @param name - the name, as written in the query
1729
+ * @returns `true` for a builtin's name
1730
+ *
1731
+ * @example
1732
+ * ```ts
1733
+ * isJqBuiltin("select"); // true
1734
+ * isJqBuiltin("revenue"); // false: a `def` could name it
1735
+ * ```
1736
+ */
1737
+ export function isJqBuiltin(name) {
1738
+ return !name.startsWith("@") && BUILTINS.has(name);
1739
+ }
1740
+ //# sourceMappingURL=catalog.js.map