@hyperscale0/hsx 1.0.0 → 1.0.124

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 (316) hide show
  1. package/CHANGELOG.md +5 -256
  2. package/LICENSE.md +356 -0
  3. package/NOTICE.md +8 -0
  4. package/README.md +44 -44
  5. package/bin/hsx.ts +0 -7
  6. package/dist/bin/hsx.d.ts +0 -4
  7. package/dist/bin/hsx.d.ts.map +1 -1
  8. package/dist/bin/hsx.js +0 -6
  9. package/dist/bin/hsx.js.map +1 -1
  10. package/dist/src/ast.d.ts +113 -308
  11. package/dist/src/ast.d.ts.map +1 -1
  12. package/dist/src/ast.js +7 -71
  13. package/dist/src/ast.js.map +1 -1
  14. package/dist/src/attachment-economics.d.ts +5 -0
  15. package/dist/src/attachment-economics.d.ts.map +1 -0
  16. package/dist/src/attachment-economics.js +55 -0
  17. package/dist/src/attachment-economics.js.map +1 -0
  18. package/dist/src/binding-contract.d.ts +22 -0
  19. package/dist/src/binding-contract.d.ts.map +1 -0
  20. package/dist/src/binding-contract.js +74 -0
  21. package/dist/src/binding-contract.js.map +1 -0
  22. package/dist/src/cli.d.ts +4 -19
  23. package/dist/src/cli.d.ts.map +1 -1
  24. package/dist/src/cli.js +89 -276
  25. package/dist/src/cli.js.map +1 -1
  26. package/dist/src/compile.d.ts +34 -66
  27. package/dist/src/compile.d.ts.map +1 -1
  28. package/dist/src/compile.js +2949 -117
  29. package/dist/src/compile.js.map +1 -1
  30. package/dist/src/cost.d.ts +8 -75
  31. package/dist/src/cost.d.ts.map +1 -1
  32. package/dist/src/cost.js +54 -364
  33. package/dist/src/cost.js.map +1 -1
  34. package/dist/src/diagnostics.d.ts +14 -9
  35. package/dist/src/diagnostics.d.ts.map +1 -1
  36. package/dist/src/diagnostics.js +39 -416
  37. package/dist/src/diagnostics.js.map +1 -1
  38. package/dist/src/examples-bundle.d.ts +3 -0
  39. package/dist/src/examples-bundle.d.ts.map +1 -0
  40. package/dist/src/examples-bundle.js +18 -0
  41. package/dist/src/examples-bundle.js.map +1 -0
  42. package/dist/src/examples.d.ts +10 -0
  43. package/dist/src/examples.d.ts.map +1 -0
  44. package/dist/src/examples.js +2 -0
  45. package/dist/src/examples.js.map +1 -0
  46. package/dist/src/format.d.ts +8 -7
  47. package/dist/src/format.d.ts.map +1 -1
  48. package/dist/src/format.js +9 -175
  49. package/dist/src/format.js.map +1 -1
  50. package/dist/src/header-source.d.ts +3 -0
  51. package/dist/src/header-source.d.ts.map +1 -0
  52. package/dist/src/header-source.js +41 -0
  53. package/dist/src/header-source.js.map +1 -0
  54. package/dist/src/headers.d.ts +64 -0
  55. package/dist/src/headers.d.ts.map +1 -0
  56. package/dist/src/headers.js +167 -0
  57. package/dist/src/headers.js.map +1 -0
  58. package/dist/src/index.d.ts +7 -11
  59. package/dist/src/index.d.ts.map +1 -1
  60. package/dist/src/index.js +4 -9
  61. package/dist/src/index.js.map +1 -1
  62. package/dist/src/keywords.d.ts +56 -0
  63. package/dist/src/keywords.d.ts.map +1 -0
  64. package/dist/src/keywords.js +133 -0
  65. package/dist/src/keywords.js.map +1 -0
  66. package/dist/src/language.d.ts +26 -0
  67. package/dist/src/language.d.ts.map +1 -0
  68. package/dist/src/language.js +440 -0
  69. package/dist/src/language.js.map +1 -0
  70. package/dist/src/lex.d.ts +13 -28
  71. package/dist/src/lex.d.ts.map +1 -1
  72. package/dist/src/lex.js +119 -145
  73. package/dist/src/lex.js.map +1 -1
  74. package/dist/src/parse.d.ts +4 -17
  75. package/dist/src/parse.d.ts.map +1 -1
  76. package/dist/src/parse.js +484 -1036
  77. package/dist/src/parse.js.map +1 -1
  78. package/dist/src/std-bundle.d.ts.map +1 -1
  79. package/dist/src/std-bundle.js +11 -84
  80. package/dist/src/std-bundle.js.map +1 -1
  81. package/dist/src/std-library.d.ts +1 -1
  82. package/dist/src/std-library.d.ts.map +1 -1
  83. package/dist/src/std-library.js +1 -5
  84. package/dist/src/std-library.js.map +1 -1
  85. package/dist/src/tunables.d.ts +7 -0
  86. package/dist/src/tunables.d.ts.map +1 -0
  87. package/dist/src/tunables.js +27 -0
  88. package/dist/src/tunables.js.map +1 -0
  89. package/docs/README.md +528 -26
  90. package/docs/assets/brand/hsx-horizontal-white.svg +1 -0
  91. package/docs/assets/brand/hsx-horizontal.svg +1 -0
  92. package/docs/assets/brand/hsx-stacked-white.svg +1 -0
  93. package/docs/assets/brand/hsx-stacked.svg +1 -0
  94. package/docs/assets/brand/manifest.json +30 -0
  95. package/docs/assets/hsx.svg +11 -0
  96. package/examples/cards.hsx +34 -0
  97. package/examples/collections.hsx +37 -0
  98. package/examples/cost-table.json +633 -385
  99. package/examples/escrow.hsx +24 -0
  100. package/examples/financing.hsx +32 -0
  101. package/examples/insurance.hsx +30 -0
  102. package/examples/lending.hsx +57 -0
  103. package/examples/library.hsx +15 -0
  104. package/examples/marketplace.hsx +32 -0
  105. package/examples/money.hsx +19 -0
  106. package/examples/rental-deposit.hsx +60 -0
  107. package/examples/repair-approval.hsx +44 -0
  108. package/examples/reporting.hsx +28 -0
  109. package/examples/savings.hsx +21 -0
  110. package/examples/serviced.hsx +25 -0
  111. package/examples/wallet.hsx +24 -0
  112. package/package.json +25 -23
  113. package/src/ast.ts +83 -440
  114. package/src/attachment-economics.ts +103 -0
  115. package/src/binding-contract.ts +104 -0
  116. package/src/cli.ts +95 -325
  117. package/src/compile.ts +4063 -209
  118. package/src/cost.ts +71 -574
  119. package/src/diagnostics.ts +57 -437
  120. package/src/examples-bundle.ts +19 -0
  121. package/src/examples.ts +9 -0
  122. package/src/format.ts +12 -256
  123. package/src/header-source.ts +54 -0
  124. package/src/headers.ts +195 -0
  125. package/src/index.ts +18 -33
  126. package/src/keywords.ts +134 -0
  127. package/src/language.ts +629 -0
  128. package/src/lex.ts +131 -192
  129. package/src/parse.ts +489 -1195
  130. package/src/std-bundle.ts +12 -88
  131. package/src/std-library.ts +2 -7
  132. package/src/tunables.ts +36 -0
  133. package/std/cards.hsx +85 -0
  134. package/std/collections.hsx +90 -0
  135. package/std/escrow.hsx +73 -0
  136. package/std/financing.hsx +683 -0
  137. package/std/insurance.hsx +89 -0
  138. package/std/lending.hsx +138 -0
  139. package/std/marketplace.hsx +123 -0
  140. package/std/money.hsx +173 -0
  141. package/std/reporting.hsx +753 -0
  142. package/std/savings.hsx +68 -0
  143. package/std/wallet.hsx +57 -0
  144. package/LICENSE +0 -661
  145. package/LICENSING.md +0 -52
  146. package/TRADEMARKS.md +0 -35
  147. package/dist/src/emit.d.ts +0 -34
  148. package/dist/src/emit.d.ts.map +0 -1
  149. package/dist/src/emit.js +0 -137
  150. package/dist/src/emit.js.map +0 -1
  151. package/dist/src/entry-overrides.d.ts +0 -58
  152. package/dist/src/entry-overrides.d.ts.map +0 -1
  153. package/dist/src/entry-overrides.js +0 -284
  154. package/dist/src/entry-overrides.js.map +0 -1
  155. package/dist/src/ir.d.ts +0 -66
  156. package/dist/src/ir.d.ts.map +0 -1
  157. package/dist/src/ir.js +0 -15
  158. package/dist/src/ir.js.map +0 -1
  159. package/dist/src/limits.d.ts +0 -21
  160. package/dist/src/limits.d.ts.map +0 -1
  161. package/dist/src/limits.js +0 -21
  162. package/dist/src/limits.js.map +0 -1
  163. package/dist/src/lsp/server.d.ts +0 -32
  164. package/dist/src/lsp/server.d.ts.map +0 -1
  165. package/dist/src/lsp/server.js +0 -391
  166. package/dist/src/lsp/server.js.map +0 -1
  167. package/dist/src/modules.d.ts +0 -38
  168. package/dist/src/modules.d.ts.map +0 -1
  169. package/dist/src/modules.js +0 -368
  170. package/dist/src/modules.js.map +0 -1
  171. package/dist/src/typecheck.d.ts +0 -8
  172. package/dist/src/typecheck.d.ts.map +0 -1
  173. package/dist/src/typecheck.js +0 -2958
  174. package/dist/src/typecheck.js.map +0 -1
  175. package/dist/src/version.d.ts +0 -5
  176. package/dist/src/version.d.ts.map +0 -1
  177. package/dist/src/version.js +0 -5
  178. package/dist/src/version.js.map +0 -1
  179. package/docs/guide/01-first-program.md +0 -24
  180. package/docs/guide/02-money.md +0 -25
  181. package/docs/guide/03-instruments.md +0 -22
  182. package/docs/guide/04-lifecycles.md +0 -25
  183. package/docs/guide/05-fees-and-splits.md +0 -45
  184. package/docs/guide/06-schedules.md +0 -22
  185. package/docs/guide/07-composition.md +0 -46
  186. package/docs/guide/08-writing-a-module.md +0 -26
  187. package/docs/guide/09-cost.md +0 -24
  188. package/docs/guide/10-diagnostics.md +0 -27
  189. package/docs/llms-full.txt +0 -1739
  190. package/docs/llms.txt +0 -45
  191. package/docs/playground.md +0 -54
  192. package/docs/reference/cli.md +0 -35
  193. package/docs/reference/diagnostics.md +0 -619
  194. package/docs/reference/grammar.md +0 -39
  195. package/docs/reference/std/advance.md +0 -35
  196. package/docs/reference/std/cancellable_booking.md +0 -35
  197. package/docs/reference/std/captured_payment.md +0 -43
  198. package/docs/reference/std/conditional_disbursement.md +0 -33
  199. package/docs/reference/std/credit_facility.md +0 -35
  200. package/docs/reference/std/held_payment.md +0 -64
  201. package/docs/reference/std/instant_transfer.md +0 -30
  202. package/docs/reference/std/metered.md +0 -27
  203. package/docs/reference/std/pooled_split.md +0 -26
  204. package/docs/reference/std/premium_forward.md +0 -39
  205. package/docs/reference/std/reconciled_payout.md +0 -33
  206. package/docs/reference/std/recurring_collection.md +0 -25
  207. package/docs/reference/std/rotating_pool.md +0 -42
  208. package/docs/reference/std/scheduled.md +0 -51
  209. package/docs/reference/std/security_deposit.md +0 -46
  210. package/docs/reference/std/settlement_batch.md +0 -42
  211. package/docs/reference/std/swap.md +0 -46
  212. package/docs/reference/std/threshold_pool.md +0 -47
  213. package/docs/reference/std/weighted_distribution.md +0 -39
  214. package/docs/reference/types.md +0 -20
  215. package/docs/reference/udl-output.md +0 -13
  216. package/docs/sessions/2026-09-02-two-instruments.hsx +0 -21
  217. package/docs/sessions/2026-09-02-two-instruments.md +0 -41
  218. package/examples/01-first-program/README.md +0 -45
  219. package/examples/01-first-program/tip-jar.hsx +0 -17
  220. package/examples/02-imports-and-archetypes/README.md +0 -96
  221. package/examples/02-imports-and-archetypes/photo-booth.hsx +0 -37
  222. package/examples/03-diagnostics/README.md +0 -68
  223. package/examples/03-diagnostics/corner-shop-fixed.hsx +0 -22
  224. package/examples/03-diagnostics/corner-shop.hsx +0 -19
  225. package/examples/04-complete-product/README.md +0 -84
  226. package/examples/04-complete-product/study-hall.hsx +0 -67
  227. package/examples/05-watch-club/README.md +0 -9
  228. package/examples/05-watch-club/watch-club.hsx +0 -124
  229. package/examples/README.md +0 -18
  230. package/examples/advance/README.md +0 -3
  231. package/examples/advance/advance.hsx +0 -13
  232. package/examples/advance/advance.udl +0 -339
  233. package/examples/cancellable_booking/README.md +0 -3
  234. package/examples/cancellable_booking/cancellable_booking.hsx +0 -14
  235. package/examples/cancellable_booking/cancellable_booking.udl +0 -391
  236. package/examples/captured_payment/README.md +0 -3
  237. package/examples/captured_payment/captured_payment.hsx +0 -21
  238. package/examples/captured_payment/captured_payment.udl +0 -677
  239. package/examples/conditional_disbursement/README.md +0 -3
  240. package/examples/conditional_disbursement/conditional_disbursement.hsx +0 -17
  241. package/examples/conditional_disbursement/conditional_disbursement.udl +0 -412
  242. package/examples/credit_facility/README.md +0 -3
  243. package/examples/credit_facility/credit_facility.hsx +0 -27
  244. package/examples/credit_facility/credit_facility.udl +0 -1373
  245. package/examples/held_payment/README.md +0 -3
  246. package/examples/held_payment/held_payment.hsx +0 -13
  247. package/examples/held_payment/held_payment.udl +0 -507
  248. package/examples/instant_transfer/README.md +0 -3
  249. package/examples/instant_transfer/instant_transfer.hsx +0 -16
  250. package/examples/instant_transfer/instant_transfer.udl +0 -364
  251. package/examples/metered/README.md +0 -3
  252. package/examples/metered/metered.hsx +0 -13
  253. package/examples/metered/metered.udl +0 -247
  254. package/examples/pooled_split/README.md +0 -3
  255. package/examples/pooled_split/pooled_split.hsx +0 -15
  256. package/examples/pooled_split/pooled_split.udl +0 -425
  257. package/examples/premium_forward/README.md +0 -3
  258. package/examples/premium_forward/premium_forward.hsx +0 -19
  259. package/examples/premium_forward/premium_forward.udl +0 -594
  260. package/examples/reconciled_payout/README.md +0 -3
  261. package/examples/reconciled_payout/reconciled_payout.hsx +0 -13
  262. package/examples/reconciled_payout/reconciled_payout.udl +0 -303
  263. package/examples/recurring_collection/README.md +0 -3
  264. package/examples/recurring_collection/recurring_collection.hsx +0 -21
  265. package/examples/recurring_collection/recurring_collection.udl +0 -1130
  266. package/examples/rotating_pool/README.md +0 -3
  267. package/examples/rotating_pool/rotating_pool.hsx +0 -18
  268. package/examples/rotating_pool/rotating_pool.udl +0 -4352
  269. package/examples/scheduled/README.md +0 -3
  270. package/examples/scheduled/scheduled.hsx +0 -12
  271. package/examples/scheduled/scheduled.udl +0 -335
  272. package/examples/security_deposit/README.md +0 -3
  273. package/examples/security_deposit/security_deposit.hsx +0 -21
  274. package/examples/security_deposit/security_deposit.udl +0 -293
  275. package/examples/settlement_batch/README.md +0 -3
  276. package/examples/settlement_batch/settlement_batch.hsx +0 -19
  277. package/examples/settlement_batch/settlement_batch.udl +0 -753
  278. package/examples/swap/README.md +0 -3
  279. package/examples/swap/swap.hsx +0 -19
  280. package/examples/swap/swap.udl +0 -876
  281. package/examples/threshold_pool/README.md +0 -3
  282. package/examples/threshold_pool/threshold_pool.hsx +0 -16
  283. package/examples/threshold_pool/threshold_pool.udl +0 -667
  284. package/examples/weighted_distribution/README.md +0 -3
  285. package/examples/weighted_distribution/weighted_distribution.hsx +0 -20
  286. package/examples/weighted_distribution/weighted_distribution.udl +0 -337
  287. package/skills/hsx/SKILL.md +0 -483
  288. package/src/emit.ts +0 -201
  289. package/src/entry-overrides.ts +0 -428
  290. package/src/ir.ts +0 -99
  291. package/src/limits.ts +0 -20
  292. package/src/lsp/server.ts +0 -460
  293. package/src/modules.ts +0 -446
  294. package/src/typecheck.ts +0 -3876
  295. package/src/version.ts +0 -5
  296. package/std/SEMANTICS.md +0 -130
  297. package/std/settlements/advance.hsx +0 -177
  298. package/std/settlements/cancellable_booking.hsx +0 -87
  299. package/std/settlements/captured_payment.hsx +0 -144
  300. package/std/settlements/conditional_disbursement.hsx +0 -185
  301. package/std/settlements/credit_facility.hsx +0 -167
  302. package/std/settlements/held_payment.hsx +0 -578
  303. package/std/settlements/index.hsx +0 -3
  304. package/std/settlements/instant_transfer.hsx +0 -190
  305. package/std/settlements/metered.hsx +0 -67
  306. package/std/settlements/pooled_split.hsx +0 -68
  307. package/std/settlements/premium_forward.hsx +0 -257
  308. package/std/settlements/reconciled_payout.hsx +0 -77
  309. package/std/settlements/recurring_collection.hsx +0 -27
  310. package/std/settlements/rotating_pool.hsx +0 -252
  311. package/std/settlements/scheduled.hsx +0 -641
  312. package/std/settlements/security_deposit.hsx +0 -166
  313. package/std/settlements/settlement_batch.hsx +0 -122
  314. package/std/settlements/swap.hsx +0 -1114
  315. package/std/settlements/threshold_pool.hsx +0 -221
  316. package/std/settlements/weighted_distribution.hsx +0 -141
package/src/lex.ts CHANGED
@@ -1,216 +1,155 @@
1
- /**
2
- * The HSX lexer. Hand-written, total: every input produces a token stream
3
- * ending in `eof`, with malformed stretches reported as diagnostics and
4
- * skipped. Tokens carry byte-offset spans; whitespace and `//` comments are
5
- * insignificant everywhere.
6
- */
7
-
8
1
  import type { Diagnostic, Span } from "./ast.ts";
9
-
10
- type TokenKind =
11
- | "eof"
12
- | "ident"
13
- | "keyword"
14
- | "number"
15
- | "percent"
16
- | "punct"
17
- | "string";
18
-
19
2
  export const KEYWORDS = [
3
+ "program",
4
+ "header",
5
+ "use",
6
+ "party",
7
+ "role",
8
+ "currency",
9
+ "instrument",
10
+ "fields",
11
+ "lifecycle",
20
12
  "action",
21
- "as",
22
- "asset",
23
- "commit",
24
- "const",
25
- "expect",
26
13
  "expose",
27
- "expires",
28
- "export",
14
+ "hide",
15
+ "as",
16
+ "cap",
17
+ "of",
18
+ "when",
19
+ "constraints",
20
+ "requires",
21
+ "invariants",
22
+ "moves",
29
23
  "from",
30
- "import",
31
- "instrument",
32
- "module",
33
- "party",
34
- "port",
35
- "program",
36
- "quote",
37
- "rate",
38
- "reconcile",
39
- "settlement",
24
+ "to",
25
+ "in",
26
+ "is",
27
+ "has",
28
+ "unique",
29
+ "on",
30
+ "count",
31
+ "sum",
32
+ "hours",
33
+ "between",
34
+ "and",
35
+ "timezone",
36
+ "evidence",
37
+ "family",
38
+ "check",
39
+ "result",
40
+ "maxAge",
41
+ "instruction",
42
+ "reserve",
43
+ "post",
44
+ "void",
45
+ "capture",
46
+ "boundary",
47
+ "key",
48
+ "fee",
49
+ "shares",
50
+ "object",
51
+ "attach",
40
52
  "subject",
41
- "type",
42
- "use",
53
+ "rename",
54
+ "columns",
43
55
  ] as const;
44
-
45
56
  export interface Token {
46
- readonly kind: TokenKind;
47
- readonly span: Span;
48
- /** Identifier name, keyword, punctuation glyph, or raw literal text. */
49
- readonly text: string;
50
- /** Decoded value for string literals; raw digits for numbers/percents. */
51
- readonly value: string;
52
- }
53
-
54
- /** Source trivia retained for tools that must reproduce author comments. */
55
- export interface CommentTrivia {
56
- readonly kind: "line_comment";
57
- readonly span: Span;
58
- readonly text: string;
57
+ kind: "name" | "number" | "string" | "date" | "punct" | "comment" | "eof";
58
+ text: string;
59
+ span: Span;
59
60
  }
60
-
61
- export const PUNCT = [
62
- "{",
63
- "}",
64
- "(",
65
- ")",
66
- "[",
67
- "]",
68
- ":",
69
- ",",
70
- ";",
71
- "=",
72
- "|",
73
- ".",
74
- "<",
75
- ">",
76
- "?",
77
- ] as const;
78
- const PUNCT_SET: ReadonlySet<string> = new Set(PUNCT);
79
- const KEYWORD_SET: ReadonlySet<string> = new Set(KEYWORDS);
80
-
81
- // Case conventions (snake_case declarations, uppercase currency codes) are
82
- // semantic rules the typechecker words per position; the lexer stays permissive.
83
- const isIdentStart = (ch: string): boolean => /[A-Za-z]/.test(ch);
84
- const isIdentPart = (ch: string): boolean => /[A-Za-z0-9_]/.test(ch);
85
- const isDigit = (ch: string): boolean => ch >= "0" && ch <= "9";
86
-
87
- export interface LexResult {
88
- readonly comments: readonly CommentTrivia[];
89
- readonly diagnostics: readonly Diagnostic[];
90
- readonly tokens: readonly Token[];
61
+ export function lex(source: string) {
62
+ return scan(source, false);
91
63
  }
92
64
 
93
- export function lex(source: string): LexResult {
65
+ /** The editor keeps comments and unfinished strings; compiler tokens stay unchanged. */
66
+ export function scan(
67
+ source: string,
68
+ editor = true,
69
+ ): {
70
+ tokens: Token[];
71
+ diagnostics: Diagnostic[];
72
+ } {
94
73
  const tokens: Token[] = [];
95
- const comments: CommentTrivia[] = [];
96
74
  const diagnostics: Diagnostic[] = [];
97
75
  let index = 0;
98
-
99
- const push = (kind: TokenKind, start: number, text: string, value = text) => {
100
- tokens.push({ kind, span: { end: index, start }, text, value });
101
- };
102
-
103
76
  while (index < source.length) {
104
- const ch = source[index] as string;
105
-
106
- if (ch === " " || ch === "\t" || ch === "\r" || ch === "\n") {
107
- index += 1;
108
- continue;
109
- }
110
-
111
- if (ch === "/" && source[index + 1] === "/") {
112
- const start = index;
113
- while (index < source.length && source[index] !== "\n") index += 1;
114
- comments.push({
115
- kind: "line_comment",
116
- span: { end: index, start },
117
- text: source.slice(start, index),
118
- });
119
- continue;
120
- }
121
-
122
- if (PUNCT_SET.has(ch)) {
123
- const start = index;
124
- index += 1;
125
- push("punct", start, ch);
126
- continue;
127
- }
128
-
129
- if (ch === "-" && source[index + 1] === ">") {
130
- const start = index;
131
- index += 2;
132
- push("punct", start, "->");
77
+ const start = index;
78
+ const tail = source.slice(index);
79
+ const whitespace = /^\s+|^\/\/[^\n]*/.exec(tail);
80
+ if (whitespace) {
81
+ index += whitespace[0].length;
82
+ if (editor && whitespace[0].startsWith("//"))
83
+ tokens.push({
84
+ kind: "comment",
85
+ text: whitespace[0],
86
+ span: { start, end: index },
87
+ });
133
88
  continue;
134
89
  }
135
-
136
- if (ch === '"') {
137
- const start = index;
138
- index += 1;
139
- let value = "";
140
- let closed = false;
141
- while (index < source.length) {
142
- const next = source[index] as string;
143
- if (next === '"') {
144
- index += 1;
145
- closed = true;
146
- break;
147
- }
148
- if (next === "\n") break;
149
- value += next;
150
- index += 1;
151
- }
152
- if (!closed) {
90
+ const date =
91
+ /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2}))?/.exec(
92
+ tail,
93
+ );
94
+ const number = /^-?\d+(?:\.\d+)?(?:%|ms|[smhdw])?/.exec(tail);
95
+ const name = /^[A-Za-z_][A-Za-z0-9_]*/.exec(tail);
96
+ let kind: Token["kind"];
97
+ let text: string;
98
+ if (date) {
99
+ kind = "date";
100
+ text = date[0];
101
+ } else if (number) {
102
+ kind = "number";
103
+ text = number[0];
104
+ } else if (name) {
105
+ kind = "name";
106
+ text = name[0];
107
+ } else if (tail[0] === '"') {
108
+ const quoted =
109
+ // oxlint-disable-next-line no-control-regex -- JSON strings must escape raw control characters.
110
+ /^"(?:[^"\\\u0000-\u001f]|\\["\\/bfnrt]|\\u[0-9a-fA-F]{4})*"/.exec(
111
+ tail,
112
+ );
113
+ if (!quoted) {
153
114
  diagnostics.push({
154
- message: "this string never closes; add the ending double quote",
155
- span: { end: index, start },
115
+ code: "HSX1000",
116
+ message: "unclosed or invalid string",
117
+ fix: "close the string and use JSON escapes",
118
+ span: { start, end: start + 1 },
156
119
  });
120
+ if (editor) {
121
+ const unfinished =
122
+ /^"(?:[^"\\\n]|\\[^\n]?)*(?:"|(?=\n)|$)/.exec(tail)?.[0] ?? '"';
123
+ index += unfinished.length;
124
+ tokens.push({
125
+ kind: "string",
126
+ text: unfinished,
127
+ span: { start, end: index },
128
+ });
129
+ } else index++;
130
+ continue;
157
131
  }
158
- push("string", start, source.slice(start, index), value);
159
- continue;
160
- }
161
-
162
- if (isDigit(ch)) {
163
- const start = index;
164
- while (index < source.length && isDigit(source[index] as string)) {
165
- index += 1;
166
- }
167
- if (source[index] === "." && isDigit(source[index + 1] ?? "")) {
168
- index += 1;
169
- while (index < source.length && isDigit(source[index] as string)) {
170
- index += 1;
171
- }
172
- }
173
- const raw = source.slice(start, index);
174
- if (source[index] === "%") {
175
- index += 1;
176
- push("percent", start, source.slice(start, index), raw);
177
- } else {
178
- push("number", start, raw, raw);
179
- }
180
- continue;
181
- }
182
-
183
- if (isIdentStart(ch)) {
184
- const start = index;
185
- while (index < source.length && isIdentPart(source[index] as string)) {
186
- index += 1;
187
- }
188
- const text = source.slice(start, index);
189
- push(KEYWORD_SET.has(text) ? "keyword" : "ident", start, text);
132
+ kind = "string";
133
+ text = quoted[0];
134
+ } else if (/^(==|!=|<=|>=)/.test(tail)) {
135
+ kind = "punct";
136
+ text = tail.slice(0, 2);
137
+ } else if (/^[{}()[\]:,;=<>?.|]/.test(tail)) {
138
+ kind = "punct";
139
+ text = tail[0]!;
140
+ } else {
141
+ diagnostics.push({
142
+ code: "HSX1000",
143
+ message: `unexpected character ${tail[0]}`,
144
+ fix: "remove this character",
145
+ span: { start, end: start + 1 },
146
+ });
147
+ index++;
190
148
  continue;
191
149
  }
192
-
193
- const start = index;
194
- while (
195
- index < source.length &&
196
- !/[\sA-Za-z0-9_"]/.test(source[index] as string) &&
197
- !PUNCT_SET.has(source[index] as string) &&
198
- !(source[index] === "/" && source[index + 1] === "/")
199
- ) {
200
- index += 1;
201
- }
202
- if (index === start) index += 1;
203
- diagnostics.push({
204
- message: `"${source.slice(start, index)}" is not part of the HSX language`,
205
- span: { end: index, start },
206
- });
150
+ index += text.length;
151
+ tokens.push({ kind, text, span: { start, end: index } });
207
152
  }
208
-
209
- tokens.push({
210
- kind: "eof",
211
- span: { end: source.length, start: source.length },
212
- text: "",
213
- value: "",
214
- });
215
- return { comments, diagnostics, tokens };
153
+ tokens.push({ kind: "eof", text: "", span: { start: index, end: index } });
154
+ return { tokens, diagnostics };
216
155
  }