@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,58 @@
1
+ import invariant from 'invariant';
2
+ import { type InputCompanion } from './inputCompanion.js';
3
+
4
+ export type SequenceBuffer<Sequence, Element> = {
5
+ push(sequence: Sequence): void;
6
+ peek(offset: number): Element | undefined;
7
+ skip(offset: number): void;
8
+ };
9
+
10
+ export class SequenceBufferImplementation<Sequence, Element> implements SequenceBuffer<Sequence, Element> {
11
+ private readonly _sequences: Sequence[] = [];
12
+ private _indexInFirstSequence = 0;
13
+
14
+ constructor(private readonly _inputCompanion: InputCompanion<Sequence, Element>) {}
15
+
16
+ push(sequence: Sequence) {
17
+ this._sequences.push(sequence);
18
+
19
+ while (this._sequences.length > 0) {
20
+ const firstSequence = this._sequences[0];
21
+ const firstSequenceLength = this._inputCompanion.length(firstSequence);
22
+
23
+ if (firstSequenceLength === 0) {
24
+ this._sequences.shift();
25
+ continue;
26
+ }
27
+
28
+ if (this._indexInFirstSequence < firstSequenceLength) {
29
+ break;
30
+ }
31
+
32
+ this._sequences.shift();
33
+ this._indexInFirstSequence -= firstSequenceLength;
34
+ }
35
+ }
36
+
37
+ peek(offset: number): Element | undefined {
38
+ invariant(offset >= 0, 'Offset must be non-negative.');
39
+
40
+ let index = this._indexInFirstSequence + offset;
41
+
42
+ for (const sequence of this._sequences) {
43
+ const sequenceLength = this._inputCompanion.length(sequence);
44
+
45
+ if (index < sequenceLength) {
46
+ return this._inputCompanion.at(sequence, index);
47
+ }
48
+
49
+ index -= sequenceLength;
50
+ }
51
+
52
+ return undefined;
53
+ }
54
+
55
+ skip(offset: number) {
56
+ this._indexInFirstSequence += offset;
57
+ }
58
+ }
@@ -0,0 +1,12 @@
1
+ import { type Parser } from './parser.js';
2
+ import { parserImplementationInvariant } from './parserImplementationInvariant.js';
3
+
4
+ export const createSkipParser = <Sequence>(length: number): Parser<undefined, Sequence, unknown> => {
5
+ parserImplementationInvariant(length > 0, 'Length must be positive.');
6
+
7
+ return async parserContext => {
8
+ parserContext.skip(length);
9
+
10
+ return undefined;
11
+ };
12
+ };
@@ -0,0 +1,28 @@
1
+ import test from 'ava';
2
+ import { createArrayParser } from './arrayParser.js';
3
+ import { createElementParser } from './elementParser.js';
4
+ import { createTupleParser } from './tupleParser.js';
5
+ import { createSliceBoundedParser } from './sliceBoundedParser.js';
6
+ import { runParser } from './parser.js';
7
+ import { stringInputCompanion } from './inputCompanion.js';
8
+
9
+ const anythingParser = createArrayParser(createElementParser<string>());
10
+
11
+ test('sliceBoundedParser', async t => {
12
+ const parser = createTupleParser([
13
+ createElementParser<string>(),
14
+ createSliceBoundedParser(anythingParser, 2),
15
+ createElementParser(),
16
+ ]);
17
+
18
+ const result = await runParser(parser, 'abba', stringInputCompanion);
19
+
20
+ t.deepEqual(result, [
21
+ 'a',
22
+ [
23
+ 'b',
24
+ 'b',
25
+ ],
26
+ 'a',
27
+ ]);
28
+ });
@@ -0,0 +1,30 @@
1
+ import { getParserName, Parser, setParserName } from "./parser.js";
2
+
3
+ export const createSliceBoundedParser = <Output, Sequence>(
4
+ childParser: Parser<Output, Sequence>,
5
+ sliceEnd: number,
6
+ ): Parser<Output, Sequence> => {
7
+ const sliceBoundedParser: typeof childParser = async parserContext => {
8
+ const childParserContext = parserContext.lookahead({
9
+ sliceEnd: parserContext.position + sliceEnd,
10
+ });
11
+
12
+ try {
13
+ const value = await childParser(childParserContext);
14
+ childParserContext.unlookahead();
15
+ return value;
16
+ } finally {
17
+ childParserContext.dispose();
18
+ }
19
+ };
20
+
21
+ setParserName(sliceBoundedParser, [
22
+ 'sliceBounded(',
23
+ getParserName(childParser, 'anonymousSliceBoundedChild'),
24
+ ',',
25
+ sliceEnd,
26
+ ')',
27
+ ].join(''));
28
+
29
+ return sliceBoundedParser;
30
+ }
@@ -0,0 +1,40 @@
1
+ import { getParserName, Parser, setParserName } from "./parser.js";
2
+ import { promiseCompose } from "./promiseCompose.js";
3
+ import { createUnionParser } from "./unionParser.js";
4
+
5
+ class Terminated<T> {
6
+ constructor(
7
+ public readonly value: T,
8
+ ) {}
9
+ }
10
+
11
+ export const createTerminatedArrayParser = <ElementOutput, TerminatorOutput, Sequence>(
12
+ elementParser: Parser<ElementOutput, Sequence>,
13
+ terminatorParser: Parser<unknown, Sequence>,
14
+ ): Parser<[ElementOutput[], TerminatorOutput], Sequence> => {
15
+ const wrappedTerminatorParser = promiseCompose(terminatorParser, terminatorValue => new Terminated(terminatorValue));
16
+
17
+ setParserName(
18
+ wrappedTerminatorParser,
19
+ getParserName(terminatorParser, 'anonymousTerminator'),
20
+ );
21
+
22
+ const elementOrTerminatorParser = createUnionParser<ElementOutput | Terminated<TerminatorOutput>, Sequence>([
23
+ elementParser,
24
+ promiseCompose(terminatorParser, terminatorValue => new Terminated(terminatorValue)),
25
+ ]);
26
+
27
+ return async parserContext => {
28
+ const elements: ElementOutput[] = [];
29
+
30
+ while (true) {
31
+ const elementOrTerminator = await elementOrTerminatorParser(parserContext);
32
+
33
+ if (elementOrTerminator instanceof Terminated) {
34
+ return [ elements, elementOrTerminator.value ];
35
+ }
36
+
37
+ elements.push(elementOrTerminator);
38
+ }
39
+ };
40
+ };
@@ -0,0 +1,33 @@
1
+ import { getParserName, setParserName, type Parser } from './parser.js';
2
+
3
+ export function createTupleParser<A, B, Sequence>([ parserA, parserB ]: [Parser<A, Sequence>, Parser<B, Sequence>]): Parser<[A, B], Sequence>;
4
+ export function createTupleParser<A, B, C, Sequence>([ parserA, parserB, parserC ]: [Parser<A, Sequence>, Parser<B, Sequence>, Parser<C, Sequence>]): Parser<[A, B, C], Sequence>;
5
+ export 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>;
6
+ export 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>;
7
+ export 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>;
8
+ export 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>;
9
+ export 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>;
10
+ export 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>;
11
+ export 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>;
12
+ export 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>;
13
+ export function createTupleParser<Sequence>(parsers: Array<Parser<unknown, Sequence>>): Parser<unknown[], Sequence> {
14
+ const tupleParser: Parser<unknown[], Sequence> = async parserContext => {
15
+ const values: unknown[] = [];
16
+
17
+ for (const parser of parsers) {
18
+ const value = await parser(parserContext);
19
+
20
+ values.push(value);
21
+ }
22
+
23
+ return values;
24
+ };
25
+
26
+ setParserName(tupleParser, [
27
+ '[',
28
+ parsers.map(parser => getParserName(parser, 'anonymousTupleChild')).join(','),
29
+ ']',
30
+ ].join(''));
31
+
32
+ return tupleParser;
33
+ }
@@ -0,0 +1,104 @@
1
+ import { allSettledStream } from './allSettledStream.js';
2
+ import { getParserName, setParserName, type Parser } from './parser.js';
3
+ import { type ParserContext } from './parserContext.js';
4
+ import { ParserParsingFailedError } from './parserError.js';
5
+ import { parserImplementationInvariant } from './parserImplementationInvariant.js';
6
+
7
+ export const createUnionParser = <
8
+ Output,
9
+ Sequence,
10
+ >(
11
+ childParsers: Array<Parser<any, Sequence, any>>,
12
+ ): Parser<Output, Sequence, unknown> => {
13
+ parserImplementationInvariant(childParsers.length > 0, 'Union parser must have at least one child parser.');
14
+
15
+ const unionParser: Parser<Output, Sequence, unknown> = async parserContext => {
16
+ let runningChildParserContexts: Array<ParserContext<unknown, unknown>> = [];
17
+
18
+ const childParserResults = allSettledStream(childParsers.map(childParser => {
19
+ const childParserContext = parserContext.lookahead({
20
+ debugName: getParserName(childParser, 'anonymousUnionChild'),
21
+ });
22
+
23
+ runningChildParserContexts.push(childParserContext);
24
+
25
+ const promise = childParser(childParserContext);
26
+
27
+ return {
28
+ promise,
29
+ context: childParserContext,
30
+ };
31
+ }));
32
+
33
+ const parserParsingFailedErrors: ParserParsingFailedError[] = [];
34
+ const successfulParserOutputs: Output[] = [];
35
+ const successfulParserContexts: Array<ParserContext<unknown, unknown>> = [];
36
+ let didUnlookahead = false;
37
+
38
+ for await (const childParserResult of childParserResults) {
39
+ runningChildParserContexts = runningChildParserContexts.filter(
40
+ runningChildParserContext => runningChildParserContext !== childParserResult.context,
41
+ );
42
+
43
+ if (childParserResult.status === 'fulfilled') {
44
+ successfulParserOutputs.push(childParserResult.value);
45
+ successfulParserContexts.push(childParserResult.context);
46
+ } else {
47
+ const error = childParserResult.reason;
48
+
49
+ if (error instanceof ParserParsingFailedError) {
50
+ parserParsingFailedErrors.push(error);
51
+ } else {
52
+ throw error;
53
+ }
54
+ }
55
+
56
+ if (
57
+ runningChildParserContexts.length === 1
58
+ && successfulParserOutputs.length === 0
59
+ ) {
60
+ parserImplementationInvariant(!didUnlookahead, 'Union parser unlookaheaded multiple times.');
61
+ didUnlookahead = true;
62
+ const [ runningChildParserContext ] = runningChildParserContexts;
63
+ runningChildParserContext.unlookahead();
64
+ }
65
+ }
66
+
67
+ parserImplementationInvariant(
68
+ successfulParserOutputs.length <= 1,
69
+ [
70
+ 'Multiple union child parsers succeeded.',
71
+ 'Successful parser outputs, indented, separated by newlines:',
72
+ '%s',
73
+ 'End of successful parser outputs.',
74
+ ],
75
+ () => successfulParserOutputs.map(output => ' ' + JSON.stringify(output)).join('\n'),
76
+ );
77
+
78
+ parserContext.invariantJoin(
79
+ successfulParserOutputs.length === 1,
80
+ parserParsingFailedErrors,
81
+ 'No union child parser succeeded.',
82
+ );
83
+
84
+ const [ successfulParserContext ] = successfulParserContexts;
85
+
86
+ if (!didUnlookahead) {
87
+ successfulParserContext.unlookahead();
88
+ }
89
+
90
+ successfulParserContext.dispose();
91
+
92
+ const [ successfulParserOutput ] = successfulParserOutputs;
93
+
94
+ return successfulParserOutput;
95
+ };
96
+
97
+ const name = [
98
+ '(',
99
+ ...childParsers.map(childParser => getParserName(childParser, 'anonymousUnionChild')).join('|'),
100
+ ')',
101
+ ].join('');
102
+
103
+ return setParserName(unionParser, name);
104
+ };
package/src/zip.ts ADDED
@@ -0,0 +1,48 @@
1
+
2
+ export type ZipCompression =
3
+ | 'store'
4
+ | 'deflate'
5
+ ;
6
+
7
+ export type ZipUnixPermissions = {
8
+ type: 'unix';
9
+ unixPermissions: number;
10
+ };
11
+
12
+ export type ZipDosPermissions = {
13
+ type: 'dos';
14
+ dosPermissions: number;
15
+ };
16
+
17
+ export type ZipPermissions =
18
+ | ZipUnixPermissions
19
+ | ZipDosPermissions
20
+ ;
21
+
22
+ export type ZipFileEntry = {
23
+ type: 'file';
24
+ path: string;
25
+ date: Date;
26
+ comment: string;
27
+ permissions: ZipPermissions;
28
+ compression: ZipCompression;
29
+ content: Uint8Array;
30
+ };
31
+
32
+ export type ZipDirectoryEntry = {
33
+ type: 'directory';
34
+ path: string;
35
+ date: Date;
36
+ comment: string;
37
+ permissions: ZipPermissions;
38
+ };
39
+
40
+ export type ZipEntry =
41
+ | ZipFileEntry
42
+ | ZipDirectoryEntry
43
+ ;
44
+
45
+ export type Zip = {
46
+ comment: string;
47
+ entries: ZipEntry[];
48
+ }
@@ -0,0 +1,31 @@
1
+ import { testProp } from '@fast-check/ava';
2
+ import { arbitraryZipStream } from './arbitraryZipStream.js';
3
+ import { zipParser } from './zipParser.js';
4
+ import { uint8ArrayInputCompanion } from './inputCompanion.js';
5
+ import { runParser } from './parser.js';
6
+
7
+ async function * readableStreamToUint8ArrayAsyncIterator(stream: ReadableStream<Uint8Array>) {
8
+ for await (const chunk of stream) {
9
+ yield chunk;
10
+ }
11
+ }
12
+
13
+ testProp(
14
+ 'zip',
15
+ [
16
+ arbitraryZipStream,
17
+ ],
18
+ async (t, [ zip, zipStream ]) => {
19
+ const actual = await runParser(zipParser, readableStreamToUint8ArrayAsyncIterator(zipStream), uint8ArrayInputCompanion, {
20
+ errorJoinMode: 'all',
21
+ });
22
+
23
+ actual.entries.sort((a, b) => a.path.localeCompare(b.path));
24
+ zip.entries.sort((a, b) => a.path.localeCompare(b.path));
25
+
26
+ t.deepEqual(actual, zip);
27
+ },
28
+ {
29
+ verbose: true,
30
+ },
31
+ );