@futpib/parser 1.0.1 → 1.0.2

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 (304) hide show
  1. package/build/allSettledStream.js +32 -14
  2. package/build/allSettledStream.test.js +32 -0
  3. package/build/androidPackage.d.ts +39 -0
  4. package/build/androidPackageParser.d.ts +17 -0
  5. package/build/androidPackageParser.js +183 -0
  6. package/build/{apkParser.test.js → androidPackageParser.test.js} +6 -6
  7. package/build/androidPackageUnparser.d.ts +4 -0
  8. package/build/{apkUnparser.js → androidPackageUnparser.js} +23 -23
  9. package/build/androidPackageUnparser.test.js +26 -0
  10. package/build/arbitrarilySlicedAsyncInterable.d.ts +3 -1
  11. package/build/arbitrarilySlicedAsyncInterable.js +3 -3
  12. package/build/arrayParser.test.js +3 -3
  13. package/build/backsmali.d.ts +1 -0
  14. package/build/backsmali.js +22 -0
  15. package/build/bsonParser.js +6 -2
  16. package/build/customInvariant.d.ts +1 -1
  17. package/build/dalvikBytecodeParser/formatParsers.d.ts +97 -0
  18. package/build/dalvikBytecodeParser/formatParsers.js +169 -0
  19. package/build/dalvikBytecodeParser.d.ts +107 -0
  20. package/build/dalvikBytecodeParser.js +836 -0
  21. package/build/dalvikExecutable.d.ts +158 -0
  22. package/build/dalvikExecutable.js +20 -0
  23. package/build/dalvikExecutableParser/stringSyntaxParser.d.ts +4 -0
  24. package/build/dalvikExecutableParser/stringSyntaxParser.js +76 -0
  25. package/build/dalvikExecutableParser/typeParsers.d.ts +10 -0
  26. package/build/dalvikExecutableParser/typeParsers.js +34 -0
  27. package/build/dalvikExecutableParser/typedNumbers.d.ts +90 -0
  28. package/build/dalvikExecutableParser/typedNumbers.js +19 -0
  29. package/build/dalvikExecutableParser.d.ts +5 -0
  30. package/build/dalvikExecutableParser.js +1439 -0
  31. package/build/dalvikExecutableParser.test.js +70 -0
  32. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +298 -0
  33. package/build/debugLogInputParser.d.ts +4 -0
  34. package/build/debugLogInputParser.js +16 -0
  35. package/build/debugLogParser.js +14 -3
  36. package/build/disjunctionParser.d.ts +2 -1
  37. package/build/disjunctionParser.js +4 -2
  38. package/build/elementTerminatedArrayParser.d.ts +3 -0
  39. package/build/elementTerminatedArrayParser.js +18 -0
  40. package/build/elementTerminatedArrayParser.test.js +52 -0
  41. package/build/elementTerminatedSequenceArrayParser.d.ts +3 -0
  42. package/build/elementTerminatedSequenceArrayParser.js +32 -0
  43. package/build/elementTerminatedSequenceArrayParser.test.js +34 -0
  44. package/build/elementTerminatedSequenceParser.d.ts +3 -0
  45. package/build/elementTerminatedSequenceParser.js +27 -0
  46. package/build/elementTerminatedSequenceParser.test.js +34 -0
  47. package/build/exactElementParser.js +10 -5
  48. package/build/exactSequenceParser.d.ts +2 -1
  49. package/build/exactSequenceParser.js +12 -2
  50. package/build/fetchCid.d.ts +1 -0
  51. package/build/fetchCid.js +107 -0
  52. package/build/fixedLengthSequenceParser.d.ts +1 -0
  53. package/build/fixedLengthSequenceParser.js +18 -1
  54. package/build/fixedLengthSequenceParser.test.js +41 -0
  55. package/build/hasExecutable.d.ts +1 -0
  56. package/build/hasExecutable.js +8 -0
  57. package/build/highResolutionTimer.d.ts +16 -0
  58. package/build/highResolutionTimer.js +42 -0
  59. package/build/inputReader.d.ts +11 -0
  60. package/build/inputReader.js +37 -0
  61. package/build/inputReader.test.js +165 -0
  62. package/build/inputReaderState.d.ts +10 -0
  63. package/build/inputReaderState.js +16 -0
  64. package/build/inspect.d.ts +1 -0
  65. package/build/inspect.js +7 -0
  66. package/build/javaKeyStoreParser.test.js +2 -2
  67. package/build/jsonParser.d.ts +2 -0
  68. package/build/jsonParser.js +11 -14
  69. package/build/leb128Parser.d.ts +7 -0
  70. package/build/leb128Parser.js +82 -0
  71. package/build/leb128Parser.test.js +107 -0
  72. package/build/lookaheadParser.d.ts +2 -0
  73. package/build/lookaheadParser.js +14 -0
  74. package/build/negativeLookaheadParser.js +21 -15
  75. package/build/negativeLookaheadParser.test.js +30 -0
  76. package/build/nonEmptyArrayParser.d.ts +2 -0
  77. package/build/nonEmptyArrayParser.js +32 -0
  78. package/build/nonEmptyArrayParser.test.js +16 -0
  79. package/build/parser.d.ts +10 -1
  80. package/build/parser.js +66 -31
  81. package/build/parser.test.js +79 -12
  82. package/build/parserAccessorParser.js +9 -1
  83. package/build/parserConsumedSequenceParser.js +20 -15
  84. package/build/parserContext.d.ts +14 -0
  85. package/build/parserContext.js +56 -27
  86. package/build/parserContext.test.js +27 -0
  87. package/build/parserCreatorCompose.d.ts +1 -0
  88. package/build/parserCreatorCompose.js +8 -2
  89. package/build/parserError.d.ts +6 -0
  90. package/build/parserError.js +6 -6
  91. package/build/parserInputCompanion.d.ts +15 -0
  92. package/build/parserInputCompanion.js +38 -0
  93. package/build/promiseCompose.d.ts +1 -1
  94. package/build/promiseCompose.js +12 -1
  95. package/build/promiseSettled.d.ts +1 -0
  96. package/build/promiseSettled.js +4 -0
  97. package/build/separatedArrayParser.d.ts +2 -0
  98. package/build/separatedArrayParser.js +39 -0
  99. package/build/separatedArrayParser.test.d.ts +1 -0
  100. package/build/separatedArrayParser.test.js +21 -0
  101. package/build/sequenceBuffer.d.ts +10 -0
  102. package/build/sequenceBuffer.js +54 -2
  103. package/build/sequenceBuffer.test.js +57 -0
  104. package/build/sequenceTerminatedSequenceParser.d.ts +5 -0
  105. package/build/sequenceTerminatedSequenceParser.js +32 -0
  106. package/build/sequenceTerminatedSequenceParser.test.d.ts +1 -0
  107. package/build/sequenceTerminatedSequenceParser.test.js +37 -0
  108. package/build/skipParser.d.ts +1 -1
  109. package/build/skipParser.js +4 -2
  110. package/build/skipToParser.d.ts +2 -0
  111. package/build/skipToParser.js +11 -0
  112. package/build/sliceBoundedParser.d.ts +1 -1
  113. package/build/sliceBoundedParser.js +7 -2
  114. package/build/sliceBoundedParser.test.js +35 -1
  115. package/build/smali.d.ts +1 -0
  116. package/build/smali.js +17 -0
  117. package/build/smaliParser.d.ts +12 -0
  118. package/build/smaliParser.js +656 -0
  119. package/build/smaliParser.test.d.ts +1 -0
  120. package/build/smaliParser.test.js +115 -0
  121. package/build/terminatedArrayParser.d.ts +3 -1
  122. package/build/terminatedArrayParser.js +79 -2
  123. package/build/terminatedArrayParser.test.d.ts +1 -0
  124. package/build/terminatedArrayParser.test.js +131 -0
  125. package/build/toAsyncIterable.d.ts +1 -0
  126. package/build/toAsyncIterable.js +7 -0
  127. package/build/toAsyncIterator.d.ts +1 -0
  128. package/build/toAsyncIterator.js +33 -0
  129. package/build/tupleParser.d.ts +4 -0
  130. package/build/tupleParser.js +1 -5
  131. package/build/unionParser.d.ts +2 -1
  132. package/build/unionParser.js +27 -12
  133. package/build/unionParser.test.d.ts +1 -0
  134. package/build/unionParser.test.js +60 -0
  135. package/build/zipParser.d.ts +7 -2
  136. package/build/zipParser.js +36 -12
  137. package/build/zipUnparser.d.ts +4 -1
  138. package/build/zipUnparser.js +55 -26
  139. package/build/zipUnparser.test.js +14 -14
  140. package/package.json +23 -7
  141. package/src/allSettledStream.test.ts +40 -0
  142. package/src/allSettledStream.ts +47 -15
  143. package/src/androidPackage.ts +48 -0
  144. package/src/{apkParser.test.ts → androidPackageParser.test.ts} +6 -7
  145. package/src/{apkParser.test.ts.md → androidPackageParser.test.ts.md} +4 -4
  146. package/src/androidPackageParser.test.ts.snap +0 -0
  147. package/src/androidPackageParser.ts +440 -0
  148. package/src/androidPackageUnparser.test.ts +36 -0
  149. package/src/androidPackageUnparser.ts +120 -0
  150. package/src/arbitrarilySlicedAsyncInterable.ts +7 -2
  151. package/src/arrayParser.test.ts +3 -3
  152. package/src/backsmali.ts +30 -0
  153. package/src/bsonParser.ts +13 -2
  154. package/src/customInvariant.ts +1 -1
  155. package/src/dalvikBytecodeParser/formatParsers.ts +421 -0
  156. package/src/dalvikBytecodeParser.ts +2074 -0
  157. package/src/dalvikExecutable.ts +220 -0
  158. package/src/dalvikExecutableParser/stringSyntaxParser.ts +145 -0
  159. package/src/dalvikExecutableParser/typeParsers.ts +65 -0
  160. package/src/dalvikExecutableParser/typedNumbers.ts +57 -0
  161. package/src/dalvikExecutableParser.test.ts +89 -0
  162. package/src/dalvikExecutableParser.test.ts.md +634 -0
  163. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  164. package/src/dalvikExecutableParser.ts +2768 -0
  165. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +346 -0
  166. package/src/debugLogInputParser.ts +28 -0
  167. package/src/debugLogParser.ts +19 -3
  168. package/src/disjunctionParser.ts +10 -5
  169. package/src/elementTerminatedArrayParser.test.ts +99 -0
  170. package/src/elementTerminatedArrayParser.ts +31 -0
  171. package/src/elementTerminatedSequenceArrayParser.test.ts +54 -0
  172. package/src/elementTerminatedSequenceArrayParser.ts +52 -0
  173. package/src/elementTerminatedSequenceParser.test.ts +54 -0
  174. package/src/elementTerminatedSequenceParser.ts +43 -0
  175. package/src/exactElementParser.ts +17 -11
  176. package/src/exactSequenceParser.ts +23 -2
  177. package/src/fetchCid.ts +125 -0
  178. package/src/fixedLengthSequenceParser.test.ts +77 -0
  179. package/src/fixedLengthSequenceParser.ts +28 -1
  180. package/src/hasExecutable.ts +11 -0
  181. package/src/highResolutionTimer.ts +49 -0
  182. package/src/inputReader.test.ts +209 -0
  183. package/src/inputReader.ts +75 -0
  184. package/src/inputReaderState.ts +33 -0
  185. package/src/inspect.ts +9 -0
  186. package/src/javaKeyStoreParser.test.ts +2 -3
  187. package/src/jsonParser.ts +13 -25
  188. package/src/leb128Parser.test.ts +171 -0
  189. package/src/leb128Parser.ts +125 -0
  190. package/src/lookaheadParser.ts +19 -0
  191. package/src/negativeLookaheadParser.test.ts +53 -0
  192. package/src/negativeLookaheadParser.ts +26 -14
  193. package/src/nonEmptyArrayParser.test.ts +20 -0
  194. package/src/nonEmptyArrayParser.ts +44 -0
  195. package/src/optionalParser.ts +1 -0
  196. package/src/parser.test.ts +131 -12
  197. package/src/parser.test.ts.md +21 -21
  198. package/src/parser.test.ts.snap +0 -0
  199. package/src/parser.ts +149 -45
  200. package/src/parserAccessorParser.ts +12 -2
  201. package/src/parserConsumedSequenceParser.ts +25 -16
  202. package/src/parserContext.test.ts +31 -0
  203. package/src/parserContext.ts +109 -37
  204. package/src/parserCreatorCompose.ts +20 -2
  205. package/src/parserError.ts +9 -6
  206. package/src/parserInputCompanion.ts +55 -0
  207. package/src/promiseCompose.ts +17 -3
  208. package/src/promiseSettled.ts +6 -0
  209. package/src/separatedArrayParser.test.ts +34 -0
  210. package/src/separatedArrayParser.ts +55 -0
  211. package/src/sequenceBuffer.test.ts +70 -0
  212. package/src/sequenceBuffer.ts +88 -2
  213. package/src/sequenceTerminatedSequenceParser.test.ts +60 -0
  214. package/src/sequenceTerminatedSequenceParser.ts +62 -0
  215. package/src/skipParser.ts +7 -5
  216. package/src/skipToParser.ts +16 -0
  217. package/src/sliceBoundedParser.test.ts +43 -1
  218. package/src/sliceBoundedParser.ts +19 -1
  219. package/src/smali.ts +24 -0
  220. package/src/smaliParser.test.ts +132 -0
  221. package/src/smaliParser.test.ts.md +2320 -0
  222. package/src/smaliParser.test.ts.snap +0 -0
  223. package/src/smaliParser.ts +1166 -0
  224. package/src/terminatedArrayParser.test.ts +258 -0
  225. package/src/terminatedArrayParser.ts +108 -3
  226. package/src/toAsyncIterable.ts +7 -0
  227. package/src/toAsyncIterator.ts +48 -0
  228. package/src/tupleParser.ts +8 -5
  229. package/src/unionParser.test.ts +79 -0
  230. package/src/unionParser.ts +44 -16
  231. package/src/zipParser.ts +77 -18
  232. package/src/zipUnparser.test.ts +18 -18
  233. package/src/zipUnparser.ts +88 -27
  234. package/build/apk.d.ts +0 -39
  235. package/build/apkParser.d.ts +0 -16
  236. package/build/apkParser.js +0 -164
  237. package/build/apkUnparser.d.ts +0 -4
  238. package/build/apkUnparser.test.js +0 -26
  239. package/build/arbitraryDosDate.d.ts +0 -2
  240. package/build/arbitraryDosDate.js +0 -8
  241. package/build/arbitraryZipEntry.d.ts +0 -3
  242. package/build/arbitraryZipEntry.js +0 -26
  243. package/build/createDisjunctionParser.d.ts +0 -2
  244. package/build/createDisjunctionParser.js +0 -47
  245. package/build/createExactParser.d.ts +0 -2
  246. package/build/createExactParser.js +0 -12
  247. package/build/createSequentialUnionParser.d.ts +0 -2
  248. package/build/createSequentialUnionParser.js +0 -69
  249. package/build/fixedLengthChunkParser.d.ts +0 -2
  250. package/build/fixedLengthChunkParser.js +0 -12
  251. package/build/fixedLengthParser.d.ts +0 -2
  252. package/build/fixedLengthParser.js +0 -12
  253. package/build/inputChunkBuffer.d.ts +0 -15
  254. package/build/inputChunkBuffer.js +0 -40
  255. package/build/inputChunkBuffer.test.js +0 -34
  256. package/build/inputCompanion.d.ts +0 -18
  257. package/build/inputCompanion.js +0 -28
  258. package/build/invariantDefined.d.ts +0 -1
  259. package/build/invariantDefined.js +0 -5
  260. package/build/invariantIdentity.d.ts +0 -3
  261. package/build/invariantIdentity.js +0 -5
  262. package/build/javaKeystoreParser.d.ts +0 -2
  263. package/build/javaKeystoreParser.js +0 -7
  264. package/build/jsonParser2.d.ts +0 -3
  265. package/build/jsonParser2.js +0 -52
  266. package/build/jsonParser2.test.js +0 -22
  267. package/build/negativeLookahead.d.ts +0 -2
  268. package/build/negativeLookahead.js +0 -18
  269. package/build/parserCompose.d.ts +0 -3
  270. package/build/parserCompose.js +0 -7
  271. package/build/parserImplementationInvariantInvariant.d.ts +0 -3
  272. package/build/parserImplementationInvariantInvariant.js +0 -15
  273. package/build/parserInvariant.d.ts +0 -4
  274. package/build/parserInvariant.js +0 -11
  275. package/build/promiseFish.d.ts +0 -1
  276. package/build/promiseFish.js +0 -3
  277. package/build/sequenceParser.d.ts +0 -3
  278. package/build/sequenceParser.js +0 -10
  279. package/build/terminatedSequenceParser.d.ts +0 -2
  280. package/build/terminatedSequenceParser.js +0 -24
  281. package/build/unparserInputCompanion.d.ts +0 -15
  282. package/build/unparserInputCompanion.js +0 -13
  283. package/build/zipEntry.d.ts +0 -28
  284. package/build/zipFile.d.ts +0 -32
  285. package/build/zipFileEntry.d.ts +0 -6
  286. package/src/apk.ts +0 -48
  287. package/src/apkParser.test.ts.snap +0 -0
  288. package/src/apkParser.ts +0 -392
  289. package/src/apkUnparser.test.ts +0 -37
  290. package/src/apkUnparser.ts +0 -120
  291. package/src/invariantDefined.ts +0 -6
  292. package/src/invariantIdentity.ts +0 -8
  293. /package/build/{apk.js → androidPackage.js} +0 -0
  294. /package/build/{apkParser.test.d.ts → androidPackageParser.test.d.ts} +0 -0
  295. /package/build/{apkUnparser.test.d.ts → androidPackageUnparser.test.d.ts} +0 -0
  296. /package/build/{arbitraryDosPermissions.d.ts → dalvikExecutableParser.test.d.ts} +0 -0
  297. /package/build/{arbitraryDosPermissions.js → dalvikExecutableParserAgainstSmaliParser.test.d.ts} +0 -0
  298. /package/build/{inputChunkBuffer.test.d.ts → elementTerminatedArrayParser.test.d.ts} +0 -0
  299. /package/build/{jsonParser2.test.d.ts → elementTerminatedSequenceArrayParser.test.d.ts} +0 -0
  300. /package/build/{parserParsingInvariant.d.ts → elementTerminatedSequenceParser.test.d.ts} +0 -0
  301. /package/build/{parserParsingInvariant.js → fixedLengthSequenceParser.test.d.ts} +0 -0
  302. /package/build/{zipEntry.js → leb128Parser.test.d.ts} +0 -0
  303. /package/build/{zipFile.js → negativeLookaheadParser.test.d.ts} +0 -0
  304. /package/build/{zipFileEntry.js → nonEmptyArrayParser.test.d.ts} +0 -0
@@ -0,0 +1,125 @@
1
+ import { Parser } from "./parser.js";
2
+
3
+ export const uleb128Parser: Parser<bigint, Uint8Array> = async (parserContext) => {
4
+ let leastSignificantValueBitIndex = 0n;
5
+ let value = 0n;
6
+
7
+ while (true) {
8
+ const byte = await parserContext.read(0);
9
+ const byteValue = BigInt(byte & 0b01111111);
10
+ const byteNotLast = BigInt(byte & 0b10000000);
11
+
12
+ value |= byteValue << leastSignificantValueBitIndex;
13
+
14
+ if (byteNotLast) {
15
+ leastSignificantValueBitIndex += 7n;
16
+ continue;
17
+ }
18
+
19
+ break;
20
+ }
21
+
22
+ return value;
23
+ }
24
+
25
+ export const sleb128Parser: Parser<bigint, Uint8Array> = async (parserContext) => {
26
+ let value = 0n;
27
+ let leastSignificantValueBitIndex = 0n;
28
+
29
+ while (true) {
30
+ const byte = await parserContext.read(0);
31
+ const byteValue = BigInt(byte & 0b01111111);
32
+ const byteNotLast = BigInt(byte & 0b10000000);
33
+
34
+ value |= byteValue << leastSignificantValueBitIndex;
35
+ leastSignificantValueBitIndex += 7n;
36
+
37
+ if (byteNotLast) {
38
+ continue;
39
+ }
40
+
41
+ const mostSignificantInputBit = byte & 0b01000000;
42
+
43
+ if (mostSignificantInputBit) {
44
+ value |= (~0n << leastSignificantValueBitIndex);
45
+ }
46
+
47
+ break;
48
+ }
49
+
50
+ return value;
51
+ };
52
+
53
+ export const uleb128NumberParser: Parser<number, Uint8Array> = async (parserContext) => {
54
+ const value = await uleb128Parser(parserContext);
55
+
56
+ parserContext.invariant(
57
+ Number(value) <= Number.MAX_SAFE_INTEGER,
58
+ 'Value is too large to be represented as a number: %s',
59
+ value,
60
+ );
61
+
62
+ return Number(value);
63
+ };
64
+
65
+ export const sleb128NumberParser: Parser<number, Uint8Array> = async (parserContext) => {
66
+ const value = await sleb128Parser(parserContext);
67
+
68
+ parserContext.invariant(
69
+ Number(value) >= Number.MIN_SAFE_INTEGER && Number(value) <= Number.MAX_SAFE_INTEGER,
70
+ 'Value is too large to be represented as a number: %s',
71
+ value,
72
+ );
73
+
74
+ return Number(value);
75
+ };
76
+
77
+ export const uleb128UnsafeNumberParser: Parser<number, Uint8Array> = async (parserContext) => {
78
+ let leastSignificantValueBitIndex = 0;
79
+ let value = 0;
80
+
81
+ while (true) {
82
+ const byte = await parserContext.read(0);
83
+ const byteValue = byte & 0b01111111;
84
+ const byteNotLast = byte & 0b10000000;
85
+
86
+ value |= byteValue << leastSignificantValueBitIndex;
87
+
88
+ if (byteNotLast) {
89
+ leastSignificantValueBitIndex += 7;
90
+ continue;
91
+ }
92
+
93
+ break;
94
+ }
95
+
96
+ return value;
97
+ }
98
+
99
+ export const sleb128UnsafeNumberParser: Parser<number, Uint8Array> = async (parserContext) => {
100
+ let value = 0;
101
+ let leastSignificantValueBitIndex = 0;
102
+
103
+ while (true) {
104
+ const byte = await parserContext.read(0);
105
+ const byteValue = byte & 0b01111111;
106
+ const byteNotLast = byte & 0b10000000;
107
+
108
+ value |= byteValue << leastSignificantValueBitIndex;
109
+ leastSignificantValueBitIndex += 7;
110
+
111
+ if (byteNotLast) {
112
+ continue;
113
+ }
114
+
115
+ const mostSignificantInputBit = byte & 0b01000000;
116
+
117
+ if (leastSignificantValueBitIndex < 32 && mostSignificantInputBit) {
118
+ value |= (~0 << leastSignificantValueBitIndex);
119
+ }
120
+
121
+ break;
122
+ }
123
+
124
+ return value;
125
+ };
@@ -0,0 +1,19 @@
1
+ import { getParserName, setParserName, type Parser } from './parser.js';
2
+
3
+ export const createLookaheadParser = <Output, Sequence>(
4
+ childParser: Parser<Output, Sequence>,
5
+ ): Parser<Output, Sequence> => {
6
+ const lookaheadParser: Parser<Output, Sequence> = async parserContext => {
7
+ const childParserContext = parserContext.lookahead();
8
+
9
+ try {
10
+ return await childParser(childParserContext);
11
+ } finally {
12
+ childParserContext.dispose();
13
+ }
14
+ };
15
+
16
+ setParserName(lookaheadParser, `(?=${getParserName(childParser)})`);
17
+
18
+ return lookaheadParser;
19
+ };
@@ -0,0 +1,53 @@
1
+ import * as fc from 'fast-check';
2
+ import { testProp } from '@fast-check/ava';
3
+ import { createNegativeLookaheadParser } from './negativeLookaheadParser.js';
4
+ import { createExactSequenceParser } from './exactSequenceParser.js';
5
+ import { runParser } from './parser.js';
6
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
7
+ import { createTupleParser } from './tupleParser.js';
8
+ import { ParserParsingFailedError } from './parserError.js';
9
+
10
+ testProp(
11
+ 'negativeLookaheadParser',
12
+ [
13
+ fc.tuple(
14
+ fc.string({
15
+ minLength: 1,
16
+ }),
17
+ fc.string({
18
+ minLength: 1,
19
+ }),
20
+ ).filter(([ a, b ]) => !a.startsWith(b))
21
+ ],
22
+ async (t, [ stringA, stringB ]) => {
23
+ const result = await runParser(
24
+ createTupleParser([
25
+ createNegativeLookaheadParser(
26
+ createExactSequenceParser(stringB),
27
+ ),
28
+ createExactSequenceParser(stringA + stringB),
29
+ ]),
30
+ stringA + stringB,
31
+ stringParserInputCompanion,
32
+ );
33
+
34
+ t.deepEqual(result, [undefined, stringA + stringB]);
35
+
36
+ await t.throwsAsync(() => runParser(
37
+ createTupleParser([
38
+ createNegativeLookaheadParser(
39
+ createExactSequenceParser(stringA),
40
+ ),
41
+ createExactSequenceParser(stringA + stringB),
42
+ ]),
43
+ stringA + stringB,
44
+ stringParserInputCompanion,
45
+ ), {
46
+ instanceOf: ParserParsingFailedError,
47
+ message: /lookahead/,
48
+ });
49
+ },
50
+ {
51
+ verbose: true,
52
+ },
53
+ );
@@ -1,24 +1,36 @@
1
- import { getParserName, type Parser } from './parser.js';
1
+ import { getParserName, setParserName, type Parser } from './parser.js';
2
2
  import { ParserParsingFailedError } from './parserError.js';
3
3
 
4
4
  export const createNegativeLookaheadParser = <Sequence>(
5
5
  childParser: Parser<unknown, Sequence>,
6
- ): Parser<void, Sequence> => async parserContext => {
7
- const childParserContext = parserContext.lookahead();
8
- try {
9
- await childParser(childParserContext);
6
+ ): Parser<void, Sequence> => {
7
+ const negativeLookaheadParser: Parser<void, Sequence> = async parserContext => {
8
+ const childParserContext = parserContext.lookahead();
9
+
10
+ let childParserSuccess: boolean;
11
+
12
+ try {
13
+ await childParser(childParserContext);
14
+
15
+ childParserSuccess = true;
16
+ } catch (error) {
17
+ if (!(error instanceof ParserParsingFailedError)) {
18
+ throw error;
19
+ }
20
+
21
+ childParserSuccess = false;
22
+ } finally {
23
+ childParserContext.dispose();
24
+ }
25
+
10
26
  parserContext.invariant(
11
- false,
27
+ !childParserSuccess,
12
28
  'Negative lookahead assertion failed for child parser %s.',
13
29
  getParserName(childParser),
14
30
  );
15
- } catch (error) {
16
- if (error instanceof ParserParsingFailedError) {
17
- return;
18
- }
31
+ };
32
+
33
+ setParserName(negativeLookaheadParser, `(?!${getParserName(childParser)})`);
19
34
 
20
- throw error;
21
- } finally {
22
- childParserContext.dispose();
23
- }
35
+ return negativeLookaheadParser;
24
36
  };
@@ -0,0 +1,20 @@
1
+ import test from 'ava';
2
+ import { createNonEmptyArrayParser } from './nonEmptyArrayParser.js';
3
+ import { type Parser, runParser } from './parser.js';
4
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
5
+ import { createExactElementParser } from './exactElementParser.js';
6
+
7
+ test('empty array does not match', async t => {
8
+ const parser: Parser<string[], string> = createNonEmptyArrayParser(createExactElementParser('0'));
9
+
10
+ await t.throwsAsync(() => runParser(parser, '', stringParserInputCompanion), {
11
+ message: /Expected .* to match at least once/,
12
+ });
13
+ });
14
+
15
+ test('non-empty array matches', async t => {
16
+ const parser: Parser<string[], string> = createNonEmptyArrayParser(createExactElementParser('0'));
17
+ const result = await runParser(parser, '0', stringParserInputCompanion);
18
+
19
+ t.deepEqual(result, ['0']);
20
+ });
@@ -0,0 +1,44 @@
1
+ import { getParserName, type Parser, setParserName } from './parser.js';
2
+ import { ParserParsingFailedError } from './parserError.js';
3
+
4
+ export const createNonEmptyArrayParser = <ElementOutput, Sequence>(
5
+ elementParser: Parser<ElementOutput, Sequence>,
6
+ ): Parser<ElementOutput[], Sequence> => {
7
+ const nonEmptyArrayParser: Parser<ElementOutput[], Sequence> = async parserContext => {
8
+ const elements: ElementOutput[] = [];
9
+
10
+ while (true) {
11
+ const elementParserContext = parserContext.lookahead();
12
+ const initialPosition = elementParserContext.position;
13
+ try {
14
+ const element = await elementParser(elementParserContext);
15
+ if (elementParserContext.position === initialPosition) {
16
+ break;
17
+ }
18
+
19
+ elements.push(element);
20
+ elementParserContext.unlookahead();
21
+ } catch (error) {
22
+ if (error instanceof ParserParsingFailedError) {
23
+ break;
24
+ }
25
+
26
+ throw error;
27
+ } finally {
28
+ elementParserContext.dispose();
29
+ }
30
+ }
31
+
32
+ parserContext.invariant(
33
+ elements.length > 0,
34
+ 'Expected elementParser (%s) to match at least once',
35
+ getParserName(elementParser, 'anonymousNonEmptyArrayChild'),
36
+ );
37
+
38
+ return elements;
39
+ };
40
+
41
+ setParserName(nonEmptyArrayParser, getParserName(elementParser, 'anonymousNonEmptyArrayChild') + '+');
42
+
43
+ return nonEmptyArrayParser;
44
+ };
@@ -6,6 +6,7 @@ export const createOptionalParser = <Output, Sequence>(
6
6
  ): Parser<undefined | Output, Sequence> => {
7
7
  const optionalParser: Parser<undefined | Output, Sequence> = async parserContext => {
8
8
  const childParserContext = parserContext.lookahead();
9
+
9
10
  try {
10
11
  const value = await childParser(childParserContext);
11
12
  childParserContext.unlookahead();
@@ -1,36 +1,44 @@
1
1
  import test from 'ava';
2
2
  import invariant from 'invariant';
3
3
  import { createUnionParser } from './unionParser.js';
4
- import { type Parser, runParser } from './parser.js';
4
+ import { type Parser, runParser, runParserWithRemainingInput } from './parser.js';
5
5
  import { stringParserInputCompanion, uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
6
6
  import {
7
- ParserParsingInvariantError, ParserParsingJoinAllError, ParserParsingJoinDeepestError, ParserParsingJoinError, ParserParsingJoinFurthestError, ParserParsingJoinNoneError,
7
+ ParserError,
8
+ ParserParsingInvariantError,
9
+ ParserParsingJoinAllError,
10
+ ParserParsingJoinDeepestError,
11
+ ParserParsingJoinError,
12
+ ParserParsingJoinFurthestError,
13
+ ParserParsingJoinNoneError,
14
+ ParserUnexpectedRemainingInputError,
8
15
  } from './parserError.js';
9
16
  import { createTupleParser } from './tupleParser.js';
10
17
  import { promiseCompose } from './promiseCompose.js';
11
18
  import { createDisjunctionParser } from './disjunctionParser.js';
12
- import { createExactSequenceParser } from './exactSequenceParser.js';
19
+ import { createExactSequenceNaiveParser } from './exactSequenceParser.js';
13
20
  import { createArrayParser } from './arrayParser.js';
14
21
  import { createElementParser } from './elementParser.js';
22
+ import { toAsyncIterable } from './toAsyncIterable.js';
15
23
 
16
24
  const aUnionParser = createUnionParser<string, string>([
17
- createExactSequenceParser('1'),
18
- createExactSequenceParser('aa'),
19
- createExactSequenceParser('AAA'),
25
+ createExactSequenceNaiveParser('1'),
26
+ createExactSequenceNaiveParser('aa'),
27
+ createExactSequenceNaiveParser('AAA'),
20
28
  ]);
21
29
 
22
30
  const abDisjunctionParser = createDisjunctionParser<string, string>([
23
31
  aUnionParser,
24
- createExactSequenceParser('2'),
25
- createExactSequenceParser('bb'),
26
- createExactSequenceParser('BBB'),
32
+ createExactSequenceNaiveParser('2'),
33
+ createExactSequenceNaiveParser('bb'),
34
+ createExactSequenceNaiveParser('BBB'),
27
35
  ]);
28
36
 
29
37
  const abcUnionParser = createUnionParser<string, string>([
30
38
  abDisjunctionParser,
31
- createExactSequenceParser('final_3'),
32
- createExactSequenceParser('final_cc'),
33
- createExactSequenceParser('final_CCC'),
39
+ createExactSequenceNaiveParser('final_3'),
40
+ createExactSequenceNaiveParser('final_cc'),
41
+ createExactSequenceNaiveParser('final_CCC'),
34
42
  ]);
35
43
 
36
44
  const sampleParser = promiseCompose(
@@ -46,6 +54,16 @@ async function * asyncIteratorFromString(string: string) {
46
54
  yield string;
47
55
  }
48
56
 
57
+ async function stringFromAsyncIterable(asyncIterable: AsyncIterable<string>) {
58
+ let string = '';
59
+
60
+ for await (const chunk of asyncIterable) {
61
+ string += chunk;
62
+ }
63
+
64
+ return string;
65
+ }
66
+
49
67
  function sortChildErrors(error: ParserParsingJoinNoneError) {
50
68
  error.childErrors.sort((a, b) => a.message.localeCompare(b.message));
51
69
 
@@ -176,3 +194,104 @@ test('throws on parserInputCompanion type mismatch', async t => {
176
194
  message: /input companion/,
177
195
  });
178
196
  });
197
+
198
+ test('thrown error has input reader state', async t => {
199
+ const error = await t.throwsAsync(
200
+ runParser(
201
+ createTupleParser([
202
+ createExactSequenceNaiveParser('foo'),
203
+ createExactSequenceNaiveParser('bar'),
204
+ ]),
205
+ (async function * () {
206
+ yield 'foo';
207
+ yield 'qux';
208
+ yield 'bar';
209
+ })(),
210
+ stringParserInputCompanion,
211
+ ),
212
+ {
213
+ instanceOf: ParserError,
214
+ },
215
+ );
216
+
217
+ t.is(error.position, 4);
218
+
219
+ invariant(error.inputReaderSate, 'error.inputReaderSate');
220
+
221
+ const {
222
+ consumedBufferedSequences,
223
+ unconsumedBufferedSequences,
224
+ unbufferedSequences,
225
+ position,
226
+ ...inputReaderStateRest
227
+ } = error.inputReaderSate;
228
+
229
+ t.is(position, 4);
230
+ t.deepEqual(inputReaderStateRest, {});
231
+
232
+ const unbufferedSequencesArray = [];
233
+
234
+ if (unbufferedSequences) {
235
+ for await (const sequence of toAsyncIterable(unbufferedSequences)) {
236
+ unbufferedSequencesArray.push(sequence);
237
+ }
238
+ }
239
+
240
+ t.deepEqual(consumedBufferedSequences, [ 'q' ]);
241
+ t.deepEqual(unconsumedBufferedSequences, [ 'ux' ]);
242
+ t.deepEqual(unbufferedSequencesArray, [ 'bar' ]);
243
+ });
244
+
245
+ test('runParser throws with remaining input', async t => {
246
+ const parser: Parser<string, string> = createExactSequenceNaiveParser('foo');
247
+ const error = await t.throwsAsync(() => runParser(parser, 'foobar', stringParserInputCompanion), {
248
+ instanceOf: ParserUnexpectedRemainingInputError,
249
+ message: /remaining input/,
250
+ });
251
+
252
+ t.is(error.position, 3);
253
+
254
+ const {
255
+ position,
256
+ consumedBufferedSequences,
257
+ unconsumedBufferedSequences,
258
+ unbufferedSequences,
259
+ ...inputReaderStateRest
260
+ } = error.inputReaderSate!;
261
+
262
+ t.deepEqual(inputReaderStateRest, {});
263
+ t.is(position, 3);
264
+ t.deepEqual(consumedBufferedSequences, [ 'foo' ]);
265
+ t.deepEqual(unconsumedBufferedSequences, [ 'bar' ]);
266
+ t.truthy(unbufferedSequences);
267
+ });
268
+
269
+ test('runParser does not throw without remaining input', async t => {
270
+ const parser: Parser<string, string> = createExactSequenceNaiveParser('foo');
271
+ const output = await runParser(parser, 'foo', stringParserInputCompanion);
272
+
273
+ t.deepEqual(output, 'foo');
274
+ });
275
+
276
+ test('runParserWithRemainingInput with remaining input', async t => {
277
+ const parser: Parser<string, string> = createExactSequenceNaiveParser('foo');
278
+ const {
279
+ output,
280
+ remainingInput,
281
+ position,
282
+ ...resultRest
283
+ } = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
284
+
285
+ t.deepEqual(resultRest, {});
286
+ t.deepEqual(output, 'foo');
287
+ t.deepEqual(await stringFromAsyncIterable(remainingInput!), 'bar');
288
+ t.is(position, 3);
289
+ });
290
+
291
+ test('runParserWithRemainingInput without remaining input', async t => {
292
+ const parser: Parser<string, string> = createExactSequenceNaiveParser('foo');
293
+ const { output, remainingInput } = await runParserWithRemainingInput(parser, 'foo', stringParserInputCompanion);
294
+
295
+ t.deepEqual(output, 'foo');
296
+ t.is(remainingInput, undefined);
297
+ });
@@ -8,32 +8,32 @@ Generated by [AVA](https://avajs.dev).
8
8
 
9
9
  > Snapshot 1
10
10
 
11
- `ParserParsingJoinNoneError: (position: 12) No union child parser succeeded.␊
11
+ `ParserParsingJoinNoneError: No union child parser succeeded.␊
12
12
  at [LOCATIONS]`
13
13
 
14
14
  ## errorJoinMode: all
15
15
 
16
16
  > Snapshot 1
17
17
 
18
- `ParserParsingJoinAllError: (position: 12) No union child parser succeeded.␊
18
+ `ParserParsingJoinAllError: No union child parser succeeded.␊
19
19
  Child error stacks, indented:␊
20
- ParserParsingInvariantError: (position: 10) Expected "3", got "C", at [LOCATIONS]␊
21
- ParserParsingInvariantError: (position: 10) Expected "c", got "C", at [LOCATIONS]␊
22
- ParserParsingJoinAllError: (position: 3) No disjunction child parser succeeded.␊
20
+ ParserParsingInvariantError: Expected "3", got "C", at [LOCATIONS]␊
21
+ ParserParsingInvariantError: Expected "c", got "C", at [LOCATIONS]␊
22
+ ParserParsingJoinAllError: No disjunction child parser succeeded.␊
23
23
  Child error stacks, indented:␊
24
- ParserParsingJoinAllError: (position: 4) No union child parser succeeded.␊
24
+ ParserParsingJoinAllError: No union child parser succeeded.␊
25
25
  Child error stacks, indented:␊
26
- ParserParsingInvariantError: (position: 4) Expected "1", got "f", at [LOCATIONS]␊
27
- ParserParsingInvariantError: (position: 4) Expected "a", got "f", at [LOCATIONS]␊
28
- ParserParsingInvariantError: (position: 4) Expected "A", got "f", at [LOCATIONS]␊
26
+ ParserParsingInvariantError: Expected "1", got "f", at [LOCATIONS]␊
27
+ ParserParsingInvariantError: Expected "a", got "f", at [LOCATIONS]␊
28
+ ParserParsingInvariantError: Expected "A", got "f", at [LOCATIONS]␊
29
29
  End of child error stacks␊
30
30
  at [LOCATIONS]␊
31
- ParserParsingInvariantError: (position: 4) Expected "2", got "f", at [LOCATIONS]␊
32
- ParserParsingInvariantError: (position: 4) Expected "b", got "f", at [LOCATIONS]␊
33
- ParserParsingInvariantError: (position: 4) Expected "B", got "f", at [LOCATIONS]␊
31
+ ParserParsingInvariantError: Expected "2", got "f", at [LOCATIONS]␊
32
+ ParserParsingInvariantError: Expected "b", got "f", at [LOCATIONS]␊
33
+ ParserParsingInvariantError: Expected "B", got "f", at [LOCATIONS]␊
34
34
  End of child error stacks␊
35
35
  at [LOCATIONS]␊
36
- ParserParsingInvariantError: (position: 12) Expected "C", got "!", at [LOCATIONS]␊
36
+ ParserParsingInvariantError: Expected "C", got "!", at [LOCATIONS]␊
37
37
  End of child error stacks␊
38
38
  at [LOCATIONS]`
39
39
 
@@ -41,15 +41,15 @@ Generated by [AVA](https://avajs.dev).
41
41
 
42
42
  > Snapshot 1
43
43
 
44
- `ParserParsingJoinDeepestError: (position: 12) No union child parser succeeded.␊
44
+ `ParserParsingJoinDeepestError: No union child parser succeeded.␊
45
45
  Deepest child error stacks, indented:␊
46
- ParserParsingJoinDeepestError: (position: 3) No disjunction child parser succeeded.␊
46
+ ParserParsingJoinDeepestError: No disjunction child parser succeeded.␊
47
47
  Deepest child error stacks, indented:␊
48
- ParserParsingJoinDeepestError: (position: 4) No union child parser succeeded.␊
48
+ ParserParsingJoinDeepestError: No union child parser succeeded.␊
49
49
  Deepest child error stacks, indented:␊
50
- ParserParsingInvariantError: (position: 4) Expected "1", got "f", at [LOCATIONS]␊
51
- ParserParsingInvariantError: (position: 4) Expected "a", got "f", at [LOCATIONS]␊
52
- ParserParsingInvariantError: (position: 4) Expected "A", got "f", at [LOCATIONS]␊
50
+ ParserParsingInvariantError: Expected "1", got "f", at [LOCATIONS]␊
51
+ ParserParsingInvariantError: Expected "a", got "f", at [LOCATIONS]␊
52
+ ParserParsingInvariantError: Expected "A", got "f", at [LOCATIONS]␊
53
53
  End of deepest child error stacks␊
54
54
  at [LOCATIONS]␊
55
55
  End of deepest child error stacks␊
@@ -61,8 +61,8 @@ Generated by [AVA](https://avajs.dev).
61
61
 
62
62
  > Snapshot 1
63
63
 
64
- `ParserParsingJoinFurthestError: (position: 12) No union child parser succeeded.␊
64
+ `ParserParsingJoinFurthestError: No union child parser succeeded.␊
65
65
  Furthest child error stacks, indented:␊
66
- ParserParsingInvariantError: (position: 12) Expected "C", got "!", at [LOCATIONS]␊
66
+ ParserParsingInvariantError: Expected "C", got "!", at [LOCATIONS]␊
67
67
  End of furthest child error stacks␊
68
68
  at [LOCATIONS]`
Binary file