@simpleapps-com/augur-web 2.4.0 → 2026.11.2

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 (243) hide show
  1. package/EXPORTS.md +18 -189
  2. package/README.md +18 -364
  3. package/dist/accordion.cjs.map +1 -1
  4. package/dist/accordion.d.ts +4 -5
  5. package/dist/accordion.d.ts.map +1 -0
  6. package/dist/add-to-cart-button.cjs.map +1 -1
  7. package/dist/add-to-cart-button.d.ts +5 -8
  8. package/dist/add-to-cart-button.d.ts.map +1 -0
  9. package/dist/breadcrumb.cjs.map +1 -1
  10. package/dist/breadcrumb.d.ts +5 -7
  11. package/dist/breadcrumb.d.ts.map +1 -0
  12. package/dist/breadcrumbs.cjs.map +1 -1
  13. package/dist/breadcrumbs.d.ts +4 -4
  14. package/dist/breadcrumbs.d.ts.map +1 -0
  15. package/dist/button.cjs.map +1 -1
  16. package/dist/button.d.ts +7 -9
  17. package/dist/button.d.ts.map +1 -0
  18. package/dist/card.cjs.map +1 -1
  19. package/dist/card.d.ts +3 -4
  20. package/dist/card.d.ts.map +1 -0
  21. package/dist/checkbox.cjs.map +1 -1
  22. package/dist/checkbox.d.ts +3 -4
  23. package/dist/checkbox.d.ts.map +1 -0
  24. package/dist/chunk-32XB3REY.cjs.map +1 -1
  25. package/dist/chunk-5VMEEKZ5.cjs.map +1 -1
  26. package/dist/chunk-5ZITWMV4.cjs.map +1 -1
  27. package/dist/chunk-76RSVRGB.cjs.map +1 -1
  28. package/dist/chunk-7EXXNELX.cjs.map +1 -1
  29. package/dist/chunk-BXMTQGKV.cjs.map +1 -1
  30. package/dist/{chunk-DCXYO3RB.js → chunk-C6K7FZNX.js} +7 -3
  31. package/dist/chunk-C6K7FZNX.js.map +1 -0
  32. package/dist/{chunk-AE4GLYJE.cjs → chunk-DMWSWL4B.cjs} +7 -3
  33. package/dist/chunk-DMWSWL4B.cjs.map +1 -0
  34. package/dist/chunk-GSR6SMQ2.cjs.map +1 -1
  35. package/dist/chunk-IO77MGHW.js +220 -0
  36. package/dist/chunk-IO77MGHW.js.map +1 -0
  37. package/dist/chunk-JXW4XE2P.cjs.map +1 -1
  38. package/dist/{chunk-OJ5G4BLS.js → chunk-KVHOMD4T.js} +15 -18
  39. package/dist/chunk-KVHOMD4T.js.map +1 -0
  40. package/dist/chunk-MAENILZP.cjs.map +1 -1
  41. package/dist/chunk-NEY26NNF.cjs.map +1 -1
  42. package/dist/chunk-QKWXJM4Q.cjs +220 -0
  43. package/dist/chunk-QKWXJM4Q.cjs.map +1 -0
  44. package/dist/chunk-T52J3SHP.cjs.map +1 -1
  45. package/dist/{chunk-I5NVZORX.cjs → chunk-TFP5RICB.cjs} +15 -18
  46. package/dist/chunk-TFP5RICB.cjs.map +1 -0
  47. package/dist/chunk-UFL6PVLI.cjs.map +1 -1
  48. package/dist/chunk-VL6L4GDA.cjs.map +1 -1
  49. package/dist/chunk-WJUDOEVB.cjs.map +1 -1
  50. package/dist/chunk-XGKBDPGD.cjs.map +1 -1
  51. package/dist/chunk-Z57QBVUC.cjs.map +1 -1
  52. package/dist/command.cjs +1 -0
  53. package/dist/command.cjs.map +1 -1
  54. package/dist/command.d.ts +13 -15
  55. package/dist/command.d.ts.map +1 -0
  56. package/dist/command.js +1 -0
  57. package/dist/command.js.map +1 -1
  58. package/dist/confirm-dialog.cjs.map +1 -1
  59. package/dist/confirm-dialog.d.ts +4 -6
  60. package/dist/confirm-dialog.d.ts.map +1 -0
  61. package/dist/data-table.cjs +35 -23
  62. package/dist/data-table.cjs.map +1 -1
  63. package/dist/data-table.d.ts +9 -11
  64. package/dist/data-table.d.ts.map +1 -0
  65. package/dist/data-table.js +34 -22
  66. package/dist/data-table.js.map +1 -1
  67. package/dist/detail-panel.cjs.map +1 -1
  68. package/dist/detail-panel.d.ts +6 -8
  69. package/dist/detail-panel.d.ts.map +1 -0
  70. package/dist/dialog.cjs.map +1 -1
  71. package/dist/dialog.d.ts +6 -8
  72. package/dist/dialog.d.ts.map +1 -0
  73. package/dist/dropdown-menu.cjs.map +1 -1
  74. package/dist/dropdown-menu.d.ts +5 -7
  75. package/dist/dropdown-menu.d.ts.map +1 -0
  76. package/dist/financing-widget.cjs +1 -3
  77. package/dist/financing-widget.cjs.map +1 -1
  78. package/dist/financing-widget.d.ts +5 -6
  79. package/dist/financing-widget.d.ts.map +1 -0
  80. package/dist/financing-widget.js +1 -3
  81. package/dist/financing-widget.js.map +1 -1
  82. package/dist/form-field.cjs.map +1 -1
  83. package/dist/form-field.d.ts +4 -5
  84. package/dist/form-field.d.ts.map +1 -0
  85. package/dist/form-input.cjs.map +1 -1
  86. package/dist/form-input.d.ts +4 -5
  87. package/dist/form-input.d.ts.map +1 -0
  88. package/dist/form-select.cjs.map +1 -1
  89. package/dist/form-select.d.ts +4 -5
  90. package/dist/form-select.d.ts.map +1 -0
  91. package/dist/form-textarea.cjs.map +1 -1
  92. package/dist/form-textarea.d.ts +4 -5
  93. package/dist/form-textarea.d.ts.map +1 -0
  94. package/dist/gtm.cjs +3 -2
  95. package/dist/gtm.cjs.map +1 -1
  96. package/dist/gtm.d.ts +12 -15
  97. package/dist/gtm.d.ts.map +1 -0
  98. package/dist/gtm.js +2 -1
  99. package/dist/input.cjs.map +1 -1
  100. package/dist/input.d.ts +4 -5
  101. package/dist/input.d.ts.map +1 -0
  102. package/dist/label.cjs.map +1 -1
  103. package/dist/label.d.ts +5 -7
  104. package/dist/label.d.ts.map +1 -0
  105. package/dist/list-view.cjs.map +1 -1
  106. package/dist/list-view.d.ts +5 -7
  107. package/dist/list-view.d.ts.map +1 -0
  108. package/dist/mdx-components.cjs +5 -2
  109. package/dist/mdx-components.cjs.map +1 -1
  110. package/dist/mdx-components.d.ts +11 -6
  111. package/dist/mdx-components.d.ts.map +1 -0
  112. package/dist/mdx-components.js +5 -2
  113. package/dist/mdx-components.js.map +1 -1
  114. package/dist/navigation-menu.cjs.map +1 -1
  115. package/dist/navigation-menu.d.ts +5 -7
  116. package/dist/navigation-menu.d.ts.map +1 -0
  117. package/dist/pagination.cjs +3 -2
  118. package/dist/pagination.cjs.map +1 -1
  119. package/dist/pagination.d.ts +10 -14
  120. package/dist/pagination.d.ts.map +1 -0
  121. package/dist/pagination.js +2 -1
  122. package/dist/payment-modal.cjs +20 -19
  123. package/dist/payment-modal.cjs.map +1 -1
  124. package/dist/payment-modal.d.ts +5 -7
  125. package/dist/payment-modal.d.ts.map +1 -0
  126. package/dist/payment-modal.js +19 -18
  127. package/dist/payment-modal.js.map +1 -1
  128. package/dist/popover.cjs.map +1 -1
  129. package/dist/popover.d.ts +4 -5
  130. package/dist/popover.d.ts.map +1 -0
  131. package/dist/price-format.cjs.map +1 -1
  132. package/dist/price-format.d.ts +4 -5
  133. package/dist/price-format.d.ts.map +1 -0
  134. package/dist/price.cjs +4 -1
  135. package/dist/price.cjs.map +1 -1
  136. package/dist/price.d.ts +8 -22
  137. package/dist/price.d.ts.map +1 -0
  138. package/dist/price.js +4 -1
  139. package/dist/price.js.map +1 -1
  140. package/dist/provider.cjs +4 -2
  141. package/dist/provider.cjs.map +1 -1
  142. package/dist/provider.d.ts +7 -10
  143. package/dist/provider.d.ts.map +1 -0
  144. package/dist/provider.js +3 -1
  145. package/dist/provider.js.map +1 -1
  146. package/dist/quantity-input.cjs +27 -40
  147. package/dist/quantity-input.cjs.map +1 -1
  148. package/dist/quantity-input.d.ts +4 -5
  149. package/dist/quantity-input.d.ts.map +1 -0
  150. package/dist/quantity-input.js +27 -40
  151. package/dist/quantity-input.js.map +1 -1
  152. package/dist/radio-group.cjs.map +1 -1
  153. package/dist/radio-group.d.ts +3 -4
  154. package/dist/radio-group.d.ts.map +1 -0
  155. package/dist/resource-tabs.cjs +1 -0
  156. package/dist/resource-tabs.cjs.map +1 -1
  157. package/dist/resource-tabs.d.ts +6 -8
  158. package/dist/resource-tabs.d.ts.map +1 -0
  159. package/dist/resource-tabs.js +1 -0
  160. package/dist/resource-tabs.js.map +1 -1
  161. package/dist/rules.d.ts +210 -0
  162. package/dist/rules.d.ts.map +1 -0
  163. package/dist/select.cjs.map +1 -1
  164. package/dist/select.d.ts +4 -5
  165. package/dist/select.d.ts.map +1 -0
  166. package/dist/separator.cjs.map +1 -1
  167. package/dist/separator.d.ts +3 -4
  168. package/dist/separator.d.ts.map +1 -0
  169. package/dist/session-replay.cjs +4 -2
  170. package/dist/session-replay.cjs.map +1 -1
  171. package/dist/session-replay.d.ts +4 -5
  172. package/dist/session-replay.d.ts.map +1 -0
  173. package/dist/session-replay.js +4 -2
  174. package/dist/session-replay.js.map +1 -1
  175. package/dist/skeleton.cjs.map +1 -1
  176. package/dist/skeleton.d.ts +2 -4
  177. package/dist/skeleton.d.ts.map +1 -0
  178. package/dist/spinner.cjs.map +1 -1
  179. package/dist/spinner.d.ts +2 -4
  180. package/dist/spinner.d.ts.map +1 -0
  181. package/dist/stock-label.cjs +14 -12
  182. package/dist/stock-label.cjs.map +1 -1
  183. package/dist/stock-label.d.ts +7 -7
  184. package/dist/stock-label.d.ts.map +1 -0
  185. package/dist/stock-label.js +14 -12
  186. package/dist/stock-label.js.map +1 -1
  187. package/dist/table.cjs.map +1 -1
  188. package/dist/table.d.ts +3 -4
  189. package/dist/table.d.ts.map +1 -0
  190. package/dist/tabs.cjs.map +1 -1
  191. package/dist/tabs.d.ts +4 -5
  192. package/dist/tabs.d.ts.map +1 -0
  193. package/dist/textarea.cjs.map +1 -1
  194. package/dist/textarea.d.ts +4 -5
  195. package/dist/textarea.d.ts.map +1 -0
  196. package/llms.txt +23 -38
  197. package/package.json +26 -17
  198. package/dist/accordion.d.cts +0 -9
  199. package/dist/add-to-cart-button.d.cts +0 -14
  200. package/dist/breadcrumb.d.cts +0 -22
  201. package/dist/breadcrumbs.d.cts +0 -31
  202. package/dist/button.d.cts +0 -27
  203. package/dist/card.d.cts +0 -10
  204. package/dist/checkbox.d.cts +0 -6
  205. package/dist/chunk-AE4GLYJE.cjs.map +0 -1
  206. package/dist/chunk-DCXYO3RB.js.map +0 -1
  207. package/dist/chunk-I5NVZORX.cjs.map +0 -1
  208. package/dist/chunk-OJ5G4BLS.js.map +0 -1
  209. package/dist/command.d.cts +0 -87
  210. package/dist/confirm-dialog.d.cts +0 -35
  211. package/dist/data-table.d.cts +0 -55
  212. package/dist/detail-panel.d.cts +0 -59
  213. package/dist/dialog.d.cts +0 -22
  214. package/dist/dropdown-menu.d.cts +0 -30
  215. package/dist/financing-widget.d.cts +0 -45
  216. package/dist/form-field.d.cts +0 -14
  217. package/dist/form-input.d.cts +0 -19
  218. package/dist/form-select.d.cts +0 -34
  219. package/dist/form-textarea.d.cts +0 -12
  220. package/dist/gtm.d.cts +0 -69
  221. package/dist/input.d.cts +0 -6
  222. package/dist/label.d.cts +0 -8
  223. package/dist/list-view.d.cts +0 -18
  224. package/dist/mdx-components.d.cts +0 -20
  225. package/dist/navigation-menu.d.cts +0 -15
  226. package/dist/pagination.d.cts +0 -50
  227. package/dist/payment-modal.d.cts +0 -30
  228. package/dist/popover.d.cts +0 -9
  229. package/dist/price-format.d.cts +0 -21
  230. package/dist/price.d.cts +0 -90
  231. package/dist/provider.d.cts +0 -47
  232. package/dist/quantity-input.d.cts +0 -33
  233. package/dist/radio-group.d.cts +0 -7
  234. package/dist/resource-tabs.d.cts +0 -33
  235. package/dist/select.d.cts +0 -15
  236. package/dist/separator.d.cts +0 -6
  237. package/dist/session-replay.d.cts +0 -44
  238. package/dist/skeleton.d.cts +0 -5
  239. package/dist/spinner.d.cts +0 -10
  240. package/dist/stock-label.d.cts +0 -47
  241. package/dist/table.d.cts +0 -12
  242. package/dist/tabs.d.cts +0 -9
  243. package/dist/textarea.d.cts +0 -6
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../utils/src/strings.ts","../../utils/src/replace.ts","../src/rules.ts"],"sourcesContent":["//@ backend dafny\nimport {\n isAlnumChar,\n isBase64UrlChar,\n isDigit,\n isHexChar,\n isJsSpace,\n isLineTerminator,\n isLowerHexChar,\n isSnakeChar,\n isWordChar,\n lowerCode,\n} from \"@atlas/foundation/chars\";\n\n/* String scans and slices, verified with LemmaScript → Dafny (hand lemmas in strings.dfy;\n model: models/Utils.dfy; link: models/links/utils-strings.dfy). Recursive and\n expression-bodied so specs can use them, and each contract pins the result exactly, so\n an importer (which sees only the contract) knows what it returns. Two of them stand in\n for constructs lsc mistranslates: `prefix` for an unclamped `slice`, and the code-unit\n scans for \"\\r\" / \"\\n\" literals. */\n\n/**\n * The code unit at `i`, or -1 when `i` is outside `s`. JS `charCodeAt` gives NaN there,\n * which no code equals, so a scan's own bounds test would change no result and no test\n * could tell it from none (an equivalent mutant); with the bound here once, the boundary is\n * observable (tests pin -1) and the scans that use it carry no bound of their own. A code\n * unit is never negative, so -1 matches no `code` a caller passes (`requires code >= 0`).\n *\n * @ensures 0 ≤ i < |s| ⟹ result = s[i]; otherwise result = -1\n */\nexport function codeAt(s: string, i: number): number {\n //@ verify\n //@ ensures (i >= 0 && i < s.length) ==> \\result === s.charCodeAt(i)\n //@ ensures !(i >= 0 && i < s.length) ==> \\result === -1\n return i >= 0 && i < s.length ? s.charCodeAt(i) : -1;\n}\n\n/**\n * Every character of `s` from index `i` on is base64url.\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isBase64UrlChar(s[k])\n */\nexport function base64UrlFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> isBase64UrlChar(s.charCodeAt(k)))\n return i >= s.length || (isBase64UrlChar(s.charCodeAt(i)) && base64UrlFrom(s, i + 1));\n}\n\n/**\n * The base64url digit for `v` (RFC 4648 §5): A-Z a-z 0-9 - _.\n *\n * @ensures exactly the model's Base64UrlDigit\n */\nexport function base64UrlDigit(v: number): string {\n //@ verify\n //@ type v nat\n //@ requires v >= 0 && v < 64\n //@ ensures \\result === \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\".slice(v, v + 1)\n return \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\".slice(v, v + 1);\n}\n\n/**\n * Bytes from `i` on as unpadded base64url: each three as four digits, a last one or two as two or\n * three (JS `btoa` with `+/` as `-_` and the `=` dropped). One frame per three bytes: a JWT part\n * is a few hundred.\n *\n * @ensures exactly the model's Base64UrlFrom (links/utils-strings.dfy)\n */\nexport function encodeBase64UrlFrom(b: number[], i: number): string {\n //@ verify\n //@ type i nat\n //@ requires i >= 0 && forall(k: nat, k < b.length ==> (b[k] >= 0 && b[k] < 256))\n //@ decreases b.length - i\n //@ ensures i >= b.length ==> \\result === \"\"\n if (i >= b.length) return \"\";\n const x = b[i] as number;\n const first = base64UrlDigit(Math.floor(x / 4));\n if (i + 1 === b.length) return first + base64UrlDigit((x % 4) * 16);\n const y = b[i + 1] as number;\n const second = base64UrlDigit((x % 4) * 16 + Math.floor(y / 16));\n if (i + 2 === b.length) return first + second + base64UrlDigit((y % 16) * 4);\n const z = b[i + 2] as number;\n return (\n first +\n second +\n base64UrlDigit((y % 16) * 4 + Math.floor(z / 64)) +\n base64UrlDigit(z % 64) +\n encodeBase64UrlFrom(b, i + 3)\n );\n}\n\n/**\n * Every character of `s` from index `i` on is lowercase hex.\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isLowerHexChar(s[k])\n */\nexport function lowerHexFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> isLowerHexChar(s.charCodeAt(k)))\n return i >= s.length || (isLowerHexChar(s.charCodeAt(i)) && lowerHexFrom(s, i + 1));\n}\n\n/**\n * Every character of `s` from index `i` on is hex, either case.\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isHexChar(s[k])\n */\nexport function hexFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> isHexChar(s.charCodeAt(k)))\n return i >= s.length || (isHexChar(s.charCodeAt(i)) && hexFrom(s, i + 1));\n}\n\n/**\n * Every character of `s` from index `i` on is an ASCII digit (`\\d` without the `u` flag).\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isDigit(s[k])\n */\nexport function digitsFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> isDigit(s.charCodeAt(k)))\n return i >= s.length || (isDigit(s.charCodeAt(i)) && digitsFrom(s, i + 1));\n}\n\n/**\n * Every character of `s` from index `i` on is a word character (`\\w`: `[A-Za-z0-9_]`).\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isWordChar(s[k])\n */\nexport function wordCharsFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> isWordChar(s.charCodeAt(k)))\n return i >= s.length || (isWordChar(s.charCodeAt(i)) && wordCharsFrom(s, i + 1));\n}\n\n/**\n * Every character of `s` from index `i` on is a snake_case character (`[a-z0-9_]`).\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isSnakeChar(s[k])\n */\nexport function snakeCharsFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> isSnakeChar(s.charCodeAt(k)))\n return i >= s.length || (isSnakeChar(s.charCodeAt(i)) && snakeCharsFrom(s, i + 1));\n}\n\n/**\n * Every character of `s` from index `i` on is an ASCII letter or digit (`[A-Za-z0-9]`).\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isAlnumChar(s[k])\n */\nexport function alnumFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> isAlnumChar(s.charCodeAt(k)))\n return i >= s.length || (isAlnumChar(s.charCodeAt(i)) && alnumFrom(s, i + 1));\n}\n\n/**\n * Every character of `s` from index `i` on is an ASCII letter, digit or `-` (`[A-Za-z0-9-]`):\n * a domain label's tail, a service name's tail.\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). isAlnumChar(s[k]) ∨ s[k] = \"-\" — the model's AlnumDashFrom\n */\nexport function alnumDashFrom(s: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> (isAlnumChar(s.charCodeAt(k)) || s.charCodeAt(k) === 45))\n if (i >= s.length) return true;\n const c = s.charCodeAt(i);\n return (isAlnumChar(c) || c === 45) && alnumDashFrom(s, i + 1);\n}\n\n/**\n * The last index before `end` holding `code`, or -1 (JS `s.lastIndexOf(c)` at end = |s|).\n *\n * @ensures result = -1 ∨ (0 ≤ result < end ∧ s[result] = code ∧ no `code` in (result, end))\n */\nexport function lastIndexOfCode(s: string, code: number, end: number): number {\n //@ verify\n //@ type end nat\n //@ requires 0 <= end && end <= s.length\n //@ decreases end\n //@ ensures \\result === -1 || (0 <= \\result && \\result < end)\n //@ ensures \\result >= 0 ==> s.charCodeAt(\\result) === code\n //@ ensures \\result >= 0 ==> forall(k: nat, (\\result < k && k < end) ==> s.charCodeAt(k) !== code)\n //@ ensures \\result === -1 ==> forall(k: nat, k < end ==> s.charCodeAt(k) !== code)\n if (end === 0) return -1;\n if (s.charCodeAt(end - 1) === code) return end - 1;\n return lastIndexOfCode(s, code, end - 1);\n}\n\n/**\n * No character of `s` from index `i` on is `code`.\n *\n * @ensures result ⟺ ∀ k ∈ [i, |s|). s[k] ≠ code\n */\nexport function lacksCode(s: string, code: number, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires 0 <= i && i <= s.length\n //@ decreases s.length - i\n //@ ensures \\result <==> forall(k: nat, (i <= k && k < s.length) ==> s.charCodeAt(k) !== code)\n // `===`, not `>=`: past the end a read is NaN !== code, so `>=` vs `>` would be equivalent\n return i === s.length || (s.charCodeAt(i) !== code && lacksCode(s, code, i + 1));\n}\n\n/**\n * The end of the run of `code` starting at `i`: the first index ≥ i that isn't `code`\n * (skip spaces: `codeRunEnd(header, 32, i)`).\n *\n * @requires i ≤ |s|\n * @ensures i ≤ result ≤ |s| ∧ ∀ k ∈ [i, result). s[k] = code ∧ (result < |s| ⟹ s[result] ≠ code)\n * — exactly the run's end\n */\nexport function codeRunEnd(s: string, code: number, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires 0 <= i && i <= s.length\n //@ requires code >= 0\n //@ decreases s.length - i\n //@ ensures i <= \\result && \\result <= s.length\n //@ ensures forall(k: nat, (i <= k && k < \\result) ==> s.charCodeAt(k) === code)\n //@ ensures \\result < s.length ==> s.charCodeAt(\\result) !== code\n return codeAt(s, i) === code ? codeRunEnd(s, code, i + 1) : i;\n}\n\n/**\n * The first index ≥ `from` holding `code`, or -1 (`indexOf` for one code unit, so \"\\n\" is\n * passed as 10, never as a literal).\n *\n * @ensures result = -1 ∨ (from ≤ result < |s| ∧ s[result] = code), with no `code` in\n * [from, result) — the first one; result = -1 ⟹ none from `from` on\n */\nexport function indexOfCode(s: string, code: number, from: number): number {\n //@ verify\n //@ type from nat\n //@ requires code >= 0 && from >= 0\n //@ decreases s.length - from\n //@ ensures \\result === -1 || (from <= \\result && \\result < s.length)\n //@ ensures \\result >= 0 ==> s.charCodeAt(\\result) === code\n //@ ensures \\result >= 0 ==> forall(k: nat, (from <= k && k < \\result) ==> s.charCodeAt(k) !== code)\n //@ ensures \\result === -1 ==> forall(k: nat, (from <= k && k < s.length) ==> s.charCodeAt(k) !== code)\n const c = codeAt(s, from);\n if (c === code) return from;\n if (c === -1) return -1;\n return indexOfCode(s, code, from + 1);\n}\n\n/**\n * The first index ≥ `i` holding `a` or `b`, or |s| (a run either code ends: a path segment's\n * run to \"/\" or \"?\"). One scan: the lesser of two `indexOfCode` ends is the same index, but\n * its two sides are equal only when both are |s|, a boundary no test can observe.\n *\n * @requires i ≤ |s|\n * @ensures i ≤ result ≤ |s| ∧ ∀ k ∈ [i, result). s[k] ∉ {a, b} ∧ (result < |s| ⟹ s[result] ∈ {a, b})\n * — exactly the first such index\n */\nexport function eitherCodeEnd(s: string, a: number, b: number, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires 0 <= i && i <= s.length\n //@ requires a >= 0 && b >= 0\n //@ decreases s.length - i\n //@ ensures i <= \\result && \\result <= s.length\n //@ ensures forall(k: nat, (i <= k && k < \\result) ==> (s.charCodeAt(k) !== a && s.charCodeAt(k) !== b))\n //@ ensures \\result < s.length ==> (s.charCodeAt(\\result) === a || s.charCodeAt(\\result) === b)\n const c = codeAt(s, i);\n if (c === -1 || c === a || c === b) return i;\n return eitherCodeEnd(s, a, b, i + 1);\n}\n\n/**\n * `s` without one trailing `code` (\"\\r\" before a \"\\n\", say); unchanged otherwise.\n *\n * @ensures s ends with code ⟹ result = s[0, |s| − 1)\n * @ensures otherwise result = s\n */\nexport function dropLast(s: string, code: number): string {\n //@ verify\n //@ requires code >= 0\n //@ ensures (s.length > 0 && s.charCodeAt(s.length - 1) === code) ==> \\result === s.slice(0, s.length - 1)\n //@ ensures !(s.length > 0 && s.charCodeAt(s.length - 1) === code) ==> \\result === s\n return codeAt(s, s.length - 1) === code ? s.slice(0, s.length - 1) : s;\n}\n\n/**\n * `s` without its leading `code` units (every one of them).\n *\n * @ensures exactly the model's LStripCode\n */\nexport function lStripCode(s: string, code: number): string {\n //@ verify\n //@ requires code >= 0\n //@ decreases s.length\n //@ ensures \\result.length <= s.length\n if (codeAt(s, 0) === code) return lStripCode(s.slice(1), code);\n return s;\n}\n\n/**\n * `s` without its trailing `code` units (every one of them).\n *\n * @ensures exactly the model's RStripCode\n */\nexport function rStripCode(s: string, code: number): string {\n //@ verify\n //@ requires code >= 0\n //@ decreases s.length\n //@ ensures \\result.length <= s.length\n if (codeAt(s, s.length - 1) === code) {\n return rStripCode(s.slice(0, s.length - 1), code);\n }\n return s;\n}\n\n/**\n * `s` without its leading and trailing `code` units, the middle kept (`/a/b/` with `/` →\n * `a/b`).\n *\n * @ensures exactly the model's StripCode — neither end is `code` (StripCodeTrims)\n */\nexport function stripCode(s: string, code: number): string {\n //@ verify\n //@ requires code >= 0\n //@ ensures \\result === rStripCode(lStripCode(s, code), code)\n return rStripCode(lStripCode(s, code), code);\n}\n\n/**\n * JS `s.startsWith(x, pos)`, which lsc mistranslates (it drops `pos`). Like JS, a `pos`\n * past the end counts as the end, so the empty string matches anywhere.\n *\n * @ensures pos ≤ |s| ⟹ (result ⟺ pos + |x| ≤ |s| ∧ s[pos, pos + |x|) = x) — so a true\n * result also gives the bounds for slicing after the match\n * @ensures pos > |s| ⟹ (result ⟺ x = \"\")\n */\nexport function startsWithAt(s: string, x: string, pos: number): boolean {\n //@ verify\n //@ type pos nat\n //@ requires pos >= 0\n //@ ensures pos <= s.length ==> (\\result <==> (pos + x.length <= s.length && s.slice(pos, pos + x.length) === x))\n //@ ensures pos > s.length ==> (\\result <==> x.length === 0)\n // Math.min, not a ternary: at pos = |s| both branches agree, so `<` vs `<=` is equivalent\n const at = Math.min(pos, s.length);\n // The slice is clamped to the end, so a too-long x differs by length: no separate fit test\n // (JS slice clamps too, which made one unobservable)\n return s.slice(at, Math.min(at + x.length, s.length)) === x;\n}\n\n/**\n * `s` with A-Z lowercased and every other character kept: what lsc's proofs take\n * `toLowerCase()` to be. JS's `toLowerCase()` also maps non-ASCII letters, some onto ASCII\n * (the Kelvin sign K, U+212A, becomes \"k\") or onto two characters (İ, U+0130), so a proved\n * function that lowercases MUST use this, or the runtime does what the proof says it\n * doesn't.\n *\n * @ensures |result| = |s| ∧ ∀ k < |s|. result[k] = (s[k] ∈ A-Z ? s[k] + 32 : s[k]) — A-Z\n * lowered, every other code unit unchanged; true in JS (a contract `=== s.toLowerCase()` held\n * only in lsc's ASCII model of the built-in, Fable review 2026-11-06). Helper-free, since an\n * importer is given only the helpers its own body calls; exactly the model's LowerAscii in\n * the link\n */\nexport function lowerAscii(s: string): string {\n //@ verify\n //@ decreases s.length\n //@ ensures \\result.length === s.length\n //@ ensures forall(k: nat, k < s.length ==> \\result.charCodeAt(k) === ((s.charCodeAt(k) >= 65 && s.charCodeAt(k) <= 90) ? s.charCodeAt(k) + 32 : s.charCodeAt(k)))\n if (s.length === 0) return \"\";\n const c = s.charCodeAt(0);\n const head =\n c >= 65 && c <= 90 ? \"abcdefghijklmnopqrstuvwxyz\".slice(c - 65, c - 64) : s.slice(0, 1);\n return head + lowerAscii(s.slice(1));\n}\n\n/**\n * `lowerAscii` as a loop: a constant stack depth (and linear time) on long text, where the\n * recursive spec takes a frame and a slice per character.\n *\n * @ensures result = lowerAscii(s)\n */\nexport function lowerAsciiText(s: string): string {\n //@ verify\n //@ ensures \\result === lowerAscii(s)\n let out = \"\";\n let i = 0;\n while (i !== s.length) {\n //@ invariant 0 <= i && i <= s.length\n //@ invariant out + lowerAscii(s.slice(i)) === lowerAscii(s)\n //@ decreases s.length - i\n const c = s.charCodeAt(i);\n out =\n out +\n (c >= 65 && c <= 90 ? \"abcdefghijklmnopqrstuvwxyz\".slice(c - 65, c - 64) : s.slice(i, i + 1));\n i = i + 1;\n }\n return out;\n}\n\n/**\n * Whether `x` from index `k` matches `s` from `pos + k`, code by code, ASCII-lowered. A code\n * past the end of `s` is -1 (`codeAt`), which no code of `x` is, so there is no bound to\n * check (a `pos + |x| ≤ |s|` guard before a slice never changed the answer at runtime, where\n * `slice` clamps: an equivalent mutant, 2026-11-02).\n *\n * @ensures exactly the model's CaselessFrom\n */\nexport function caselessFrom(s: string, x: string, pos: number, k: number): boolean {\n //@ verify\n //@ type pos nat\n //@ type k nat\n //@ requires pos >= 0 && k >= 0 && k <= x.length\n //@ decreases x.length - k\n //@ ensures k === x.length ==> \\result\n if (k === x.length) return true;\n return lowerCode(codeAt(s, pos + k)) === x.charCodeAt(k) && caselessFrom(s, x, pos, k + 1);\n}\n\n/**\n * Whether the text of `s` at `pos`, ASCII-lowered, is `x` (`x` given lowercase): a case-free\n * `startsWith`; callers carry no length guard of their own. Only `pos ≤ |s|` is checked: it\n * decides an empty `x` past the end, the one case the code-by-code test can't see.\n *\n * @ensures result ⟺ pos + |x| ≤ |s| ∧ ∀ j < |x|. lowered(s[pos + j]) = x[j] — the text at pos,\n * ASCII-lowered (A-Z + 32), is x; helper-free; exactly the model's StartsWithCaseless in the link\n */\nexport function startsWithCaseless(s: string, x: string, pos: number): boolean {\n //@ verify\n //@ type pos nat\n //@ requires pos >= 0\n //@ ensures \\result <==> (pos + x.length <= s.length && forall(j: nat, j < x.length ==> ((s.charCodeAt(pos + j) >= 65 && s.charCodeAt(pos + j) <= 90) ? s.charCodeAt(pos + j) + 32 : s.charCodeAt(pos + j)) === x.charCodeAt(j)))\n return pos <= s.length && caselessFrom(s, x, pos, 0);\n}\n\n/**\n * Whether `s` ends with `suffix` (JS one-argument `endsWith`, which lsc reads as its\n * two-argument form; moved from the augur-api generator 2026-11-01).\n *\n * @ensures result ⟺ |s| ≥ |suffix| ∧ s[|s| − |suffix|, |s|) = suffix — exactly the model's EndsWith\n */\nexport function endsWith(s: string, suffix: string): boolean {\n //@ verify\n //@ ensures \\result <==> (s.length >= suffix.length && s.slice(s.length - suffix.length) === suffix)\n // No length test: from max(|s| − |suffix|, 0), a too-long suffix compares unequal by length\n return s.slice(Math.max(s.length - suffix.length, 0)) === suffix;\n}\n\n/**\n * The order of `a` and `b` by UTF-16 code unit from index `i`, as a recursive spec: -1, 0\n * or 1 (JS `<` on strings; a proper prefix comes first). Locale-free, unlike `localeCompare`.\n *\n * @ensures result ∈ {-1, 0, 1} — exactly the model's CompareFrom\n */\nexport function compareFrom(a: string, b: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases a.length - i\n //@ ensures \\result === -1 || \\result === 0 || \\result === 1\n if (i >= a.length) return i >= b.length ? 0 : -1;\n if (i >= b.length) return 1;\n const x = a.charCodeAt(i);\n const y = b.charCodeAt(i);\n if (x < y) return -1;\n if (x > y) return 1;\n return compareFrom(a, b, i + 1);\n}\n\n/**\n * The order of two strings by UTF-16 code unit, for `sort` (what the default `sort` uses on\n * strings), so sorted output never depends on locale.\n *\n * @ensures result = compareFrom(a, b, 0)\n */\nexport function compareCodeUnits(a: string, b: string): number {\n //@ verify\n //@ ensures \\result === compareFrom(a, b, 0)\n return compareFrom(a, b, 0);\n}\n\n/**\n * JS `s.slice(0, n)`: at most `n` characters, clamped to the length. lsc reads a bare\n * `slice(0, n)` without JS's clamp, so use this instead.\n *\n * @ensures result = s[0, min(n, |s|))\n */\nexport function prefix(s: string, n: number): string {\n //@ verify\n //@ type n nat\n //@ requires n >= 0\n //@ ensures n < s.length ==> \\result === s.slice(0, n)\n //@ ensures n >= s.length ==> \\result === s\n // Math.min, not a ternary: JS slice already clamps, so a ternary's branch is unobservable\n return s.slice(0, Math.min(n, s.length));\n}\n\n/**\n * The end of the JS-whitespace (`\\s`) run starting at `i`: the first index ≥ i that is not\n * whitespace, or |s|.\n *\n * @ensures i ≤ result ≤ |s| ∧ s[i, result) all whitespace ∧ (result = |s| ∨ ¬space(s[result]))\n */\nexport function spaceRunEnd(s: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires 0 <= i && i <= s.length\n //@ decreases s.length - i\n //@ ensures i <= \\result && \\result <= s.length\n //@ ensures forall(k: nat, (i <= k && k < \\result) ==> isJsSpace(s.charCodeAt(k)))\n //@ ensures \\result < s.length ==> !isJsSpace(s.charCodeAt(\\result))\n // codeAt is -1 at the end, which is no space: the bound needs no test of its own here\n if (!isJsSpace(codeAt(s, i))) return i;\n return spaceRunEnd(s, i + 1);\n}\n\n/**\n * The end of the ASCII-digit run starting at `i` (a regex's `\\d+`, from `i`): the first index\n * ≥ i that is not 0-9, or |s|.\n *\n * @ensures i ≤ result ≤ |s| ∧ s[i, result) all digits ∧ (result = |s| ∨ ¬digit(s[result])) —\n * exactly the model's DigitRunEnd\n */\nexport function digitRunEnd(s: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires 0 <= i && i <= s.length\n //@ decreases s.length - i\n //@ ensures i <= \\result && \\result <= s.length\n //@ ensures forall(k: nat, (i <= k && k < \\result) ==> (s.charCodeAt(k) >= 48 && s.charCodeAt(k) <= 57))\n //@ ensures \\result < s.length ==> !(s.charCodeAt(\\result) >= 48 && s.charCodeAt(\\result) <= 57)\n // codeAt is -1 at the end, which is no digit\n if (!isDigit(codeAt(s, i))) return i;\n return digitRunEnd(s, i + 1);\n}\n\n/**\n * A natural number written canonically (`^(0|[1-9][0-9]*)$`): the keys JS objects move\n * first, ahead of their source order.\n *\n * @ensures exactly the model's CanonicalNat, stated over the codes themselves so an importer\n * can use it (a contract naming `digitsFrom` can't be resolved there, models/LSC-GAPS.md)\n */\nexport function isCanonicalNat(s: string): boolean {\n //@ verify\n //@ ensures \\result <==> (s === \"0\" || (s.length > 0 && s.charCodeAt(0) >= 49 && s.charCodeAt(0) <= 57 && forall(k: nat, (1 <= k && k < s.length) ==> (s.charCodeAt(k) >= 48 && s.charCodeAt(k) <= 57))))\n if (s === \"0\") return true;\n const first = codeAt(s, 0);\n return first >= 49 && first <= 57 && digitsFrom(s, 1);\n}\n\n/**\n * The value of a run of decimal digits, most significant first (\"\" is 0).\n *\n * @requires ∀ k ∈ [0, |s|). isDigit(s[k])\n * @ensures exactly the model's DigitsValue (proved in links/utils-strings.dfy)\n */\nexport function digitsValue(s: string): number {\n //@ verify\n //@ requires forall(k: nat, k < s.length ==> (s.charCodeAt(k) >= 48 && s.charCodeAt(k) <= 57))\n //@ decreases s.length\n //@ ensures \\result >= 0\n if (s.length === 0) return 0;\n return digitsValue(s.slice(0, s.length - 1)) * 10 + (s.charCodeAt(s.length - 1) - 48);\n}\n\n/**\n * What a number from the environment means (owner 2026-11-04: a bad one fails at start):\n * \"default\" when unset (\"\": the wrapper reads a missing variable as \"\"), \"value\" when it is\n * a canonical natural number at least `min` (its value is `digitsValue(raw)`), and \"bad\"\n * otherwise: a sign, a space, a fraction, an exponent, hex, text, or below `min`.\n *\n * @ensures exactly the model's EnvNumberOf (proved in links/utils-strings.dfy)\n */\nexport function envNumberKind(raw: string, min: number): string {\n //@ verify\n //@ type min nat\n //@ ensures raw === \"\" ==> \\result === \"default\"\n //@ ensures (raw !== \"\" && !isCanonicalNat(raw)) ==> \\result === \"bad\"\n if (raw === \"\") return \"default\";\n if (!isCanonicalNat(raw)) return \"bad\";\n return digitsValue(raw) < min ? \"bad\" : \"value\";\n}\n\n/**\n * A canonical natural number's value, 0 for any other text (a count written as JSON).\n *\n * @ensures exactly the model's CanonicalNatValue (in the link: `digitsValue` needs the digits\n * isCanonicalNat's contract gives, which a contract can't call for); 0 for other text\n */\nexport function canonicalNatValue(s: string): number {\n //@ verify\n //@ ensures \\result >= 0\n //@ ensures !isCanonicalNat(s) ==> \\result === 0\n if (!isCanonicalNat(s)) return 0;\n return digitsValue(s);\n}\n\n/**\n * The first index ≥ `i` holding a line terminator, or |s|: where a regex `.+` started at `i`\n * stops.\n *\n * @ensures i ≤ result ≤ |s| ∧ no terminator in s[i, result) ∧ (result = |s| ∨ terminator at result)\n */\nexport function lineEnd(s: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires 0 <= i && i <= s.length\n //@ decreases s.length - i\n //@ ensures i <= \\result && \\result <= s.length\n //@ ensures forall(k: nat, (i <= k && k < \\result) ==> !isLineTerminator(s.charCodeAt(k)))\n //@ ensures \\result < s.length ==> isLineTerminator(s.charCodeAt(\\result))\n if (i === s.length || isLineTerminator(s.charCodeAt(i))) return i;\n return lineEnd(s, i + 1);\n}\n\n/**\n * The largest p with lo ≤ p < hi whose character is not a line terminator, or -1: where a\n * backtracking regex `.` can start.\n *\n * @ensures result = -1 ∨ (lo ≤ result < hi ∧ ¬terminator(s[result]) ∧ only terminators in (result, hi))\n */\nexport function lastLineCharBelow(s: string, hi: number, lo: number): number {\n //@ verify\n //@ type hi nat\n //@ type lo nat\n //@ requires 0 <= lo && 0 <= hi && hi <= s.length\n //@ decreases hi\n //@ ensures \\result === -1 || (lo <= \\result && \\result < hi)\n //@ ensures \\result >= 0 ==> !isLineTerminator(s.charCodeAt(\\result))\n //@ ensures \\result >= 0 ==> forall(k: nat, (\\result < k && k < hi) ==> isLineTerminator(s.charCodeAt(k)))\n //@ ensures \\result === -1 ==> forall(k: nat, (lo <= k && k < hi) ==> isLineTerminator(s.charCodeAt(k)))\n if (hi <= lo) return -1;\n if (!isLineTerminator(s.charCodeAt(hi - 1))) return hi - 1;\n return lastLineCharBelow(s, hi - 1, lo);\n}\n\n/**\n * Nothing but JS whitespace (`s.trim() === \"\"`).\n *\n * @ensures exactly the model's Blank\n */\nexport function isBlank(s: string): boolean {\n //@ verify\n //@ ensures \\result <==> s.trim() === \"\"\n return s.trim() === \"\";\n}\n\n/**\n * The first index ≥ `i` where `x` occurs in `s`, or -1 (JS `s.indexOf(x, i)` for i ≤ |s|).\n *\n * @ensures result = -1 ∨ (i ≤ result ∧ s[result, result + |x|) = x) — and the first such\n * index: links/utils-strings.dfy proves it is exactly the model's IndexOfFrom (lsc can't\n * give the \"no earlier match\" quantifier a trigger)\n */\nexport function indexOfFrom(s: string, x: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires i >= 0 && i <= s.length\n //@ decreases s.length - i\n //@ ensures \\result === -1 || (i <= \\result && \\result + x.length <= s.length)\n //@ ensures \\result >= 0 ==> s.slice(\\result, \\result + x.length) === x\n // A match here, else the end, else the next index: stopping at `i === |s|` (not \"x no\n // longer fits\") leaves no bound whose slip a later, harmless step would hide\n if (startsWithAt(s, x, i)) return i;\n if (i === s.length) return -1;\n return indexOfFrom(s, x, i + 1);\n}\n\n/**\n * `indexOfFrom` as a loop: the same answer at a constant stack depth, for text long enough that\n * one frame per character would overflow the stack (a rendered page, 50–60 KB with its inlined\n * stylesheet). Specs and links use `indexOfFrom`; runtime scans over long text use this.\n *\n * @ensures result = indexOfFrom(s, x, i)\n */\nexport function findFrom(s: string, x: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires i >= 0 && i <= s.length\n //@ ensures \\result === indexOfFrom(s, x, i)\n let k = i;\n while (k !== s.length) {\n //@ invariant i <= k && k <= s.length\n //@ invariant indexOfFrom(s, x, k) === indexOfFrom(s, x, i)\n //@ decreases s.length - k\n if (startsWithAt(s, x, k)) return k;\n k = k + 1;\n }\n return startsWithAt(s, x, k) ? k : -1;\n}\n\n/**\n * `indexOfCode` as a loop: the same answer at a constant stack depth (see `findFrom`).\n *\n * @ensures result = indexOfCode(s, code, from)\n */\nexport function findCodeFrom(s: string, code: number, from: number): number {\n //@ verify\n //@ type from nat\n //@ requires code >= 0 && from >= 0\n //@ ensures \\result === indexOfCode(s, code, from)\n let k = from;\n while (k < s.length) {\n //@ invariant from <= k\n //@ invariant indexOfCode(s, code, k) === indexOfCode(s, code, from)\n //@ decreases s.length - k\n if (s.charCodeAt(k) === code) return k;\n k = k + 1;\n }\n return -1;\n}\n\n/**\n * How many times `x` occurs in `s` from `i` on, left to right without overlaps (repeated JS\n * `s.indexOf(x, at + x.length)`).\n *\n * @requires |x| > 0\n * @ensures result ≥ 0 — exactly the model's CountFrom (links/utils-strings.dfy)\n */\nexport function countFrom(s: string, x: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires x.length > 0 && i >= 0 && i <= s.length\n //@ decreases s.length - i\n //@ ensures \\result >= 0\n const at = indexOfFrom(s, x, i);\n if (at === -1) return 0;\n return 1 + countFrom(s, x, at + x.length);\n}\n\n/**\n * `countFrom(s, x, 0)` as a loop: a constant stack depth on long text (see `findFrom`).\n *\n * @requires |x| > 0\n * @ensures result = countFrom(s, x, 0)\n */\nexport function countOf(s: string, x: string): number {\n //@ verify\n //@ requires x.length > 0\n //@ ensures \\result === countFrom(s, x, 0)\n let n = 0;\n let i = 0;\n let at = findFrom(s, x, 0);\n while (at !== -1) {\n //@ invariant 0 <= i && i <= s.length\n //@ invariant at === indexOfFrom(s, x, i)\n //@ invariant n + countFrom(s, x, i) === countFrom(s, x, 0)\n //@ decreases s.length - i\n n = n + 1;\n i = at + x.length;\n at = findFrom(s, x, i);\n }\n return n;\n}\n\n/**\n * The text before the first `code`, or all of it when there is none (JS `s.split(c)[0]`).\n *\n * @ensures result = s[0, first code) when s holds one, else s — the model's UntilCode\n */\nexport function untilCode(s: string, code: number): string {\n //@ verify\n //@ requires code >= 0\n //@ ensures \\result === (indexOfCode(s, code, 0) >= 0 && indexOfCode(s, code, 0) <= s.length ? s.slice(0, indexOfCode(s, code, 0)) : s)\n const k = indexOfCode(s, code, 0);\n return k >= 0 ? s.slice(0, k) : s;\n}\n\n/**\n * `s` from `i` on split at every `code` (JS `s.split(c)` at i = 0, for a one-character\n * separator): always at least one part.\n *\n * @ensures |result| ≥ 1 — exactly the model's SplitCodeFrom (links/utils-strings.dfy)\n */\nexport function splitCodeFrom(s: string, code: number, i: number): string[] {\n //@ verify\n //@ type i nat\n //@ requires code >= 0 && i >= 0 && i <= s.length\n //@ decreases s.length - i\n //@ ensures \\result.length > 0\n const k = indexOfCode(s, code, i);\n if (k === -1) return [s.slice(i)];\n return [s.slice(i, k), ...splitCodeFrom(s, code, k + 1)];\n}\n\n/**\n * Every run of JS whitespace in `s` from `i` on as one space (JS `s.replace(/\\s+/g, \" \")` at\n * i = 0).\n *\n * @ensures |result| ≤ |s| − i — exactly the model's CollapseSpacesFrom (links/utils-strings.dfy)\n */\nexport function collapseSpacesFrom(s: string, i: number): string {\n //@ verify\n //@ type i nat\n //@ requires 0 <= i && i <= s.length\n //@ decreases s.length - i\n //@ ensures \\result.length <= s.length - i\n if (i === s.length) return \"\";\n if (isJsSpace(s.charCodeAt(i))) return \" \" + collapseSpacesFrom(s, spaceRunEnd(s, i));\n return s.slice(i, i + 1) + collapseSpacesFrom(s, i + 1);\n}\n\n/**\n * `collapseSpacesFrom(s, 0)` at a constant stack depth (a page's text is tens of KB).\n *\n * @ensures result = collapseSpacesFrom(s, 0)\n */\nexport function collapseSpaces(s: string): string {\n //@ verify\n //@ ensures \\result === collapseSpacesFrom(s, 0)\n let out = \"\";\n let i = 0;\n while (i < s.length) {\n //@ invariant 0 <= i && i <= s.length\n //@ invariant out + collapseSpacesFrom(s, i) === collapseSpacesFrom(s, 0)\n //@ decreases s.length - i\n if (isJsSpace(s.charCodeAt(i))) {\n out = out + \" \";\n // the run's end as a loop too: spaceRunEnd takes a frame per space (Fable review 2026-11-06)\n let e = i + 1;\n while (e !== s.length && isJsSpace(s.charCodeAt(e))) {\n //@ invariant i < e && e <= s.length\n //@ invariant forall(k: nat, (i <= k && k < e) ==> isJsSpace(s.charCodeAt(k)))\n //@ decreases s.length - e\n e = e + 1;\n }\n i = e;\n } else {\n out = out + s.slice(i, i + 1);\n i = i + 1;\n }\n }\n return out;\n}\n\n/**\n * `n` spaces.\n *\n * @ensures result = \" \" repeated n times — the model's Spaces\n */\nexport function spaces(n: number): string {\n //@ verify\n //@ type n nat\n //@ requires n >= 0\n //@ decreases n\n //@ ensures \\result.length === n\n //@ ensures forall(k: nat, k < n ==> \\result.charCodeAt(k) === 32)\n // `<= 0`, not `=== 0`: the same for a nat, and a fraction a caller slips in (outside the\n // contract) ends instead of recursing forever (Fable review 2026-11-06: spaces(0.5))\n if (n <= 0) return \"\";\n return \" \" + spaces(n - 1);\n}\n\n/**\n * A line feed, `\"\\n\"`, for proved text that spans lines: lsc emits a `\"\\n\"` escape raw, which\n * Dafny cannot parse (models/LSC-GAPS.md), so the contract pins it by code unit and the body is\n * a template literal holding the line break itself.\n *\n * @ensures result = \"\\n\" — one code unit, 10\n */\nexport function lineFeed(): string {\n //@ verify\n //@ ensures \\result.length === 1 && \\result.charCodeAt(0) === 10\n return `\n`;\n}\n\n/**\n * `s` padded on the left with spaces to `width` (JS `s.padStart(width)`).\n *\n * @ensures result = Spaces(width − |s|) + s when width > |s|, else s\n */\nexport function padLeft(s: string, width: number): string {\n //@ verify\n //@ ensures width <= s.length ==> \\result === s\n // width > |s| ⟹ spaces(width − |s|) + s: a hand ensures in strings.dfy, so importers'\n // axioms name no helper (models/LSC-GAPS.md). Math.max, not a ternary: at width = |s|\n // both branches agree (spaces(0) is \"\"), so `>` vs `>=` would be equivalent.\n return spaces(Math.max(width - s.length, 0)) + s;\n}\n\n/**\n * `s` padded on the right with spaces to `width` (JS `s.padEnd(width)`).\n *\n * @ensures result = s + Spaces(width − |s|) when width > |s|, else s\n */\nexport function padRight(s: string, width: number): string {\n //@ verify\n //@ ensures width <= s.length ==> \\result === s\n // width > |s| ⟹ s + spaces(width − |s|): a hand ensures in strings.dfy, as padLeft's.\n return s + spaces(Math.max(width - s.length, 0));\n}\n\n/**\n * An optional part of a key: `tag` then `text`, or nothing when `text` is empty, so an absent\n * part never leaves a bare tag.\n *\n * @ensures result = \"\" when text = \"\", else tag + text — exactly the model's KeyPart\n */\nexport function keyPart(tag: string, text: string): string {\n //@ verify\n //@ ensures \\result === (text === \"\" ? \"\" : tag + text)\n return text === \"\" ? \"\" : tag + text;\n}\n\n/**\n * Two texts joined by one space: the one rule behind a loader key's `<column> <direction>`, a\n * sync line's `METHOD /path` and a field's description then note.\n *\n * @ensures result = a + \" \" + b — exactly the model's SpaceJoined\n */\nexport function spaceJoined(a: string, b: string): string {\n //@ verify\n //@ ensures \\result === a + \" \" + b\n return a + \" \" + b;\n}\n\n/**\n * The first code point of `w` as text: a surrogate pair whole, else the first code unit, or \"\"\n * (Fable review 2026-11-06: an astral initial was a lone surrogate).\n *\n * @ensures exactly the model's FirstChar\n */\nexport function firstCodePoint(w: string): string {\n //@ verify\n //@ ensures \\result === ((w.length >= 2 && w.charCodeAt(0) >= 55296 && w.charCodeAt(0) <= 56319 && w.charCodeAt(1) >= 56320 && w.charCodeAt(1) <= 57343) ? w.slice(0, 2) : (w.length > 0 ? w.slice(0, 1) : \"\"))\n if (w.length >= 2) {\n const hi = w.charCodeAt(0);\n const lo = w.charCodeAt(1);\n if (hi >= 55296 && hi <= 56319 && lo >= 56320 && lo <= 57343) return w.slice(0, 2);\n }\n return w.length > 0 ? w.slice(0, 1) : \"\";\n}\n\n/**\n * An ASCII letter (A-Z, a-z) somewhere in `w` from `i` on (moved from readability.ts\n * 2026-11-06, so `readableWords`' contract can name it and importers resolve it).\n *\n * @ensures result ⟺ ∃ k ∈ [i, |w|). w[k] ∈ A-Z ∪ a-z — at i = 0 exactly the model's HasAsciiLetter\n */\nexport function hasAsciiLetterFrom(w: string, i: number): boolean {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases w.length - i\n //@ ensures \\result <==> exists(k: nat, i <= k && k < w.length && ((w.charCodeAt(k) >= 65 && w.charCodeAt(k) <= 90) || (w.charCodeAt(k) >= 97 && w.charCodeAt(k) <= 122)))\n if (i >= w.length) return false;\n const c = w.charCodeAt(i);\n if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) return true;\n return hasAsciiLetterFrom(w, i + 1);\n}\n\n/**\n * `s` with a-z uppercased and every other character kept, the mirror of `lowerAscii`: JS's\n * `toUpperCase()` also maps non-ASCII letters (ß becomes \"SS\").\n *\n * @ensures |result| = |s| ∧ ∀ k < |s|. result[k] = (s[k] ∈ a-z ? s[k] − 32 : s[k]) — a-z\n * raised, every other code unit unchanged; exactly the model's UpperAscii in the link\n */\nexport function upperAscii(s: string): string {\n //@ verify\n //@ decreases s.length\n //@ ensures \\result.length === s.length\n //@ ensures forall(k: nat, k < s.length ==> \\result.charCodeAt(k) === ((s.charCodeAt(k) >= 97 && s.charCodeAt(k) <= 122) ? s.charCodeAt(k) - 32 : s.charCodeAt(k)))\n if (s.length === 0) return \"\";\n const c = s.charCodeAt(0);\n const head =\n c >= 97 && c <= 122 ? \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\".slice(c - 97, c - 96) : s.slice(0, 1);\n return head + upperAscii(s.slice(1));\n}\n","//@ backend dafny\nimport { codeAt, indexOfFrom } from \"./strings\";\n\n/* Whole-string rewrites, verified with LemmaScript → Dafny (model: models/Utils.dfy \"text\n replacement\"; link: models/links/utils-replace.dfy). Each has a recursive spec (for\n proofs and tests) and a loop proved to build exactly it (for callers: its depth doesn't\n grow with the input). The `\\result === spec(s)` clause of each loop is a hand `ensures`\n in replace.dfy, as utils `escapeHtml`'s is: lsc would put it in every importer's axiom,\n where this file's own spec isn't emitted. */\n\n// --- One substitution rule (model `Utils.Substituted`, 2026-11-03): each code unit found in a\n// table is replaced by its text, every other kept. replaceCode, pointerToken, escapeHtml and\n// the generator's look-alike fold are this rule, each with its own table.\n\n/**\n * The first index ≥ `i` holding `c` in `codes`, or -1.\n *\n * @ensures result = -1 ∨ (i ≤ result < |codes| ∧ codes[result] = c) — the model's CodeIndex\n */\nexport function codeIndex(codes: number[], c: number, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires i <= codes.length\n //@ decreases codes.length - i\n //@ ensures \\result === -1 || (i <= \\result && \\result < codes.length && codes[\\result] === c)\n // `===`, not `>=`: past the end codes[i] is undefined, never c, so `>=` vs `>` is equivalent\n if (i === codes.length) return -1;\n return (codes[i] as number) === c ? i : codeIndex(codes, c, i + 1);\n}\n\n/** `s` with each code unit in `codes` replaced by its text, recursively: the spec `substitute` builds. */\nexport function substitutedText(s: string, codes: number[], texts: string[]): string {\n //@ verify\n //@ decreases s.length\n //@ ensures s.length === 0 ==> \\result === \"\"\n //@ ensures codes.length === 0 ==> \\result === s\n if (s.length === 0) return \"\";\n const k = codeIndex(codes, s.charCodeAt(0), 0);\n const head = k >= 0 && k < texts.length ? (texts[k] as string) : s.slice(0, 1);\n return head + substitutedText(s.slice(1), codes, texts);\n}\n\n/**\n * `s` with each code unit in `codes` replaced by the text at its first index there, every\n * other kept. A loop, so its depth doesn't grow with the input.\n *\n * @ensures result = substitutedText(s, codes, texts) — the model's Substituted (a hand\n * ensures in replace.dfy: importers can't resolve substitutedText)\n * @ensures |s| = 0 ⟹ result = \"\" ∧ |codes| = 0 ⟹ result = s — no table, no change\n */\nexport function substitute(s: string, codes: number[], texts: string[]): string {\n //@ verify\n //@ ensures s.length === 0 ==> \\result === \"\"\n //@ ensures codes.length === 0 ==> \\result === s\n let out = \"\";\n // `!==`, not `<`: one step past the end reads NaN and adds \"\", so `<=` would be equivalent\n for (let i = 0; i !== s.length; i++) {\n //@ invariant 0 <= i && i <= s.length\n //@ invariant out + substitutedText(s.slice(i), codes, texts) === substitutedText(s, codes, texts)\n //@ decreases s.length - i\n const k = codeIndex(codes, s.charCodeAt(i), 0);\n out = k >= 0 && k < texts.length ? out + (texts[k] as string) : out + s.slice(i, i + 1);\n }\n return out;\n}\n\n/**\n * `s` with every `from` code unit replaced by `to`, recursively: the one-entry table.\n *\n * @ensures no `from` survives when `to` holds none — exactly the model's ReplaceCode in the link\n */\nexport function replacedCode(s: string, from: number, to: string): string {\n //@ verify\n //@ ensures forall(j: nat, j < to.length ==> to.charCodeAt(j) !== from) ==> forall(k: nat, k < \\result.length ==> \\result.charCodeAt(k) !== from)\n return substitutedText(s, [from], [to]);\n}\n\n/**\n * `s` with every `from` code unit replaced by `to` (`replaceAll` of one character).\n *\n * @ensures no `from` survives when `to` holds none (ReplaceCodeRemoves) — = replacedCode(s,\n * from, to), the model's ReplaceCode, as a hand ensures in replace.dfy\n */\nexport function replaceCode(s: string, from: number, to: string): string {\n //@ verify\n //@ ensures forall(j: nat, j < to.length ==> to.charCodeAt(j) !== from) ==> forall(k: nat, k < \\result.length ==> \\result.charCodeAt(k) !== from)\n return substitute(s, [from], [to]);\n}\n\n/**\n * `s` with its first `find` replaced by `put`; no match leaves it: JS `s.replace(find, put)` for\n * a string `find`, when `put` holds no `$` (JS reads `$&`, `$1` there as a pattern).\n *\n * @ensures exactly the model's ReplaceFirst\n */\nexport function replaceFirst(s: string, find: string, put: string): string {\n //@ verify\n //@ ensures \\result === (indexOfFrom(s, find, 0) < 0 ? s : s.slice(0, indexOfFrom(s, find, 0)) + put + s.slice(indexOfFrom(s, find, 0) + find.length))\n const i = indexOfFrom(s, find, 0);\n if (i < 0) return s;\n return s.slice(0, i) + put + s.slice(i + find.length);\n}\n\n/**\n * `s` with every `find` replaced by `put`, left to right without overlaps: JS\n * `s.split(find).join(put)` for a non-empty `find` (tests pin the two). Recursive, with no\n * loop twin: its callers fill short templates (the SDK's registry paths), so the depth stays\n * small; a long-input caller would need one.\n *\n * @requires |find| > 0 — split(\"\") splits into characters, a different rule\n * @ensures text shorter than `find` is unchanged, and so is any text when `put` = `find` —\n * exactly the model's ReplaceText in the link\n */\nexport function replaceText(s: string, find: string, put: string): string {\n //@ verify\n //@ requires find.length > 0\n //@ decreases s.length\n //@ ensures s.length < find.length ==> \\result === s\n //@ ensures put === find ==> \\result === s\n if (s.length < find.length) return s;\n if (s.slice(0, find.length) === find) {\n return put + replaceText(s.slice(find.length), find, put);\n }\n return s.slice(0, 1) + replaceText(s.slice(1), find, put);\n}\n\n/**\n * A JSON Pointer token of `s`, recursively: `~` → `~0`, `/` → `~1`.\n *\n * @ensures never holds \"/\" — exactly the model's PointerToken in the link\n */\nexport function pointerTokenOf(s: string): string {\n //@ verify\n //@ ensures forall(k: nat, k < \\result.length ==> \\result.charCodeAt(k) !== 47)\n return substitutedText(s, [126, 47], [\"~0\", \"~1\"]);\n}\n\n/**\n * `s` as a JSON Pointer reference token (RFC 6901 §3): `~` as `~0`, `/` as `~1`.\n *\n * @ensures never holds \"/\" (PointerTokenHasNoSlash) — = pointerTokenOf(s), the model's\n * PointerToken, as a hand ensures in replace.dfy\n */\nexport function pointerToken(s: string): string {\n //@ verify\n //@ ensures forall(k: nat, k < \\result.length ==> \\result.charCodeAt(k) !== 47)\n return substitute(s, [126, 47], [\"~0\", \"~1\"]);\n}\n\n/**\n * The escape of `s`, recursively: each `&` `<` `>` `\"` `'` as its entity.\n *\n * @ensures no `<` `>` `\"` `'` in result — exactly the model's EscapeHtml in the link\n */\nexport function escapedText(s: string): string {\n //@ verify\n //@ ensures forall(k: nat, k < \\result.length ==> (\\result.charCodeAt(k) !== 60 && \\result.charCodeAt(k) !== 62 && \\result.charCodeAt(k) !== 34 && \\result.charCodeAt(k) !== 39))\n return substitutedText(s, [38, 60, 62, 34, 39], [\"&amp;\", \"&lt;\", \"&gt;\", \"&quot;\", \"&#39;\"]);\n}\n\n/**\n * Escape text for an HTML body or a double-quoted attribute.\n *\n * @ensures result = escapedText(value) — exactly the model's EscapeHtml (a hand ensures in\n * replace.dfy, since importers can't see escapedText)\n * @ensures ∀ k < |result|. result[k] ∉ {\"<\", \">\", \"\\\"\", \"'\"} — nothing in the output can\n * open a tag or close the attribute; \"&\" appears only as the start of an entity\n */\nexport function escapeHtml(value: string): string {\n //@ verify\n //@ ensures forall(k: nat, k < \\result.length ==> (\\result.charCodeAt(k) !== 60 && \\result.charCodeAt(k) !== 62 && \\result.charCodeAt(k) !== 34 && \\result.charCodeAt(k) !== 39))\n return substitute(value, [38, 60, 62, 34, 39], [\"&amp;\", \"&lt;\", \"&gt;\", \"&quot;\", \"&#39;\"]);\n}\n\n/**\n * The code units a JSON string escapes: `\"`, `\\`, then the control characters with short\n * escapes (\\b \\t \\n \\f \\r), then the other code units below 0x20.\n *\n * @ensures exactly the model's JsonCodes\n */\nexport function jsonCodes(): number[] {\n //@ verify\n //@ ensures \\result === [34, 92, 8, 9, 10, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]\n return [\n 34, 92, 8, 9, 10, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\n 24, 25, 26, 27, 28, 29, 30, 31,\n ];\n}\n\n/**\n * Each `jsonCodes` entry's escape (ECMA-262 QuoteJSONString; lowercase hex, as JSON.stringify).\n *\n * @ensures exactly the model's JsonTexts\n */\nexport function jsonTexts(): string[] {\n //@ verify\n //@ ensures \\result === [\"\\\\\\\"\", \"\\\\\\\\\", \"\\\\b\", \"\\\\t\", \"\\\\n\", \"\\\\f\", \"\\\\r\", \"\\\\u0000\", \"\\\\u0001\", \"\\\\u0002\", \"\\\\u0003\", \"\\\\u0004\", \"\\\\u0005\", \"\\\\u0006\", \"\\\\u0007\", \"\\\\u000b\", \"\\\\u000e\", \"\\\\u000f\", \"\\\\u0010\", \"\\\\u0011\", \"\\\\u0012\", \"\\\\u0013\", \"\\\\u0014\", \"\\\\u0015\", \"\\\\u0016\", \"\\\\u0017\", \"\\\\u0018\", \"\\\\u0019\", \"\\\\u001a\", \"\\\\u001b\", \"\\\\u001c\", \"\\\\u001d\", \"\\\\u001e\", \"\\\\u001f\"]\n return [\n '\\\\\"',\n \"\\\\\\\\\",\n \"\\\\b\",\n \"\\\\t\",\n \"\\\\n\",\n \"\\\\f\",\n \"\\\\r\",\n \"\\\\u0000\",\n \"\\\\u0001\",\n \"\\\\u0002\",\n \"\\\\u0003\",\n \"\\\\u0004\",\n \"\\\\u0005\",\n \"\\\\u0006\",\n \"\\\\u0007\",\n \"\\\\u000b\",\n \"\\\\u000e\",\n \"\\\\u000f\",\n \"\\\\u0010\",\n \"\\\\u0011\",\n \"\\\\u0012\",\n \"\\\\u0013\",\n \"\\\\u0014\",\n \"\\\\u0015\",\n \"\\\\u0016\",\n \"\\\\u0017\",\n \"\\\\u0018\",\n \"\\\\u0019\",\n \"\\\\u001a\",\n \"\\\\u001b\",\n \"\\\\u001c\",\n \"\\\\u001d\",\n \"\\\\u001e\",\n \"\\\\u001f\",\n ];\n}\n\n/**\n * A string as JSON text, as `JSON.stringify(s)` writes it for well-formed text: quoted, `\"`\n * and `\\` backslashed, control characters escaped. A lone surrogate is kept as it is\n * (JSON.stringify writes `\\udxxx`); callers pass well-formed text. Built by the `substitute`\n * loop, so its depth doesn't grow with the text (an FAQ answer can be long; Fable review\n * 2026-11-06); importers still see a function (its contract as an axiom), so their premise\n * `jsonString(s) == Utils.JsonString(s)` stands.\n *\n * @ensures result = `\"` + substitutedText(s, jsonCodes(), jsonTexts()) + `\"` — a hand ensures in\n * replace.dfy; the model's JsonString (proved in links/utils-replace.dfy)\n * @ensures result starts and ends with `\"`\n */\nexport function jsonString(s: string): string {\n //@ verify\n //@ ensures \\result.length >= 2 && \\result.charCodeAt(0) === 34 && \\result.charCodeAt(\\result.length - 1) === 34\n return '\"' + substitute(s, jsonCodes(), jsonTexts()) + '\"';\n}\n\n/**\n * `s` with every `*` `/` pair written `* /`, recursively: the spec `commentSafe` builds.\n *\n * @ensures no \"*\" \"/\" pair in result — exactly the model's CommentSafe in the link\n */\nexport function commentSafeOf(s: string): string {\n //@ verify\n //@ decreases s.length\n //@ ensures forall(k: nat, k + 1 < \\result.length ==> !(\\result.charCodeAt(k) === 42 && \\result.charCodeAt(k + 1) === 47))\n if (s.length === 0) return \"\";\n if (codeAt(s, 0) === 42 && codeAt(s, 1) === 47) {\n return \"* /\" + commentSafeOf(s.slice(2));\n }\n return s.slice(0, 1) + commentSafeOf(s.slice(1));\n}\n\n/**\n * Text safe inside a `/* … *\\/` comment: every `*` `/` pair written `* /`.\n *\n * @ensures no \"*\" \"/\" pair in result: nothing can close the comment — = commentSafeOf(s), the\n * model's CommentSafe, as a hand ensures in replace.dfy\n */\nexport function commentSafe(s: string): string {\n //@ verify\n //@ ensures forall(k: nat, k + 1 < \\result.length ==> !(\\result.charCodeAt(k) === 42 && \\result.charCodeAt(k + 1) === 47))\n let out = \"\";\n let i = 0;\n while (i !== s.length) {\n //@ invariant 0 <= i && i <= s.length\n //@ invariant out + commentSafeOf(s.slice(i)) === commentSafeOf(s)\n //@ decreases s.length - i\n if (codeAt(s, i) === 42 && codeAt(s, i + 1) === 47) {\n out = out + \"* /\";\n i = i + 2;\n } else {\n out = out + s.slice(i, i + 1);\n i = i + 1;\n }\n }\n return out;\n}\n","//@ backend dafny\nimport { codeAt, indexOfCode, startsWithAt, untilCode } from \"@atlas/utils/strings\";\nimport { replaceCode } from \"@atlas/utils/replace\";\n\n/* The components' decisions, as pure functions verified with LemmaScript → Dafny (model:\n models/AugurWeb.dfy; link: models/links/augur-web-rules.dfy). JSX, the DOM, timers,\n `parseFloat`/`toFixed` and `Math.random` stay in the components. */\n\n/** One entry of a pagination bar: a page number or an ellipsis. */\nexport type PageEntry = { kind: \"page\"; n: number } | { kind: \"ellipsis\" };\n\n/**\n * Pages i + 1 … total, in order.\n *\n * @ensures exactly the model's Range1\n */\nexport function pageRangeFrom(total: number, i: number): PageEntry[] {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases total - i\n //@ ensures i >= total ==> \\result.length === 0\n //@ ensures i < total ==> \\result.length === total - i\n if (i >= total) return [];\n return [{ kind: \"page\", n: i + 1 }, ...pageRangeFrom(total, i + 1)];\n}\n\n/**\n * getPageNumbers: none for no pages; all of them up to 5; else the first, the last, and a window\n * around the (clamped) current page with ellipses.\n *\n * @ensures exactly the model's PageNumbers\n */\nexport function pageNumbersOf(current: number, total: number): PageEntry[] {\n //@ verify\n //@ ensures total <= 0 ==> \\result.length === 0\n //@ ensures total === 1 ==> \\result.length === 1\n if (total <= 0) return [];\n if (total === 1) return [{ kind: \"page\", n: 1 }];\n const page = clampPage(current, total);\n if (total <= 5) return pageRangeFrom(total, 0);\n const first: PageEntry = { kind: \"page\", n: 1 };\n const last: PageEntry = { kind: \"page\", n: total };\n const gap: PageEntry = { kind: \"ellipsis\" };\n if (page <= 3) {\n return [\n first,\n { kind: \"page\", n: 2 },\n { kind: \"page\", n: 3 },\n { kind: \"page\", n: 4 },\n gap,\n last,\n ];\n }\n if (page >= total - 2) {\n return [\n first,\n gap,\n { kind: \"page\", n: total - 3 },\n { kind: \"page\", n: total - 2 },\n { kind: \"page\", n: total - 1 },\n last,\n ];\n }\n return [\n first,\n gap,\n { kind: \"page\", n: page - 1 },\n { kind: \"page\", n: page },\n { kind: \"page\", n: page + 1 },\n gap,\n last,\n ];\n}\n\n/**\n * The current page clamped to [1, total] (`Math.max(1, Math.min(current, total))`).\n *\n * @ensures result = 1 below 1, total above it, else current\n */\nexport function clampPage(current: number, total: number): number {\n //@ verify\n //@ ensures current > total && total >= 1 ==> \\result === total\n //@ ensures current > total && total < 1 ==> \\result === 1\n //@ ensures current <= total && current < 1 ==> \\result === 1\n //@ ensures current <= total && current >= 1 ==> \\result === current\n const capped = current > total ? total : current;\n return capped < 1 ? 1 : capped;\n}\n\n/**\n * ListPagination's first page: at or before page 1 (on the unclamped page).\n *\n * @ensures exactly the model's IsFirstPage\n */\nexport function isFirstPage(page: number): boolean {\n //@ verify\n //@ ensures \\result === (page <= 1)\n return page <= 1;\n}\n\n/**\n * ListPagination's last page: at or past the total (on the unclamped page).\n *\n * @ensures exactly the model's IsLastPage\n */\nexport function isLastPage(page: number, totalPages: number): boolean {\n //@ verify\n //@ ensures \\result === (page >= totalPages)\n return page >= totalPages;\n}\n\n/**\n * The Prev link's target: page 1 on the first page, else the one before.\n *\n * @ensures exactly the model's PrevTarget\n */\nexport function prevTarget(page: number): number {\n //@ verify\n //@ ensures isFirstPage(page) ==> \\result === 1\n //@ ensures !isFirstPage(page) ==> \\result === page - 1\n return isFirstPage(page) ? 1 : page - 1;\n}\n\n/**\n * The Next link's target: the last page on it, else the one after.\n *\n * @ensures exactly the model's NextTarget\n */\nexport function nextTarget(page: number, totalPages: number): number {\n //@ verify\n //@ ensures isLastPage(page, totalPages) ==> \\result === totalPages\n //@ ensures !isLastPage(page, totalPages) ==> \\result === page + 1\n return isLastPage(page, totalPages) ? totalPages : page + 1;\n}\n\n/**\n * commit's clamp: at least min, then at most max when there is one (max wins if max < min).\n *\n * @ensures exactly the model's Clamp\n */\nexport function clampQuantity(value: number, min: number, max: number | undefined): number {\n //@ verify\n //@ ensures max === undefined ==> \\result === (value < min ? min : value)\n //@ ensures max !== undefined && (value < min ? min : value) > max ==> \\result === max\n //@ ensures max !== undefined && (value < min ? min : value) <= max ==> \\result === (value < min ? min : value)\n const atLeast = value < min ? min : value;\n if (max === undefined) return atLeast;\n return atLeast > max ? max : atLeast;\n}\n\n/**\n * The decrease stepper: one step down, not below min (`Math.max(value - step, min)`).\n *\n * @ensures exactly the model's StepDown\n */\nexport function stepDown(value: number, step: number, min: number): number {\n //@ verify\n //@ ensures value - step > min ==> \\result === value - step\n //@ ensures value - step <= min ==> \\result === min\n return value - step > min ? value - step : min;\n}\n\n/**\n * The increase stepper: one step up, not above max when there is one.\n *\n * @ensures exactly the model's StepUp\n */\nexport function stepUp(value: number, step: number, max: number | undefined): number {\n //@ verify\n //@ ensures max === undefined ==> \\result === value + step\n //@ ensures max !== undefined && value + step > max ==> \\result === max\n //@ ensures max !== undefined && value + step <= max ==> \\result === value + step\n if (max === undefined) return value + step;\n return value + step > max ? max : value + step;\n}\n\n/**\n * The decrease button is off when the input is, or the value is already at the minimum.\n *\n * @ensures exactly the model's MinDisabled\n */\nexport function decreaseDisabled(disabled: boolean, value: number, min: number): boolean {\n //@ verify\n //@ ensures \\result === (disabled || value <= min)\n return disabled || value <= min;\n}\n\n/**\n * The increase button is off when the input is, or the value is already at the maximum.\n *\n * @ensures exactly the model's MaxDisabled\n */\nexport function increaseDisabled(\n disabled: boolean,\n value: number,\n max: number | undefined,\n): boolean {\n //@ verify\n //@ ensures max === undefined ==> \\result === disabled\n //@ ensures max !== undefined ==> \\result === (disabled || value >= max)\n if (max === undefined) return disabled;\n return disabled || value >= max;\n}\n\n/**\n * The quantity input's digit test, JS's `key >= \"0\" && key <= \"9\"` (string order): a first code\n * unit 0–8 with anything after it, or exactly \"9\".\n *\n * @ensures exactly the model's KeyAllowed digit clause\n */\nexport function digitKey(key: string): boolean {\n //@ verify\n //@ ensures \\result === ((codeAt(key, 0) >= 48 && codeAt(key, 0) <= 56) || key === \"9\")\n const c = codeAt(key, 0);\n return (c >= 48 && c <= 56) || key === \"9\";\n}\n\n/**\n * The editing and navigation keys the input always lets through.\n *\n * @ensures result ⟺ key ∈ {Backspace, Delete, ArrowLeft, ArrowRight, Tab, Enter}\n */\nexport function editingKey(key: string): boolean {\n //@ verify\n //@ ensures \\result === (key === \"Backspace\" || key === \"Delete\" || key === \"ArrowLeft\" || key === \"ArrowRight\" || key === \"Tab\" || key === \"Enter\")\n return (\n key === \"Backspace\" ||\n key === \"Delete\" ||\n key === \"ArrowLeft\" ||\n key === \"ArrowRight\" ||\n key === \"Tab\" ||\n key === \"Enter\"\n );\n}\n\n/**\n * A keypress is allowed: an editing key, one \".\" when decimals are allowed, or a digit.\n *\n * @ensures exactly the model's KeyAllowed\n */\nexport function keyAllowed(key: string, decimals: number, hasDot: boolean): boolean {\n //@ verify\n //@ ensures \\result === (editingKey(key) || (decimals > 0 && key === \".\" && !hasDot) || digitKey(key))\n return editingKey(key) || (decimals > 0 && key === \".\" && !hasDot) || digitKey(key);\n}\n\n/**\n * handleChange from index `i`: digits only, plus the first \".\" when decimals are allowed.\n *\n * @ensures exactly the model's CleanQtyFrom\n */\nexport function cleanQtyFrom(raw: string, allowDot: boolean, seenDot: boolean, i: number): string {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases raw.length - i\n //@ ensures i >= raw.length ==> \\result === \"\"\n if (i >= raw.length) return \"\";\n const c = codeAt(raw, i);\n if (c >= 48 && c <= 57) return raw.slice(i, i + 1) + cleanQtyFrom(raw, allowDot, seenDot, i + 1);\n if (allowDot && c === 46 && !seenDot) return \".\" + cleanQtyFrom(raw, allowDot, true, i + 1);\n return cleanQtyFrom(raw, allowDot, seenDot, i + 1);\n}\n\n/** What a stock label shows. */\nexport type StockView = \"loading\" | \"out-of-stock\" | \"low-stock\" | \"in-stock\";\n\n/**\n * Loading first; out of stock overrides low stock.\n *\n * @ensures exactly the model's StockViewOf\n */\nexport function stockViewOf(loading: boolean, isInStock: boolean, isLowStock: boolean): StockView {\n //@ verify\n //@ ensures loading ==> \\result === \"loading\"\n //@ ensures !loading && !isInStock ==> \\result === \"out-of-stock\"\n //@ ensures !loading && isInStock && isLowStock ==> \\result === \"low-stock\"\n //@ ensures !loading && isInStock && !isLowStock ==> \\result === \"in-stock\"\n if (loading) return \"loading\";\n if (!isInStock) return \"out-of-stock\";\n return isLowStock ? \"low-stock\" : \"in-stock\";\n}\n\n/**\n * The quantity shows only when given and the item is in stock (low or not).\n *\n * @ensures exactly the model's ShowStockQuantity\n */\nexport function showStockQuantity(view: StockView, hasQuantity: boolean): boolean {\n //@ verify\n //@ ensures \\result === (hasQuantity && view !== \"out-of-stock\" && view !== \"loading\")\n return hasQuantity && view !== \"out-of-stock\" && view !== \"loading\";\n}\n\n/** What a price shows. */\nexport type PriceView = \"skeleton\" | \"zero-label\" | \"amount\";\n\n/**\n * Loading first; a 0 value with no original price shows the zero label (\"Call for Price\").\n *\n * @ensures exactly the model's PriceViewOf\n */\nexport function priceViewOf(\n loading: boolean,\n valueIsZero: boolean,\n hasOriginal: boolean,\n): PriceView {\n //@ verify\n //@ ensures loading ==> \\result === \"skeleton\"\n //@ ensures !loading && valueIsZero && !hasOriginal ==> \\result === \"zero-label\"\n //@ ensures !loading && !(valueIsZero && !hasOriginal) ==> \\result === \"amount\"\n if (loading) return \"skeleton\";\n if (valueIsZero && !hasOriginal) return \"zero-label\";\n return \"amount\";\n}\n\n/**\n * A CSV field needs quotes iff it holds a comma, a quote or a line feed (a carriage return alone\n * does not).\n *\n * @ensures exactly the model's NeedsQuotes\n */\nexport function needsQuotes(s: string): boolean {\n //@ verify\n //@ ensures \\result === (indexOfCode(s, 44, 0) >= 0 || indexOfCode(s, 34, 0) >= 0 || indexOfCode(s, 10, 0) >= 0)\n return indexOfCode(s, 44, 0) >= 0 || indexOfCode(s, 34, 0) >= 0 || indexOfCode(s, 10, 0) >= 0;\n}\n\n/**\n * A CSV field: quoted, with quotes doubled, when it needs quotes; else as is.\n *\n * @ensures exactly the model's CsvField\n */\nexport function csvField(s: string): string {\n //@ verify\n //@ ensures needsQuotes(s) ==> \\result === \"\\\"\" + replaceCode(s, 34, \"\\\"\\\"\") + \"\\\"\"\n //@ ensures !needsQuotes(s) ==> \\result === s\n if (!needsQuotes(s)) return s;\n return '\"' + replaceCode(s, 34, '\"\"') + '\"';\n}\n\n/** A column's sort direction. */\nexport type SortDir = \"asc\" | \"desc\" | \"unsorted\";\n\n/**\n * aria-sort: only on a sortable column, naming its direction. A string, not a literal union:\n * lsc names a `\"none\"` literal `None`, which clashes with Option's (models/LSC-GAPS.md).\n *\n * @ensures exactly the model's AriaSort\n */\nexport function ariaSortOf(sortable: boolean, dir: SortDir): string | undefined {\n //@ verify\n //@ ensures !sortable ==> \\result === undefined\n //@ ensures sortable && dir === \"asc\" ==> \\result === \"ascending\"\n //@ ensures sortable && dir === \"desc\" ==> \\result === \"descending\"\n //@ ensures sortable && dir === \"unsorted\" ==> \\result === \"none\"\n if (!sortable) return undefined;\n if (dir === \"asc\") return \"ascending\";\n if (dir === \"desc\") return \"descending\";\n return \"none\";\n}\n\n/**\n * A column's cell alignment class from its meta's `align` (\"left\" when it has none); any other\n * value has none.\n *\n * @ensures exactly the model's AlignClass\n */\nexport function alignClass(align: string): string {\n //@ verify\n //@ ensures align === \"left\" ==> \\result === \"text-left\"\n //@ ensures align === \"center\" ==> \\result === \"text-center\"\n //@ ensures align === \"right\" ==> \\result === \"text-right\"\n //@ ensures align !== \"left\" && align !== \"center\" && align !== \"right\" ==> \\result === \"\"\n if (align === \"left\") return \"text-left\";\n if (align === \"center\") return \"text-center\";\n return align === \"right\" ? \"text-right\" : \"\";\n}\n\n/** What the table body shows. */\nexport type BodyView = \"loading\" | \"empty\" | \"rows\";\n\n/**\n * Loading first, then the empty message for no rows.\n *\n * @ensures exactly the model's BodyViewOf\n */\nexport function bodyViewOf(loading: boolean, rowCount: number): BodyView {\n //@ verify\n //@ ensures loading ==> \\result === \"loading\"\n //@ ensures !loading && rowCount === 0 ==> \\result === \"empty\"\n //@ ensures !loading && rowCount !== 0 ==> \\result === \"rows\"\n if (loading) return \"loading\";\n return rowCount === 0 ? \"empty\" : \"rows\";\n}\n\n/** When GTM loads. */\nexport type LoadTiming = \"idle\" | \"next-tick\" | \"now\";\n\n/**\n * GTM loads at idle for lazyOnload when the browser has requestIdleCallback, on the next tick for\n * afterInteractive, else at once.\n *\n * @ensures exactly the model's GtmTiming\n */\nexport function gtmTiming(strategy: string, hasIdleCallback: boolean): LoadTiming {\n //@ verify\n //@ ensures strategy === \"lazyOnload\" && hasIdleCallback ==> \\result === \"idle\"\n //@ ensures !(strategy === \"lazyOnload\" && hasIdleCallback) && strategy === \"afterInteractive\" ==> \\result === \"next-tick\"\n //@ ensures !(strategy === \"lazyOnload\" && hasIdleCallback) && strategy !== \"afterInteractive\" ==> \\result === \"now\"\n if (strategy === \"lazyOnload\" && hasIdleCallback) return \"idle\";\n return strategy === \"afterInteractive\" ? \"next-tick\" : \"now\";\n}\n\n/**\n * Session replay is injected unless disabled or already there, and, under a rate below 1, only\n * when the draw is at or under it.\n *\n * @ensures exactly the model's ReplaySampled\n */\nexport function replaySampled(\n disabled: boolean,\n injected: boolean,\n rate: number,\n draw: number,\n): boolean {\n //@ verify\n //@ type rate real\n //@ type draw real\n //@ ensures \\result === (!disabled && !injected && !(rate < 1 && draw > rate))\n return !disabled && !injected && !(rate < 1 && draw > rate);\n}\n\n/**\n * A \"?\" or \"&\" at `k`, \"Bin=\" right after it, and a value character (not \"&\") after that: what\n * `[?&]Bin=[^&]` matches there.\n *\n * @ensures result ⟺ s[k] ∈ {?, &} ∧ s[k+1 ..] starts with \"Bin=\" ∧ s[k+5] is a char ≠ \"&\"\n */\nexport function binMarkAt(s: string, k: number): boolean {\n //@ verify\n //@ type k nat\n //@ requires k >= 0\n //@ ensures \\result === ((codeAt(s, k) === 63 || codeAt(s, k) === 38) && startsWithAt(s, \"Bin=\", k + 1) && codeAt(s, k + 5) >= 0 && codeAt(s, k + 5) !== 38)\n const c = codeAt(s, k);\n const v = codeAt(s, k + 5);\n return (c === 63 || c === 38) && startsWithAt(s, \"Bin=\", k + 1) && v >= 0 && v !== 38;\n}\n\n/**\n * The first \"?Bin=\" or \"&Bin=\" from index `i` with a value after it, or −1 (the regex skips a\n * mark with an empty value and keeps searching).\n *\n * @ensures result is the first k ≥ i with k + 6 ≤ |s| where `binMarkAt(s, k)`, else −1 —\n * exactly the model's BinAt\n */\nexport function binAt(s: string, i: number): number {\n //@ verify\n //@ type i nat\n //@ requires i >= 0\n //@ decreases s.length - i\n //@ ensures \\result === -1 || (i <= \\result && \\result + 6 <= s.length)\n //@ ensures \\result >= 0 ==> binMarkAt(s, \\result)\n //@ ensures \\result >= 0 ==> forall(k: nat, (i <= k && k < \\result) ==> !binMarkAt(s, k))\n //@ ensures \\result === -1 ==> forall(k: nat, (i <= k && k + 6 <= s.length) ==> !binMarkAt(s, k))\n if (i + 6 > s.length) return -1;\n if (binMarkAt(s, i)) return i;\n return binAt(s, i + 1);\n}\n\n/**\n * extractBin from a message string (`/[?&]Bin=([^&]+)/`): the first mark's value up to the next\n * \"&\" (never empty), or undefined.\n *\n * @ensures exactly the model's BinFromString\n */\nexport function binFromString(s: string): string | undefined {\n //@ verify\n //@ ensures binAt(s, 0) < 0 ==> \\result === undefined\n //@ ensures binAt(s, 0) >= 0 ==> \\result === untilCode(afterBinMark(s, binAt(s, 0)), 38)\n const k = binAt(s, 0);\n if (k < 0) return undefined;\n return untilCode(afterBinMark(s, k), 38);\n}\n\n/**\n * The text after a \"?Bin=\" mark at `k`, or \"\" when no mark fits there (`binAt` never gives\n * such a k; the guard keeps the slice in range for the proof).\n *\n * @ensures result = s[k + 5 ..] when 0 ≤ k ∧ k + 5 ≤ |s|, else \"\"\n */\nexport function afterBinMark(s: string, k: number): string {\n //@ verify\n //@ ensures (k < 0 || k + 5 > s.length) ==> \\result === \"\"\n //@ ensures !(k < 0 || k + 5 > s.length) ==> \\result === s.slice(k + 5)\n if (k < 0 || k + 5 > s.length) return \"\";\n return s.slice(k + 5);\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/augur-packages/augur-packages/packages/augur-web/dist/chunk-JXW4XE2P.cjs","../src/dropdown-menu.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/augur-packages/augur-packages/packages/augur-web/dist/chunk-JXW4XE2P.cjs","sourcesContent":[null,"/** Styled wrapper around @radix-ui/react-dropdown-menu. See https://www.radix-ui.com/primitives/docs/components/dropdown-menu */\n\"use client\";\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { LuCheck, LuChevronRight, LuCircle } from \"react-icons/lu\";\nimport { cn } from \"@simpleapps-com/augur-utils/web\";\n\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"focus:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n >\n {children}\n <LuChevronRight className=\"ml-auto\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;\n\nconst DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nconst DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <LuCheck className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <LuCircle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\"px-2 py-1.5 text-sm font-semibold\", inset && \"pl-8\", className)}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"bg-muted -mx-1 my-1 h-px\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\nconst DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)} {...props} />\n );\n};\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n};\n"]}
1
+ {"version":3,"sources":["/Users/stuartjackson/Projects/simpleapps/atlas/repo/packages/augur-web/dist/chunk-JXW4XE2P.cjs","../src/dropdown-menu.tsx"],"names":[],"mappings":"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","file":"/Users/stuartjackson/Projects/simpleapps/atlas/repo/packages/augur-web/dist/chunk-JXW4XE2P.cjs","sourcesContent":[null,"/** Styled wrapper around @radix-ui/react-dropdown-menu. See https://www.radix-ui.com/primitives/docs/components/dropdown-menu */\n\"use client\";\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { LuCheck, LuChevronRight, LuCircle } from \"react-icons/lu\";\nimport { cn } from \"@simpleapps-com/augur-utils/web\";\n\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"focus:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n >\n {children}\n <LuChevronRight className=\"ml-auto\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;\n\nconst DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nconst DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <LuCheck className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <LuCircle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\"px-2 py-1.5 text-sm font-semibold\", inset && \"pl-8\", className)}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"bg-muted -mx-1 my-1 h-px\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\nconst DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)} {...props} />\n );\n};\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n};\n"]}
@@ -1,4 +1,11 @@
1
1
  "use client";
2
+ import {
3
+ isFirstPage,
4
+ isLastPage,
5
+ nextTarget,
6
+ pageNumbersOf,
7
+ prevTarget
8
+ } from "./chunk-IO77MGHW.js";
2
9
  import {
3
10
  buttonVariants
4
11
  } from "./chunk-QICSGVX3.js";
@@ -86,19 +93,9 @@ var PaginationEllipsis = ({ className, ...props }) => /* @__PURE__ */ jsxs(
86
93
  );
87
94
  PaginationEllipsis.displayName = "PaginationEllipsis";
88
95
  function getPageNumbers(current, total) {
89
- if (total <= 0) return [];
90
- if (total === 1) return [1];
91
- const page = Math.max(1, Math.min(current, total));
92
- if (total <= 5) {
93
- return Array.from({ length: total }, (_, i) => i + 1);
94
- }
95
- if (page <= 3) {
96
- return [1, 2, 3, 4, "ellipsis", total];
97
- }
98
- if (page >= total - 2) {
99
- return [1, "ellipsis", total - 3, total - 2, total - 1, total];
100
- }
101
- return [1, "ellipsis", page - 1, page, page + 1, "ellipsis", total];
96
+ return pageNumbersOf(current, total).map(
97
+ (entry) => entry.kind === "page" ? entry.n : "ellipsis"
98
+ );
102
99
  }
103
100
  var ListPagination = ({
104
101
  page,
@@ -109,8 +106,8 @@ var ListPagination = ({
109
106
  }) => {
110
107
  if (totalPages <= 1) return null;
111
108
  const pages = getPageNumbers(page, totalPages);
112
- const isFirst = page <= 1;
113
- const isLast = page >= totalPages;
109
+ const isFirst = isFirstPage(page);
110
+ const isLast = isLastPage(page, totalPages);
114
111
  const handleClick = (target) => (e) => {
115
112
  if (onPageChange) {
116
113
  e.preventDefault();
@@ -122,7 +119,7 @@ var ListPagination = ({
122
119
  /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(
123
120
  PaginationPrevious,
124
121
  {
125
- href: isFirst ? getHref(1) : getHref(page - 1),
122
+ href: getHref(prevTarget(page)),
126
123
  "aria-disabled": isFirst || void 0,
127
124
  className: isFirst ? "pointer-events-none opacity-50" : void 0,
128
125
  onClick: isFirst ? preventDisabled : handleClick(page - 1)
@@ -142,7 +139,7 @@ var ListPagination = ({
142
139
  /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(
143
140
  PaginationNext,
144
141
  {
145
- href: isLast ? getHref(totalPages) : getHref(page + 1),
142
+ href: getHref(nextTarget(page, totalPages)),
146
143
  "aria-disabled": isLast || void 0,
147
144
  className: isLast ? "pointer-events-none opacity-50" : void 0,
148
145
  onClick: isLast ? preventDisabled : handleClick(page + 1)
@@ -163,4 +160,4 @@ export {
163
160
  getPageNumbers,
164
161
  ListPagination
165
162
  };
166
- //# sourceMappingURL=chunk-OJ5G4BLS.js.map
163
+ //# sourceMappingURL=chunk-KVHOMD4T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pagination.tsx"],"sourcesContent":["/** Pagination navigation components, styled with buttonVariants. */\n\"use client\";\n\nimport * as React from \"react\";\nimport { LuChevronLeft, LuChevronRight, LuEllipsis } from \"react-icons/lu\";\nimport { cn } from \"@simpleapps-com/augur-utils/web\";\nimport { type ButtonProps, buttonVariants } from \"./button\";\nimport { isFirstPage, isLastPage, nextTarget, pageNumbersOf, prevTarget } from \"./rules\";\n\nconst Pagination = ({ className, ...props }: React.ComponentProps<\"nav\">) => (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n);\nPagination.displayName = \"Pagination\";\n\nconst PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<\"ul\">>(\n ({ className, ...props }, ref) => (\n <ul ref={ref} className={cn(\"flex flex-row items-center gap-1\", className)} {...props} />\n ),\n);\nPaginationContent.displayName = \"PaginationContent\";\n\nconst PaginationItem = React.forwardRef<HTMLLIElement, React.ComponentProps<\"li\">>(\n ({ className, ...props }, ref) => <li ref={ref} className={cn(\"\", className)} {...props} />,\n);\nPaginationItem.displayName = \"PaginationItem\";\n\ntype PaginationLinkProps = {\n isActive?: boolean;\n} & Pick<ButtonProps, \"size\"> &\n React.ComponentProps<\"a\">;\n\nconst PaginationLink = ({ className, isActive, size = \"icon\", ...props }: PaginationLinkProps) => (\n <a\n aria-current={isActive ? \"page\" : undefined}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className,\n )}\n {...props}\n />\n);\nPaginationLink.displayName = \"PaginationLink\";\n\nconst PaginationPrevious = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 pl-2.5\", className)}\n {...props}\n >\n <LuChevronLeft className=\"h-4 w-4\" />\n <span>Prev</span>\n </PaginationLink>\n);\nPaginationPrevious.displayName = \"PaginationPrevious\";\n\nconst PaginationNext = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 pr-2.5\", className)}\n {...props}\n >\n <span>Next</span>\n <LuChevronRight className=\"h-4 w-4\" />\n </PaginationLink>\n);\nPaginationNext.displayName = \"PaginationNext\";\n\nconst PaginationEllipsis = ({ className, ...props }: React.ComponentProps<\"span\">) => (\n <span\n aria-hidden\n className={cn(\"flex h-9 w-9 items-center justify-center\", className)}\n {...props}\n >\n <LuEllipsis className=\"h-4 w-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n);\nPaginationEllipsis.displayName = \"PaginationEllipsis\";\n\n/** Build an array of page numbers and ellipsis markers for pagination UI. */\nfunction getPageNumbers(current: number, total: number): (number | \"ellipsis\")[] {\n return pageNumbersOf(current, total).map((entry) =>\n entry.kind === \"page\" ? entry.n : \"ellipsis\",\n );\n}\n\ntype ListPaginationProps = {\n /** Current page number (1-indexed). */\n page: number;\n /** Total number of pages. */\n totalPages: number;\n /** Builds a crawlable href for each page link (required for SEO). */\n getHref: (page: number) => string;\n /** Optional client-side callback layered on top of href navigation. */\n onPageChange?: (page: number) => void;\n className?: string;\n};\n\nconst ListPagination = ({\n page,\n totalPages,\n getHref,\n onPageChange,\n className,\n}: ListPaginationProps) => {\n if (totalPages <= 1) return null;\n\n const pages = getPageNumbers(page, totalPages);\n const isFirst = isFirstPage(page);\n const isLast = isLastPage(page, totalPages);\n\n const handleClick = (target: number) => (e: React.MouseEvent) => {\n if (onPageChange) {\n e.preventDefault();\n onPageChange(target);\n }\n };\n\n // Disabled Prev/Next keep an href for layout, but MUST NOT navigate\n // (pointer-events-none blocks the mouse, not keyboard activation).\n const preventDisabled = (e: React.MouseEvent) => e.preventDefault();\n\n return (\n <Pagination className={className}>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious\n href={getHref(prevTarget(page))}\n aria-disabled={isFirst || undefined}\n className={isFirst ? \"pointer-events-none opacity-50\" : undefined}\n onClick={isFirst ? preventDisabled : handleClick(page - 1)}\n />\n </PaginationItem>\n\n {pages.map((entry, i) =>\n entry === \"ellipsis\" ? (\n <PaginationItem key={`ellipsis-${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={entry}>\n <PaginationLink\n href={getHref(entry)}\n isActive={entry === page}\n onClick={handleClick(entry)}\n >\n {entry}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n\n <PaginationItem>\n <PaginationNext\n href={getHref(nextTarget(page, totalPages))}\n aria-disabled={isLast || undefined}\n className={isLast ? \"pointer-events-none opacity-50\" : undefined}\n onClick={isLast ? preventDisabled : handleClick(page + 1)}\n />\n </PaginationItem>\n </PaginationContent>\n </Pagination>\n );\n};\nListPagination.displayName = \"ListPagination\";\n\nexport {\n Pagination,\n PaginationContent,\n PaginationLink,\n PaginationItem,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n getPageNumbers,\n ListPagination,\n};\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/augur-packages/augur-packages/packages/augur-web/dist/chunk-MAENILZP.cjs","../src/label.tsx"],"names":[],"mappings":"AAAA,uWAAY;AACZ;AACA;ACCA,2EAAuB;AACvB,8GAAgC;AAChC,kEAAuC;AACvC,sDAAmB;AAUjB,+CAAA;AARF,IAAM,cAAA,EAAgB,yCAAA;AAAA,EACpB;AACF,CAAA;AAEA,IAAM,MAAA,EAAc,KAAA,CAAA,UAAA,CAGlB,CAAC,EAAE,SAAA,EAAW,GAAG,MAAM,CAAA,EAAG,GAAA,EAAA,mBAC1B,6BAAA,cAAgB,CAAA,IAAA,EAAf,EAAoB,GAAA,EAAU,SAAA,EAAW,qBAAA,aAAG,CAAc,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,MAAA,CAAO,CACtF,CAAA;AACD,KAAA,CAAM,YAAA,EAA6B,cAAA,CAAA,IAAA,CAAK,WAAA;ADLxC;AACA;AACE;AACF,sBAAC","file":"/home/runner/work/augur-packages/augur-packages/packages/augur-web/dist/chunk-MAENILZP.cjs","sourcesContent":[null,"/** Styled wrapper around @radix-ui/react-label. See https://www.radix-ui.com/primitives/docs/components/label */\n\"use client\";\n\nimport * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@simpleapps-com/augur-utils/web\";\n\nconst labelVariants = cva(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n);\n\nconst Label = React.forwardRef<\n React.ComponentRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n"]}
1
+ {"version":3,"sources":["/Users/stuartjackson/Projects/simpleapps/atlas/repo/packages/augur-web/dist/chunk-MAENILZP.cjs","../src/label.tsx"],"names":[],"mappings":"AAAA,uWAAY;AACZ;AACA;ACCA,2EAAuB;AACvB,8GAAgC;AAChC,kEAAuC;AACvC,sDAAmB;AAUjB,+CAAA;AARF,IAAM,cAAA,EAAgB,yCAAA;AAAA,EACpB;AACF,CAAA;AAEA,IAAM,MAAA,EAAc,KAAA,CAAA,UAAA,CAGlB,CAAC,EAAE,SAAA,EAAW,GAAG,MAAM,CAAA,EAAG,GAAA,EAAA,mBAC1B,6BAAA,cAAgB,CAAA,IAAA,EAAf,EAAoB,GAAA,EAAU,SAAA,EAAW,qBAAA,aAAG,CAAc,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,MAAA,CAAO,CACtF,CAAA;AACD,KAAA,CAAM,YAAA,EAA6B,cAAA,CAAA,IAAA,CAAK,WAAA;ADLxC;AACA;AACE;AACF,sBAAC","file":"/Users/stuartjackson/Projects/simpleapps/atlas/repo/packages/augur-web/dist/chunk-MAENILZP.cjs","sourcesContent":[null,"/** Styled wrapper around @radix-ui/react-label. See https://www.radix-ui.com/primitives/docs/components/label */\n\"use client\";\n\nimport * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@simpleapps-com/augur-utils/web\";\n\nconst labelVariants = cva(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n);\n\nconst Label = React.forwardRef<\n React.ComponentRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/augur-packages/augur-packages/packages/augur-web/dist/chunk-NEY26NNF.cjs","../src/table.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/augur-packages/augur-packages/packages/augur-web/dist/chunk-NEY26NNF.cjs","sourcesContent":[null,"/** Styled HTML table with responsive overflow wrapper. */\n\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@simpleapps-com/augur-utils/web\";\n\nconst Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(\n ({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-auto\">\n <table ref={ref} className={cn(\"w-full caption-bottom text-sm\", className)} {...props} />\n </div>\n ),\n);\nTable.displayName = \"Table\";\n\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n));\nTableHeader.displayName = \"TableHeader\";\n\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody ref={ref} className={cn(\"[&_tr:last-child]:border-0\", className)} {...props} />\n));\nTableBody.displayName = \"TableBody\";\n\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0\", className)}\n {...props}\n />\n));\nTableFooter.displayName = \"TableFooter\";\n\nconst TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(\n ({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors\",\n className,\n )}\n {...props}\n />\n ),\n);\nTableRow.displayName = \"TableRow\";\n\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"text-muted-foreground h-10 px-2 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className,\n )}\n {...props}\n />\n));\nTableHead.displayName = \"TableHead\";\n\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\n \"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className,\n )}\n {...props}\n />\n));\nTableCell.displayName = \"TableCell\";\n\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption ref={ref} className={cn(\"text-muted-foreground mt-4 text-sm\", className)} {...props} />\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };\n"]}
1
+ {"version":3,"sources":["/Users/stuartjackson/Projects/simpleapps/atlas/repo/packages/augur-web/dist/chunk-NEY26NNF.cjs","../src/table.tsx"],"names":[],"mappings":"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","file":"/Users/stuartjackson/Projects/simpleapps/atlas/repo/packages/augur-web/dist/chunk-NEY26NNF.cjs","sourcesContent":[null,"/** Styled HTML table with responsive overflow wrapper. */\n\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@simpleapps-com/augur-utils/web\";\n\nconst Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(\n ({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-auto\">\n <table ref={ref} className={cn(\"w-full caption-bottom text-sm\", className)} {...props} />\n </div>\n ),\n);\nTable.displayName = \"Table\";\n\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n));\nTableHeader.displayName = \"TableHeader\";\n\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody ref={ref} className={cn(\"[&_tr:last-child]:border-0\", className)} {...props} />\n));\nTableBody.displayName = \"TableBody\";\n\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0\", className)}\n {...props}\n />\n));\nTableFooter.displayName = \"TableFooter\";\n\nconst TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(\n ({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors\",\n className,\n )}\n {...props}\n />\n ),\n);\nTableRow.displayName = \"TableRow\";\n\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"text-muted-foreground h-10 px-2 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className,\n )}\n {...props}\n />\n));\nTableHead.displayName = \"TableHead\";\n\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\n \"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className,\n )}\n {...props}\n />\n));\nTableCell.displayName = \"TableCell\";\n\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption ref={ref} className={cn(\"text-muted-foreground mt-4 text-sm\", className)} {...props} />\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };\n"]}
@@ -0,0 +1,220 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
+
3
+ // ../utils/src/strings.ts
4
+ function codeAt(s, i) {
5
+ return i >= 0 && i < s.length ? s.charCodeAt(i) : -1;
6
+ }
7
+ function indexOfCode(s, code, from) {
8
+ const c = codeAt(s, from);
9
+ if (c === code) return from;
10
+ if (c === -1) return -1;
11
+ return indexOfCode(s, code, from + 1);
12
+ }
13
+ function startsWithAt(s, x, pos) {
14
+ const at = Math.min(pos, s.length);
15
+ return s.slice(at, Math.min(at + x.length, s.length)) === x;
16
+ }
17
+ function untilCode(s, code) {
18
+ const k = indexOfCode(s, code, 0);
19
+ return k >= 0 ? s.slice(0, k) : s;
20
+ }
21
+
22
+ // ../utils/src/replace.ts
23
+ function codeIndex(codes, c, i) {
24
+ if (i === codes.length) return -1;
25
+ return codes[i] === c ? i : codeIndex(codes, c, i + 1);
26
+ }
27
+ function substitute(s, codes, texts) {
28
+ let out = "";
29
+ for (let i = 0; i !== s.length; i++) {
30
+ const k = codeIndex(codes, s.charCodeAt(i), 0);
31
+ out = k >= 0 && k < texts.length ? out + texts[k] : out + s.slice(i, i + 1);
32
+ }
33
+ return out;
34
+ }
35
+ function replaceCode(s, from, to) {
36
+ return substitute(s, [from], [to]);
37
+ }
38
+
39
+ // src/rules.ts
40
+ function pageRangeFrom(total, i) {
41
+ if (i >= total) return [];
42
+ return [{ kind: "page", n: i + 1 }, ...pageRangeFrom(total, i + 1)];
43
+ }
44
+ function pageNumbersOf(current, total) {
45
+ if (total <= 0) return [];
46
+ if (total === 1) return [{ kind: "page", n: 1 }];
47
+ const page = clampPage(current, total);
48
+ if (total <= 5) return pageRangeFrom(total, 0);
49
+ const first = { kind: "page", n: 1 };
50
+ const last = { kind: "page", n: total };
51
+ const gap = { kind: "ellipsis" };
52
+ if (page <= 3) {
53
+ return [
54
+ first,
55
+ { kind: "page", n: 2 },
56
+ { kind: "page", n: 3 },
57
+ { kind: "page", n: 4 },
58
+ gap,
59
+ last
60
+ ];
61
+ }
62
+ if (page >= total - 2) {
63
+ return [
64
+ first,
65
+ gap,
66
+ { kind: "page", n: total - 3 },
67
+ { kind: "page", n: total - 2 },
68
+ { kind: "page", n: total - 1 },
69
+ last
70
+ ];
71
+ }
72
+ return [
73
+ first,
74
+ gap,
75
+ { kind: "page", n: page - 1 },
76
+ { kind: "page", n: page },
77
+ { kind: "page", n: page + 1 },
78
+ gap,
79
+ last
80
+ ];
81
+ }
82
+ function clampPage(current, total) {
83
+ const capped = current > total ? total : current;
84
+ return capped < 1 ? 1 : capped;
85
+ }
86
+ function isFirstPage(page) {
87
+ return page <= 1;
88
+ }
89
+ function isLastPage(page, totalPages) {
90
+ return page >= totalPages;
91
+ }
92
+ function prevTarget(page) {
93
+ return isFirstPage(page) ? 1 : page - 1;
94
+ }
95
+ function nextTarget(page, totalPages) {
96
+ return isLastPage(page, totalPages) ? totalPages : page + 1;
97
+ }
98
+ function clampQuantity(value, min, max) {
99
+ const atLeast = value < min ? min : value;
100
+ if (max === void 0) return atLeast;
101
+ return atLeast > max ? max : atLeast;
102
+ }
103
+ function stepDown(value, step, min) {
104
+ return value - step > min ? value - step : min;
105
+ }
106
+ function stepUp(value, step, max) {
107
+ if (max === void 0) return value + step;
108
+ return value + step > max ? max : value + step;
109
+ }
110
+ function decreaseDisabled(disabled, value, min) {
111
+ return disabled || value <= min;
112
+ }
113
+ function increaseDisabled(disabled, value, max) {
114
+ if (max === void 0) return disabled;
115
+ return disabled || value >= max;
116
+ }
117
+ function digitKey(key) {
118
+ const c = codeAt(key, 0);
119
+ return c >= 48 && c <= 56 || key === "9";
120
+ }
121
+ function editingKey(key) {
122
+ return key === "Backspace" || key === "Delete" || key === "ArrowLeft" || key === "ArrowRight" || key === "Tab" || key === "Enter";
123
+ }
124
+ function keyAllowed(key, decimals, hasDot) {
125
+ return editingKey(key) || decimals > 0 && key === "." && !hasDot || digitKey(key);
126
+ }
127
+ function cleanQtyFrom(raw, allowDot, seenDot, i) {
128
+ if (i >= raw.length) return "";
129
+ const c = codeAt(raw, i);
130
+ if (c >= 48 && c <= 57) return raw.slice(i, i + 1) + cleanQtyFrom(raw, allowDot, seenDot, i + 1);
131
+ if (allowDot && c === 46 && !seenDot) return "." + cleanQtyFrom(raw, allowDot, true, i + 1);
132
+ return cleanQtyFrom(raw, allowDot, seenDot, i + 1);
133
+ }
134
+ function stockViewOf(loading, isInStock, isLowStock) {
135
+ if (loading) return "loading";
136
+ if (!isInStock) return "out-of-stock";
137
+ return isLowStock ? "low-stock" : "in-stock";
138
+ }
139
+ function showStockQuantity(view, hasQuantity) {
140
+ return hasQuantity && view !== "out-of-stock" && view !== "loading";
141
+ }
142
+ function priceViewOf(loading, valueIsZero, hasOriginal) {
143
+ if (loading) return "skeleton";
144
+ if (valueIsZero && !hasOriginal) return "zero-label";
145
+ return "amount";
146
+ }
147
+ function needsQuotes(s) {
148
+ return indexOfCode(s, 44, 0) >= 0 || indexOfCode(s, 34, 0) >= 0 || indexOfCode(s, 10, 0) >= 0;
149
+ }
150
+ function csvField(s) {
151
+ if (!needsQuotes(s)) return s;
152
+ return '"' + replaceCode(s, 34, '""') + '"';
153
+ }
154
+ function ariaSortOf(sortable, dir) {
155
+ if (!sortable) return void 0;
156
+ if (dir === "asc") return "ascending";
157
+ if (dir === "desc") return "descending";
158
+ return "none";
159
+ }
160
+ function alignClass(align) {
161
+ if (align === "left") return "text-left";
162
+ if (align === "center") return "text-center";
163
+ return align === "right" ? "text-right" : "";
164
+ }
165
+ function bodyViewOf(loading, rowCount) {
166
+ if (loading) return "loading";
167
+ return rowCount === 0 ? "empty" : "rows";
168
+ }
169
+ function gtmTiming(strategy, hasIdleCallback) {
170
+ if (strategy === "lazyOnload" && hasIdleCallback) return "idle";
171
+ return strategy === "afterInteractive" ? "next-tick" : "now";
172
+ }
173
+ function replaySampled(disabled, injected, rate, draw) {
174
+ return !disabled && !injected && !(rate < 1 && draw > rate);
175
+ }
176
+ function binMarkAt(s, k) {
177
+ const c = codeAt(s, k);
178
+ const v = codeAt(s, k + 5);
179
+ return (c === 63 || c === 38) && startsWithAt(s, "Bin=", k + 1) && v >= 0 && v !== 38;
180
+ }
181
+ function binAt(s, i) {
182
+ if (i + 6 > s.length) return -1;
183
+ if (binMarkAt(s, i)) return i;
184
+ return binAt(s, i + 1);
185
+ }
186
+ function binFromString(s) {
187
+ const k = binAt(s, 0);
188
+ if (k < 0) return void 0;
189
+ return untilCode(afterBinMark(s, k), 38);
190
+ }
191
+ function afterBinMark(s, k) {
192
+ if (k < 0 || k + 5 > s.length) return "";
193
+ return s.slice(k + 5);
194
+ }
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+ exports.pageNumbersOf = pageNumbersOf; exports.isFirstPage = isFirstPage; exports.isLastPage = isLastPage; exports.prevTarget = prevTarget; exports.nextTarget = nextTarget; exports.clampQuantity = clampQuantity; exports.stepDown = stepDown; exports.stepUp = stepUp; exports.decreaseDisabled = decreaseDisabled; exports.increaseDisabled = increaseDisabled; exports.keyAllowed = keyAllowed; exports.cleanQtyFrom = cleanQtyFrom; exports.stockViewOf = stockViewOf; exports.showStockQuantity = showStockQuantity; exports.priceViewOf = priceViewOf; exports.csvField = csvField; exports.ariaSortOf = ariaSortOf; exports.alignClass = alignClass; exports.bodyViewOf = bodyViewOf; exports.gtmTiming = gtmTiming; exports.replaySampled = replaySampled; exports.binFromString = binFromString;
220
+ //# sourceMappingURL=chunk-QKWXJM4Q.cjs.map