@futpib/parser 1.0.3 → 1.0.6

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 (262) hide show
  1. package/.claude/settings.local.json +24 -0
  2. package/.github/workflows/main.yml +1 -0
  3. package/build/androidPackageParser.js +30 -32
  4. package/build/arbitraryDalvikBytecode.d.ts +3 -3
  5. package/build/arbitraryDalvikBytecode.js +33 -27
  6. package/build/arbitraryDalvikExecutable.js +55 -17
  7. package/build/arbitraryJava.d.ts +31 -0
  8. package/build/arbitraryJava.js +532 -0
  9. package/build/arbitraryJavaScript.d.ts +3 -0
  10. package/build/arbitraryJavaScript.js +263 -0
  11. package/build/arbitraryJavascript.d.ts +3 -0
  12. package/build/arbitraryJavascript.js +263 -0
  13. package/build/arbitraryZig.d.ts +3 -0
  14. package/build/arbitraryZig.js +240 -0
  15. package/build/arbitraryZipStream.d.ts +1 -1
  16. package/build/arrayParser.js +72 -13
  17. package/build/backsmali.d.ts +4 -3
  18. package/build/backsmali.js +26 -6
  19. package/build/bash.d.ts +89 -0
  20. package/build/bash.js +1 -0
  21. package/build/bashParser.d.ts +6 -0
  22. package/build/bashParser.js +335 -0
  23. package/build/bashParser.test.d.ts +1 -0
  24. package/build/bashParser.test.js +343 -0
  25. package/build/bashParserEdgeCases.test.d.ts +1 -0
  26. package/build/bashParserEdgeCases.test.js +117 -0
  27. package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
  28. package/build/dalvikBytecodeParser/addressConversion.js +334 -0
  29. package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
  30. package/build/dalvikBytecodeParser/formatParsers.js +13 -14
  31. package/build/dalvikBytecodeParser.d.ts +60 -31
  32. package/build/dalvikBytecodeParser.js +92 -35
  33. package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
  34. package/build/dalvikBytecodeParser.test-d.js +268 -0
  35. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
  36. package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
  37. package/build/dalvikBytecodeUnparser.d.ts +2 -2
  38. package/build/dalvikBytecodeUnparser.js +23 -23
  39. package/build/dalvikBytecodeUnparser.test.js +7 -7
  40. package/build/dalvikExecutable.d.ts +3 -3
  41. package/build/dalvikExecutable.test-d.d.ts +1 -0
  42. package/build/dalvikExecutable.test-d.js +59 -0
  43. package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
  44. package/build/dalvikExecutableParser/typedNumbers.js +3 -0
  45. package/build/dalvikExecutableParser.d.ts +2 -1
  46. package/build/dalvikExecutableParser.js +96 -77
  47. package/build/dalvikExecutableParser.test.js +24 -3
  48. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
  49. package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
  50. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
  51. package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
  52. package/build/dalvikExecutableUnparser.d.ts +2 -2
  53. package/build/dalvikExecutableUnparser.test.js +2 -1
  54. package/build/disjunctionParser.d.ts +5 -3
  55. package/build/disjunctionParser.js +79 -17
  56. package/build/disjunctionParser.test-d.d.ts +1 -0
  57. package/build/disjunctionParser.test-d.js +72 -0
  58. package/build/elementSwitchParser.d.ts +4 -0
  59. package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
  60. package/build/elementSwitchParser.test-d.d.ts +1 -0
  61. package/build/elementSwitchParser.test-d.js +44 -0
  62. package/build/exactSequenceParser.d.ts +4 -2
  63. package/build/exactSequenceParser.test-d.d.ts +1 -0
  64. package/build/exactSequenceParser.test-d.js +36 -0
  65. package/build/fetchCid.js +2 -66
  66. package/build/index.d.ts +25 -2
  67. package/build/index.js +23 -1
  68. package/build/index.test.js +16 -1
  69. package/build/inputReader.d.ts +10 -0
  70. package/build/inputReader.js +36 -0
  71. package/build/java.d.ts +502 -0
  72. package/build/java.js +2 -0
  73. package/build/javaKeyStoreParser.js +14 -17
  74. package/build/javaParser.d.ts +51 -0
  75. package/build/javaParser.js +1538 -0
  76. package/build/javaParser.test.d.ts +1 -0
  77. package/build/javaParser.test.js +1287 -0
  78. package/build/javaScript.d.ts +35 -0
  79. package/build/javaScript.js +1 -0
  80. package/build/javaScriptParser.d.ts +9 -0
  81. package/build/javaScriptParser.js +34 -0
  82. package/build/javaScriptUnparser.d.ts +3 -0
  83. package/build/javaScriptUnparser.js +4 -0
  84. package/build/javaScriptUnparser.test.d.ts +1 -0
  85. package/build/javaScriptUnparser.test.js +24 -0
  86. package/build/javaUnparser.d.ts +2 -0
  87. package/build/javaUnparser.js +519 -0
  88. package/build/javaUnparser.test.d.ts +1 -0
  89. package/build/javaUnparser.test.js +24 -0
  90. package/build/javascript.d.ts +35 -0
  91. package/build/javascript.js +1 -0
  92. package/build/javascriptParser.d.ts +9 -0
  93. package/build/javascriptParser.js +34 -0
  94. package/build/javascriptUnparser.d.ts +3 -0
  95. package/build/javascriptUnparser.js +4 -0
  96. package/build/javascriptUnparser.test.d.ts +1 -0
  97. package/build/javascriptUnparser.test.js +24 -0
  98. package/build/jsonParser.js +2 -12
  99. package/build/lazyMessageError.d.ts +3 -0
  100. package/build/lookaheadParser.js +60 -3
  101. package/build/negativeLookaheadParser.js +70 -11
  102. package/build/nonEmptyArrayParser.js +72 -13
  103. package/build/objectParser.d.ts +12 -0
  104. package/build/objectParser.js +31 -0
  105. package/build/objectParser.test-d.d.ts +1 -0
  106. package/build/objectParser.test-d.js +112 -0
  107. package/build/objectParser.test.d.ts +1 -0
  108. package/build/objectParser.test.js +55 -0
  109. package/build/optionalParser.js +69 -10
  110. package/build/parser.d.ts +4 -0
  111. package/build/parser.js +3 -1
  112. package/build/parser.test.js +114 -1
  113. package/build/parserConsumedSequenceParser.js +66 -7
  114. package/build/parserContext.d.ts +6 -0
  115. package/build/parserContext.js +20 -11
  116. package/build/parserError.d.ts +119 -27
  117. package/build/parserError.js +16 -8
  118. package/build/regexpParser.d.ts +2 -0
  119. package/build/regexpParser.js +101 -0
  120. package/build/regexpParser.test.d.ts +1 -0
  121. package/build/regexpParser.test.js +114 -0
  122. package/build/regularExpression.d.ts +63 -0
  123. package/build/regularExpression.js +1 -0
  124. package/build/regularExpressionParser.d.ts +3 -0
  125. package/build/regularExpressionParser.js +600 -0
  126. package/build/regularExpressionParser.test.d.ts +1 -0
  127. package/build/regularExpressionParser.test.js +89 -0
  128. package/build/separatedArrayParser.js +73 -14
  129. package/build/separatedNonEmptyArrayParser.js +73 -14
  130. package/build/sliceBoundedParser.js +62 -5
  131. package/build/smaliParser.d.ts +7 -7
  132. package/build/smaliParser.js +185 -268
  133. package/build/smaliParser.test.js +58 -0
  134. package/build/stringEscapes.d.ts +5 -0
  135. package/build/stringEscapes.js +244 -0
  136. package/build/symbolicExpression.d.ts +29 -0
  137. package/build/symbolicExpression.js +1 -0
  138. package/build/symbolicExpressionParser.d.ts +4 -0
  139. package/build/symbolicExpressionParser.js +123 -0
  140. package/build/symbolicExpressionParser.test.d.ts +1 -0
  141. package/build/symbolicExpressionParser.test.js +289 -0
  142. package/build/terminatedArrayParser.js +113 -38
  143. package/build/terminatedArrayParser.test.js +4 -2
  144. package/build/tupleParser.d.ts +7 -15
  145. package/build/tupleParser.js +1 -0
  146. package/build/unionParser.d.ts +5 -3
  147. package/build/unionParser.js +7 -2
  148. package/build/unionParser.test-d.d.ts +1 -0
  149. package/build/unionParser.test-d.js +72 -0
  150. package/build/unionParser.test.js +10 -11
  151. package/build/zig.d.ts +280 -0
  152. package/build/zig.js +2 -0
  153. package/build/zigParser.d.ts +3 -0
  154. package/build/zigParser.js +1119 -0
  155. package/build/zigParser.test.d.ts +1 -0
  156. package/build/zigParser.test.js +1590 -0
  157. package/build/zigUnparser.d.ts +2 -0
  158. package/build/zigUnparser.js +460 -0
  159. package/build/zigUnparser.test.d.ts +1 -0
  160. package/build/zigUnparser.test.js +24 -0
  161. package/build/zipParser.js +19 -32
  162. package/build/zipUnparser.js +19 -7
  163. package/build/zipUnparser.test.js +1 -1
  164. package/node_modules-@types/s-expression/index.d.ts +5 -0
  165. package/package.json +25 -6
  166. package/src/androidPackageParser.ts +33 -60
  167. package/src/arbitraryDalvikBytecode.ts +39 -31
  168. package/src/arbitraryDalvikExecutable.ts +65 -20
  169. package/src/arbitraryJava.ts +804 -0
  170. package/src/arbitraryJavaScript.ts +410 -0
  171. package/src/arbitraryZig.ts +380 -0
  172. package/src/arrayParser.ts +1 -3
  173. package/src/backsmali.ts +35 -4
  174. package/src/bash.ts +127 -0
  175. package/src/bashParser.test.ts +590 -0
  176. package/src/bashParser.ts +498 -0
  177. package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
  178. package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
  179. package/src/dalvikBytecodeParser.test-d.ts +310 -0
  180. package/src/dalvikBytecodeParser.ts +194 -69
  181. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
  182. package/src/dalvikBytecodeUnparser.test.ts +7 -7
  183. package/src/dalvikBytecodeUnparser.ts +31 -30
  184. package/src/dalvikExecutable.test-d.ts +132 -0
  185. package/src/dalvikExecutable.ts +3 -3
  186. package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
  187. package/src/dalvikExecutableParser.test.ts +37 -3
  188. package/src/dalvikExecutableParser.test.ts.md +163 -2
  189. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  190. package/src/dalvikExecutableParser.ts +121 -139
  191. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
  192. package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
  193. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
  194. package/src/dalvikExecutableUnparser.test.ts +3 -2
  195. package/src/dalvikExecutableUnparser.ts +4 -4
  196. package/src/disjunctionParser.test-d.ts +105 -0
  197. package/src/disjunctionParser.ts +18 -15
  198. package/src/elementSwitchParser.test-d.ts +74 -0
  199. package/src/elementSwitchParser.ts +51 -0
  200. package/src/exactSequenceParser.test-d.ts +43 -0
  201. package/src/exactSequenceParser.ts +13 -8
  202. package/src/fetchCid.ts +2 -76
  203. package/src/index.test.ts +22 -1
  204. package/src/index.ts +119 -2
  205. package/src/inputReader.ts +53 -0
  206. package/src/java.ts +708 -0
  207. package/src/javaKeyStoreParser.ts +18 -32
  208. package/src/javaParser.test.ts +1592 -0
  209. package/src/javaParser.ts +2640 -0
  210. package/src/javaScript.ts +36 -0
  211. package/src/javaScriptParser.ts +57 -0
  212. package/src/javaScriptUnparser.test.ts +37 -0
  213. package/src/javaScriptUnparser.ts +7 -0
  214. package/src/javaUnparser.test.ts +37 -0
  215. package/src/javaUnparser.ts +640 -0
  216. package/src/jsonParser.ts +6 -27
  217. package/src/lookaheadParser.ts +2 -6
  218. package/src/negativeLookaheadParser.ts +1 -3
  219. package/src/nonEmptyArrayParser.ts +1 -3
  220. package/src/objectParser.test-d.ts +152 -0
  221. package/src/objectParser.test.ts +71 -0
  222. package/src/objectParser.ts +69 -0
  223. package/src/optionalParser.ts +1 -3
  224. package/src/parser.test.ts +151 -4
  225. package/src/parser.ts +11 -1
  226. package/src/parserConsumedSequenceParser.ts +2 -4
  227. package/src/parserContext.ts +26 -11
  228. package/src/parserError.ts +17 -3
  229. package/src/regexpParser.test.ts +264 -0
  230. package/src/regexpParser.ts +126 -0
  231. package/src/regularExpression.ts +24 -0
  232. package/src/regularExpressionParser.test.ts +102 -0
  233. package/src/regularExpressionParser.ts +920 -0
  234. package/src/separatedArrayParser.ts +1 -3
  235. package/src/separatedNonEmptyArrayParser.ts +1 -3
  236. package/src/sliceBoundedParser.test.ts +2 -2
  237. package/src/sliceBoundedParser.ts +15 -19
  238. package/src/smaliParser.test.ts +64 -0
  239. package/src/smaliParser.test.ts.md +12 -12
  240. package/src/smaliParser.test.ts.snap +0 -0
  241. package/src/smaliParser.ts +246 -534
  242. package/src/stringEscapes.ts +253 -0
  243. package/src/symbolicExpression.ts +17 -0
  244. package/src/symbolicExpressionParser.test.ts +466 -0
  245. package/src/symbolicExpressionParser.ts +190 -0
  246. package/src/terminatedArrayParser.test.ts +9 -6
  247. package/src/terminatedArrayParser.ts +25 -29
  248. package/src/tupleParser.ts +21 -18
  249. package/src/unionParser.test-d.ts +105 -0
  250. package/src/unionParser.test.ts +18 -17
  251. package/src/unionParser.ts +28 -16
  252. package/src/zig.ts +411 -0
  253. package/src/zigParser.test.ts +1693 -0
  254. package/src/zigParser.ts +1745 -0
  255. package/src/zigUnparser.test.ts +37 -0
  256. package/src/zigUnparser.ts +615 -0
  257. package/src/zipParser.ts +20 -56
  258. package/src/zipUnparser.test.ts +1 -1
  259. package/src/zipUnparser.ts +22 -7
  260. package/tsconfig.json +2 -2
  261. package/build/exactElementSwitchParser.d.ts +0 -3
  262. package/src/exactElementSwitchParser.ts +0 -41
@@ -0,0 +1,289 @@
1
+ import test from 'ava';
2
+ import { testProp, fc } from '@fast-check/ava';
3
+ import sExpression from 's-expression';
4
+ import { runParser } from './parser.js';
5
+ const seed = process.env.SEED ? Number(process.env.SEED) : undefined;
6
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
7
+ import { symbolicExpressionParser, symbolicExpressionDocumentParser, } from './symbolicExpressionParser.js';
8
+ // Convert s-expression package output to our discriminated union format
9
+ function convertToDiscriminatedUnion(value) {
10
+ if (Array.isArray(value)) {
11
+ // Handle quote forms: ['quote', x], ['quasiquote', x], etc.
12
+ if (value.length === 2 && typeof value[0] === 'string') {
13
+ const [type, inner] = value;
14
+ if (type === 'quote') {
15
+ return { type: 'quote', value: convertToDiscriminatedUnion(inner) };
16
+ }
17
+ if (type === 'quasiquote') {
18
+ return { type: 'quasiquote', value: convertToDiscriminatedUnion(inner) };
19
+ }
20
+ if (type === 'unquote') {
21
+ return { type: 'unquote', value: convertToDiscriminatedUnion(inner) };
22
+ }
23
+ if (type === 'unquote-splicing') {
24
+ return { type: 'unquote-splicing', value: convertToDiscriminatedUnion(inner) };
25
+ }
26
+ }
27
+ return { type: 'list', value: value.map(convertToDiscriminatedUnion) };
28
+ }
29
+ if (value instanceof String) {
30
+ return { type: 'string', value: value.valueOf() };
31
+ }
32
+ if (typeof value === 'string') {
33
+ return { type: 'atom', value };
34
+ }
35
+ throw new Error(`Unknown value type: ${typeof value}`);
36
+ }
37
+ // Basic atom parsing
38
+ test('atom - simple', async (t) => {
39
+ const result = await runParser(symbolicExpressionParser, 'a', stringParserInputCompanion);
40
+ t.deepEqual(result, { type: 'atom', value: 'a' });
41
+ });
42
+ test('atom - with numbers', async (t) => {
43
+ const result = await runParser(symbolicExpressionParser, 'abc123', stringParserInputCompanion);
44
+ t.deepEqual(result, { type: 'atom', value: 'abc123' });
45
+ });
46
+ // List parsing
47
+ test('list - empty', async (t) => {
48
+ const result = await runParser(symbolicExpressionParser, '()', stringParserInputCompanion);
49
+ t.deepEqual(result, { type: 'list', value: [] });
50
+ });
51
+ test('list - single element', async (t) => {
52
+ const result = await runParser(symbolicExpressionParser, '(a)', stringParserInputCompanion);
53
+ t.deepEqual(result, {
54
+ type: 'list',
55
+ value: [{ type: 'atom', value: 'a' }],
56
+ });
57
+ });
58
+ test('list - multiple elements', async (t) => {
59
+ const result = await runParser(symbolicExpressionParser, '(a b c)', stringParserInputCompanion);
60
+ t.deepEqual(result, {
61
+ type: 'list',
62
+ value: [
63
+ { type: 'atom', value: 'a' },
64
+ { type: 'atom', value: 'b' },
65
+ { type: 'atom', value: 'c' },
66
+ ],
67
+ });
68
+ });
69
+ test('list - nested', async (t) => {
70
+ const result = await runParser(symbolicExpressionParser, '((a b c)(()()))', stringParserInputCompanion);
71
+ t.deepEqual(result, {
72
+ type: 'list',
73
+ value: [
74
+ {
75
+ type: 'list',
76
+ value: [
77
+ { type: 'atom', value: 'a' },
78
+ { type: 'atom', value: 'b' },
79
+ { type: 'atom', value: 'c' },
80
+ ],
81
+ },
82
+ {
83
+ type: 'list',
84
+ value: [
85
+ { type: 'list', value: [] },
86
+ { type: 'list', value: [] },
87
+ ],
88
+ },
89
+ ],
90
+ });
91
+ });
92
+ // String parsing
93
+ test('string - simple', async (t) => {
94
+ const result = await runParser(symbolicExpressionParser, '"hello"', stringParserInputCompanion);
95
+ t.deepEqual(result, { type: 'string', value: 'hello' });
96
+ });
97
+ test('string - with escape sequences', async (t) => {
98
+ const result = await runParser(symbolicExpressionParser, '"hello\\nworld"', stringParserInputCompanion);
99
+ t.deepEqual(result, { type: 'string', value: 'hello\nworld' });
100
+ });
101
+ test('string - in list', async (t) => {
102
+ const result = await runParser(symbolicExpressionParser, '(a "hello")', stringParserInputCompanion);
103
+ t.deepEqual(result, {
104
+ type: 'list',
105
+ value: [
106
+ { type: 'atom', value: 'a' },
107
+ { type: 'string', value: 'hello' },
108
+ ],
109
+ });
110
+ });
111
+ // Quote parsing
112
+ test('quote - atom', async (t) => {
113
+ const result = await runParser(symbolicExpressionParser, "'a", stringParserInputCompanion);
114
+ t.deepEqual(result, {
115
+ type: 'quote',
116
+ value: { type: 'atom', value: 'a' },
117
+ });
118
+ });
119
+ test('quote - empty list', async (t) => {
120
+ const result = await runParser(symbolicExpressionParser, "'()", stringParserInputCompanion);
121
+ t.deepEqual(result, {
122
+ type: 'quote',
123
+ value: { type: 'list', value: [] },
124
+ });
125
+ });
126
+ test('quote - list', async (t) => {
127
+ const result = await runParser(symbolicExpressionParser, "'(a b c)", stringParserInputCompanion);
128
+ t.deepEqual(result, {
129
+ type: 'quote',
130
+ value: {
131
+ type: 'list',
132
+ value: [
133
+ { type: 'atom', value: 'a' },
134
+ { type: 'atom', value: 'b' },
135
+ { type: 'atom', value: 'c' },
136
+ ],
137
+ },
138
+ });
139
+ });
140
+ test('quote - nested', async (t) => {
141
+ const result = await runParser(symbolicExpressionParser, "''a", stringParserInputCompanion);
142
+ t.deepEqual(result, {
143
+ type: 'quote',
144
+ value: {
145
+ type: 'quote',
146
+ value: { type: 'atom', value: 'a' },
147
+ },
148
+ });
149
+ });
150
+ // Quasiquote parsing
151
+ test('quasiquote - atom', async (t) => {
152
+ const result = await runParser(symbolicExpressionParser, '`a', stringParserInputCompanion);
153
+ t.deepEqual(result, {
154
+ type: 'quasiquote',
155
+ value: { type: 'atom', value: 'a' },
156
+ });
157
+ });
158
+ test('quasiquote - list', async (t) => {
159
+ const result = await runParser(symbolicExpressionParser, '`(a b c)', stringParserInputCompanion);
160
+ t.deepEqual(result, {
161
+ type: 'quasiquote',
162
+ value: {
163
+ type: 'list',
164
+ value: [
165
+ { type: 'atom', value: 'a' },
166
+ { type: 'atom', value: 'b' },
167
+ { type: 'atom', value: 'c' },
168
+ ],
169
+ },
170
+ });
171
+ });
172
+ // Unquote parsing
173
+ test('unquote - atom', async (t) => {
174
+ const result = await runParser(symbolicExpressionParser, ',a', stringParserInputCompanion);
175
+ t.deepEqual(result, {
176
+ type: 'unquote',
177
+ value: { type: 'atom', value: 'a' },
178
+ });
179
+ });
180
+ test('unquote - list', async (t) => {
181
+ const result = await runParser(symbolicExpressionParser, ',(a b c)', stringParserInputCompanion);
182
+ t.deepEqual(result, {
183
+ type: 'unquote',
184
+ value: {
185
+ type: 'list',
186
+ value: [
187
+ { type: 'atom', value: 'a' },
188
+ { type: 'atom', value: 'b' },
189
+ { type: 'atom', value: 'c' },
190
+ ],
191
+ },
192
+ });
193
+ });
194
+ // Unquote-splicing parsing
195
+ test('unquote-splicing - atom', async (t) => {
196
+ const result = await runParser(symbolicExpressionParser, ',@a', stringParserInputCompanion);
197
+ t.deepEqual(result, {
198
+ type: 'unquote-splicing',
199
+ value: { type: 'atom', value: 'a' },
200
+ });
201
+ });
202
+ test('unquote-splicing - list', async (t) => {
203
+ const result = await runParser(symbolicExpressionParser, ',@(a b c)', stringParserInputCompanion);
204
+ t.deepEqual(result, {
205
+ type: 'unquote-splicing',
206
+ value: {
207
+ type: 'list',
208
+ value: [
209
+ { type: 'atom', value: 'a' },
210
+ { type: 'atom', value: 'b' },
211
+ { type: 'atom', value: 'c' },
212
+ ],
213
+ },
214
+ });
215
+ });
216
+ // Complex expressions
217
+ test('complex - quote inside list', async (t) => {
218
+ const result = await runParser(symbolicExpressionParser, "(a '(a b c))", stringParserInputCompanion);
219
+ t.deepEqual(result, {
220
+ type: 'list',
221
+ value: [
222
+ { type: 'atom', value: 'a' },
223
+ {
224
+ type: 'quote',
225
+ value: {
226
+ type: 'list',
227
+ value: [
228
+ { type: 'atom', value: 'a' },
229
+ { type: 'atom', value: 'b' },
230
+ { type: 'atom', value: 'c' },
231
+ ],
232
+ },
233
+ },
234
+ ],
235
+ });
236
+ });
237
+ test('complex - multiple quotes in list', async (t) => {
238
+ const result = await runParser(symbolicExpressionParser, "((a 'b 'c))", stringParserInputCompanion);
239
+ t.deepEqual(result, {
240
+ type: 'list',
241
+ value: [
242
+ {
243
+ type: 'list',
244
+ value: [
245
+ { type: 'atom', value: 'a' },
246
+ { type: 'quote', value: { type: 'atom', value: 'b' } },
247
+ { type: 'quote', value: { type: 'atom', value: 'c' } },
248
+ ],
249
+ },
250
+ ],
251
+ });
252
+ });
253
+ // Document parser with whitespace
254
+ test('document - with leading whitespace', async (t) => {
255
+ const result = await runParser(symbolicExpressionDocumentParser, ' a', stringParserInputCompanion);
256
+ t.deepEqual(result, { type: 'atom', value: 'a' });
257
+ });
258
+ test('document - with trailing whitespace', async (t) => {
259
+ const result = await runParser(symbolicExpressionDocumentParser, 'a ', stringParserInputCompanion);
260
+ t.deepEqual(result, { type: 'atom', value: 'a' });
261
+ });
262
+ // Arbitrary symbolic expression generator for property-based testing
263
+ const arbitraryAtomChar = fc.string({ minLength: 1, maxLength: 10 }).filter(s => s.length > 0 && !/[\s()"'`,;]/.test(s));
264
+ const arbitraryStringContent = fc.string({ maxLength: 20 }).map(s =>
265
+ // Escape special characters for string literals
266
+ s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t'));
267
+ const arbitrarySymbolicExpression = fc.letrec(tie => ({
268
+ atom: arbitraryAtomChar,
269
+ string: arbitraryStringContent.map(s => `"${s}"`),
270
+ list: fc.array(tie('expression'), { maxLength: 5 }).map(exprs => `(${exprs.join(' ')})`),
271
+ quote: tie('expression').map(e => `'${e}`),
272
+ quasiquote: tie('expression').map(e => `\`${e}`),
273
+ unquote: tie('expression').map(e => `,${e}`),
274
+ unquoteSplicing: tie('expression').map(e => `,@${e}`),
275
+ expression: fc.oneof({ weight: 5, arbitrary: tie('atom') }, { weight: 2, arbitrary: tie('string') }, { weight: 3, arbitrary: tie('list') }, { weight: 1, arbitrary: tie('quote') }, { weight: 1, arbitrary: tie('quasiquote') }, { weight: 1, arbitrary: tie('unquote') }, { weight: 1, arbitrary: tie('unquoteSplicing') }),
276
+ })).expression;
277
+ // Property-based test comparing with s-expression package
278
+ testProp('matches s-expression package output', [arbitrarySymbolicExpression], async (t, input) => {
279
+ const reference = sExpression(input);
280
+ if (reference instanceof Error) {
281
+ // If s-expression fails, our parser should also fail
282
+ await t.throwsAsync(() => runParser(symbolicExpressionParser, input, stringParserInputCompanion));
283
+ }
284
+ else {
285
+ const expected = convertToDiscriminatedUnion(reference);
286
+ const actual = await runParser(symbolicExpressionParser, input, stringParserInputCompanion);
287
+ t.deepEqual(actual, expected);
288
+ }
289
+ }, { seed });
@@ -1,3 +1,55 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  import { getParserName, setParserName } from './parser.js';
2
54
  import { isParserParsingFailedError } from './parserError.js';
3
55
  import { parserImplementationInvariant } from './parserImplementationInvariant.js';
@@ -33,43 +85,59 @@ export const createTerminatedArrayParser = (elementParser, terminatorParser) =>
33
85
  const terminatedArrayParser = async (parserContext) => {
34
86
  const elements = [];
35
87
  while (true) {
36
- const terminatorParserContext = parserContext.lookahead({
37
- debugName: getParserName(terminatorParser, 'anonymousTerminator'),
38
- });
88
+ const env_1 = { stack: [], error: void 0, hasError: false };
39
89
  try {
40
- const terminatorValue = await terminatorParser(terminatorParserContext);
41
- const elementParserContext = parserContext.lookahead({
42
- debugName: getParserName(elementParser, 'anonymousElement'),
43
- });
90
+ const terminatorParserContext = __addDisposableResource(env_1, parserContext.lookahead({
91
+ debugName: getParserName(terminatorParser, 'anonymousTerminator'),
92
+ }), false);
44
93
  try {
45
- await elementParser(elementParserContext);
46
- parserImplementationInvariant(false, [
47
- 'Both element and terminator parsers matched.',
48
- 'Element parser: %s',
49
- 'Terminator parser: %s',
50
- ], getParserName(elementParser, 'anonymousElement'), getParserName(terminatorParser, 'anonymousTerminator'));
94
+ const terminatorValue = await terminatorParser(terminatorParserContext);
95
+ {
96
+ const env_2 = { stack: [], error: void 0, hasError: false };
97
+ try {
98
+ const elementParserContext = __addDisposableResource(env_2, parserContext.lookahead({
99
+ debugName: getParserName(elementParser, 'anonymousElement'),
100
+ }), false);
101
+ try {
102
+ await elementParser(elementParserContext);
103
+ parserImplementationInvariant(false, [
104
+ 'Both element and terminator parsers matched.',
105
+ 'Element parser: %s',
106
+ 'Terminator parser: %s',
107
+ ], getParserName(elementParser, 'anonymousElement'), getParserName(terminatorParser, 'anonymousTerminator'));
108
+ }
109
+ catch (error) {
110
+ if (!(isParserParsingFailedError(error))) {
111
+ throw error;
112
+ }
113
+ }
114
+ }
115
+ catch (e_1) {
116
+ env_2.error = e_1;
117
+ env_2.hasError = true;
118
+ }
119
+ finally {
120
+ __disposeResources(env_2);
121
+ }
122
+ }
123
+ terminatorParserContext.unlookahead();
124
+ return [elements, terminatorValue];
51
125
  }
52
126
  catch (error) {
53
127
  if (!(isParserParsingFailedError(error))) {
54
128
  throw error;
55
129
  }
56
130
  }
57
- finally {
58
- elementParserContext.dispose();
59
- }
60
- terminatorParserContext.unlookahead();
61
- return [elements, terminatorValue];
131
+ const element = await elementParser(parserContext);
132
+ elements.push(element);
62
133
  }
63
- catch (error) {
64
- if (!(isParserParsingFailedError(error))) {
65
- throw error;
66
- }
134
+ catch (e_2) {
135
+ env_1.error = e_2;
136
+ env_1.hasError = true;
67
137
  }
68
138
  finally {
69
- terminatorParserContext.dispose();
139
+ __disposeResources(env_1);
70
140
  }
71
- const element = await elementParser(parserContext);
72
- elements.push(element);
73
141
  }
74
142
  };
75
143
  setParserName(terminatedArrayParser, `${getParserName(elementParser, 'anonymousElement')}*?${getParserName(terminatorParser, 'anonymousTerminator')}`);
@@ -79,24 +147,31 @@ export const createTerminatedArrayParserUnsafe = (elementParser, terminatorParse
79
147
  const terminatedArrayParserUnsafe = async (parserContext) => {
80
148
  const elements = [];
81
149
  while (true) {
82
- const terminatorParserContext = parserContext.lookahead({
83
- debugName: getParserName(terminatorParser, 'anonymousTerminator'),
84
- });
150
+ const env_3 = { stack: [], error: void 0, hasError: false };
85
151
  try {
86
- const terminatorValue = await terminatorParser(terminatorParserContext);
87
- terminatorParserContext.unlookahead();
88
- return [elements, terminatorValue];
89
- }
90
- catch (error) {
91
- if (!(isParserParsingFailedError(error))) {
92
- throw error;
152
+ const terminatorParserContext = __addDisposableResource(env_3, parserContext.lookahead({
153
+ debugName: getParserName(terminatorParser, 'anonymousTerminator'),
154
+ }), false);
155
+ try {
156
+ const terminatorValue = await terminatorParser(terminatorParserContext);
157
+ terminatorParserContext.unlookahead();
158
+ return [elements, terminatorValue];
93
159
  }
160
+ catch (error) {
161
+ if (!(isParserParsingFailedError(error))) {
162
+ throw error;
163
+ }
164
+ }
165
+ const element = await elementParser(parserContext);
166
+ elements.push(element);
167
+ }
168
+ catch (e_3) {
169
+ env_3.error = e_3;
170
+ env_3.hasError = true;
94
171
  }
95
172
  finally {
96
- terminatorParserContext.dispose();
173
+ __disposeResources(env_3);
97
174
  }
98
- const element = await elementParser(parserContext);
99
- elements.push(element);
100
175
  }
101
176
  };
102
177
  setParserName(terminatedArrayParserUnsafe, `${getParserName(elementParser, 'anonymousElement')}*?${getParserName(terminatorParser, 'anonymousTerminator')}`);
@@ -13,10 +13,12 @@ import { promiseCompose } from './promiseCompose.js';
13
13
  import { createUnionParser } from './unionParser.js';
14
14
  import { createExactElementParser } from './exactElementParser.js';
15
15
  test('terminatedArrayParser of union parsers', async (t) => {
16
- const parser = createTerminatedArrayParser(createUnionParser([
16
+ const elementParser = createUnionParser([
17
17
  createExactElementParser(1),
18
18
  createExactElementParser(2),
19
- ]), createExactElementParser(0));
19
+ ]);
20
+ const terminatorParser = createExactElementParser(0);
21
+ const parser = createTerminatedArrayParser(elementParser, terminatorParser);
20
22
  const input = new Uint8Array([0]);
21
23
  const result = await runParser(parser, input, uint8ArrayParserInputCompanion);
22
24
  t.deepEqual(result, [[], 0]);
@@ -1,15 +1,7 @@
1
- import { type Parser } from './parser.js';
2
- export declare function createTupleParser<A, B, Sequence>([parserA, parserB]: [Parser<A, Sequence>, Parser<B, Sequence>]): Parser<[A, B], Sequence>;
3
- export declare function createTupleParser<A, B, C, Sequence>([parserA, parserB, parserC]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>]): Parser<[A, B, C], Sequence>;
4
- export declare function createTupleParser<A, B, C, D, Sequence>([parserA, parserB, parserC, parserD]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>]): Parser<[A, B, C, D], Sequence>;
5
- export declare function createTupleParser<A, B, C, D, E, Sequence>([parserA, parserB, parserC, parserD, parserE]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>]): Parser<[A, B, C, D, E], Sequence>;
6
- export declare function createTupleParser<A, B, C, D, E, F, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>]): Parser<[A, B, C, D, E, F], Sequence>;
7
- export declare function createTupleParser<A, B, C, D, E, F, G, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>]): Parser<[A, B, C, D, E, F, G], Sequence>;
8
- export declare function createTupleParser<A, B, C, D, E, F, G, H, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>]): Parser<[A, B, C, D, E, F, G, H], Sequence>;
9
- export declare function createTupleParser<A, B, C, D, E, F, G, H, I, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH, parserI]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>, Parser<I, Sequence>]): Parser<[A, B, C, D, E, F, G, H, I], Sequence>;
10
- export declare function createTupleParser<A, B, C, D, E, F, G, H, I, J, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH, parserI, parserJ]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>, Parser<I, Sequence>, Parser<J, Sequence>]): Parser<[A, B, C, D, E, F, G, H, I, J], Sequence>;
11
- export declare function createTupleParser<A, B, C, D, E, F, G, H, I, J, K, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH, parserI, parserJ, parserK]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>, Parser<I, Sequence>, Parser<J, Sequence>, Parser<K, Sequence>]): Parser<[A, B, C, D, E, F, G, H, I, J, K], Sequence>;
12
- export declare function createTupleParser<A, B, C, D, E, F, G, H, I, J, K, L, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH, parserI, parserJ, parserK, parserL]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>, Parser<I, Sequence>, Parser<J, Sequence>, Parser<K, Sequence>, Parser<L, Sequence>]): Parser<[A, B, C, D, E, F, G, H, I, J, K, L], Sequence>;
13
- export declare function createTupleParser<A, B, C, D, E, F, G, H, I, J, K, L, M, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH, parserI, parserJ, parserK, parserL, parserM]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>, Parser<I, Sequence>, Parser<J, Sequence>, Parser<K, Sequence>, Parser<L, Sequence>, Parser<M, Sequence>]): Parser<[A, B, C, D, E, F, G, H, I, J, K, L, M], Sequence>;
14
- export declare function createTupleParser<A, B, C, D, E, F, G, H, I, J, K, L, M, N, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH, parserI, parserJ, parserK, parserL, parserM, parserN]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>, Parser<I, Sequence>, Parser<J, Sequence>, Parser<K, Sequence>, Parser<L, Sequence>, Parser<M, Sequence>, Parser<N, Sequence>]): Parser<[A, B, C, D, E, F, G, H, I, J, K, L, M, N], Sequence>;
15
- export declare function createTupleParser<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, Sequence>([parserA, parserB, parserC, parserD, parserE, parserF, parserG, parserH, parserI, parserJ, parserK, parserL, parserM, parserN, parserO]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>, Parser<D, Sequence>, Parser<E, Sequence>, Parser<F, Sequence>, Parser<G, Sequence>, Parser<H, Sequence>, Parser<I, Sequence>, Parser<J, Sequence>, Parser<K, Sequence>, Parser<L, Sequence>, Parser<M, Sequence>, Parser<N, Sequence>, Parser<O, Sequence>]): Parser<[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O], Sequence>;
1
+ import { type Parser, type ParserOutput, type ParserSequence } from './parser.js';
2
+ type TupleParserOutput<Parsers extends readonly Parser<any, any, any>[]> = {
3
+ [K in keyof Parsers]: Parsers[K] extends Parser<any, any, any> ? ParserOutput<Parsers[K]> : never;
4
+ };
5
+ type InferSequenceFromParserArray<T extends readonly unknown[]> = ParserSequence<T[number]>;
6
+ export declare function createTupleParser<const Parsers extends readonly Parser<any, any, any>[]>(parsers: Parsers): Parser<TupleParserOutput<Parsers>, InferSequenceFromParserArray<Parsers>, any>;
7
+ export {};
@@ -1,5 +1,6 @@
1
1
  import { getParserName, setParserName } from './parser.js';
2
2
  export function createTupleParser(parsers) {
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
4
  const tupleParser = async (parserContext) => {
4
5
  const values = [];
5
6
  for (const parser of parsers) {
@@ -1,3 +1,5 @@
1
- import { type Parser } from './parser.js';
2
- import { type DeriveSequenceElement } from './sequence.js';
3
- export declare const createUnionParser: <Output, Sequence, Element = DeriveSequenceElement<Sequence>>(childParsers: Array<Parser<unknown, Sequence, Element>>) => Parser<Output, Sequence, Element>;
1
+ import { type Parser, type ParserOutput, type ParserSequence } from './parser.js';
2
+ type UnionParserOutput<Parsers extends readonly unknown[]> = ParserOutput<Parsers[number]>;
3
+ type InferSequenceFromParserArray<T extends readonly unknown[]> = ParserSequence<T[number]>;
4
+ export declare function createUnionParser<const Parsers extends readonly Parser<any, any, any>[]>(childParsers: Parsers): Parser<UnionParserOutput<Parsers>, InferSequenceFromParserArray<Parsers>>;
5
+ export {};
@@ -8,10 +8,12 @@ const bigintReplacer = (_key, value) => {
8
8
  }
9
9
  return value;
10
10
  };
11
- export const createUnionParser = (childParsers) => {
11
+ export function createUnionParser(childParsers) {
12
12
  parserImplementationInvariant(childParsers.length > 0, 'Union parser must have at least one child parser.');
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
14
  const unionParser = async (parserContext) => {
14
15
  let runningChildParserContexts = [];
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
17
  const createChildParserTask = (childParser) => {
16
18
  const childParserContext = parserContext.lookahead({
17
19
  debugName: getParserName(childParser, 'anonymousUnionChild'),
@@ -21,6 +23,7 @@ export const createUnionParser = (childParsers) => {
21
23
  childParserContext,
22
24
  };
23
25
  runningChildParserContexts.push(context);
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
27
  const getChildParserPromise = (async () => childParser(childParserContext));
25
28
  const promise = getChildParserPromise();
26
29
  return {
@@ -28,8 +31,10 @@ export const createUnionParser = (childParsers) => {
28
31
  context,
29
32
  };
30
33
  };
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
35
  const childParserResults = allSettledStream(childParsers.map(createChildParserTask));
32
36
  const parserParsingFailedErrors = [];
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
38
  const successfulParserOutputs = [];
34
39
  const successfulTaskContexts = [];
35
40
  let didUnlookahead = false;
@@ -80,4 +85,4 @@ export const createUnionParser = (childParsers) => {
80
85
  ')',
81
86
  ].join('');
82
87
  return setParserName(unionParser, name);
83
- };
88
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ import { expectAssignable } from 'tsd';
2
+ import { createUnionParser } from './unionParser.js';
3
+ import { createExactSequenceParser } from './exactSequenceParser.js';
4
+ import { createExactElementParser } from './exactElementParser.js';
5
+ import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
6
+ // Test: basic union of string parsers - output inferred as string
7
+ {
8
+ const parser = createUnionParser([
9
+ createExactElementParser('a'),
10
+ createExactElementParser('b'),
11
+ ]);
12
+ expectAssignable(null);
13
+ expectAssignable(null);
14
+ }
15
+ // Test: union preserves literal types when parsers have explicit literal output types
16
+ {
17
+ const parserA = async () => 'a';
18
+ const parserB = async () => 'b';
19
+ const parser = createUnionParser([parserA, parserB]);
20
+ // Output should be 'a' | 'b', not string
21
+ expectAssignable(null);
22
+ expectAssignable(null);
23
+ }
24
+ // Test: union of parsers with different output types
25
+ {
26
+ const stringParser = createFixedLengthSequenceParser(3);
27
+ const numberParser = () => 42;
28
+ const parser = createUnionParser([
29
+ stringParser,
30
+ numberParser,
31
+ ]);
32
+ // Output should be string | number
33
+ expectAssignable(null);
34
+ expectAssignable(null);
35
+ }
36
+ // Test: nested unions
37
+ {
38
+ const inner = createUnionParser([
39
+ createExactElementParser('a'),
40
+ createExactElementParser('b'),
41
+ ]);
42
+ const parser = createUnionParser([
43
+ inner,
44
+ createExactElementParser('c'),
45
+ ]);
46
+ expectAssignable(null);
47
+ expectAssignable(null);
48
+ }
49
+ // Test: sequence type inferred from child parsers
50
+ {
51
+ const parser = createUnionParser([
52
+ createExactSequenceParser('hello'),
53
+ createExactSequenceParser('world'),
54
+ ]);
55
+ // Parser should be for string sequences, output is string (widened from literals)
56
+ expectAssignable(null);
57
+ }
58
+ // Test: single parser in union
59
+ {
60
+ const parser = createUnionParser([
61
+ createExactSequenceParser('only'),
62
+ ]);
63
+ // Output is string (widened from literal 'only')
64
+ expectAssignable(null);
65
+ }
66
+ // Test: union of object-producing parsers
67
+ {
68
+ const parser1 = async () => ({ type: 'a', value: 1 });
69
+ const parser2 = async () => ({ type: 'b', name: 'test' });
70
+ const parser = createUnionParser([parser1, parser2]);
71
+ expectAssignable(null);
72
+ }