@futpib/parser 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/.editorconfig +12 -0
  2. package/.gitattributes +2 -0
  3. package/.github/workflows/main.yml +29 -0
  4. package/.yarn/releases/yarn-4.5.3.cjs +934 -0
  5. package/.yarnrc.yml +7 -0
  6. package/build/allSettledStream.d.ts +17 -0
  7. package/build/allSettledStream.js +21 -0
  8. package/build/allSettledStream.test.d.ts +1 -0
  9. package/build/allSettledStream.test.js +56 -0
  10. package/build/apk.d.ts +13 -0
  11. package/build/apk.js +1 -0
  12. package/build/apkParser.d.ts +3 -0
  13. package/build/apkParser.js +135 -0
  14. package/build/apkParser.test.d.ts +1 -0
  15. package/build/apkParser.test.js +22 -0
  16. package/build/arbitrarilySlicedAsyncInterable.d.ts +2 -0
  17. package/build/arbitrarilySlicedAsyncInterable.js +46 -0
  18. package/build/arbitrarilySlicedAsyncInterator.d.ts +2 -0
  19. package/build/arbitrarilySlicedAsyncInterator.js +17 -0
  20. package/build/arbitraryDosDate.d.ts +2 -0
  21. package/build/arbitraryDosDate.js +8 -0
  22. package/build/arbitraryDosDateTime.d.ts +2 -0
  23. package/build/arbitraryDosDateTime.js +9 -0
  24. package/build/arbitraryDosPermissions.d.ts +1 -0
  25. package/build/arbitraryDosPermissions.js +1 -0
  26. package/build/arbitraryFileSystemEntry.d.ts +14 -0
  27. package/build/arbitraryFileSystemEntry.js +12 -0
  28. package/build/arbitraryZip.d.ts +6 -0
  29. package/build/arbitraryZip.js +88 -0
  30. package/build/arbitraryZipEntry.d.ts +3 -0
  31. package/build/arbitraryZipEntry.js +26 -0
  32. package/build/arbitraryZipPermissions.d.ts +8 -0
  33. package/build/arbitraryZipPermissions.js +16 -0
  34. package/build/arbitraryZipStream.d.ts +5 -0
  35. package/build/arbitraryZipStream.js +50 -0
  36. package/build/arrayParser.d.ts +2 -0
  37. package/build/arrayParser.js +30 -0
  38. package/build/arrayParser.test.d.ts +1 -0
  39. package/build/arrayParser.test.js +9 -0
  40. package/build/bsonParser.d.ts +3 -0
  41. package/build/bsonParser.js +70 -0
  42. package/build/bsonParser.test.d.ts +1 -0
  43. package/build/bsonParser.test.js +24 -0
  44. package/build/createDisjunctionParser.d.ts +2 -0
  45. package/build/createDisjunctionParser.js +47 -0
  46. package/build/createExactParser.d.ts +2 -0
  47. package/build/createExactParser.js +12 -0
  48. package/build/createSequentialUnionParser.d.ts +2 -0
  49. package/build/createSequentialUnionParser.js +69 -0
  50. package/build/debugLogParser.d.ts +2 -0
  51. package/build/debugLogParser.js +23 -0
  52. package/build/disjunctionParser.d.ts +2 -0
  53. package/build/disjunctionParser.js +35 -0
  54. package/build/elementParser.d.ts +3 -0
  55. package/build/elementParser.js +1 -0
  56. package/build/endOfInputParser.d.ts +4 -0
  57. package/build/endOfInputParser.js +4 -0
  58. package/build/exactElementParser.d.ts +3 -0
  59. package/build/exactElementParser.js +6 -0
  60. package/build/exactSequenceParser.d.ts +2 -0
  61. package/build/exactSequenceParser.js +15 -0
  62. package/build/fixedLengthChunkParser.d.ts +2 -0
  63. package/build/fixedLengthChunkParser.js +12 -0
  64. package/build/fixedLengthParser.d.ts +2 -0
  65. package/build/fixedLengthParser.js +12 -0
  66. package/build/fixedLengthSequenceParser.d.ts +2 -0
  67. package/build/fixedLengthSequenceParser.js +16 -0
  68. package/build/index.d.ts +18 -0
  69. package/build/index.js +17 -0
  70. package/build/index.test.d.ts +1 -0
  71. package/build/index.test.js +2 -0
  72. package/build/inputChunkBuffer.d.ts +15 -0
  73. package/build/inputChunkBuffer.js +40 -0
  74. package/build/inputChunkBuffer.test.d.ts +1 -0
  75. package/build/inputChunkBuffer.test.js +34 -0
  76. package/build/inputCompanion.d.ts +18 -0
  77. package/build/inputCompanion.js +28 -0
  78. package/build/inputReader.d.ts +22 -0
  79. package/build/inputReader.js +105 -0
  80. package/build/inputReader.test.d.ts +1 -0
  81. package/build/inputReader.test.js +174 -0
  82. package/build/invariantDefined.d.ts +1 -0
  83. package/build/invariantDefined.js +5 -0
  84. package/build/invariantIdentity.d.ts +3 -0
  85. package/build/invariantIdentity.js +5 -0
  86. package/build/jsonParser.d.ts +3 -0
  87. package/build/jsonParser.js +133 -0
  88. package/build/jsonParser.test.d.ts +1 -0
  89. package/build/jsonParser.test.js +17 -0
  90. package/build/jsonParser2.d.ts +3 -0
  91. package/build/jsonParser2.js +52 -0
  92. package/build/jsonParser2.test.d.ts +1 -0
  93. package/build/jsonParser2.test.js +22 -0
  94. package/build/listParser.d.ts +2 -0
  95. package/build/listParser.js +34 -0
  96. package/build/negativeLookahead.d.ts +2 -0
  97. package/build/negativeLookahead.js +20 -0
  98. package/build/optionalParser.d.ts +2 -0
  99. package/build/optionalParser.js +23 -0
  100. package/build/parser.d.ts +10 -0
  101. package/build/parser.js +53 -0
  102. package/build/parser.test.d.ts +1 -0
  103. package/build/parser.test.js +126 -0
  104. package/build/parserAccessorParser.d.ts +2 -0
  105. package/build/parserAccessorParser.js +1 -0
  106. package/build/parserCompose.d.ts +3 -0
  107. package/build/parserCompose.js +7 -0
  108. package/build/parserContext.d.ts +48 -0
  109. package/build/parserContext.js +193 -0
  110. package/build/parserContext.test.d.ts +1 -0
  111. package/build/parserContext.test.js +115 -0
  112. package/build/parserCreatorCompose.d.ts +3 -0
  113. package/build/parserCreatorCompose.js +10 -0
  114. package/build/parserError.d.ts +43 -0
  115. package/build/parserError.js +61 -0
  116. package/build/parserImplementationInvariant.d.ts +2 -0
  117. package/build/parserImplementationInvariant.js +5 -0
  118. package/build/parserImplementationInvariantInvariant.d.ts +3 -0
  119. package/build/parserImplementationInvariantInvariant.js +15 -0
  120. package/build/parserInvariant.d.ts +4 -0
  121. package/build/parserInvariant.js +11 -0
  122. package/build/parserParsingInvariant.d.ts +1 -0
  123. package/build/parserParsingInvariant.js +1 -0
  124. package/build/promiseCompose.d.ts +1 -0
  125. package/build/promiseCompose.js +3 -0
  126. package/build/promiseFish.d.ts +1 -0
  127. package/build/promiseFish.js +3 -0
  128. package/build/sequence.d.ts +1 -0
  129. package/build/sequence.js +1 -0
  130. package/build/sequenceBuffer.d.ts +15 -0
  131. package/build/sequenceBuffer.js +40 -0
  132. package/build/sequenceBuffer.test.d.ts +1 -0
  133. package/build/sequenceBuffer.test.js +34 -0
  134. package/build/sequenceParser.d.ts +3 -0
  135. package/build/sequenceParser.js +10 -0
  136. package/build/skipParser.d.ts +2 -0
  137. package/build/skipParser.js +8 -0
  138. package/build/sliceBoundedParser.d.ts +2 -0
  139. package/build/sliceBoundedParser.js +24 -0
  140. package/build/sliceBoundedParser.test.d.ts +1 -0
  141. package/build/sliceBoundedParser.test.js +24 -0
  142. package/build/terminatedArrayParser.d.ts +2 -0
  143. package/build/terminatedArrayParser.js +27 -0
  144. package/build/terminatedSequenceParser.d.ts +2 -0
  145. package/build/terminatedSequenceParser.js +24 -0
  146. package/build/tupleParser.d.ts +11 -0
  147. package/build/tupleParser.js +17 -0
  148. package/build/unionParser.d.ts +2 -0
  149. package/build/unionParser.js +68 -0
  150. package/build/zip.d.ts +31 -0
  151. package/build/zip.js +1 -0
  152. package/build/zipEntry.d.ts +28 -0
  153. package/build/zipEntry.js +1 -0
  154. package/build/zipFile.d.ts +32 -0
  155. package/build/zipFile.js +1 -0
  156. package/build/zipFileEntry.d.ts +6 -0
  157. package/build/zipFileEntry.js +1 -0
  158. package/build/zipParser.d.ts +70 -0
  159. package/build/zipParser.js +255 -0
  160. package/build/zipParser.test.d.ts +1 -0
  161. package/build/zipParser.test.js +22 -0
  162. package/package.json +52 -0
  163. package/readme.md +17 -0
  164. package/renovate.json +6 -0
  165. package/src/allSettledStream.test.ts +59 -0
  166. package/src/allSettledStream.test.ts.md +52 -0
  167. package/src/allSettledStream.test.ts.snap +0 -0
  168. package/src/allSettledStream.ts +44 -0
  169. package/src/apk.ts +16 -0
  170. package/src/apkParser.test.ts +30 -0
  171. package/src/apkParser.test.ts.md +268 -0
  172. package/src/apkParser.test.ts.snap +0 -0
  173. package/src/apkParser.ts +327 -0
  174. package/src/arbitrarilySlicedAsyncInterable.ts +73 -0
  175. package/src/arbitrarilySlicedAsyncInterator.ts +25 -0
  176. package/src/arbitraryDosDateTime.ts +10 -0
  177. package/src/arbitraryFileSystemEntry.ts +36 -0
  178. package/src/arbitraryZip.ts +132 -0
  179. package/src/arbitraryZipPermissions.ts +25 -0
  180. package/src/arbitraryZipStream.ts +60 -0
  181. package/src/arrayParser.test.ts +11 -0
  182. package/src/arrayParser.ts +35 -0
  183. package/src/bsonParser.test.ts +37 -0
  184. package/src/bsonParser.ts +131 -0
  185. package/src/debugLogParser.ts +51 -0
  186. package/src/disjunctionParser.ts +55 -0
  187. package/src/elementParser.ts +4 -0
  188. package/src/endOfInputParser.ts +11 -0
  189. package/src/exactElementParser.ts +20 -0
  190. package/src/exactSequenceParser.ts +27 -0
  191. package/src/fixedLengthSequenceParser.ts +24 -0
  192. package/src/index.test.ts +3 -0
  193. package/src/index.ts +76 -0
  194. package/src/inputCompanion.ts +43 -0
  195. package/src/inputReader.test.ts +238 -0
  196. package/src/inputReader.ts +159 -0
  197. package/src/invariantDefined.ts +6 -0
  198. package/src/invariantIdentity.ts +8 -0
  199. package/src/jsonParser.test.ts +26 -0
  200. package/src/jsonParser.ts +225 -0
  201. package/src/listParser.ts +52 -0
  202. package/src/negativeLookahead.ts +26 -0
  203. package/src/optionalParser.ts +27 -0
  204. package/src/parser.test.ts +176 -0
  205. package/src/parser.test.ts.md +68 -0
  206. package/src/parser.test.ts.snap +0 -0
  207. package/src/parser.ts +103 -0
  208. package/src/parserAccessorParser.ts +3 -0
  209. package/src/parserContext.test.ts +154 -0
  210. package/src/parserContext.ts +316 -0
  211. package/src/parserCreatorCompose.ts +23 -0
  212. package/src/parserError.ts +85 -0
  213. package/src/parserImplementationInvariant.ts +6 -0
  214. package/src/parserInvariant.ts +26 -0
  215. package/src/promiseCompose.ts +7 -0
  216. package/src/sequence.ts +10 -0
  217. package/src/sequenceBuffer.test.ts +50 -0
  218. package/src/sequenceBuffer.ts +58 -0
  219. package/src/skipParser.ts +12 -0
  220. package/src/sliceBoundedParser.test.ts +28 -0
  221. package/src/sliceBoundedParser.ts +30 -0
  222. package/src/terminatedArrayParser.ts +40 -0
  223. package/src/tupleParser.ts +33 -0
  224. package/src/unionParser.ts +104 -0
  225. package/src/zip.ts +48 -0
  226. package/src/zipParser.test.ts +31 -0
  227. package/src/zipParser.ts +501 -0
  228. package/tsconfig.json +109 -0
@@ -0,0 +1,225 @@
1
+ import {
2
+ type JsonArray, type JsonObject, type JsonPrimitive, type JsonValue, type Writable,
3
+ } from 'type-fest';
4
+ import { setParserName, type Parser } from './parser.js';
5
+ import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
6
+ import { createUnionParser } from './unionParser.js';
7
+ import { createExactSequenceParser } from './exactSequenceParser.js';
8
+ import { promiseCompose } from './promiseCompose.js';
9
+ import { createTupleParser } from './tupleParser.js';
10
+ import { createDisjunctionParser } from './disjunctionParser.js';
11
+ import { createTerminatedArrayParser } from './terminatedArrayParser.js';
12
+ import { createArrayParser } from './arrayParser.js';
13
+ import { createParserAccessorParser } from './parserAccessorParser.js';
14
+ import { createElementParser } from './elementParser.js';
15
+ import { parserCreatorCompose } from './parserCreatorCompose.js';
16
+
17
+ const whitespaceParser: Parser<unknown, string> = createArrayParser(
18
+ createUnionParser([
19
+ createExactSequenceParser(' '),
20
+ createExactSequenceParser('\t'),
21
+ createExactSequenceParser('\r'),
22
+ createExactSequenceParser('\n'),
23
+ ]),
24
+ );
25
+
26
+ const jsonQuoteEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\"'), () => '"');
27
+ const jsonBackslashEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\\\'), () => '\\');
28
+ const jsonSlashEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\/'), () => '/');
29
+ const jsonBackspaceEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\b'), () => '\b');
30
+ const jsonFormFeedEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\f'), () => '\f');
31
+ const jsonNewLineEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\n'), () => '\n');
32
+ const jsonCarriageReturnEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\r'), () => '\r');
33
+ const jsonTabEscapeSequenceParser: Parser<string, string> = promiseCompose(createExactSequenceParser('\\t'), () => '\t');
34
+
35
+ const jsonUnicodeEscapeSequenceParser: Parser<string, string> = promiseCompose(
36
+ createTupleParser([
37
+ createExactSequenceParser('\\u'),
38
+ createFixedLengthSequenceParser<string>(4),
39
+ ]),
40
+ ([ , hexCode ]) => String.fromCharCode(Number.parseInt(hexCode, 16)),
41
+ );
42
+
43
+ const jsonStringEscapeSequenceParser: Parser<string, string> = createUnionParser([
44
+ jsonQuoteEscapeSequenceParser,
45
+ jsonBackslashEscapeSequenceParser,
46
+ jsonSlashEscapeSequenceParser,
47
+ jsonBackspaceEscapeSequenceParser,
48
+ jsonFormFeedEscapeSequenceParser,
49
+ jsonNewLineEscapeSequenceParser,
50
+ jsonCarriageReturnEscapeSequenceParser,
51
+ jsonTabEscapeSequenceParser,
52
+ jsonUnicodeEscapeSequenceParser,
53
+ ]);
54
+
55
+ const elementParser: Parser<string, string> = createElementParser();
56
+
57
+ const jsonStringCharacterParser: Parser<string, string> = createDisjunctionParser([
58
+ jsonStringEscapeSequenceParser,
59
+ parserCreatorCompose(
60
+ () => elementParser,
61
+ character => async parserContext => {
62
+ parserContext.invariant(character !== '"', 'Unexpected """');
63
+ return character;
64
+ },
65
+ )(),
66
+ ]);
67
+
68
+ const jsonStringParser: Parser<string, string> = promiseCompose(
69
+ createTupleParser([
70
+ createExactSequenceParser('"'),
71
+ promiseCompose(
72
+ createTerminatedArrayParser(
73
+ jsonStringCharacterParser,
74
+ createExactSequenceParser('"'),
75
+ ),
76
+ ([ characters ]) => characters.join(''),
77
+ ),
78
+ ]),
79
+ ([ , string ]) => string,
80
+ );
81
+
82
+ const jsonNumberParser: Parser<number, string> = parserCreatorCompose(
83
+ () => createArrayParser(
84
+ parserCreatorCompose(
85
+ () => elementParser,
86
+ (character) => async parserContext => {
87
+ parserContext.invariant(
88
+ (
89
+ character === '-'
90
+ || (character >= '0' && character <= '9')
91
+ || character === '.'
92
+ || character === 'e'
93
+ || character === 'E'
94
+ || character === '+'
95
+ ),
96
+ 'Expected "-", "0" to "9", ".", "e", "E", "+", got "%s"',
97
+ character,
98
+ );
99
+
100
+ return character;
101
+ },
102
+ )(),
103
+ ),
104
+ (characters) => async parserContext => {
105
+ parserContext.invariant(characters.length > 0, 'Expected at least one character');
106
+
107
+ return Number(characters.join(''));
108
+ },
109
+ )();
110
+
111
+ const jsonTrueParser: Parser<true, string> = promiseCompose(createExactSequenceParser('true'), () => true);
112
+
113
+ setParserName(jsonTrueParser, 'jsonTrueParser');
114
+
115
+ const jsonFalseParser: Parser<false, string> = promiseCompose(createExactSequenceParser('false'), () => false);
116
+
117
+ setParserName(jsonFalseParser, 'jsonFalseParser');
118
+
119
+ const jsonNullParser: Parser<null, string> = promiseCompose(createExactSequenceParser('null'), () => null);
120
+
121
+ setParserName(jsonNullParser, 'jsonNullParser');
122
+
123
+ const jsonPrimitiveParser: Parser<JsonPrimitive, string> = createUnionParser([
124
+ jsonStringParser,
125
+ jsonNumberParser,
126
+ jsonTrueParser,
127
+ jsonFalseParser,
128
+ jsonNullParser,
129
+ ]);
130
+
131
+ setParserName(jsonPrimitiveParser, 'jsonPrimitiveParser');
132
+
133
+ const jsonObjectEntryParser: Parser<[string, JsonValue], string> = promiseCompose(
134
+ createTupleParser([
135
+ jsonStringParser,
136
+ whitespaceParser,
137
+ createExactSequenceParser(':'),
138
+ whitespaceParser,
139
+ createParserAccessorParser(() => jsonValueParser),
140
+ ]),
141
+ ([key, _whitespace1, _colon, _whitespace2, value]) => [key, value],
142
+ );
143
+
144
+ const jsonObjectParser: Parser<JsonObject, string> = promiseCompose(
145
+ createTupleParser([
146
+ createExactSequenceParser('{'),
147
+ whitespaceParser,
148
+ promiseCompose(
149
+ createTerminatedArrayParser(
150
+ createDisjunctionParser<[string, JsonValue], string>([
151
+ promiseCompose(
152
+ createTupleParser([
153
+ createParserAccessorParser(() => jsonObjectEntryParser),
154
+ whitespaceParser,
155
+ createExactSequenceParser(','),
156
+ whitespaceParser,
157
+ ]),
158
+ ([entry]) => entry,
159
+ ),
160
+ promiseCompose(
161
+ createTupleParser([
162
+ createParserAccessorParser(() => jsonObjectEntryParser),
163
+ whitespaceParser,
164
+ ]),
165
+ ([value]) => value,
166
+ ),
167
+ ]),
168
+ createExactSequenceParser('}'),
169
+ ),
170
+ ([entries]) => entries,
171
+ ),
172
+ ]),
173
+ ([ _brace, _whitespace, entries]) => {
174
+ const object: Writable<JsonObject> = {};
175
+
176
+ for (const [key, value] of entries) {
177
+ Object.defineProperty(object, key, {
178
+ value,
179
+ enumerable: true,
180
+ });
181
+ }
182
+
183
+ return object;
184
+ },
185
+ );
186
+
187
+ const jsonArrayParser: Parser<JsonArray, string> = promiseCompose(
188
+ createTupleParser([
189
+ createExactSequenceParser('['),
190
+ whitespaceParser,
191
+ promiseCompose(
192
+ createTerminatedArrayParser(
193
+ createDisjunctionParser<JsonValue, string>([
194
+ promiseCompose(
195
+ createTupleParser([
196
+ createParserAccessorParser(() => jsonValueParser),
197
+ whitespaceParser,
198
+ createExactSequenceParser(','),
199
+ whitespaceParser,
200
+ ]),
201
+ ([value]) => value,
202
+ ),
203
+ promiseCompose(
204
+ createTupleParser([
205
+ createParserAccessorParser(() => jsonValueParser),
206
+ whitespaceParser,
207
+ ]),
208
+ ([value]) => value,
209
+ ),
210
+ ]),
211
+ createExactSequenceParser(']'),
212
+ ),
213
+ ([values]) => values,
214
+ ),
215
+ ]),
216
+ ([_bracket, _whitespace, values]) => values,
217
+ );
218
+
219
+ export const jsonValueParser: Parser<JsonValue, string> = createUnionParser([
220
+ jsonObjectParser,
221
+ jsonArrayParser,
222
+ jsonPrimitiveParser,
223
+ ]);
224
+
225
+ setParserName(jsonValueParser, 'jsonValueParser');
@@ -0,0 +1,52 @@
1
+ import { createNegativeLookaheadParser } from "./negativeLookahead.js";
2
+ import { Parser } from "./parser.js";
3
+ import { createParserAccessorParser } from "./parserAccessorParser.js";
4
+ import { promiseCompose } from "./promiseCompose.js";
5
+ import { createTupleParser } from "./tupleParser.js";
6
+ import { createUnionParser } from "./unionParser.js";
7
+
8
+ class Nil {}
9
+ class Cons<Head, Tail> {
10
+ constructor(
11
+ public readonly head: Head,
12
+ public readonly tail: Tail,
13
+ ) {}
14
+ }
15
+
16
+ export const createListParser = <ElementOutput, Sequence>(
17
+ elementParser: Parser<ElementOutput, Sequence>,
18
+ ): Parser<ElementOutput[], Sequence> => {
19
+ type List = Nil | Cons<ElementOutput, List>;
20
+
21
+ const consParser = promiseCompose(
22
+ createTupleParser([
23
+ elementParser,
24
+ createParserAccessorParser(() => listParser),
25
+ ]),
26
+ ([ head, tail ]) => new Cons(head, tail),
27
+ );
28
+
29
+ const nilParser = promiseCompose(
30
+ createNegativeLookaheadParser(elementParser),
31
+ () => new Nil(),
32
+ );
33
+
34
+ const listParser: Parser<List, Sequence> = createUnionParser([
35
+ consParser,
36
+ nilParser,
37
+ ]);
38
+
39
+ return promiseCompose(
40
+ listParser,
41
+ list => {
42
+ const array: ElementOutput[] = [];
43
+
44
+ while (list instanceof Cons) {
45
+ array.push(list.head);
46
+ list = list.tail;
47
+ }
48
+
49
+ return array;
50
+ },
51
+ );
52
+ };
@@ -0,0 +1,26 @@
1
+ import { getParserName, Parser } from "./parser.js";
2
+ import { ParserParsingFailedError } from "./parserError.js";
3
+
4
+ export const createNegativeLookaheadParser = <Sequence>(
5
+ childParser: Parser<unknown, Sequence>,
6
+ ): Parser<void, Sequence> => {
7
+ return async parserContext => {
8
+ const childParserContext = parserContext.lookahead();
9
+ try {
10
+ await childParser(childParserContext);
11
+ parserContext.invariant(
12
+ false,
13
+ 'Negative lookahead assertion failed for child parser %s.',
14
+ getParserName(childParser),
15
+ );
16
+ } catch (error) {
17
+ if (error instanceof ParserParsingFailedError) {
18
+ return;
19
+ }
20
+
21
+ throw error;
22
+ } finally {
23
+ childParserContext.dispose();
24
+ }
25
+ };
26
+ };
@@ -0,0 +1,27 @@
1
+ import { getParserName, Parser, setParserName } from "./parser.js";
2
+ import { ParserParsingFailedError } from "./parserError.js";
3
+
4
+ export const createOptionalParser = <Output, Sequence>(
5
+ childParser: Parser<Output, Sequence>,
6
+ ): Parser<undefined | Output, Sequence> => {
7
+ const optionalParser: Parser<undefined | Output, Sequence> = async parserContext => {
8
+ const childParserContext = parserContext.lookahead();
9
+ try {
10
+ const value = await childParser(childParserContext);
11
+ childParserContext.unlookahead();
12
+ return value;
13
+ } catch (error) {
14
+ if (error instanceof ParserParsingFailedError) {
15
+ return undefined;
16
+ }
17
+
18
+ throw error;
19
+ } finally {
20
+ childParserContext.dispose();
21
+ }
22
+ };
23
+
24
+ setParserName(optionalParser, getParserName(childParser, 'anonymousOptionalChild') + '?');
25
+
26
+ return optionalParser;
27
+ }
@@ -0,0 +1,176 @@
1
+ import test from 'ava';
2
+ import { createUnionParser } from './unionParser.js';
3
+ import { Parser, runParser } from './parser.js';
4
+ import { stringInputCompanion, uint8ArrayInputCompanion } from './inputCompanion.js';
5
+ import { ParserParsingInvariantError, ParserParsingJoinAllError, ParserParsingJoinDeepestError, ParserParsingJoinError, ParserParsingJoinFurthestError, ParserParsingJoinNoneError } from './parserError.js';
6
+ import { createTupleParser } from './tupleParser.js';
7
+ import { promiseCompose } from './promiseCompose.js';
8
+ import { createDisjunctionParser } from './disjunctionParser.js';
9
+ import invariant from 'invariant';
10
+ import { createExactSequenceParser } from './exactSequenceParser.js';
11
+ import { createArrayParser } from './arrayParser.js';
12
+ import { createElementParser } from './elementParser.js';
13
+
14
+ const aUnionParser = createUnionParser<string, string>([
15
+ createExactSequenceParser('1'),
16
+ createExactSequenceParser('aa'),
17
+ createExactSequenceParser('AAA'),
18
+ ]);
19
+
20
+ const abDisjunctionParser = createDisjunctionParser<string, string>([
21
+ aUnionParser,
22
+ createExactSequenceParser('2'),
23
+ createExactSequenceParser('bb'),
24
+ createExactSequenceParser('BBB'),
25
+ ]);
26
+
27
+ const abcUnionParser = createUnionParser<string, string>([
28
+ abDisjunctionParser,
29
+ createExactSequenceParser('final_3'),
30
+ createExactSequenceParser('final_cc'),
31
+ createExactSequenceParser('final_CCC'),
32
+ ]);
33
+
34
+ const sampleParser = promiseCompose(
35
+ createTupleParser<string, string, string, string>([
36
+ aUnionParser,
37
+ abDisjunctionParser,
38
+ abcUnionParser,
39
+ ]),
40
+ strings => strings.join(''),
41
+ );
42
+
43
+ async function * asyncIteratorFromString(string: string) {
44
+ yield string;
45
+ }
46
+
47
+ function sortChildErrors(error: ParserParsingJoinNoneError) {
48
+ error.childErrors.sort((a, b) => a.message.localeCompare(b.message));
49
+
50
+ for (const childError of error.childErrors) {
51
+ if (childError instanceof ParserParsingJoinError) {
52
+ sortChildErrors(childError);
53
+ }
54
+ }
55
+ }
56
+
57
+ function removeStackLocations(errorStack: string) {
58
+ return errorStack.replace(/((at [^\n]+)[\s\n]+)+(at [^\n]+)/g, 'at [LOCATIONS]');
59
+ }
60
+
61
+ test('errorJoinMode: none', async t => {
62
+ const error = await t.throwsAsync(runParser(sampleParser, asyncIteratorFromString('1bbfinal_CC!'), stringInputCompanion, {
63
+ errorJoinMode: 'none',
64
+ }), {
65
+ instanceOf: ParserParsingJoinNoneError
66
+ });
67
+
68
+ t.is(error.position, 12);
69
+ t.deepEqual(error.childErrors, []);
70
+
71
+ t.snapshot(removeStackLocations(error.stack!));
72
+ });
73
+
74
+ test('errorJoinMode: all', async t => {
75
+ const error = await t.throwsAsync(runParser(sampleParser, asyncIteratorFromString('1bbfinal_CC!'), stringInputCompanion, {
76
+ errorJoinMode: 'all',
77
+ }), {
78
+ instanceOf: ParserParsingJoinAllError
79
+ });
80
+
81
+ sortChildErrors(error);
82
+
83
+ t.snapshot(removeStackLocations(error.stack!));
84
+
85
+ t.is(error.position, 12, 'error.position');
86
+ t.is(error.childErrors.length, 4);
87
+
88
+ const error1 = error.childErrors.at(-1)!;
89
+
90
+ invariant(error1 instanceof ParserParsingJoinAllError, 'error1 instanceof ParserParsingJoinAllError');
91
+
92
+ t.is(error1.position, 3, 'error1.position');
93
+ t.is(error1.childErrors.length, 4);
94
+
95
+ const error2 = error1.childErrors.at(-1)!;
96
+
97
+ invariant(error2 instanceof ParserParsingJoinAllError, 'error2 instanceof ParserParsingJoinAllError');
98
+
99
+ t.is(error2.position, 4, 'error2.position');
100
+ t.is(error2.childErrors.length, 3);
101
+
102
+ const error3 = error2.childErrors.at(-1)!;
103
+
104
+ invariant(error3 instanceof ParserParsingInvariantError, 'error3 instanceof ParserParsingInvariantError');
105
+
106
+ t.is(error3.position, 4, 'error3.position');
107
+ });
108
+
109
+ test('errorJoinMode: deepest', async t => {
110
+ const error = await t.throwsAsync(runParser(sampleParser, asyncIteratorFromString('1bbfinal_CC!'), stringInputCompanion, {
111
+ errorJoinMode: 'deepest',
112
+ }), {
113
+ instanceOf: ParserParsingJoinDeepestError,
114
+ });
115
+
116
+ sortChildErrors(error);
117
+
118
+ t.snapshot(removeStackLocations(error.stack!));
119
+
120
+ t.is(error.position, 12);
121
+ t.is(error.childErrors.length, 1);
122
+
123
+ const error1 = error.childErrors.at(-1)!;
124
+
125
+ invariant(error1 instanceof ParserParsingJoinDeepestError, 'error1 instanceof ParserParsingJoinDeepestError');
126
+
127
+ t.is(error1.position, 3);
128
+ t.is(error1.childErrors.length, 1);
129
+
130
+ const error2 = error1.childErrors.at(-1)!;
131
+
132
+ invariant(error2 instanceof ParserParsingJoinDeepestError, 'error2 instanceof ParserParsingJoinDeepestError');
133
+
134
+ t.is(error2.position, 4);
135
+ t.is(error2.childErrors.length, 3);
136
+
137
+ const error3 = error2.childErrors.at(-1)!;
138
+
139
+ invariant(error3 instanceof ParserParsingInvariantError, 'error3 instanceof ParserParsingInvariantError');
140
+
141
+ t.is(error3.position, 4);
142
+ });
143
+
144
+ test('errorJoinMode: furthest', async t => {
145
+ const error = await t.throwsAsync(runParser(sampleParser, asyncIteratorFromString('1bbfinal_CC!'), stringInputCompanion, {
146
+ errorJoinMode: 'furthest',
147
+ }), {
148
+ instanceOf: ParserParsingJoinFurthestError,
149
+ });
150
+
151
+ sortChildErrors(error);
152
+
153
+ t.snapshot(removeStackLocations(error.stack!));
154
+
155
+ t.is(error.position, 12);
156
+ t.is(error.childErrors.length, 1);
157
+
158
+ const error1 = error.childErrors.at(-1)!;
159
+
160
+ invariant(error1 instanceof ParserParsingInvariantError, 'error1 instanceof ParserParsingInvariantError');
161
+
162
+ t.is(error1.position, 12);
163
+ });
164
+
165
+ test('throws on inputCompanion type mismatch', async t => {
166
+ const anythingParser: Parser<any, any> = createArrayParser(createElementParser());
167
+
168
+ await runParser(anythingParser, asyncIteratorFromString('anything'), stringInputCompanion);
169
+ await runParser(anythingParser, 'anything', stringInputCompanion);
170
+ await runParser(anythingParser, Buffer.from('anything'), uint8ArrayInputCompanion);
171
+ await runParser(anythingParser, new Uint8Array([ 1, 2, 3 ]), uint8ArrayInputCompanion);
172
+
173
+ await t.throwsAsync(runParser(anythingParser, asyncIteratorFromString('anything'), uint8ArrayInputCompanion), {
174
+ message: /input companion/,
175
+ });
176
+ });
@@ -0,0 +1,68 @@
1
+ # Snapshot report for `src/parser.test.ts`
2
+
3
+ The actual snapshot is saved in `parser.test.ts.snap`.
4
+
5
+ Generated by [AVA](https://avajs.dev).
6
+
7
+ ## errorJoinMode: none
8
+
9
+ > Snapshot 1
10
+
11
+ `ParserParsingJoinNoneError: (position: 12) No union child parser succeeded.␊
12
+ at [LOCATIONS]`
13
+
14
+ ## errorJoinMode: all
15
+
16
+ > Snapshot 1
17
+
18
+ `ParserParsingJoinAllError: (position: 12) No union child parser succeeded.␊
19
+ Child error stacks, indented:␊
20
+ ParserParsingInvariantError: (position: 10) Expected "3", got "C", at [LOCATIONS]␊
21
+ ParserParsingInvariantError: (position: 10) Expected "c", got "C", at [LOCATIONS]␊
22
+ ParserParsingJoinAllError: (position: 3) No disjunction child parser succeeded.␊
23
+ Child error stacks, indented:␊
24
+ ParserParsingJoinAllError: (position: 4) No union child parser succeeded.␊
25
+ Child error stacks, indented:␊
26
+ ParserParsingInvariantError: (position: 4) Expected "1", got "f", at [LOCATIONS]␊
27
+ ParserParsingInvariantError: (position: 4) Expected "a", got "f", at [LOCATIONS]␊
28
+ ParserParsingInvariantError: (position: 4) Expected "A", got "f", at [LOCATIONS]␊
29
+ End of child error stacks␊
30
+ at [LOCATIONS]␊
31
+ ParserParsingInvariantError: (position: 4) Expected "2", got "f", at [LOCATIONS]␊
32
+ ParserParsingInvariantError: (position: 4) Expected "b", got "f", at [LOCATIONS]␊
33
+ ParserParsingInvariantError: (position: 4) Expected "B", got "f", at [LOCATIONS]␊
34
+ End of child error stacks␊
35
+ at [LOCATIONS]␊
36
+ ParserParsingInvariantError: (position: 12) Expected "C", got "!", at [LOCATIONS]␊
37
+ End of child error stacks␊
38
+ at [LOCATIONS]`
39
+
40
+ ## errorJoinMode: deepest
41
+
42
+ > Snapshot 1
43
+
44
+ `ParserParsingJoinDeepestError: (position: 12) No union child parser succeeded.␊
45
+ Deepest child error stacks, indented:␊
46
+ ParserParsingJoinDeepestError: (position: 3) No disjunction child parser succeeded.␊
47
+ Deepest child error stacks, indented:␊
48
+ ParserParsingJoinDeepestError: (position: 4) No union child parser succeeded.␊
49
+ Deepest child error stacks, indented:␊
50
+ ParserParsingInvariantError: (position: 4) Expected "1", got "f", at [LOCATIONS]␊
51
+ ParserParsingInvariantError: (position: 4) Expected "a", got "f", at [LOCATIONS]␊
52
+ ParserParsingInvariantError: (position: 4) Expected "A", got "f", at [LOCATIONS]␊
53
+ End of deepest child error stacks␊
54
+ at [LOCATIONS]␊
55
+ End of deepest child error stacks␊
56
+ at [LOCATIONS]␊
57
+ End of deepest child error stacks␊
58
+ at [LOCATIONS]`
59
+
60
+ ## errorJoinMode: furthest
61
+
62
+ > Snapshot 1
63
+
64
+ `ParserParsingJoinFurthestError: (position: 12) No union child parser succeeded.␊
65
+ Furthest child error stacks, indented:␊
66
+ ParserParsingInvariantError: (position: 12) Expected "C", got "!", at [LOCATIONS]␊
67
+ End of furthest child error stacks␊
68
+ at [LOCATIONS]`
Binary file
package/src/parser.ts ADDED
@@ -0,0 +1,103 @@
1
+ import invariant from 'invariant';
2
+ import { type InputCompanion } from './inputCompanion.js';
3
+ import { InputReaderImplementation } from './inputReader.js';
4
+ import { type ParserContext, ParserContextImplementation } from './parserContext.js';
5
+ import { DeriveSequenceElement } from './sequence.js';
6
+
7
+ export type Parser<
8
+ Output,
9
+ Sequence,
10
+ Element = DeriveSequenceElement<Sequence>,
11
+ > = (parserContext: ParserContext<Sequence, Element>) => Promise<Output>;
12
+
13
+ export function getParserName(parser: Parser<any, any, any>, default_ = 'anonymous'): string {
14
+ return parser.name || default_;
15
+ }
16
+
17
+ export function setParserName<
18
+ Output,
19
+ Sequence,
20
+ Element = DeriveSequenceElement<Sequence>,
21
+ >(parser: Parser<Output, Sequence, Element>, name: string): Parser<Output, Sequence, Element> {
22
+ Object.defineProperty(parser, 'name', {
23
+ value: name,
24
+ });
25
+
26
+ return parser;
27
+ }
28
+
29
+ export type RunParserOptions<
30
+ Output,
31
+ Sequence,
32
+ Element = DeriveSequenceElement<Sequence>,
33
+ > = {
34
+ errorJoinMode?: 'none' | 'deepest' | 'furthest' | 'all';
35
+ }
36
+
37
+ function isAsyncIterable<T>(value: any): value is AsyncIterable<T> {
38
+ return value && typeof value[Symbol.asyncIterator] === 'function';
39
+ }
40
+
41
+ function isIterable<T>(value: any): value is Iterable<T> {
42
+ return value && typeof value[Symbol.iterator] === 'function';
43
+ }
44
+
45
+ function isIterator<T>(value: any): value is Iterator<T> {
46
+ return value && typeof value.next === 'function';
47
+ }
48
+
49
+ function iteratorToAsyncIterator<T>(iterator: Iterator<T>): AsyncIterator<T> {
50
+ return {
51
+ next: async () => iterator.next(),
52
+ };
53
+ }
54
+
55
+ function toAsyncIterator<T>(value: AsyncIterator<T> | AsyncIterable<T> | Iterable<T> | T): AsyncIterator<T> {
56
+ if (
57
+ typeof value === 'string'
58
+ || value instanceof Uint8Array
59
+ ) {
60
+ return (async function*() {
61
+ yield value as any;
62
+ })();
63
+ }
64
+
65
+ if (isAsyncIterable(value)) {
66
+ return value[Symbol.asyncIterator]();
67
+ }
68
+
69
+ if (isIterable(value)) {
70
+ return iteratorToAsyncIterator(value[Symbol.iterator]());
71
+ }
72
+
73
+ if (isIterator<T>(value)) {
74
+ return iteratorToAsyncIterator(value);
75
+ }
76
+
77
+ invariant(
78
+ false,
79
+ 'Value must be an async iterator, async iterable, iterable or iterator got %s.',
80
+ value,
81
+ );
82
+ }
83
+
84
+ export async function runParser<
85
+ Output,
86
+ Sequence,
87
+ Element = DeriveSequenceElement<Sequence>,
88
+ >(
89
+ parser: Parser<Output, Sequence, Element>,
90
+ input: AsyncIterator<Sequence> | AsyncIterable<Sequence> | Iterable<Sequence> | Sequence,
91
+ inputCompanion: InputCompanion<Sequence, Element>,
92
+ options: RunParserOptions<Output, Sequence, Element> = {},
93
+ ): Promise<Output> {
94
+ const inputAsyncIterator = toAsyncIterator(input);
95
+
96
+ const inputReader = new InputReaderImplementation<Sequence, Element>(inputCompanion, inputAsyncIterator);
97
+ const parserContext = new ParserContextImplementation<Sequence, Element>(inputCompanion, inputReader, undefined, {
98
+ ...options,
99
+ debugName: 'root',
100
+ });
101
+
102
+ return parser(parserContext);
103
+ }
@@ -0,0 +1,3 @@
1
+ import { Parser } from "./parser.js";
2
+
3
+ export const createParserAccessorParser = <Output, Sequence>(parserAccessor: () => Parser<Output, Sequence>): Parser<Output, Sequence> => async parserContext => parserAccessor()(parserContext);