@futpib/parser 1.0.0 → 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 (380) 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} +7 -7
  7. package/build/androidPackageUnparser.d.ts +4 -0
  8. package/build/androidPackageUnparser.js +90 -0
  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/arbitraryFileSystemEntry.js +1 -1
  13. package/build/arbitraryZip.d.ts +1 -1
  14. package/build/arbitraryZip.js +13 -19
  15. package/build/arbitraryZipPermissions.d.ts +1 -8
  16. package/build/arbitraryZipPermissions.js +1 -16
  17. package/build/arbitraryZipStream.d.ts +1 -1
  18. package/build/arbitraryZipStream.js +3 -3
  19. package/build/arrayParser.d.ts +1 -1
  20. package/build/arrayParser.js +2 -2
  21. package/build/arrayParser.test.js +4 -4
  22. package/build/arrayUnparser.d.ts +2 -0
  23. package/build/arrayUnparser.js +8 -0
  24. package/build/backsmali.d.ts +1 -0
  25. package/build/backsmali.js +22 -0
  26. package/build/bsonParser.js +6 -2
  27. package/build/bsonParser.test.js +2 -2
  28. package/build/{parserInvariant.d.ts → customInvariant.d.ts} +1 -1
  29. package/build/{parserInvariant.js → customInvariant.js} +1 -1
  30. package/build/dalvikBytecodeParser/formatParsers.d.ts +97 -0
  31. package/build/dalvikBytecodeParser/formatParsers.js +169 -0
  32. package/build/dalvikBytecodeParser.d.ts +107 -0
  33. package/build/dalvikBytecodeParser.js +836 -0
  34. package/build/dalvikExecutable.d.ts +158 -0
  35. package/build/dalvikExecutable.js +20 -0
  36. package/build/dalvikExecutableParser/stringSyntaxParser.d.ts +4 -0
  37. package/build/dalvikExecutableParser/stringSyntaxParser.js +76 -0
  38. package/build/dalvikExecutableParser/typeParsers.d.ts +10 -0
  39. package/build/dalvikExecutableParser/typeParsers.js +34 -0
  40. package/build/dalvikExecutableParser/typedNumbers.d.ts +90 -0
  41. package/build/dalvikExecutableParser/typedNumbers.js +19 -0
  42. package/build/dalvikExecutableParser.d.ts +5 -0
  43. package/build/dalvikExecutableParser.js +1439 -0
  44. package/build/dalvikExecutableParser.test.js +70 -0
  45. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +298 -0
  46. package/build/debugLogInputParser.d.ts +4 -0
  47. package/build/debugLogInputParser.js +16 -0
  48. package/build/debugLogParser.d.ts +1 -1
  49. package/build/debugLogParser.js +15 -4
  50. package/build/disjunctionParser.d.ts +2 -1
  51. package/build/disjunctionParser.js +4 -2
  52. package/build/elementParser.d.ts +2 -2
  53. package/build/elementParser.js +1 -1
  54. package/build/elementTerminatedArrayParser.d.ts +3 -0
  55. package/build/elementTerminatedArrayParser.js +18 -0
  56. package/build/elementTerminatedArrayParser.test.js +52 -0
  57. package/build/elementTerminatedSequenceArrayParser.d.ts +3 -0
  58. package/build/elementTerminatedSequenceArrayParser.js +32 -0
  59. package/build/elementTerminatedSequenceArrayParser.test.js +34 -0
  60. package/build/elementTerminatedSequenceParser.d.ts +3 -0
  61. package/build/elementTerminatedSequenceParser.js +27 -0
  62. package/build/elementTerminatedSequenceParser.test.js +34 -0
  63. package/build/endOfInputParser.d.ts +2 -2
  64. package/build/exactElementParser.d.ts +1 -1
  65. package/build/exactElementParser.js +10 -5
  66. package/build/exactSequenceParser.d.ts +2 -1
  67. package/build/exactSequenceParser.js +12 -2
  68. package/build/fetchCid.d.ts +1 -0
  69. package/build/fetchCid.js +107 -0
  70. package/build/fixedLengthSequenceParser.d.ts +1 -0
  71. package/build/fixedLengthSequenceParser.js +18 -1
  72. package/build/fixedLengthSequenceParser.test.js +41 -0
  73. package/build/hasExecutable.d.ts +1 -0
  74. package/build/hasExecutable.js +8 -0
  75. package/build/highResolutionTimer.d.ts +16 -0
  76. package/build/highResolutionTimer.js +42 -0
  77. package/build/index.d.ts +5 -2
  78. package/build/index.js +3 -0
  79. package/build/inputReader.d.ts +14 -3
  80. package/build/inputReader.js +43 -6
  81. package/build/inputReader.test.js +172 -7
  82. package/build/inputReaderState.d.ts +10 -0
  83. package/build/inputReaderState.js +16 -0
  84. package/build/inspect.d.ts +1 -0
  85. package/build/inspect.js +7 -0
  86. package/build/javaKeyStoreParser.d.ts +2 -0
  87. package/build/javaKeyStoreParser.js +67 -0
  88. package/build/javaKeyStoreParser.test.d.ts +1 -0
  89. package/build/javaKeyStoreParser.test.js +16 -0
  90. package/build/jsonParser.d.ts +2 -0
  91. package/build/jsonParser.js +13 -15
  92. package/build/jsonParser.test.js +2 -2
  93. package/build/leb128Parser.d.ts +7 -0
  94. package/build/leb128Parser.js +82 -0
  95. package/build/leb128Parser.test.d.ts +1 -0
  96. package/build/leb128Parser.test.js +107 -0
  97. package/build/listParser.d.ts +1 -1
  98. package/build/listParser.js +5 -5
  99. package/build/lookaheadParser.d.ts +2 -0
  100. package/build/lookaheadParser.js +14 -0
  101. package/build/{negativeLookahead.d.ts → negativeLookaheadParser.d.ts} +1 -1
  102. package/build/negativeLookaheadParser.js +24 -0
  103. package/build/negativeLookaheadParser.test.d.ts +1 -0
  104. package/build/negativeLookaheadParser.test.js +30 -0
  105. package/build/nonEmptyArrayParser.d.ts +2 -0
  106. package/build/nonEmptyArrayParser.js +32 -0
  107. package/build/nonEmptyArrayParser.test.d.ts +1 -0
  108. package/build/nonEmptyArrayParser.test.js +16 -0
  109. package/build/optionalParser.d.ts +1 -1
  110. package/build/optionalParser.js +2 -2
  111. package/build/parser.d.ts +13 -4
  112. package/build/parser.js +67 -32
  113. package/build/parser.test.js +94 -27
  114. package/build/parserAccessorParser.d.ts +1 -1
  115. package/build/parserAccessorParser.js +9 -1
  116. package/build/parserConsumedSequenceParser.d.ts +2 -0
  117. package/build/parserConsumedSequenceParser.js +22 -0
  118. package/build/parserContext.d.ts +20 -6
  119. package/build/parserContext.js +70 -40
  120. package/build/parserContext.test.js +34 -7
  121. package/build/parserCreatorCompose.d.ts +4 -3
  122. package/build/parserCreatorCompose.js +9 -3
  123. package/build/parserError.d.ts +6 -0
  124. package/build/parserError.js +6 -6
  125. package/build/parserImplementationInvariant.d.ts +1 -1
  126. package/build/parserImplementationInvariant.js +2 -2
  127. package/build/parserInputCompanion.d.ts +35 -0
  128. package/build/parserInputCompanion.js +68 -0
  129. package/build/promiseCompose.d.ts +1 -1
  130. package/build/promiseCompose.js +12 -1
  131. package/build/promiseSettled.d.ts +1 -0
  132. package/build/promiseSettled.js +4 -0
  133. package/build/quantifierParser.d.ts +2 -0
  134. package/build/quantifierParser.js +17 -0
  135. package/build/separatedArrayParser.d.ts +2 -0
  136. package/build/separatedArrayParser.js +39 -0
  137. package/build/separatedArrayParser.test.d.ts +1 -0
  138. package/build/separatedArrayParser.test.js +21 -0
  139. package/build/sequenceBuffer.d.ts +13 -3
  140. package/build/sequenceBuffer.js +60 -8
  141. package/build/sequenceBuffer.test.js +59 -2
  142. package/build/sequenceTerminatedSequenceParser.d.ts +5 -0
  143. package/build/sequenceTerminatedSequenceParser.js +32 -0
  144. package/build/sequenceTerminatedSequenceParser.test.d.ts +1 -0
  145. package/build/sequenceTerminatedSequenceParser.test.js +37 -0
  146. package/build/sequenceUnparser.d.ts +2 -0
  147. package/build/sequenceUnparser.js +6 -0
  148. package/build/skipParser.d.ts +1 -1
  149. package/build/skipParser.js +4 -2
  150. package/build/skipToParser.d.ts +2 -0
  151. package/build/skipToParser.js +11 -0
  152. package/build/sliceBoundedParser.d.ts +2 -2
  153. package/build/sliceBoundedParser.js +8 -3
  154. package/build/sliceBoundedParser.test.js +37 -3
  155. package/build/smali.d.ts +1 -0
  156. package/build/smali.js +17 -0
  157. package/build/smaliParser.d.ts +12 -0
  158. package/build/smaliParser.js +656 -0
  159. package/build/smaliParser.test.d.ts +1 -0
  160. package/build/smaliParser.test.js +115 -0
  161. package/build/terminatedArrayParser.d.ts +4 -2
  162. package/build/terminatedArrayParser.js +82 -5
  163. package/build/terminatedArrayParser.test.d.ts +1 -0
  164. package/build/terminatedArrayParser.test.js +131 -0
  165. package/build/toAsyncIterable.d.ts +1 -0
  166. package/build/toAsyncIterable.js +7 -0
  167. package/build/toAsyncIterator.d.ts +1 -0
  168. package/build/toAsyncIterator.js +33 -0
  169. package/build/tupleParser.d.ts +4 -0
  170. package/build/tupleParser.js +1 -5
  171. package/build/uint8Array.d.ts +1 -0
  172. package/build/uint8Array.js +7 -0
  173. package/build/unionParser.d.ts +2 -1
  174. package/build/unionParser.js +27 -12
  175. package/build/unionParser.test.d.ts +1 -0
  176. package/build/unionParser.test.js +60 -0
  177. package/build/unparser.d.ts +8 -0
  178. package/build/unparser.js +104 -0
  179. package/build/unparser.test.d.ts +1 -0
  180. package/build/unparser.test.js +150 -0
  181. package/build/unparserContext.d.ts +31 -0
  182. package/build/unparserContext.js +74 -0
  183. package/build/unparserError.d.ts +9 -0
  184. package/build/unparserError.js +9 -0
  185. package/build/unparserImplementationInvariant.d.ts +2 -0
  186. package/build/unparserImplementationInvariant.js +5 -0
  187. package/build/unparserOutputCompanion.d.ts +15 -0
  188. package/build/unparserOutputCompanion.js +13 -0
  189. package/build/zip.d.ts +9 -17
  190. package/build/zipParser.d.ts +20 -12
  191. package/build/zipParser.js +83 -71
  192. package/build/zipParser.test.js +2 -7
  193. package/build/zipUnparser.d.ts +8 -0
  194. package/build/zipUnparser.js +200 -0
  195. package/build/zipUnparser.test.d.ts +1 -0
  196. package/build/zipUnparser.test.js +80 -0
  197. package/package.json +26 -8
  198. package/src/allSettledStream.test.ts +40 -0
  199. package/src/allSettledStream.ts +47 -15
  200. package/src/androidPackage.ts +48 -0
  201. package/src/{apkParser.test.ts → androidPackageParser.test.ts} +7 -8
  202. package/src/androidPackageParser.test.ts.md +271 -0
  203. package/src/androidPackageParser.test.ts.snap +0 -0
  204. package/src/androidPackageParser.ts +440 -0
  205. package/src/androidPackageUnparser.test.ts +36 -0
  206. package/src/androidPackageUnparser.ts +120 -0
  207. package/src/arbitrarilySlicedAsyncInterable.ts +7 -2
  208. package/src/arbitraryFileSystemEntry.ts +2 -4
  209. package/src/arbitraryZip.ts +20 -27
  210. package/src/arbitraryZipPermissions.ts +0 -25
  211. package/src/arbitraryZipStream.ts +4 -4
  212. package/src/arrayParser.test.ts +4 -4
  213. package/src/arrayParser.ts +3 -2
  214. package/src/arrayUnparser.ts +13 -0
  215. package/src/backsmali.ts +30 -0
  216. package/src/bsonParser.test.ts +2 -2
  217. package/src/bsonParser.ts +16 -5
  218. package/src/{parserInvariant.ts → customInvariant.ts} +2 -2
  219. package/src/dalvikBytecodeParser/formatParsers.ts +421 -0
  220. package/src/dalvikBytecodeParser.ts +2074 -0
  221. package/src/dalvikExecutable.ts +220 -0
  222. package/src/dalvikExecutableParser/stringSyntaxParser.ts +145 -0
  223. package/src/dalvikExecutableParser/typeParsers.ts +65 -0
  224. package/src/dalvikExecutableParser/typedNumbers.ts +57 -0
  225. package/src/dalvikExecutableParser.test.ts +89 -0
  226. package/src/dalvikExecutableParser.test.ts.md +634 -0
  227. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  228. package/src/dalvikExecutableParser.ts +2768 -0
  229. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +346 -0
  230. package/src/debugLogInputParser.ts +28 -0
  231. package/src/debugLogParser.ts +20 -4
  232. package/src/disjunctionParser.ts +10 -5
  233. package/src/elementParser.ts +3 -3
  234. package/src/elementTerminatedArrayParser.test.ts +99 -0
  235. package/src/elementTerminatedArrayParser.ts +31 -0
  236. package/src/elementTerminatedSequenceArrayParser.test.ts +54 -0
  237. package/src/elementTerminatedSequenceArrayParser.ts +52 -0
  238. package/src/elementTerminatedSequenceParser.test.ts +54 -0
  239. package/src/elementTerminatedSequenceParser.ts +43 -0
  240. package/src/endOfInputParser.ts +4 -4
  241. package/src/exactElementParser.ts +18 -12
  242. package/src/exactSequenceParser.ts +24 -3
  243. package/src/fetchCid.ts +125 -0
  244. package/src/fixedLengthSequenceParser.test.ts +77 -0
  245. package/src/fixedLengthSequenceParser.ts +28 -1
  246. package/src/hasExecutable.ts +11 -0
  247. package/src/highResolutionTimer.ts +49 -0
  248. package/src/index.ts +15 -2
  249. package/src/inputReader.test.ts +216 -7
  250. package/src/inputReader.ts +80 -5
  251. package/src/inputReaderState.ts +33 -0
  252. package/src/inspect.ts +9 -0
  253. package/src/javaKeyStore.ts +0 -0
  254. package/src/javaKeyStoreParser.test.ts +22 -0
  255. package/src/javaKeyStoreParser.test.ts.md +103 -0
  256. package/src/javaKeyStoreParser.test.ts.snap +0 -0
  257. package/src/javaKeyStoreParser.ts +136 -0
  258. package/src/jsonParser.test.ts +2 -2
  259. package/src/jsonParser.ts +23 -34
  260. package/src/leb128Parser.test.ts +171 -0
  261. package/src/leb128Parser.ts +125 -0
  262. package/src/listParser.ts +6 -6
  263. package/src/lookaheadParser.ts +19 -0
  264. package/src/negativeLookaheadParser.test.ts +53 -0
  265. package/src/negativeLookaheadParser.ts +36 -0
  266. package/src/nonEmptyArrayParser.test.ts +20 -0
  267. package/src/nonEmptyArrayParser.ts +44 -0
  268. package/src/optionalParser.ts +4 -3
  269. package/src/parser.test.ts +148 -27
  270. package/src/parser.test.ts.md +21 -21
  271. package/src/parser.test.ts.snap +0 -0
  272. package/src/parser.ts +153 -49
  273. package/src/parserAccessorParser.ts +12 -2
  274. package/src/parserConsumedSequenceParser.ts +29 -0
  275. package/src/parserContext.test.ts +38 -7
  276. package/src/parserContext.ts +127 -51
  277. package/src/parserCreatorCompose.ts +25 -7
  278. package/src/parserError.ts +9 -6
  279. package/src/parserImplementationInvariant.ts +2 -2
  280. package/src/parserInputCompanion.ts +102 -0
  281. package/src/promiseCompose.ts +17 -3
  282. package/src/promiseSettled.ts +6 -0
  283. package/src/quantifierParser.ts +25 -0
  284. package/src/separatedArrayParser.test.ts +34 -0
  285. package/src/separatedArrayParser.ts +55 -0
  286. package/src/sequenceBuffer.test.ts +72 -2
  287. package/src/sequenceBuffer.ts +93 -7
  288. package/src/sequenceTerminatedSequenceParser.test.ts +60 -0
  289. package/src/sequenceTerminatedSequenceParser.ts +62 -0
  290. package/src/sequenceUnparser.ts +9 -0
  291. package/src/skipParser.ts +7 -5
  292. package/src/skipToParser.ts +16 -0
  293. package/src/sliceBoundedParser.test.ts +45 -3
  294. package/src/sliceBoundedParser.ts +21 -3
  295. package/src/smali.ts +24 -0
  296. package/src/smaliParser.test.ts +132 -0
  297. package/src/smaliParser.test.ts.md +2320 -0
  298. package/src/smaliParser.test.ts.snap +0 -0
  299. package/src/smaliParser.ts +1166 -0
  300. package/src/terminatedArrayParser.test.ts +258 -0
  301. package/src/terminatedArrayParser.ts +111 -6
  302. package/src/toAsyncIterable.ts +7 -0
  303. package/src/toAsyncIterator.ts +48 -0
  304. package/src/tupleParser.ts +8 -5
  305. package/src/uint8Array.ts +10 -0
  306. package/src/unionParser.test.ts +79 -0
  307. package/src/unionParser.ts +44 -16
  308. package/src/unparser.test.ts +221 -0
  309. package/src/unparser.ts +209 -0
  310. package/src/unparserContext.ts +127 -0
  311. package/src/unparserError.ts +12 -0
  312. package/src/unparserImplementationInvariant.ts +6 -0
  313. package/src/unparserOutputCompanion.ts +24 -0
  314. package/src/zip.ts +10 -22
  315. package/src/zipParser.test.ts +2 -8
  316. package/src/zipParser.ts +223 -146
  317. package/src/zipUnparser.test.ts +119 -0
  318. package/src/zipUnparser.ts +300 -0
  319. package/build/apk.d.ts +0 -13
  320. package/build/apkParser.d.ts +0 -3
  321. package/build/apkParser.js +0 -135
  322. package/build/arbitraryDosDate.d.ts +0 -2
  323. package/build/arbitraryDosDate.js +0 -8
  324. package/build/arbitraryZipEntry.d.ts +0 -3
  325. package/build/arbitraryZipEntry.js +0 -26
  326. package/build/createDisjunctionParser.d.ts +0 -2
  327. package/build/createDisjunctionParser.js +0 -47
  328. package/build/createExactParser.d.ts +0 -2
  329. package/build/createExactParser.js +0 -12
  330. package/build/createSequentialUnionParser.d.ts +0 -2
  331. package/build/createSequentialUnionParser.js +0 -69
  332. package/build/fixedLengthChunkParser.d.ts +0 -2
  333. package/build/fixedLengthChunkParser.js +0 -12
  334. package/build/fixedLengthParser.d.ts +0 -2
  335. package/build/fixedLengthParser.js +0 -12
  336. package/build/inputChunkBuffer.d.ts +0 -15
  337. package/build/inputChunkBuffer.js +0 -40
  338. package/build/inputChunkBuffer.test.js +0 -34
  339. package/build/inputCompanion.d.ts +0 -18
  340. package/build/inputCompanion.js +0 -28
  341. package/build/invariantDefined.d.ts +0 -1
  342. package/build/invariantDefined.js +0 -5
  343. package/build/invariantIdentity.d.ts +0 -3
  344. package/build/invariantIdentity.js +0 -5
  345. package/build/jsonParser2.d.ts +0 -3
  346. package/build/jsonParser2.js +0 -52
  347. package/build/jsonParser2.test.js +0 -22
  348. package/build/negativeLookahead.js +0 -20
  349. package/build/parserCompose.d.ts +0 -3
  350. package/build/parserCompose.js +0 -7
  351. package/build/parserImplementationInvariantInvariant.d.ts +0 -3
  352. package/build/parserImplementationInvariantInvariant.js +0 -15
  353. package/build/promiseFish.d.ts +0 -1
  354. package/build/promiseFish.js +0 -3
  355. package/build/sequenceParser.d.ts +0 -3
  356. package/build/sequenceParser.js +0 -10
  357. package/build/terminatedSequenceParser.d.ts +0 -2
  358. package/build/terminatedSequenceParser.js +0 -24
  359. package/build/zipEntry.d.ts +0 -28
  360. package/build/zipFile.d.ts +0 -32
  361. package/build/zipFileEntry.d.ts +0 -6
  362. package/src/apk.ts +0 -16
  363. package/src/apkParser.test.ts.md +0 -268
  364. package/src/apkParser.test.ts.snap +0 -0
  365. package/src/apkParser.ts +0 -327
  366. package/src/inputCompanion.ts +0 -43
  367. package/src/invariantDefined.ts +0 -6
  368. package/src/invariantIdentity.ts +0 -8
  369. package/src/negativeLookahead.ts +0 -26
  370. /package/build/{apk.js → androidPackage.js} +0 -0
  371. /package/build/{apkParser.test.d.ts → androidPackageParser.test.d.ts} +0 -0
  372. /package/build/{arbitraryDosPermissions.d.ts → androidPackageUnparser.test.d.ts} +0 -0
  373. /package/build/{arbitraryDosPermissions.js → dalvikExecutableParser.test.d.ts} +0 -0
  374. /package/build/{inputChunkBuffer.test.d.ts → dalvikExecutableParserAgainstSmaliParser.test.d.ts} +0 -0
  375. /package/build/{jsonParser2.test.d.ts → elementTerminatedArrayParser.test.d.ts} +0 -0
  376. /package/build/{parserParsingInvariant.d.ts → elementTerminatedSequenceArrayParser.test.d.ts} +0 -0
  377. /package/build/{parserParsingInvariant.js → elementTerminatedSequenceParser.test.d.ts} +0 -0
  378. /package/build/{zipEntry.js → fixedLengthSequenceParser.test.d.ts} +0 -0
  379. /package/build/{zipFile.js → javaKeyStore.d.ts} +0 -0
  380. /package/build/{zipFileEntry.js → javaKeyStore.js} +0 -0
@@ -0,0 +1,70 @@
1
+ import test from 'ava';
2
+ import { runParser } from './parser.js';
3
+ import { uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
4
+ import { dalvikExecutableParser, dalvikExecutableWithRawInstructionsParser } from './dalvikExecutableParser.js';
5
+ import { fetchCid } from './fetchCid.js';
6
+ for (const [dexCid, shouldSnapshot] of [
7
+ ['bafkreibb4gsprc3fvmnyqx6obswvm7e7wngnfj64gz65ey72r7xgyzymt4', true],
8
+ ['bafybeiebe27ylo53trgitu6fqfbmba43c4ivxj3nt4kumsilkucpbdxtqq', false],
9
+ ['bafybeibbupm7uzhuq4pa674rb2amxsenbdaoijigmaf4onaodaql4mh7yy', false],
10
+ ['bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda', false],
11
+ ]) {
12
+ test.serial('dex (with instructions as bytes) ' + dexCid, async (t) => {
13
+ const dexStream = await fetchCid(dexCid);
14
+ const actual = await runParser(dalvikExecutableWithRawInstructionsParser, dexStream, uint8ArrayParserInputCompanion, {
15
+ errorJoinMode: 'all',
16
+ });
17
+ if (shouldSnapshot) {
18
+ t.snapshot(actual);
19
+ }
20
+ else {
21
+ //console.dir(actual, { depth: null });
22
+ t.pass();
23
+ }
24
+ });
25
+ }
26
+ function objectWalk(object, f, initialPath = []) {
27
+ f(initialPath, object);
28
+ if (!object
29
+ || typeof object !== 'object') {
30
+ return;
31
+ }
32
+ if (Array.isArray(object)) {
33
+ for (const [index, value] of object.entries()) {
34
+ objectWalk(value, f, [...initialPath, index]);
35
+ }
36
+ }
37
+ else {
38
+ for (const [key, value] of Object.entries(object)) {
39
+ objectWalk(value, f, [...initialPath, key]);
40
+ }
41
+ }
42
+ }
43
+ for (const [dexCid, shouldSnapshot] of [
44
+ ['bafkreibb4gsprc3fvmnyqx6obswvm7e7wngnfj64gz65ey72r7xgyzymt4', true],
45
+ // [ 'bafybeiebe27ylo53trgitu6fqfbmba43c4ivxj3nt4kumsilkucpbdxtqq', false ],
46
+ // [ 'bafybeibbupm7uzhuq4pa674rb2amxsenbdaoijigmaf4onaodaql4mh7yy', false ],
47
+ // [ 'bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda', false ],
48
+ ]) {
49
+ test.serial('dex (with parsed instructions) ' + dexCid, async (t) => {
50
+ const dexStream = await fetchCid(dexCid);
51
+ const actual = await runParser(dalvikExecutableParser, dexStream, uint8ArrayParserInputCompanion, {
52
+ errorJoinMode: 'all',
53
+ });
54
+ objectWalk(actual, (path) => {
55
+ const key = path.at(-1);
56
+ if (typeof key !== 'string') {
57
+ return;
58
+ }
59
+ t.false(key.endsWith('Offset'), 'All offsets should be resolved: ' + path.join('.'));
60
+ t.false(key.endsWith('Index'), 'All indexes should be resolved: ' + path.join('.'));
61
+ });
62
+ if (shouldSnapshot) {
63
+ t.snapshot(actual);
64
+ }
65
+ else {
66
+ //console.dir(actual, { depth: null });
67
+ t.pass();
68
+ }
69
+ });
70
+ }
@@ -0,0 +1,298 @@
1
+ import test from 'ava';
2
+ import { runParser } from './parser.js';
3
+ import { stringParserInputCompanion, uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
4
+ import { dalvikExecutableParser } from './dalvikExecutableParser.js';
5
+ import { fetchCid } from './fetchCid.js';
6
+ import { hasExecutable } from './hasExecutable.js';
7
+ import { baksmaliClass } from './backsmali.js';
8
+ import { smaliParser } from './smaliParser.js';
9
+ import { smaliClass } from './smali.js';
10
+ const hasBaksmaliPromise = hasExecutable('baksmali');
11
+ const hasSmaliPromise = hasExecutable('smali');
12
+ function objectWalk(object, f, initialPath = []) {
13
+ f(initialPath, object);
14
+ if (!object
15
+ || typeof object !== 'object') {
16
+ return;
17
+ }
18
+ if (Array.isArray(object)) {
19
+ for (const [index, value] of object.entries()) {
20
+ objectWalk(value, f, [...initialPath, index]);
21
+ }
22
+ }
23
+ else {
24
+ for (const [key, value] of Object.entries(object)) {
25
+ objectWalk(value, f, [...initialPath, key]);
26
+ }
27
+ }
28
+ }
29
+ for (const [dexCid, smaliFilePaths] of [
30
+ [
31
+ 'bafkreibb4gsprc3fvmnyqx6obswvm7e7wngnfj64gz65ey72r7xgyzymt4',
32
+ [
33
+ 'pl/czak/minimal/MainActivity',
34
+ ],
35
+ ],
36
+ // [
37
+ // 'bafybeiebe27ylo53trgitu6fqfbmba43c4ivxj3nt4kumsilkucpbdxtqq',
38
+ // [
39
+ // 'd/m',
40
+ // ],
41
+ // ],
42
+ // [ 'bafybeiebe27ylo53trgitu6fqfbmba43c4ivxj3nt4kumsilkucpbdxtqq' ],
43
+ // [
44
+ // 'bafybeibbupm7uzhuq4pa674rb2amxsenbdaoijigmaf4onaodaql4mh7yy',
45
+ // [
46
+ // 'com/journeyapps/barcodescanner/CaptureActivity',
47
+ // ],
48
+ // ],
49
+ // [ 'bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda' ],
50
+ ]) {
51
+ for (const smaliFilePath of smaliFilePaths) {
52
+ test.serial('parse(dex) against parse(smali(dex))' + dexCid + ' ' + smaliFilePath, async (t) => {
53
+ const hasBaksmali = await hasBaksmaliPromise;
54
+ if (!hasBaksmali) {
55
+ t.pass('skipping test because baksmali is not available');
56
+ return;
57
+ }
58
+ const dexStream = await fetchCid(dexCid);
59
+ const smali = await baksmaliClass(dexStream, smaliFilePath);
60
+ const classDefinitionFromSmali = await runParser(smaliParser, smali, stringParserInputCompanion, {
61
+ errorJoinMode: 'all',
62
+ });
63
+ const dexStream2 = await fetchCid(dexCid);
64
+ const executableFromDex = await runParser(dalvikExecutableParser, dexStream2, uint8ArrayParserInputCompanion, {
65
+ errorJoinMode: 'all',
66
+ });
67
+ const classDefinitionFromDex = executableFromDex.classDefinitions.find(classDefinition => classDefinition.class === classDefinitionFromSmali.class);
68
+ // console.log(smali);
69
+ // console.dir({
70
+ // classDefinitionFromDex,
71
+ // classDefinitionFromSmali,
72
+ // }, {
73
+ // depth: null,
74
+ // });
75
+ objectWalk(classDefinitionFromDex, (_path, value) => {
76
+ if (value
77
+ && typeof value === 'object'
78
+ && 'debugInfo' in value) {
79
+ value.debugInfo = undefined;
80
+ }
81
+ });
82
+ t.deepEqual(classDefinitionFromDex, classDefinitionFromSmali);
83
+ });
84
+ }
85
+ }
86
+ const smali = `
87
+ .class public Lcom/journeyapps/barcodescanner/CaptureActivity;
88
+ .super Landroid/app/Activity;
89
+ .source "CaptureActivity.java"
90
+
91
+
92
+ # instance fields
93
+ .field private barcodeScannerView:Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;
94
+
95
+ .field private capture:Lcom/journeyapps/barcodescanner/CaptureManager;
96
+
97
+
98
+ # direct methods
99
+ .method public constructor <init>()V
100
+ .registers 1
101
+
102
+ .line 13
103
+ invoke-direct {p0}, Landroid/app/Activity;-><init>()V
104
+
105
+ return-void
106
+ .end method
107
+
108
+
109
+ # virtual methods
110
+ .method protected initializeContent()Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;
111
+ .registers 2
112
+
113
+ sget v0, Lcom/google/zxing/client/android/R$layout;->zxing_capture:I
114
+
115
+ .line 34
116
+ invoke-virtual {p0, v0}, Landroid/app/Activity;->setContentView(I)V
117
+
118
+ sget v0, Lcom/google/zxing/client/android/R$id;->zxing_barcode_scanner:I
119
+
120
+ .line 35
121
+ invoke-virtual {p0, v0}, Landroid/app/Activity;->findViewById(I)Landroid/view/View;
122
+
123
+ move-result-object v0
124
+
125
+ check-cast v0, Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;
126
+
127
+ return-object v0
128
+ .end method
129
+
130
+ .method protected onCreate(Landroid/os/Bundle;)V
131
+ .registers 4
132
+
133
+ .line 19
134
+ invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
135
+
136
+ .line 21
137
+ invoke-virtual {p0}, Lcom/journeyapps/barcodescanner/CaptureActivity;->initializeContent()Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;
138
+
139
+ move-result-object v0
140
+
141
+ iput-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->barcodeScannerView:Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;
142
+
143
+ .line 23
144
+ new-instance v0, Lcom/journeyapps/barcodescanner/CaptureManager;
145
+
146
+ iget-object v1, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->barcodeScannerView:Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;
147
+
148
+ invoke-direct {v0, p0, v1}, Lcom/journeyapps/barcodescanner/CaptureManager;-><init>(Landroid/app/Activity;Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;)V
149
+
150
+ iput-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->capture:Lcom/journeyapps/barcodescanner/CaptureManager;
151
+
152
+ .line 24
153
+ invoke-virtual {p0}, Landroid/app/Activity;->getIntent()Landroid/content/Intent;
154
+
155
+ move-result-object v1
156
+
157
+ invoke-virtual {v0, v1, p1}, Lcom/journeyapps/barcodescanner/CaptureManager;->initializeFromIntent(Landroid/content/Intent;Landroid/os/Bundle;)V
158
+
159
+ iget-object p1, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->capture:Lcom/journeyapps/barcodescanner/CaptureManager;
160
+
161
+ .line 25
162
+ invoke-virtual {p1}, Lcom/journeyapps/barcodescanner/CaptureManager;->decode()V
163
+
164
+ return-void
165
+ .end method
166
+
167
+ .method protected onDestroy()V
168
+ .registers 2
169
+
170
+ .line 52
171
+ invoke-super {p0}, Landroid/app/Activity;->onDestroy()V
172
+
173
+ iget-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->capture:Lcom/journeyapps/barcodescanner/CaptureManager;
174
+
175
+ .line 53
176
+ invoke-virtual {v0}, Lcom/journeyapps/barcodescanner/CaptureManager;->onDestroy()V
177
+
178
+ return-void
179
+ .end method
180
+
181
+ .method public onKeyDown(ILandroid/view/KeyEvent;)Z
182
+ .registers 4
183
+
184
+ iget-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->barcodeScannerView:Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;
185
+
186
+ .line 69
187
+ invoke-virtual {v0, p1, p2}, Lcom/journeyapps/barcodescanner/DecoratedBarcodeView;->onKeyDown(ILandroid/view/KeyEvent;)Z
188
+
189
+ move-result v0
190
+
191
+ if-nez v0, :cond_11
192
+
193
+ invoke-super {p0, p1, p2}, Landroid/app/Activity;->onKeyDown(ILandroid/view/KeyEvent;)Z
194
+
195
+ move-result p1
196
+
197
+ if-eqz p1, :cond_f
198
+
199
+ goto :goto_11
200
+
201
+ :cond_f
202
+ const/4 p1, 0x0
203
+
204
+ goto :goto_12
205
+
206
+ :cond_11
207
+ :goto_11
208
+ const/4 p1, 0x1
209
+
210
+ :goto_12
211
+ return p1
212
+ .end method
213
+
214
+ .method protected onPause()V
215
+ .registers 2
216
+
217
+ .line 46
218
+ invoke-super {p0}, Landroid/app/Activity;->onPause()V
219
+
220
+ iget-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->capture:Lcom/journeyapps/barcodescanner/CaptureManager;
221
+
222
+ .line 47
223
+ invoke-virtual {v0}, Lcom/journeyapps/barcodescanner/CaptureManager;->onPause()V
224
+
225
+ return-void
226
+ .end method
227
+
228
+ .method public onRequestPermissionsResult(I[Ljava/lang/String;[I)V
229
+ .registers 5
230
+
231
+ iget-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->capture:Lcom/journeyapps/barcodescanner/CaptureManager;
232
+
233
+ .line 64
234
+ invoke-virtual {v0, p1, p2, p3}, Lcom/journeyapps/barcodescanner/CaptureManager;->onRequestPermissionsResult(I[Ljava/lang/String;[I)V
235
+
236
+ return-void
237
+ .end method
238
+
239
+ .method protected onResume()V
240
+ .registers 2
241
+
242
+ .line 40
243
+ invoke-super {p0}, Landroid/app/Activity;->onResume()V
244
+
245
+ iget-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->capture:Lcom/journeyapps/barcodescanner/CaptureManager;
246
+
247
+ .line 41
248
+ invoke-virtual {v0}, Lcom/journeyapps/barcodescanner/CaptureManager;->onResume()V
249
+
250
+ return-void
251
+ .end method
252
+
253
+ .method protected onSaveInstanceState(Landroid/os/Bundle;)V
254
+ .registers 3
255
+
256
+ .line 58
257
+ invoke-super {p0, p1}, Landroid/app/Activity;->onSaveInstanceState(Landroid/os/Bundle;)V
258
+
259
+ iget-object v0, p0, Lcom/journeyapps/barcodescanner/CaptureActivity;->capture:Lcom/journeyapps/barcodescanner/CaptureManager;
260
+
261
+ .line 59
262
+ invoke-virtual {v0, p1}, Lcom/journeyapps/barcodescanner/CaptureManager;->onSaveInstanceState(Landroid/os/Bundle;)V
263
+
264
+ return-void
265
+ .end method
266
+ `;
267
+ test.serial.skip('parse(dex(smali)) againts parse(smali)', async (t) => {
268
+ const hasSmali = await hasSmaliPromise;
269
+ if (!hasSmali) {
270
+ t.pass('skipping test because smali is not available');
271
+ return;
272
+ }
273
+ const dexBuffer = await smaliClass(async function* () {
274
+ yield smali;
275
+ }());
276
+ const classDefinitionFromSmali = await runParser(smaliParser, smali, stringParserInputCompanion, {
277
+ errorJoinMode: 'all',
278
+ });
279
+ const executableFromDex = await runParser(dalvikExecutableParser, dexBuffer, uint8ArrayParserInputCompanion, {
280
+ errorJoinMode: 'all',
281
+ });
282
+ const classDefinitionFromDex = executableFromDex.classDefinitions.find(classDefinition => classDefinition.class === classDefinitionFromSmali.class);
283
+ // console.log(smali);
284
+ console.dir({
285
+ classDefinitionFromDex,
286
+ classDefinitionFromSmali,
287
+ }, {
288
+ depth: null,
289
+ });
290
+ objectWalk(classDefinitionFromDex, (_path, value) => {
291
+ if (value
292
+ && typeof value === 'object'
293
+ && 'debugInfo' in value) {
294
+ value.debugInfo = undefined;
295
+ }
296
+ });
297
+ t.deepEqual(classDefinitionFromDex, classDefinitionFromSmali);
298
+ });
@@ -0,0 +1,4 @@
1
+ import { type Parser } from './parser.js';
2
+ export declare const createDebugLogInputParser: <Sequence>({ maxLookahead, }?: {
3
+ maxLookahead?: number;
4
+ }) => Parser<void, Sequence>;
@@ -0,0 +1,16 @@
1
+ export const createDebugLogInputParser = ({ maxLookahead = 8, } = {}) => async (parserContext) => {
2
+ let lookahead = maxLookahead;
3
+ while (lookahead > 0) {
4
+ const sequence = await parserContext.peekSequence(0, lookahead);
5
+ if (!sequence) {
6
+ lookahead = lookahead - 1;
7
+ continue;
8
+ }
9
+ let prettySequence = sequence;
10
+ if (prettySequence instanceof Uint8Array) {
11
+ prettySequence = Buffer.from(prettySequence).toString('hex');
12
+ }
13
+ console.log('debugLogInput (position: %s): %s', parserContext.position, prettySequence);
14
+ break;
15
+ }
16
+ };
@@ -1,2 +1,2 @@
1
- import { Parser } from "./parser.js";
1
+ import { type Parser } from './parser.js';
2
2
  export declare const createDebugLogParser: <Output, Sequence>(childParser: Parser<Output, Sequence>) => Parser<Output, Sequence>;
@@ -1,17 +1,28 @@
1
- import { getParserName, setParserName } from "./parser.js";
1
+ import { getParserName, setParserName } from './parser.js';
2
2
  export const createDebugLogParser = (childParser) => {
3
3
  let idCounter = 0;
4
+ function getLogParserName() {
5
+ const childParserName = getParserName(childParser);
6
+ if (childParserName !== 'anonymous') {
7
+ return childParserName;
8
+ }
9
+ const debugLogParserName = getParserName(debugLogParser);
10
+ if (!debugLogParserName.startsWith('debugLog(')) {
11
+ return debugLogParserName;
12
+ }
13
+ return 'anonymousDebugLogChild';
14
+ }
4
15
  const debugLogParser = async (parserContext) => {
5
16
  const id = idCounter++;
6
17
  const initialPosition = parserContext.position;
7
- console.debug('%s %s: started (position: %s)', getParserName(childParser), id, initialPosition);
18
+ console.debug('%s %s: started (position: %s)', getLogParserName(), id, initialPosition);
8
19
  try {
9
20
  const result = await childParser(parserContext);
10
- console.debug('%s %s: finished (position: %s, consumed: %s): %o', getParserName(childParser), id, parserContext.position, parserContext.position - initialPosition, result);
21
+ console.debug('%s %s: finished (position: %s, consumed: %s): %o', getLogParserName(), id, parserContext.position, parserContext.position - initialPosition, result);
11
22
  return result;
12
23
  }
13
24
  catch (error) {
14
- console.debug('%s %s: failed (position: %s, consumed: %s): %o', getParserName(childParser), id, parserContext.position, parserContext.position - initialPosition, error);
25
+ console.debug('%s %s: failed (position: %s, consumed: %s): %o', getLogParserName(), id, parserContext.position, parserContext.position - initialPosition, error);
15
26
  throw error;
16
27
  }
17
28
  };
@@ -1,2 +1,3 @@
1
1
  import { type Parser } from './parser.js';
2
- export declare const createDisjunctionParser: <Output, Sequence>(childParsers: Array<Parser<any, Sequence, any>>) => Parser<Output, Sequence, unknown>;
2
+ import { DeriveSequenceElement } from './sequence.js';
3
+ export declare const createDisjunctionParser: <Output, Sequence, Element = DeriveSequenceElement<Sequence>>(childParsers: Array<Parser<any, Sequence, Element>>) => Parser<Output, Sequence, Element>;
@@ -1,6 +1,7 @@
1
1
  import { getParserName, setParserName } from './parser.js';
2
2
  import { ParserParsingFailedError } from './parserError.js';
3
3
  import { parserImplementationInvariant } from './parserImplementationInvariant.js';
4
+ import { promiseSettled } from './promiseSettled.js';
4
5
  export const createDisjunctionParser = (childParsers) => {
5
6
  parserImplementationInvariant(childParsers.length > 0, 'Disjunction parser must have at least one child parser.');
6
7
  const disjunctionParser = async (parserContext) => {
@@ -9,13 +10,14 @@ export const createDisjunctionParser = (childParsers) => {
9
10
  const childParserContext = parserContext.lookahead({
10
11
  debugName: getParserName(childParser, 'anonymousDisjunctionChild'),
11
12
  });
12
- const [childParserResult] = await Promise.allSettled([childParser(childParserContext)]);
13
+ const childParserResult = await promiseSettled(childParser(childParserContext));
13
14
  if (childParserResult.status === 'fulfilled') {
14
15
  const successfulParserOutput = childParserResult.value;
15
16
  childParserContext.unlookahead();
16
17
  childParserContext.dispose();
17
18
  return successfulParserOutput;
18
19
  }
20
+ childParserContext.dispose();
19
21
  const error = childParserResult.reason;
20
22
  if (error instanceof ParserParsingFailedError) {
21
23
  parserParsingFailedErrors.push(error);
@@ -24,7 +26,7 @@ export const createDisjunctionParser = (childParsers) => {
24
26
  throw error;
25
27
  }
26
28
  }
27
- parserContext.invariantJoin(false, parserParsingFailedErrors, 'No disjunction child parser succeeded.');
29
+ return parserContext.invariantJoin(false, parserParsingFailedErrors, 'No disjunction child parser succeeded.');
28
30
  };
29
31
  const name = [
30
32
  '(',
@@ -1,3 +1,3 @@
1
- import { Parser } from "./parser.js";
2
- import { DeriveSequenceElement } from "./sequence.js";
1
+ import { type Parser } from './parser.js';
2
+ import { type DeriveSequenceElement } from './sequence.js';
3
3
  export declare const createElementParser: <Sequence, Element = DeriveSequenceElement<Sequence>>() => Parser<Element, Sequence, Element>;
@@ -1 +1 @@
1
- export const createElementParser = () => parserContext => parserContext.read(0);
1
+ export const createElementParser = () => async (parserContext) => parserContext.read(0);
@@ -0,0 +1,3 @@
1
+ import { Parser } from "./parser.js";
2
+ import { DeriveSequenceElement } from "./sequence.js";
3
+ export declare const createElementTerminatedArrayParserUnsafe: <ElementOutput, Sequence, Element = DeriveSequenceElement<Sequence>>(elementParser: Parser<ElementOutput, Sequence>, terminatorElement: Element) => Parser<ElementOutput[], Sequence>;
@@ -0,0 +1,18 @@
1
+ import { getParserName, setParserName } from "./parser.js";
2
+ export const createElementTerminatedArrayParserUnsafe = (elementParser, terminatorElement) => {
3
+ const elementTerminatedArrayParserUnsafe = async (parserContext) => {
4
+ const elements = [];
5
+ while (true) {
6
+ const inputElement = await parserContext.peek(0);
7
+ if (inputElement === terminatorElement) {
8
+ parserContext.skip(1);
9
+ break;
10
+ }
11
+ const element = await elementParser(parserContext);
12
+ elements.push(element);
13
+ }
14
+ return elements;
15
+ };
16
+ setParserName(elementTerminatedArrayParserUnsafe, `${getParserName(elementParser, 'anonymousElement')}*?${JSON.stringify(terminatorElement)}`);
17
+ return elementTerminatedArrayParserUnsafe;
18
+ };
@@ -0,0 +1,52 @@
1
+ import test from 'ava';
2
+ import * as fc from 'fast-check';
3
+ import { testProp } from '@fast-check/ava';
4
+ import { createTerminatedArrayParserNaive } from './terminatedArrayParser.js';
5
+ import { runParser } from './parser.js';
6
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
7
+ import { HighResolutionTotalTimer } from './highResolutionTimer.js';
8
+ import { createElementParser } from './elementParser.js';
9
+ import { createExactSequenceParser } from './exactSequenceParser.js';
10
+ import { createTupleParser } from './tupleParser.js';
11
+ import { createNegativeLookaheadParser } from './negativeLookaheadParser.js';
12
+ import { promiseCompose } from './promiseCompose.js';
13
+ import { createElementTerminatedArrayParserUnsafe } from './elementTerminatedArrayParser.js';
14
+ const naiveTotalTimer = new HighResolutionTotalTimer();
15
+ const elementTotalTimer = new HighResolutionTotalTimer();
16
+ testProp.serial('elementTerminatedArrayParserUnsafe', [
17
+ fc
18
+ .string({
19
+ minLength: 1,
20
+ })
21
+ .map(string => ({
22
+ string,
23
+ terminator: string.slice(-1)
24
+ }))
25
+ .filter(({ string, terminator }) => string.split(terminator).length === 2)
26
+ ], async (t, { string, terminator }) => {
27
+ const terminatedArrayParserNaive = promiseCompose(createTerminatedArrayParserNaive(promiseCompose(createTupleParser([
28
+ createNegativeLookaheadParser(createExactSequenceParser(terminator)),
29
+ createElementParser(),
30
+ ]), ([_, element]) => element), createExactSequenceParser(terminator)), ([characters]) => characters);
31
+ const elementTerminatedArrayParserUnsafe = createElementTerminatedArrayParserUnsafe(promiseCompose(createTupleParser([
32
+ createNegativeLookaheadParser(createExactSequenceParser(terminator)),
33
+ createElementParser(),
34
+ ]), ([_, element]) => element), terminator);
35
+ const createTestWrapperParser = (innerParser) => async (parserContext) => {
36
+ const characters = await innerParser(parserContext);
37
+ return {
38
+ string: characters.join(''),
39
+ nextPeek: await parserContext.peek(0),
40
+ position: parserContext.position,
41
+ };
42
+ };
43
+ const actualNaive = await naiveTotalTimer.measureAsync(() => runParser(createTestWrapperParser(terminatedArrayParserNaive), string, stringParserInputCompanion));
44
+ t.is(actualNaive.string.length, string.split(terminator)[0].length);
45
+ const actual = await elementTotalTimer.measureAsync(() => runParser(createTestWrapperParser(elementTerminatedArrayParserUnsafe), string, stringParserInputCompanion));
46
+ t.deepEqual(actual, actualNaive);
47
+ }, {
48
+ verbose: true,
49
+ });
50
+ test.serial('elementTerminatedArrayParserUnsafe performance', t => {
51
+ t.true(elementTotalTimer.time * 4n < naiveTotalTimer.time, `Naive: ${naiveTotalTimer.time / 1000000n}ms, Unsafe: ${elementTotalTimer.time / 1000000n}ms`);
52
+ });
@@ -0,0 +1,3 @@
1
+ import { Parser } from "./parser.js";
2
+ import { DeriveSequenceElement } from "./sequence.js";
3
+ export declare const createElementTerminatedSequenceArrayParser: <Sequence, Element = DeriveSequenceElement<Sequence>>(terminatorElement: Element) => Parser<Sequence[], Sequence, Element>;
@@ -0,0 +1,32 @@
1
+ import { setParserName } from "./parser.js";
2
+ export const createElementTerminatedSequenceArrayParser = (terminatorElement) => {
3
+ const elementTerminatedSequenceArrayParser = async (parserContext) => {
4
+ const sequences = [];
5
+ let start = 0;
6
+ let window = 1;
7
+ while (true) {
8
+ const sequence = await parserContext.peekSequence(start, start + window);
9
+ if (sequence === undefined) {
10
+ window = Math.floor(window / 2);
11
+ if (start === 0 && window === 0) {
12
+ break;
13
+ }
14
+ parserContext.invariant(window > 0, 'Unexpected end of input without terminator');
15
+ continue;
16
+ }
17
+ const terminatorIndex = parserContext.indexOf(sequence, terminatorElement);
18
+ if (terminatorIndex === -1) {
19
+ start += window;
20
+ window *= 2;
21
+ continue;
22
+ }
23
+ const sequence_ = await parserContext.readSequence(0, start + terminatorIndex);
24
+ parserContext.skip(1);
25
+ sequences.push(sequence_);
26
+ start = 0;
27
+ }
28
+ return sequences;
29
+ };
30
+ setParserName(elementTerminatedSequenceArrayParser, `(.*?${JSON.stringify(terminatorElement)})*`);
31
+ return elementTerminatedSequenceArrayParser;
32
+ };
@@ -0,0 +1,34 @@
1
+ import * as fc from 'fast-check';
2
+ import { testProp } from '@fast-check/ava';
3
+ import { runParser } from './parser.js';
4
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
5
+ import { createElementTerminatedSequenceArrayParser } from './elementTerminatedSequenceArrayParser.js';
6
+ testProp.serial('elementTerminatedSequenceArrayParser', [
7
+ fc
8
+ .string({
9
+ minLength: 1,
10
+ })
11
+ .map(string => ({
12
+ string,
13
+ terminator: string.slice(-1)
14
+ }))
15
+ .filter(({ string, terminator }) => string.split(terminator).length === 2)
16
+ ], async (t, { string, terminator }) => {
17
+ const elementTerminatedSequenceArrayParser = createElementTerminatedSequenceArrayParser(terminator);
18
+ const createTestWrapperParser = (innerParser) => async (parserContext) => {
19
+ const strings = await innerParser(parserContext);
20
+ return {
21
+ strings,
22
+ nextPeek: await parserContext.peek(0),
23
+ position: parserContext.position,
24
+ };
25
+ };
26
+ const actual = await runParser(createTestWrapperParser(elementTerminatedSequenceArrayParser), string, stringParserInputCompanion);
27
+ t.deepEqual(actual, {
28
+ strings: [string.split(terminator)[0]],
29
+ nextPeek: undefined,
30
+ position: string.length,
31
+ });
32
+ }, {
33
+ verbose: true,
34
+ });
@@ -0,0 +1,3 @@
1
+ import { Parser } from "./parser.js";
2
+ import { DeriveSequenceElement } from "./sequence.js";
3
+ export declare const createElementTerminatedSequenceParser: <Sequence, Element = DeriveSequenceElement<Sequence>>(terminatorElement: Element) => Parser<Sequence, Sequence, Element>;
@@ -0,0 +1,27 @@
1
+ import { setParserName } from "./parser.js";
2
+ export const createElementTerminatedSequenceParser = (terminatorElement) => {
3
+ const elementTerminatedSequenceParser = async (parserContext) => {
4
+ let start = 0;
5
+ let window = 1;
6
+ while (true) {
7
+ const sequence = await parserContext.peekSequence(start, start + window);
8
+ if (sequence === undefined) {
9
+ window = Math.floor(window / 2);
10
+ parserContext.invariant(!(start === 0 && window === 0), 'Unexpected end of input without terminated sequence');
11
+ parserContext.invariant(window > 0, 'Unexpected end of input without terminator');
12
+ continue;
13
+ }
14
+ const terminatorIndex = parserContext.indexOf(sequence, terminatorElement);
15
+ if (terminatorIndex === -1) {
16
+ start += window;
17
+ window *= 2;
18
+ continue;
19
+ }
20
+ const sequence_ = await parserContext.readSequence(0, start + terminatorIndex);
21
+ parserContext.skip(1);
22
+ return sequence_;
23
+ }
24
+ };
25
+ setParserName(elementTerminatedSequenceParser, `.*?${JSON.stringify(terminatorElement)}`);
26
+ return elementTerminatedSequenceParser;
27
+ };