@futpib/parser 1.0.2 → 1.0.3

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 (284) hide show
  1. package/.github/copilot-instructions.md +149 -0
  2. package/.github/workflows/copilot-setup-steps.yml +18 -0
  3. package/.github/workflows/main.yml +29 -8
  4. package/.yarn/releases/yarn-4.9.4.cjs +942 -0
  5. package/.yarnrc.yml +1 -1
  6. package/build/allSettledStream.js +1 -1
  7. package/build/allSettledStream.test.js +2 -2
  8. package/build/androidPackageParser.d.ts +1 -1
  9. package/build/androidPackageParser.js +5 -3
  10. package/build/androidPackageParser.test.js +7 -7
  11. package/build/androidPackageUnparser.d.ts +2 -2
  12. package/build/androidPackageUnparser.js +18 -14
  13. package/build/androidPackageUnparser.test.js +7 -7
  14. package/build/arbitrarilySlicedAsyncInterator.js +2 -1
  15. package/build/arbitraryDalvikBytecode.d.ts +4 -0
  16. package/build/arbitraryDalvikBytecode.js +640 -0
  17. package/build/arbitraryDalvikExecutable.d.ts +3 -0
  18. package/build/arbitraryDalvikExecutable.js +282 -0
  19. package/build/arbitraryDosDateTime.js +1 -0
  20. package/build/arbitraryZipStream.js +1 -1
  21. package/build/arrayParser.js +2 -2
  22. package/build/arrayUnparser.d.ts +1 -1
  23. package/build/backsmali.d.ts +3 -1
  24. package/build/backsmali.js +31 -3
  25. package/build/customInvariant.d.ts +2 -1
  26. package/build/customInvariant.js +4 -6
  27. package/build/dalvikBytecodeParser/formatParsers.d.ts +76 -2
  28. package/build/dalvikBytecodeParser/formatParsers.js +146 -11
  29. package/build/dalvikBytecodeParser/formatSizes.d.ts +34 -0
  30. package/build/dalvikBytecodeParser/formatSizes.js +34 -0
  31. package/build/dalvikBytecodeParser/operationFormats.d.ts +225 -0
  32. package/build/dalvikBytecodeParser/operationFormats.js +225 -0
  33. package/build/dalvikBytecodeParser.d.ts +1105 -5
  34. package/build/dalvikBytecodeParser.js +658 -205
  35. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +152 -0
  36. package/build/dalvikBytecodeUnparser/formatUnparsers.js +225 -0
  37. package/build/dalvikBytecodeUnparser.d.ts +3 -0
  38. package/build/dalvikBytecodeUnparser.js +642 -0
  39. package/build/dalvikBytecodeUnparser.test.d.ts +1 -0
  40. package/build/dalvikBytecodeUnparser.test.js +25 -0
  41. package/build/dalvikExecutable.d.ts +65 -8
  42. package/build/dalvikExecutable.js +36 -0
  43. package/build/dalvikExecutableParser/stringSyntaxParser.d.ts +1 -1
  44. package/build/dalvikExecutableParser/stringSyntaxParser.js +17 -17
  45. package/build/dalvikExecutableParser/typeParsers.d.ts +2 -1
  46. package/build/dalvikExecutableParser/typeParsers.js +16 -11
  47. package/build/dalvikExecutableParser/typedNumbers.d.ts +85 -69
  48. package/build/dalvikExecutableParser/typedNumbers.js +0 -1
  49. package/build/dalvikExecutableParser.d.ts +2 -2
  50. package/build/dalvikExecutableParser.js +655 -337
  51. package/build/dalvikExecutableParser.test.js +24 -22
  52. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +223 -246
  53. package/build/dalvikExecutableUnparser/annotationUnparsers.d.ts +14 -0
  54. package/build/dalvikExecutableUnparser/annotationUnparsers.js +97 -0
  55. package/build/dalvikExecutableUnparser/poolBuilders.d.ts +49 -0
  56. package/build/dalvikExecutableUnparser/poolBuilders.js +140 -0
  57. package/build/dalvikExecutableUnparser/poolScanners.d.ts +4 -0
  58. package/build/dalvikExecutableUnparser/poolScanners.js +220 -0
  59. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +25 -0
  60. package/build/dalvikExecutableUnparser/sectionUnparsers.js +581 -0
  61. package/build/dalvikExecutableUnparser/utils.d.ts +10 -0
  62. package/build/dalvikExecutableUnparser/utils.js +108 -0
  63. package/build/dalvikExecutableUnparser.d.ts +4 -0
  64. package/build/dalvikExecutableUnparser.js +406 -0
  65. package/build/dalvikExecutableUnparser.test.d.ts +1 -0
  66. package/build/dalvikExecutableUnparser.test.js +31 -0
  67. package/build/debugLogInputParser.js +1 -1
  68. package/build/disjunctionParser.d.ts +2 -2
  69. package/build/disjunctionParser.js +2 -2
  70. package/build/elementTerminatedArrayParser.d.ts +2 -2
  71. package/build/elementTerminatedArrayParser.js +1 -1
  72. package/build/elementTerminatedArrayParser.test.js +5 -5
  73. package/build/elementTerminatedSequenceArrayParser.d.ts +2 -2
  74. package/build/elementTerminatedSequenceArrayParser.js +1 -1
  75. package/build/elementTerminatedSequenceArrayParser.test.js +2 -2
  76. package/build/elementTerminatedSequenceParser.d.ts +2 -2
  77. package/build/elementTerminatedSequenceParser.js +1 -1
  78. package/build/elementTerminatedSequenceParser.test.js +2 -2
  79. package/build/endOfInputParser.d.ts +1 -1
  80. package/build/exactElementSwitchParser.d.ts +3 -0
  81. package/build/exactElementSwitchParser.js +22 -0
  82. package/build/fetchCid.js +2 -6
  83. package/build/fetchCid.test.d.ts +1 -0
  84. package/build/fetchCid.test.js +16 -0
  85. package/build/fixedLengthSequenceParser.test.js +2 -2
  86. package/build/hasExecutable.js +2 -2
  87. package/build/highResolutionTimer.js +1 -1
  88. package/build/inputReader.d.ts +1 -1
  89. package/build/inputReader.test.js +33 -45
  90. package/build/javaKeyStoreParser.test.js +6 -6
  91. package/build/jsonParser.js +8 -8
  92. package/build/lazyMessageError.d.ts +48 -0
  93. package/build/lazyMessageError.js +53 -0
  94. package/build/lazyMessageError.test.d.ts +1 -0
  95. package/build/lazyMessageError.test.js +15 -0
  96. package/build/leb128Parser.d.ts +1 -1
  97. package/build/leb128Parser.js +10 -10
  98. package/build/leb128Parser.test.js +7 -7
  99. package/build/negativeLookaheadParser.js +2 -2
  100. package/build/negativeLookaheadParser.test.js +4 -4
  101. package/build/noStackCaptureOverheadError.d.ts +4 -0
  102. package/build/noStackCaptureOverheadError.js +9 -0
  103. package/build/noStackCaptureOverheadError.test.d.ts +1 -0
  104. package/build/noStackCaptureOverheadError.test.js +15 -0
  105. package/build/nonEmptyArrayParser.js +2 -2
  106. package/build/nonEmptyArrayParser.test.js +2 -1
  107. package/build/optionalParser.js +2 -2
  108. package/build/parser.d.ts +2 -1
  109. package/build/parser.js +23 -8
  110. package/build/parser.test.js +78 -29
  111. package/build/parserConsumedSequenceParser.d.ts +1 -1
  112. package/build/parserConsumedSequenceParser.js +2 -2
  113. package/build/parserContext.d.ts +8 -6
  114. package/build/parserContext.js +60 -33
  115. package/build/parserContext.test.js +7 -3
  116. package/build/parserError.d.ts +603 -44
  117. package/build/parserError.js +98 -53
  118. package/build/parserImplementationInvariant.d.ts +1 -1
  119. package/build/parserImplementationInvariant.js +2 -2
  120. package/build/parserInputCompanion.js +2 -2
  121. package/build/promiseCompose.js +1 -2
  122. package/build/separatedArrayParser.js +2 -2
  123. package/build/separatedNonEmptyArrayParser.d.ts +2 -0
  124. package/build/separatedNonEmptyArrayParser.js +40 -0
  125. package/build/separatedNonEmptyArrayParser.test.d.ts +1 -0
  126. package/build/separatedNonEmptyArrayParser.test.js +66 -0
  127. package/build/sequenceBuffer.js +1 -1
  128. package/build/sequenceTerminatedSequenceParser.d.ts +2 -2
  129. package/build/sequenceTerminatedSequenceParser.js +3 -3
  130. package/build/sequenceTerminatedSequenceParser.test.js +1 -1
  131. package/build/sequenceUnparser.d.ts +1 -1
  132. package/build/skipToParser.d.ts +1 -1
  133. package/build/skipToParser.js +2 -2
  134. package/build/sliceBoundedParser.test.js +4 -9
  135. package/build/smali.d.ts +1 -1
  136. package/build/smali.js +6 -2
  137. package/build/smaliParser.d.ts +62 -6
  138. package/build/smaliParser.js +1721 -296
  139. package/build/smaliParser.test.js +338 -43
  140. package/build/stringFromAsyncIterable.d.ts +1 -0
  141. package/build/stringFromAsyncIterable.js +7 -0
  142. package/build/terminatedArrayParser.js +4 -4
  143. package/build/terminatedArrayParser.test.js +7 -7
  144. package/build/toAsyncIterator.js +4 -4
  145. package/build/unionParser.d.ts +1 -1
  146. package/build/unionParser.js +2 -2
  147. package/build/unionParser.test.js +3 -3
  148. package/build/unparser.d.ts +3 -3
  149. package/build/unparser.js +6 -4
  150. package/build/unparser.test.js +7 -19
  151. package/build/unparserContext.d.ts +2 -2
  152. package/build/unparserContext.js +2 -3
  153. package/build/unparserError.d.ts +2 -1
  154. package/build/unparserError.js +2 -1
  155. package/build/unparserImplementationInvariant.d.ts +1 -1
  156. package/build/unparserOutputCompanion.d.ts +1 -1
  157. package/build/unparserOutputCompanion.js +1 -1
  158. package/build/zipParser.js +1 -1
  159. package/build/zipUnparser.d.ts +3 -3
  160. package/build/zipUnparser.js +9 -19
  161. package/build/zipUnparser.test.js +1 -1
  162. package/package.json +19 -26
  163. package/src/allSettledStream.test.ts +2 -2
  164. package/src/allSettledStream.ts +3 -3
  165. package/src/androidPackageParser.test.ts +17 -19
  166. package/src/androidPackageParser.ts +129 -171
  167. package/src/androidPackageUnparser.test.ts +19 -21
  168. package/src/androidPackageUnparser.ts +23 -17
  169. package/src/arbitrarilySlicedAsyncInterable.ts +1 -1
  170. package/src/arbitrarilySlicedAsyncInterator.ts +4 -4
  171. package/src/arbitraryDalvikBytecode.ts +992 -0
  172. package/src/arbitraryDalvikExecutable.ts +434 -0
  173. package/src/arbitraryDosDateTime.ts +1 -0
  174. package/src/arbitraryZipStream.ts +1 -1
  175. package/src/arrayParser.ts +2 -2
  176. package/src/arrayUnparser.ts +2 -2
  177. package/src/backsmali.ts +48 -4
  178. package/src/bsonParser.test.ts +12 -14
  179. package/src/customInvariant.ts +8 -12
  180. package/src/dalvikBytecodeParser/formatParsers.ts +376 -17
  181. package/src/dalvikBytecodeParser/formatSizes.ts +35 -0
  182. package/src/dalvikBytecodeParser/operationFormats.ts +226 -0
  183. package/src/dalvikBytecodeParser.ts +1042 -243
  184. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +442 -0
  185. package/src/dalvikBytecodeUnparser.test.ts +44 -0
  186. package/src/dalvikBytecodeUnparser.ts +758 -0
  187. package/src/dalvikExecutable.ts +110 -48
  188. package/src/dalvikExecutableParser/stringSyntaxParser.ts +33 -33
  189. package/src/dalvikExecutableParser/typeParsers.ts +23 -14
  190. package/src/dalvikExecutableParser/typedNumbers.ts +19 -19
  191. package/src/dalvikExecutableParser.test.ts +60 -60
  192. package/src/dalvikExecutableParser.test.ts.md +6 -6
  193. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  194. package/src/dalvikExecutableParser.ts +911 -434
  195. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +256 -239
  196. package/src/dalvikExecutableUnparser/annotationUnparsers.ts +135 -0
  197. package/src/dalvikExecutableUnparser/poolBuilders.ts +189 -0
  198. package/src/dalvikExecutableUnparser/poolScanners.ts +297 -0
  199. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +683 -0
  200. package/src/dalvikExecutableUnparser/utils.ts +149 -0
  201. package/src/dalvikExecutableUnparser.test.ts +57 -0
  202. package/src/dalvikExecutableUnparser.ts +581 -0
  203. package/src/debugLogInputParser.ts +1 -1
  204. package/src/disjunctionParser.ts +5 -5
  205. package/src/elementTerminatedArrayParser.test.ts +8 -8
  206. package/src/elementTerminatedArrayParser.ts +2 -2
  207. package/src/elementTerminatedSequenceArrayParser.test.ts +4 -6
  208. package/src/elementTerminatedSequenceArrayParser.ts +2 -2
  209. package/src/elementTerminatedSequenceParser.test.ts +4 -6
  210. package/src/elementTerminatedSequenceParser.ts +2 -2
  211. package/src/endOfInputParser.ts +1 -1
  212. package/src/exactElementSwitchParser.ts +41 -0
  213. package/src/fetchCid.test.ts +20 -0
  214. package/src/fetchCid.ts +3 -7
  215. package/src/fixedLengthSequenceParser.test.ts +10 -12
  216. package/src/hasExecutable.ts +2 -2
  217. package/src/highResolutionTimer.ts +1 -1
  218. package/src/inputReader.test.ts +39 -52
  219. package/src/inputReader.ts +2 -4
  220. package/src/inputReaderState.ts +1 -1
  221. package/src/inspect.ts +1 -1
  222. package/src/javaKeyStoreParser.test.ts +12 -14
  223. package/src/javaKeyStoreParser.ts +2 -6
  224. package/src/jsonParser.test.ts +2 -4
  225. package/src/jsonParser.ts +34 -38
  226. package/src/lazyMessageError.test.ts +21 -0
  227. package/src/lazyMessageError.ts +88 -0
  228. package/src/leb128Parser.test.ts +25 -23
  229. package/src/leb128Parser.ts +19 -19
  230. package/src/negativeLookaheadParser.test.ts +7 -11
  231. package/src/negativeLookaheadParser.ts +2 -2
  232. package/src/noStackCaptureOverheadError.test.ts +17 -0
  233. package/src/noStackCaptureOverheadError.ts +12 -0
  234. package/src/nonEmptyArrayParser.test.ts +3 -2
  235. package/src/nonEmptyArrayParser.ts +2 -2
  236. package/src/optionalParser.ts +2 -2
  237. package/src/parser.test.ts +96 -43
  238. package/src/parser.test.ts.md +13 -6
  239. package/src/parser.test.ts.snap +0 -0
  240. package/src/parser.ts +35 -12
  241. package/src/parserAccessorParser.ts +1 -1
  242. package/src/parserConsumedSequenceParser.ts +3 -3
  243. package/src/parserContext.test.ts +7 -3
  244. package/src/parserContext.ts +82 -48
  245. package/src/parserError.ts +143 -63
  246. package/src/parserImplementationInvariant.ts +3 -3
  247. package/src/parserInputCompanion.ts +2 -2
  248. package/src/promiseCompose.ts +2 -2
  249. package/src/separatedArrayParser.ts +3 -3
  250. package/src/separatedNonEmptyArrayParser.test.ts +117 -0
  251. package/src/separatedNonEmptyArrayParser.ts +61 -0
  252. package/src/sequenceBuffer.test.ts +9 -9
  253. package/src/sequenceBuffer.ts +4 -4
  254. package/src/sequenceTerminatedSequenceParser.test.ts +3 -5
  255. package/src/sequenceTerminatedSequenceParser.ts +4 -4
  256. package/src/sequenceUnparser.ts +2 -2
  257. package/src/skipToParser.ts +2 -2
  258. package/src/sliceBoundedParser.test.ts +4 -12
  259. package/src/sliceBoundedParser.ts +2 -2
  260. package/src/smali.ts +8 -3
  261. package/src/smaliParser.test.ts +377 -66
  262. package/src/smaliParser.test.ts.md +1635 -48
  263. package/src/smaliParser.test.ts.snap +0 -0
  264. package/src/smaliParser.ts +2751 -569
  265. package/src/stringFromAsyncIterable.ts +9 -0
  266. package/src/terminatedArrayParser.test.ts +11 -11
  267. package/src/terminatedArrayParser.ts +5 -7
  268. package/src/toAsyncIterator.ts +8 -8
  269. package/src/uint8Array.ts +2 -3
  270. package/src/unionParser.test.ts +22 -23
  271. package/src/unionParser.ts +6 -8
  272. package/src/unparser.test.ts +18 -34
  273. package/src/unparser.ts +13 -9
  274. package/src/unparserContext.ts +9 -13
  275. package/src/unparserError.ts +2 -1
  276. package/src/unparserImplementationInvariant.ts +1 -1
  277. package/src/unparserOutputCompanion.ts +1 -1
  278. package/src/zip.ts +2 -6
  279. package/src/zipParser.ts +10 -18
  280. package/src/zipUnparser.test.ts +1 -1
  281. package/src/zipUnparser.ts +52 -64
  282. package/tsconfig.json +7 -1
  283. package/xo.config.ts +15 -0
  284. package/.yarn/releases/yarn-4.5.3.cjs +0 -934
@@ -3,11 +3,14 @@
3
3
  import { type ParserInputCompanion } from './parserInputCompanion.js';
4
4
  import { type InputReader } from './inputReader.js';
5
5
  import {
6
- type ParserParsingFailedError, ParserUnexpectedEndOfInputError, ParserParsingInvariantError, ParserParsingJoinNoneError, ParserParsingJoinAllError, ParserParsingJoinDeepestError, ParserParsingJoinFurthestError,
6
+ normalParserErrorModule,
7
+ noStackCaptureOverheadParserErrorModule,
8
+ ParserParsingFailedError,
7
9
  } from './parserError.js';
8
10
  import { type RunParserOptions } from './parser.js';
9
11
  import { type Falsy, customInvariant, type ValueOrAccessor } from './customInvariant.js';
10
12
  import { parserImplementationInvariant } from './parserImplementationInvariant.js';
13
+ import { formatLazyMessage, isLazyMessageError, LazyMessage } from './lazyMessageError.js';
11
14
 
12
15
  type LookaheadOptions = {
13
16
  debugName?: string;
@@ -17,6 +20,9 @@ type LookaheadOptions = {
17
20
  type ParserContextOptions<Sequence, Element> =
18
21
  & RunParserOptions<unknown, Sequence, Element>
19
22
  & LookaheadOptions
23
+ & {
24
+ errorsModule: typeof normalParserErrorModule | typeof noStackCaptureOverheadParserErrorModule;
25
+ }
20
26
  ;
21
27
 
22
28
  export type ParserContext<Sequence, Element> = {
@@ -41,8 +47,8 @@ export type ParserContext<Sequence, Element> = {
41
47
  unlookahead(): void;
42
48
  dispose(): void;
43
49
 
44
- invariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: any[]): Exclude<T, Falsy>;
45
- invariantJoin<T>(value: T, childErrors: ParserParsingFailedError[], format: ValueOrAccessor<string | string[]>, ...formatArguments: any[]): Exclude<T, Falsy>;
50
+ invariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy>;
51
+ invariantJoin<T>(value: T, childErrors: ParserParsingFailedError[], format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy>;
46
52
  };
47
53
 
48
54
  let parserContextId = 0;
@@ -114,7 +120,7 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
114
120
  async peek(offset: number): Promise<Element | undefined> {
115
121
  if (
116
122
  this._options.sliceEnd !== undefined
117
- && (this.position + offset) >= this._options.sliceEnd
123
+ && (this.position + offset) >= this._options.sliceEnd
118
124
  ) {
119
125
  return undefined;
120
126
  }
@@ -125,7 +131,7 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
125
131
  async peekSequence(start: number, end: number): Promise<Sequence | undefined> {
126
132
  if (
127
133
  this._options.sliceEnd !== undefined
128
- && (this.position + end - 1) >= this._options.sliceEnd
134
+ && (this.position + end - 1) >= this._options.sliceEnd
129
135
  ) {
130
136
  return undefined;
131
137
  }
@@ -163,7 +169,7 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
163
169
  const element = await this.peek(offset);
164
170
 
165
171
  if (element === undefined) {
166
- throw new ParserUnexpectedEndOfInputError('', this._depth, this.position);
172
+ throw new this._options.errorsModule.ParserUnexpectedEndOfInputError('', this._depth, this.position);
167
173
  }
168
174
 
169
175
  this.skip(offset + 1);
@@ -175,7 +181,7 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
175
181
  const sequence = await this.peekSequence(start, end);
176
182
 
177
183
  if (sequence === undefined) {
178
- throw new ParserUnexpectedEndOfInputError('', this._depth, this.position);
184
+ throw new this._options.errorsModule.ParserUnexpectedEndOfInputError('', this._depth, this.position);
179
185
  }
180
186
 
181
187
  this.skip(end);
@@ -238,10 +244,10 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
238
244
  'this: %s',
239
245
  'parent: %s',
240
246
  'parent.exclusiveChild: %s',
241
- ].join('\n'),
242
- this.toString(),
243
- parentParserContext.toString(),
244
- parentParserContext._exclusiveChildParserContext?.toString(),
247
+ ],
248
+ () => this.toString(),
249
+ () => parentParserContext.toString(),
250
+ () => parentParserContext._exclusiveChildParserContext?.toString(),
245
251
  );
246
252
  parserImplementationInvariant(
247
253
  parentParserContext.position <= this.position,
@@ -284,38 +290,38 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
284
290
  'this: %s',
285
291
  'parent: %s',
286
292
  'parent.exclusiveChild: %s',
287
- ].join('\n'),
288
- this.toString(),
289
- parentParserContext.toString(),
290
- parentParserContext._exclusiveChildParserContext?.toString(),
293
+ ],
294
+ () => this.toString(),
295
+ () => parentParserContext.toString(),
296
+ () => parentParserContext._exclusiveChildParserContext?.toString(),
291
297
  );
292
298
 
293
299
  parentParserContext._exclusiveChildParserContext = undefined;
294
300
  this._parentParserContext = undefined;
295
301
  }
296
302
 
297
- invariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: any[]): Exclude<T, Falsy> {
303
+ invariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy> {
298
304
  const parserContext = this;
299
305
 
300
- return customInvariant(function (message: string) {
301
- return new ParserParsingInvariantError(message, parserContext._depth, parserContext.position);
306
+ return customInvariant(function (lazyMessage: LazyMessage) {
307
+ return new parserContext._options.errorsModule.ParserParsingInvariantError(lazyMessage, parserContext._depth, parserContext.position);
302
308
  }, value, format, ...formatArguments);
303
309
  }
304
310
 
305
- invariantJoin<T>(value: T, childErrors: ParserParsingFailedError[], format: ValueOrAccessor<string | string[]>, ...formatArguments: any[]): Exclude<T, Falsy> {
311
+ invariantJoin<T>(value: T, childErrors: ParserParsingFailedError[], format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy> {
306
312
  parserImplementationInvariant(childErrors.length > 0, 'childErrors.length > 0');
307
313
 
308
314
  const errorJoinMode = this._options.errorJoinMode ?? 'none';
309
315
  const parserContext = this;
310
316
 
311
317
  if (errorJoinMode === 'none') {
312
- return customInvariant(function (message: string) {
313
- return new ParserParsingJoinNoneError(message, parserContext._depth, parserContext.position);
318
+ return customInvariant(function (lazyMessage: LazyMessage) {
319
+ return new parserContext._options.errorsModule.ParserParsingJoinNoneError(lazyMessage, parserContext._depth, parserContext.position);
314
320
  }, value, format, ...formatArguments);
315
321
  }
316
322
 
317
323
  if (errorJoinMode === 'furthest') {
318
- return customInvariant(function (message: string) {
324
+ return customInvariant(function (userLazyMessage: LazyMessage) {
319
325
  let furthestPosition = 0;
320
326
  let furthestChildErrors: ParserParsingFailedError[] = [];
321
327
 
@@ -333,23 +339,35 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
333
339
  furthestChildErrors.push(childError);
334
340
  }
335
341
 
336
- message += [
337
- '',
338
- 'Furthest child error stacks, indented:',
339
- ...furthestChildErrors.flatMap(furthestChildError => furthestChildError.stack?.split('\n').map(line => ' ' + line)),
340
- 'End of furthest child error stacks',
341
- ].join('\n');
342
-
343
- return new ParserParsingJoinFurthestError(message, parserContext._depth, furthestPosition, furthestChildErrors);
342
+ return new parserContext._options.errorsModule.ParserParsingJoinFurthestError([
343
+ [
344
+ '%s',
345
+ 'Furthest child error stacks, indented:',
346
+ '%s',
347
+ 'End of furthest child error stacks',
348
+ ],
349
+ () => formatLazyMessage(userLazyMessage),
350
+ () => furthestChildErrors.flatMap(furthestChildError => {
351
+ if (isLazyMessageError(furthestChildError)) {
352
+ furthestChildError.computeMessage();
353
+ }
354
+
355
+ return furthestChildError.stack?.split('\n').map(line => ' ' + line);
356
+ }).join('\n'),
357
+ ], parserContext._depth, furthestPosition, furthestChildErrors);
344
358
  }, value, format, ...formatArguments);
345
359
  }
346
360
 
347
361
  if (errorJoinMode === 'deepest') {
348
- return customInvariant(function (message: string) {
362
+ return customInvariant(function (userLazyMessage: LazyMessage) {
349
363
  let deepestDepth = 0;
350
364
  let deepestChildErrors: ParserParsingFailedError[] = [];
351
365
 
352
366
  for (const childError of childErrors) {
367
+ if (isLazyMessageError(childError)) {
368
+ childError.computeMessage();
369
+ }
370
+
353
371
  if (childError.depth < deepestDepth) {
354
372
  continue;
355
373
  }
@@ -363,27 +381,43 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
363
381
  deepestChildErrors.push(childError);
364
382
  }
365
383
 
366
- message += [
367
- '',
368
- 'Deepest child error stacks, indented:',
369
- ...deepestChildErrors.flatMap(deepestChildError => deepestChildError.stack?.split('\n').map(line => ' ' + line)),
370
- 'End of deepest child error stacks',
371
- ].join('\n');
372
-
373
- return new ParserParsingJoinDeepestError(message, deepestDepth, parserContext.position, deepestChildErrors);
384
+ return new parserContext._options.errorsModule.ParserParsingJoinDeepestError([
385
+ [
386
+ '%s',
387
+ 'Deepest child error stacks, indented:',
388
+ '%s',
389
+ 'End of deepest child error stacks',
390
+ ],
391
+ () => formatLazyMessage(userLazyMessage),
392
+ () => deepestChildErrors.flatMap(deepestChildError => {
393
+ if (isLazyMessageError(deepestChildError)) {
394
+ deepestChildError.computeMessage();
395
+ }
396
+
397
+ return deepestChildError.stack?.split('\n').map(line => ' ' + line);
398
+ }).join('\n'),
399
+ ], deepestDepth, parserContext.position, deepestChildErrors);
374
400
  }, value, format, ...formatArguments);
375
401
  }
376
402
 
377
403
  if (errorJoinMode === 'all') {
378
- return customInvariant(function (message: string) {
379
- message += [
380
- '',
381
- 'Child error stacks, indented:',
382
- ...childErrors.flatMap(childError => childError.stack?.split('\n').map(line => ' ' + line)),
383
- 'End of child error stacks',
384
- ].join('\n');
385
-
386
- return new ParserParsingJoinAllError(message, parserContext._depth, parserContext.position, childErrors);
404
+ return customInvariant(function (userLazyMessage: LazyMessage) {
405
+ return new parserContext._options.errorsModule.ParserParsingJoinAllError([
406
+ [
407
+ '%s',
408
+ 'All child error stacks, indented:',
409
+ '%s',
410
+ 'End of all child error stacks',
411
+ ],
412
+ () => formatLazyMessage(userLazyMessage),
413
+ () => childErrors.flatMap(childError => {
414
+ if (isLazyMessageError(childError)) {
415
+ childError.computeMessage();
416
+ }
417
+
418
+ return childError.stack?.split('\n').map(line => ' ' + line);
419
+ }).join('\n'),
420
+ ], parserContext._depth, parserContext.position, childErrors);
387
421
  }, value, format, ...formatArguments);
388
422
  }
389
423
 
@@ -1,88 +1,168 @@
1
- import { InputReaderState } from "./inputReaderState.js";
1
+ import { type InputReaderState } from './inputReaderState.js';
2
+ import { LazyMessage, NormalLazyMessageError, NoStackCaptureOverheadLazyMessageError } from './lazyMessageError.js';
2
3
 
3
- export class ParserError extends Error {
4
- name = 'ParserError';
5
-
6
- public position: undefined | number = undefined;
7
- public inputReaderSate: undefined | InputReaderState<unknown> = undefined;
4
+ export interface ParserError extends Error {
5
+ position: undefined | number;
6
+ inputReaderSate: undefined | InputReaderState<unknown>;
8
7
  }
9
8
 
10
- export class ParserImplementationError extends ParserError {
11
- name = 'ParserImplementationError';
12
- }
13
- export class ParserImplementationInvariantError extends ParserImplementationError {
14
- name = 'ParserImplementationInvariantError';
9
+ export function isParserError(value: unknown): value is ParserError {
10
+ return (
11
+ typeof value === 'object'
12
+ && value !== null
13
+ && value instanceof Error
14
+ && 'position' in value
15
+ && (typeof value.position === 'number' || value.position === undefined)
16
+ && 'inputReaderSate' in value
17
+ && (value.inputReaderSate === undefined || typeof value.inputReaderSate === 'object')
18
+ );
15
19
  }
16
20
 
17
- export class ParserParsingFailedError extends ParserError {
18
- name = 'ParserParsingFailedError';
21
+ type ParserErrorInterface = ParserError;
19
22
 
20
- constructor(
21
- message: string,
22
- public readonly depth: number,
23
- public readonly position: number,
24
- ) {
25
- super(message);
26
- }
23
+ export interface ParserParsingFailedError extends ParserErrorInterface {
24
+ depth: number;
25
+ position: number;
27
26
  }
28
27
 
29
- export class ParserParsingJoinError extends ParserParsingFailedError {
30
- name = 'ParserParsingJoinError';
28
+ export function isParserParsingFailedError(value: unknown): value is ParserParsingFailedError {
29
+ return (
30
+ typeof value === 'object'
31
+ && value !== null
32
+ && value instanceof Error
33
+ && 'depth' in value
34
+ && typeof value.depth === 'number'
35
+ && 'position' in value
36
+ && typeof value.position === 'number'
37
+ );
38
+ }
31
39
 
32
- public readonly childErrors: ParserParsingFailedError[] = [];
40
+ type ParserParsingFailedErrorInterface = ParserParsingFailedError;
41
+
42
+ export interface ParserParsingJoinError extends ParserParsingFailedErrorInterface {
43
+ childErrors: ParserParsingFailedErrorInterface[];
33
44
  }
34
45
 
35
- export class ParserParsingJoinNoneError extends ParserParsingJoinError {
36
- name = 'ParserParsingJoinNoneError';
46
+ export function isParserParsingJoinError(value: unknown): value is ParserParsingJoinError {
47
+ return (
48
+ typeof value === 'object'
49
+ && value !== null
50
+ && value instanceof Error
51
+ && 'childErrors' in value
52
+ && Array.isArray(value.childErrors)
53
+ && value.childErrors.every((childError: unknown) => isParserParsingFailedError(childError))
54
+ );
37
55
  }
38
56
 
39
- export class ParserParsingJoinAllError extends ParserParsingJoinError {
40
- name = 'ParserParsingJoinAllError';
57
+ type ParserParsingJoinErrorInterface = ParserParsingJoinError;
58
+
59
+ function createParserErrorModule(
60
+ BaseLazyMessageError: typeof NormalLazyMessageError | typeof NoStackCaptureOverheadLazyMessageError,
61
+ ) {
62
+ class ParserError extends BaseLazyMessageError implements ParserErrorInterface {
63
+ name = 'ParserError';
41
64
 
42
- constructor(
43
- message: string,
44
- depth: number,
45
- position: number,
46
- public readonly childErrors: ParserParsingFailedError[],
47
- ) {
48
- super(message, depth, position);
65
+ public position: undefined | number = undefined;
66
+ public inputReaderSate: undefined | InputReaderState<unknown> = undefined;
49
67
  }
50
- }
51
68
 
52
- export class ParserParsingJoinDeepestError extends ParserParsingJoinError {
53
- name = 'ParserParsingJoinDeepestError';
69
+ class ParserImplementationError extends ParserError {
70
+ name = 'ParserImplementationError';
71
+ }
72
+ class ParserImplementationInvariantError extends ParserImplementationError {
73
+ name = 'ParserImplementationInvariantError';
74
+ }
54
75
 
55
- constructor(
56
- message: string,
57
- depth: number,
58
- position: number,
59
- public readonly childErrors: ParserParsingFailedError[],
60
- ) {
61
- super(message, depth, position);
76
+ class ParserParsingFailedError extends ParserError implements ParserParsingFailedErrorInterface {
77
+ name = 'ParserParsingFailedError';
78
+
79
+ constructor(
80
+ message: LazyMessage,
81
+ public readonly depth: number,
82
+ public readonly position: number,
83
+ ) {
84
+ super(message);
85
+ }
62
86
  }
63
- }
64
87
 
65
- export class ParserParsingJoinFurthestError extends ParserParsingJoinError {
66
- name = 'ParserParsingJoinFurthestError';
88
+ class ParserParsingJoinError extends ParserParsingFailedError implements ParserParsingJoinErrorInterface {
89
+ name = 'ParserParsingJoinError';
67
90
 
68
- constructor(
69
- message: string,
70
- depth: number,
71
- position: number,
72
- public readonly childErrors: ParserParsingFailedError[],
73
- ) {
74
- super(message, depth, position);
91
+ public readonly childErrors: ParserParsingFailedErrorInterface[] = [];
75
92
  }
76
- }
77
93
 
78
- export class ParserParsingInvariantError extends ParserParsingFailedError {
79
- name = 'ParserParsingInvariantError';
80
- }
94
+ class ParserParsingJoinNoneError extends ParserParsingJoinError {
95
+ name = 'ParserParsingJoinNoneError';
96
+ }
81
97
 
82
- export class ParserUnexpectedEndOfInputError extends ParserParsingFailedError {
83
- name = 'ParserUnexpectedEndOfInputError';
84
- }
98
+ class ParserParsingJoinAllError extends ParserParsingJoinError {
99
+ name = 'ParserParsingJoinAllError';
100
+
101
+ constructor(
102
+ message: LazyMessage,
103
+ depth: number,
104
+ position: number,
105
+ public readonly childErrors: ParserParsingFailedErrorInterface[],
106
+ ) {
107
+ super(message, depth, position);
108
+ }
109
+ }
110
+
111
+ class ParserParsingJoinDeepestError extends ParserParsingJoinError {
112
+ name = 'ParserParsingJoinDeepestError';
113
+
114
+ constructor(
115
+ message: LazyMessage,
116
+ depth: number,
117
+ position: number,
118
+ public readonly childErrors: ParserParsingFailedErrorInterface[],
119
+ ) {
120
+ super(message, depth, position);
121
+ }
122
+ }
123
+
124
+ class ParserParsingJoinFurthestError extends ParserParsingJoinError {
125
+ name = 'ParserParsingJoinFurthestError';
126
+
127
+ constructor(
128
+ message: LazyMessage,
129
+ depth: number,
130
+ position: number,
131
+ public readonly childErrors: ParserParsingFailedErrorInterface[],
132
+ ) {
133
+ super(message, depth, position);
134
+ }
135
+ }
136
+
137
+ class ParserParsingInvariantError extends ParserParsingFailedError {
138
+ name = 'ParserParsingInvariantError';
139
+ }
140
+
141
+ class ParserUnexpectedEndOfInputError extends ParserParsingFailedError {
142
+ name = 'ParserUnexpectedEndOfInputError';
143
+ }
85
144
 
86
- export class ParserUnexpectedRemainingInputError extends ParserParsingFailedError {
87
- name = 'ParserUnexpectedRemainingInputError';
145
+ class ParserUnexpectedRemainingInputError extends ParserParsingFailedError {
146
+ name = 'ParserUnexpectedRemainingInputError';
147
+ }
148
+
149
+ return {
150
+ ParserError,
151
+ ParserImplementationError,
152
+ ParserImplementationInvariantError,
153
+ ParserParsingFailedError,
154
+ ParserParsingJoinError,
155
+ ParserParsingJoinNoneError,
156
+ ParserParsingJoinAllError,
157
+ ParserParsingJoinDeepestError,
158
+ ParserParsingJoinFurthestError,
159
+ ParserParsingInvariantError,
160
+ ParserUnexpectedEndOfInputError,
161
+ ParserUnexpectedRemainingInputError,
162
+ };
88
163
  }
164
+
165
+ export type ParserErrorModule = ReturnType<typeof createParserErrorModule>;
166
+
167
+ export const normalParserErrorModule = createParserErrorModule(NormalLazyMessageError);
168
+ export const noStackCaptureOverheadParserErrorModule = createParserErrorModule(NoStackCaptureOverheadLazyMessageError);
@@ -1,6 +1,6 @@
1
- import { ParserImplementationInvariantError } from './parserError.js';
2
1
  import { type Falsy, customInvariant, type ValueOrAccessor } from './customInvariant.js';
2
+ import { normalParserErrorModule } from './parserError.js';
3
3
 
4
- export function parserImplementationInvariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: any[]): Exclude<T, Falsy> {
5
- return customInvariant(ParserImplementationInvariantError, value, format, ...formatArguments);
4
+ export function parserImplementationInvariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy> {
5
+ return customInvariant(normalParserErrorModule.ParserImplementationInvariantError, value, format, ...formatArguments);
6
6
  }
@@ -89,8 +89,8 @@ export class Uint8ArrayParserInputCompanion implements ParserInputCompanion<Uint
89
89
  return false;
90
90
  }
91
91
 
92
- for (let index = 0; index < sequenceA.length; index++) {
93
- if (sequenceA[index] !== sequenceB[index]) {
92
+ for (const [ index, element ] of sequenceA.entries()) {
93
+ if (element !== sequenceB[index]) {
94
94
  return false;
95
95
  }
96
96
  }
@@ -3,7 +3,7 @@ export function promiseCompose<A, B, C>(
3
3
  f1: (a: A) => B | Promise<B>,
4
4
  f2: (b: B) => C | Promise<C>,
5
5
  ): (a: A) => C | Promise<C> {
6
- function promiseComposed(a: A) {
6
+ async function promiseComposed(a: A) {
7
7
  const bOrBPromise = f1(a);
8
8
 
9
9
  if (bOrBPromise instanceof Promise) {
@@ -11,7 +11,7 @@ export function promiseCompose<A, B, C>(
11
11
  }
12
12
 
13
13
  return f2(bOrBPromise);
14
- };
14
+ }
15
15
 
16
16
  Object.defineProperty(promiseComposed, 'name', {
17
17
  value: `promiseCompose(${f1.name}, ${f2.name})`,
@@ -1,5 +1,5 @@
1
1
  import { getParserName, type Parser, setParserName } from './parser.js';
2
- import { ParserParsingFailedError } from './parserError.js';
2
+ import { isParserParsingFailedError } from './parserError.js';
3
3
  import { promiseCompose } from './promiseCompose.js';
4
4
  import { createTupleParser } from './tupleParser.js';
5
5
 
@@ -34,7 +34,7 @@ export const createSeparatedArrayParser = <ElementOutput, Sequence>(
34
34
  elements.push(element);
35
35
  elementParserContext.unlookahead();
36
36
  } catch (error) {
37
- if (error instanceof ParserParsingFailedError) {
37
+ if (isParserParsingFailedError(error)) {
38
38
  break;
39
39
  }
40
40
 
@@ -43,7 +43,7 @@ export const createSeparatedArrayParser = <ElementOutput, Sequence>(
43
43
  elementParserContext.dispose();
44
44
  }
45
45
 
46
- parser = separatorThenElementParser
46
+ parser = separatorThenElementParser;
47
47
  }
48
48
 
49
49
  return elements;
@@ -0,0 +1,117 @@
1
+ import test from 'ava';
2
+ import { testProp, fc } from '@fast-check/ava';
3
+ import { createSeparatedNonEmptyArrayParser } from './separatedNonEmptyArrayParser.js';
4
+ import { type Parser, runParser, runParserWithRemainingInput } from './parser.js';
5
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
6
+ import { createExactSequenceParser } from './exactSequenceParser.js';
7
+ import { stringFromAsyncIterable } from './stringFromAsyncIterable.js';
8
+
9
+ test('empty input throws error', async t => {
10
+ const parser: Parser<string[], string> = createSeparatedNonEmptyArrayParser(
11
+ createExactSequenceParser('element'),
12
+ createExactSequenceParser(','),
13
+ );
14
+
15
+ await t.throwsAsync(async () => runParser(parser, '', stringParserInputCompanion), {
16
+ any: true,
17
+ message: /Expected .* to match at least once/,
18
+ });
19
+ });
20
+
21
+ test('single element without separator matches', async t => {
22
+ const parser: Parser<string[], string> = createSeparatedNonEmptyArrayParser(
23
+ createExactSequenceParser('element'),
24
+ createExactSequenceParser(','),
25
+ );
26
+
27
+ const result = await runParser(parser, 'element', stringParserInputCompanion);
28
+ t.deepEqual(result, [ 'element' ]);
29
+ });
30
+
31
+ test('two elements with separator matches', async t => {
32
+ const parser: Parser<string[], string> = createSeparatedNonEmptyArrayParser(
33
+ createExactSequenceParser('element'),
34
+ createExactSequenceParser(','),
35
+ );
36
+
37
+ const result = await runParser(parser, 'element,element', stringParserInputCompanion);
38
+ t.deepEqual(result, [ 'element', 'element' ]);
39
+ });
40
+
41
+ test('multiple elements with separator matches', async t => {
42
+ const parser: Parser<string[], string> = createSeparatedNonEmptyArrayParser(
43
+ createExactSequenceParser('a'),
44
+ createExactSequenceParser(','),
45
+ );
46
+
47
+ const result = await runParser(parser, 'a,a,a,a', stringParserInputCompanion);
48
+ t.deepEqual(result, [ 'a', 'a', 'a', 'a' ]);
49
+ });
50
+
51
+ test('does not consume trailing separator', async t => {
52
+ const parser: Parser<string[], string> = createSeparatedNonEmptyArrayParser(
53
+ createExactSequenceParser('element'),
54
+ createExactSequenceParser(','),
55
+ );
56
+
57
+ const { output, remainingInput } = await runParserWithRemainingInput(parser, 'element,element,', stringParserInputCompanion);
58
+ t.deepEqual(output, [ 'element', 'element' ]);
59
+ t.is(await stringFromAsyncIterable(remainingInput!), ',');
60
+ });
61
+
62
+ test('does not loop forever with a child parser that does not consume anything', async t => {
63
+ const parser: Parser<undefined[], string> = createSeparatedNonEmptyArrayParser(
64
+ async () => undefined,
65
+ () => undefined,
66
+ );
67
+
68
+ await t.throwsAsync(async () => runParser(parser, 'foo', stringParserInputCompanion), {
69
+ any: true,
70
+ message: /Expected .* to match at least once/,
71
+ });
72
+ });
73
+
74
+ test('partial match throws error', async t => {
75
+ const parser: Parser<string[], string> = createSeparatedNonEmptyArrayParser(
76
+ createExactSequenceParser('element'),
77
+ createExactSequenceParser(','),
78
+ );
79
+
80
+ await t.throwsAsync(async () => runParser(parser, 'elem', stringParserInputCompanion), {
81
+ any: true,
82
+ message: /Expected .* to match at least once/,
83
+ });
84
+ });
85
+
86
+ testProp(
87
+ 'separatedNonEmptyArray with at least one element',
88
+ [
89
+ fc.array(fc.constant('element'), { minLength: 1 }),
90
+ ],
91
+ async (t, elements) => {
92
+ const separatedNonEmptyArrayParser = createSeparatedNonEmptyArrayParser(
93
+ createExactSequenceParser('element'),
94
+ createExactSequenceParser('separator'),
95
+ );
96
+
97
+ const actual = await runParser(separatedNonEmptyArrayParser, elements.join('separator'), stringParserInputCompanion);
98
+ const expected = elements;
99
+
100
+ t.deepEqual(actual, expected);
101
+ },
102
+ {
103
+ verbose: true,
104
+ },
105
+ );
106
+
107
+ test('separatedNonEmptyArray throws on empty array', async t => {
108
+ const separatedNonEmptyArrayParser = createSeparatedNonEmptyArrayParser(
109
+ createExactSequenceParser('element'),
110
+ createExactSequenceParser('separator'),
111
+ );
112
+
113
+ await t.throwsAsync(async () => runParser(separatedNonEmptyArrayParser, '', stringParserInputCompanion), {
114
+ any: true,
115
+ message: /Expected .* to match at least once/,
116
+ });
117
+ });