@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
package/src/index.ts ADDED
@@ -0,0 +1,76 @@
1
+
2
+ export {
3
+ Parser,
4
+ runParser,
5
+
6
+ setParserName,
7
+ getParserName,
8
+ } from './parser.js';
9
+
10
+ export {
11
+ ParserContext,
12
+ } from './parserContext.js';
13
+
14
+ export {
15
+ createTupleParser,
16
+ } from './tupleParser.js';
17
+
18
+ export {
19
+ createExactSequenceParser,
20
+ } from './exactSequenceParser.js';
21
+
22
+ export {
23
+ createFixedLengthSequenceParser,
24
+ } from './fixedLengthSequenceParser.js';
25
+
26
+ export {
27
+ createArrayParser,
28
+ } from './arrayParser.js';
29
+
30
+ export {
31
+ createOptionalParser,
32
+ } from './optionalParser.js';
33
+
34
+ export {
35
+ createUnionParser,
36
+ } from './unionParser.js';
37
+
38
+ export {
39
+ createDisjunctionParser,
40
+ } from './disjunctionParser.js';
41
+
42
+ export {
43
+ createParserAccessorParser,
44
+ } from './parserAccessorParser.js';
45
+
46
+ export {
47
+ createElementParser,
48
+ } from './elementParser.js';
49
+
50
+ export {
51
+ createTerminatedArrayParser,
52
+ } from './terminatedArrayParser.js';
53
+
54
+ export {
55
+ createSliceBoundedParser,
56
+ } from './sliceBoundedParser.js';
57
+
58
+ export {
59
+ createExactElementParser,
60
+ } from './exactElementParser.js';
61
+
62
+ export {
63
+ createSkipParser,
64
+ } from './skipParser.js';
65
+
66
+ export {
67
+ createEndOfInputParser,
68
+ } from './endOfInputParser.js';
69
+
70
+ export {
71
+ createListParser,
72
+ } from './listParser.js';
73
+
74
+ export {
75
+ createDebugLogParser,
76
+ } from './debugLogParser.js';
@@ -0,0 +1,43 @@
1
+
2
+ export type InputCompanion<Sequence, Element> = {
3
+ is(value: unknown): value is Sequence;
4
+ from(elements: Element[]): Sequence;
5
+ length(sequence: Sequence): number;
6
+ at(sequence: Sequence, index: number): Element | undefined;
7
+ };
8
+
9
+ export const stringInputCompanion = new class StringInputCompanion implements InputCompanion<string, string> {
10
+ is(value: unknown): value is string {
11
+ return typeof value === 'string';
12
+ }
13
+
14
+ from(elements: string[]): string {
15
+ return elements.join('');
16
+ }
17
+
18
+ length(sequence: string): number {
19
+ return sequence.length;
20
+ }
21
+
22
+ at(sequence: string, index: number): string | undefined {
23
+ return sequence.at(index);
24
+ }
25
+ }();
26
+
27
+ export const uint8ArrayInputCompanion = new class Uint8ArrayInputCompanion implements InputCompanion<Uint8Array, number> {
28
+ is(value: unknown): value is Uint8Array {
29
+ return value instanceof Uint8Array
30
+ }
31
+
32
+ from(elements: number[]): Uint8Array {
33
+ return new Uint8Array(elements);
34
+ }
35
+
36
+ length(sequence: Uint8Array): number {
37
+ return sequence.length;
38
+ }
39
+
40
+ at(sequence: Uint8Array, index: number): number | undefined {
41
+ return sequence.at(index);
42
+ }
43
+ }();
@@ -0,0 +1,238 @@
1
+ import test from 'ava';
2
+ import { InputReaderImplementation } from './inputReader.js';
3
+ import { stringInputCompanion } from './inputCompanion.js';
4
+ import { ParserImplementationError } from './parserError.js';
5
+
6
+ test('inputReader', async t => {
7
+ const inputReader = new InputReaderImplementation(stringInputCompanion, (async function * () {
8
+ yield '';
9
+ yield 'abc';
10
+ yield 'def';
11
+ yield '';
12
+ yield 'gh';
13
+ })());
14
+
15
+ t.is(await inputReader.peek(0), 'a');
16
+
17
+ inputReader.skip(0);
18
+
19
+ t.is(await inputReader.peek(1), 'b');
20
+
21
+ inputReader.skip(1);
22
+
23
+ t.is(await inputReader.peek(1), 'c');
24
+ t.is(await inputReader.peek(2), 'd');
25
+ t.is(await inputReader.peek(3), 'e');
26
+ t.is(await inputReader.peek(4), 'f');
27
+ t.is(await inputReader.peek(5), 'g');
28
+ t.is(await inputReader.peek(6), 'h');
29
+ t.is(await inputReader.peek(7), undefined);
30
+
31
+ inputReader.skip(6);
32
+
33
+ t.is(await inputReader.peek(0), 'h');
34
+ t.is(await inputReader.peek(1), undefined);
35
+
36
+ inputReader.skip(1);
37
+
38
+ t.is(await inputReader.peek(0), undefined);
39
+
40
+ inputReader.skip(0);
41
+
42
+ t.is(await inputReader.peek(0), undefined);
43
+
44
+ inputReader.skip(1);
45
+
46
+ t.is(await inputReader.peek(0), undefined);
47
+ });
48
+
49
+ test('inputReader.peek concurrent', async t => {
50
+ const inputReader = new InputReaderImplementation(stringInputCompanion, (async function * () {
51
+ yield * 'abcdefgh';
52
+ })());
53
+
54
+ const peeks = await Promise.all([
55
+ inputReader.peek(0),
56
+ inputReader.peek(0),
57
+ inputReader.peek(0),
58
+ inputReader.peek(0),
59
+ inputReader.peek(1),
60
+ inputReader.peek(2),
61
+ inputReader.peek(3),
62
+ inputReader.peek(4),
63
+ inputReader.peek(5),
64
+ inputReader.peek(6),
65
+ inputReader.peek(7),
66
+ ]);
67
+
68
+ t.deepEqual(peeks, [ 'a', 'a', 'a', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' ]);
69
+ });
70
+
71
+ test('inputReader skip while peeking', async t => {
72
+ const inputReader = new InputReaderImplementation(stringInputCompanion, (async function * () {
73
+ yield * 'abcdefgh';
74
+ })());
75
+
76
+ const peekPromise = inputReader.peek(0);
77
+
78
+ inputReader.skip(1);
79
+
80
+ t.is(await peekPromise, 'a');
81
+ t.is(await inputReader.peek(0), 'b');
82
+ });
83
+
84
+ test('inputReader.lookahead', async t => {
85
+ let read = 0;
86
+
87
+ const inputReader = new InputReaderImplementation(stringInputCompanion, (async function * () {
88
+ for (const character of 'abcdefgh') {
89
+ read++;
90
+ yield character;
91
+ }
92
+ })());
93
+
94
+ const lookahead0a = inputReader.lookahead();
95
+ const lookahead0b = lookahead0a.lookahead();
96
+ const lookahead0c = lookahead0b.lookahead();
97
+
98
+ t.is(await inputReader.peek(0), 'a');
99
+ t.is(await lookahead0a.peek(0), 'a');
100
+ t.is(await lookahead0b.peek(0), 'a');
101
+ t.is(await lookahead0c.peek(0), 'a');
102
+
103
+ t.is(inputReader.position, 0);
104
+ t.is(lookahead0a.position, 0);
105
+ t.is(lookahead0b.position, 0);
106
+ t.is(lookahead0c.position, 0);
107
+
108
+ t.is(read, 1);
109
+
110
+ t.is(await lookahead0b.peek(1), 'b');
111
+ t.is(await inputReader.peek(0), 'a');
112
+
113
+ t.is(read, 2);
114
+
115
+ inputReader.skip(1);
116
+
117
+ await t.throwsAsync(async () => lookahead0a.peek(0), {
118
+ instanceOf: ParserImplementationError,
119
+ });
120
+ await t.throwsAsync(async () => lookahead0b.peek(0));
121
+ await t.throwsAsync(async () => lookahead0c.peek(0));
122
+
123
+ const lookahead1a = inputReader.lookahead();
124
+ const lookahead1b = inputReader.lookahead();
125
+
126
+ t.is(await lookahead1a.peek(0), 'b');
127
+ t.is(await lookahead1b.peek(0), 'b');
128
+
129
+ t.is(lookahead1a.position, 1);
130
+ t.is(lookahead1b.position, 1);
131
+
132
+ lookahead1a.skip(1);
133
+
134
+ t.is(await lookahead1a.peek(0), 'c');
135
+ t.is(await lookahead1b.peek(0), 'b');
136
+
137
+ t.is(lookahead1a.position, 2);
138
+ t.is(lookahead1b.position, 1);
139
+
140
+ const lookahead2a = lookahead1a.lookahead();
141
+ const lookahead2b = lookahead1a.lookahead();
142
+
143
+ lookahead2a.skip(1);
144
+
145
+ t.is(await lookahead2a.peek(0), 'd');
146
+ t.is(await lookahead2b.peek(0), 'c');
147
+
148
+ t.is(lookahead2a.position, 3);
149
+ t.is(lookahead2b.position, 2);
150
+
151
+ t.is(read, 4);
152
+
153
+ t.is(await inputReader.peek(0), 'b');
154
+
155
+ t.is(inputReader.position, 1);
156
+
157
+ inputReader.skip(1);
158
+
159
+ t.is(await inputReader.peek(0), 'c');
160
+
161
+ t.is(inputReader.position, 2);
162
+
163
+ await t.throwsAsync(async () => lookahead0a.peek(0));
164
+ await t.throwsAsync(async () => lookahead0b.peek(0));
165
+ await t.throwsAsync(async () => lookahead0c.peek(0));
166
+ t.is(await lookahead1a.peek(0), 'c');
167
+ await t.throwsAsync(async () => lookahead1b.peek(0));
168
+ t.is(await lookahead2a.peek(0), 'd');
169
+ t.is(await lookahead2b.peek(0), 'c');
170
+
171
+ t.is(lookahead0a.position, 0);
172
+ t.is(lookahead0b.position, 0);
173
+ t.is(lookahead0c.position, 0);
174
+ t.is(lookahead1a.position, 2);
175
+ t.is(lookahead1b.position, 1);
176
+ t.is(lookahead2a.position, 3);
177
+ t.is(lookahead2b.position, 2);
178
+ });
179
+
180
+ test('inputReader.lookahead concurrent', async t => {
181
+ let read = 0;
182
+
183
+ const inputReader = new InputReaderImplementation(stringInputCompanion, (async function * () {
184
+ for (const character of 'abcdefgh') {
185
+ read++;
186
+ yield character;
187
+ }
188
+ })());
189
+
190
+ const lookahead1 = inputReader.lookahead();
191
+ const lookahead2 = inputReader.lookahead();
192
+ const lookahead3 = inputReader.lookahead();
193
+
194
+ const peeks = await Promise.all([
195
+ lookahead1.peek(0),
196
+ lookahead2.peek(0),
197
+ lookahead3.peek(0),
198
+ ]);
199
+
200
+ const positions = [
201
+ lookahead1.position,
202
+ lookahead2.position,
203
+ lookahead3.position,
204
+ ];
205
+
206
+ t.deepEqual(peeks, [ 'a', 'a', 'a' ]);
207
+ t.deepEqual(positions, [ 0, 0, 0 ]);
208
+ t.is(read, 1);
209
+ });
210
+
211
+ test('inputReader.lookahead skip position', async t => {
212
+ let read = 0;
213
+
214
+ const inputReader = new InputReaderImplementation(stringInputCompanion, (async function * () {
215
+ for (const character of 'abcdefgh') {
216
+ read++;
217
+ yield character;
218
+ }
219
+ })());
220
+
221
+ inputReader.skip(1);
222
+
223
+ const lookahead = inputReader.lookahead();
224
+
225
+ lookahead.skip(1);
226
+
227
+ const lookahead1 = lookahead.lookahead();
228
+
229
+ lookahead1.skip(1);
230
+
231
+ t.is(inputReader.position, 1);
232
+ t.is(lookahead.position, 2);
233
+ t.is(lookahead1.position, 3);
234
+
235
+ t.is(await inputReader.peek(0), 'b');
236
+ t.is(await lookahead.peek(0), 'c');
237
+ t.is(await lookahead1.peek(0), 'd');
238
+ });
@@ -0,0 +1,159 @@
1
+ import PromiseMutex from 'p-mutex';
2
+ import invariant from 'invariant';
3
+ import { type SequenceBuffer, SequenceBufferImplementation } from './sequenceBuffer.js';
4
+ import { type InputCompanion } from './inputCompanion.js';
5
+ import { parserImplementationInvariant } from './parserImplementationInvariant.js';
6
+
7
+ export type InputReader<Sequence, Element> = {
8
+ get position(): number;
9
+
10
+ peek(offset: number): Promise<Element | undefined>;
11
+ skip(offset: number): void;
12
+
13
+ lookahead(): InputReader<Sequence, Element>;
14
+ };
15
+
16
+ let inputReaderId = 0;
17
+
18
+ export class InputReaderImplementation<Sequence, Element> implements InputReader<Sequence, Element> {
19
+ private readonly _id = inputReaderId++;
20
+
21
+ private _position = 0;
22
+ private _uncommitedSkipOffset = 0;
23
+
24
+ private readonly _promiseMutex = new PromiseMutex();
25
+
26
+ private readonly _sequenceBuffer: SequenceBuffer<Sequence, Element>;
27
+
28
+ constructor(
29
+ private readonly _inputCompanion: InputCompanion<Sequence, Element>,
30
+ private readonly _inputAsyncIterator: AsyncIterator<Sequence>,
31
+ ) {
32
+ this._sequenceBuffer = new SequenceBufferImplementation<Sequence, Element>(this._inputCompanion);
33
+ }
34
+
35
+ get [Symbol.toStringTag]() {
36
+ return [
37
+ 'InputReader',
38
+ this._id,
39
+ this.position,
40
+ ].join(' ');
41
+ }
42
+
43
+ get position() {
44
+ return this._position;
45
+ }
46
+
47
+ async peek(offset: number): Promise<Element | undefined> {
48
+ parserImplementationInvariant(offset >= 0, 'offset >= 0');
49
+
50
+ offset += this._uncommitedSkipOffset;
51
+
52
+ const element = this._sequenceBuffer.peek(offset);
53
+
54
+ if (element !== undefined) {
55
+ return element;
56
+ }
57
+
58
+ return this._promiseMutex.withLock(async () => {
59
+ while (true) {
60
+ const element = this._sequenceBuffer.peek(offset);
61
+
62
+ if (element !== undefined) {
63
+ return element;
64
+ }
65
+
66
+ const inputIteratorResult = await this._inputAsyncIterator.next();
67
+
68
+ if (inputIteratorResult.done) {
69
+ return undefined;
70
+ }
71
+
72
+ parserImplementationInvariant(
73
+ this._inputCompanion.is(inputIteratorResult.value),
74
+ [
75
+ 'Input iterator result value (%s) is of unexpected type.',
76
+ 'Expected a sequence (a chunk of input) recognized by the input companion (%s).',
77
+ 'You may have provided a wrong input companion for the input.',
78
+ ],
79
+ inputIteratorResult.value,
80
+ this._inputCompanion.constructor.name,
81
+ );
82
+
83
+ this._sequenceBuffer.push(inputIteratorResult.value);
84
+ }
85
+ });
86
+ }
87
+
88
+ skip(offset: number) {
89
+ parserImplementationInvariant(offset >= 0, 'offset >= 0');
90
+
91
+ this._position += offset;
92
+
93
+ if (this._promiseMutex.isLocked) {
94
+ this._uncommitedSkipOffset += offset;
95
+ } else {
96
+ this._sequenceBuffer.skip(offset + this._uncommitedSkipOffset);
97
+ this._uncommitedSkipOffset = 0;
98
+ }
99
+ }
100
+
101
+ lookahead(): InputReader<Sequence, Element> {
102
+ return new InputReaderLookaheadImplementation(this);
103
+ }
104
+ }
105
+
106
+ class InputReaderLookaheadImplementation<Sequence, Element> implements InputReader<Sequence, Element> {
107
+ private _initialInputReaderPosition = 0;
108
+ private _offset = 0;
109
+
110
+ constructor(
111
+ private readonly _inputReader: InputReaderImplementation<Sequence, Element>,
112
+ ) {
113
+ this._initialInputReaderPosition = this._inputReader.position;
114
+ }
115
+
116
+ get [Symbol.toStringTag]() {
117
+ return [
118
+ 'InputReaderLookahead',
119
+ this._inputReader.toString(),
120
+ this.position,
121
+ ].join(' ');
122
+ }
123
+
124
+ get position() {
125
+ return this._initialInputReaderPosition + this._offset;
126
+ }
127
+
128
+ async peek(offset: number): Promise<Element | undefined> {
129
+ const inputReaderMovedForward = this._inputReader.position - this._initialInputReaderPosition;
130
+
131
+ this._initialInputReaderPosition = this._inputReader.position;
132
+ this._offset -= inputReaderMovedForward;
133
+
134
+ return this._inputReader.peek(this._offset + offset);
135
+ }
136
+
137
+ skip(offset: number) {
138
+ parserImplementationInvariant(offset >= 0, 'offset >= 0');
139
+
140
+ this._offset += offset;
141
+ }
142
+
143
+ lookahead(): InputReader<Sequence, Element> {
144
+ const lookahead = new InputReaderLookaheadImplementation(this._inputReader);
145
+
146
+ const offset = this.position - lookahead.position;
147
+
148
+ lookahead.skip(offset);
149
+
150
+ invariant(
151
+ this.position === lookahead.position,
152
+ 'this.position (%s) === lookahead.position (%s)',
153
+ this.position,
154
+ lookahead.position,
155
+ );
156
+
157
+ return lookahead;
158
+ }
159
+ }
@@ -0,0 +1,6 @@
1
+ import invariant from 'invariant';
2
+
3
+ export function invariantDefined<T>(value: T, format: string, ...extra: any[]): Exclude<T, undefined> {
4
+ invariant(value !== undefined, format, ...extra);
5
+ return value as any;
6
+ }
@@ -0,0 +1,8 @@
1
+ import invariant from 'invariant';
2
+
3
+ type Falsy = '' | 0 | false | undefined ;
4
+
5
+ export function invariantIdentity<T>(value: T, format: string, ...extra: any[]): Exclude<T, Falsy> {
6
+ invariant(value, format, ...extra);
7
+ return value as any;
8
+ }
@@ -0,0 +1,26 @@
1
+ import { testProp, fc } from '@fast-check/ava';
2
+ import { jsonValueParser } from './jsonParser.js';
3
+ import { runParser } from './parser.js';
4
+ import { arbitrarilySlicedAsyncIterator } from './arbitrarilySlicedAsyncInterator.js';
5
+ import { stringInputCompanion } from './inputCompanion.js';
6
+
7
+ testProp(
8
+ 'json',
9
+ [
10
+ arbitrarilySlicedAsyncIterator(
11
+ fc.tuple(fc.json(), fc.nat())
12
+ .map(([ jsonString, indent ]) => JSON.stringify(JSON.parse(jsonString), null, indent)),
13
+ ),
14
+ ],
15
+ async (t, [ jsonString, jsonStringChunkIterator ]) => {
16
+ const actual = await runParser(jsonValueParser, jsonStringChunkIterator, stringInputCompanion, {
17
+ errorJoinMode: 'none',
18
+ });
19
+ const expected = JSON.parse(jsonString);
20
+
21
+ t.deepEqual(actual, expected);
22
+ },
23
+ {
24
+ verbose: true,
25
+ },
26
+ );