@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,16 @@
1
+ export const inputReaderStateCompanion = {
2
+ isDone({ unconsumedBufferedSequences, unbufferedSequences, }) {
3
+ return (unconsumedBufferedSequences.length === 0
4
+ && unbufferedSequences === undefined);
5
+ },
6
+ async *toRemainingInputAsyncIterator({ unconsumedBufferedSequences, unbufferedSequences, }) {
7
+ yield* unconsumedBufferedSequences;
8
+ if (unbufferedSequences !== undefined) {
9
+ yield* {
10
+ [Symbol.asyncIterator]() {
11
+ return unbufferedSequences;
12
+ },
13
+ };
14
+ }
15
+ },
16
+ };
@@ -0,0 +1 @@
1
+ export declare const inspect: (value: unknown) => string;
@@ -0,0 +1,7 @@
1
+ import { inspect as nodeInspect } from 'node:util';
2
+ export const inspect = (value) => {
3
+ if (value instanceof Uint8Array) {
4
+ value = Buffer.from(value);
5
+ }
6
+ return nodeInspect(value);
7
+ };
@@ -2,12 +2,12 @@ import test from 'ava';
2
2
  import { uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
3
3
  import { runParser } from './parser.js';
4
4
  import { javaKeyStoreParser } from './javaKeyStoreParser.js';
5
+ import { fetchCid } from './fetchCid.js';
5
6
  for (const javaKeyStoreCid of [
6
7
  'bafkreig6k53b6p7bdvfjxc5mcb4qv3mffqls5ymqerxkqd6ih2xy5cs3n4',
7
8
  ]) {
8
9
  test('javaKeyStore ' + javaKeyStoreCid, async (t) => {
9
- const javaKeyStoreResponse = await fetch('https://ipfs.io/ipfs/' + javaKeyStoreCid);
10
- const javaKeyStoreStream = javaKeyStoreResponse.body;
10
+ const javaKeyStoreStream = await fetchCid(javaKeyStoreCid);
11
11
  const actual = await runParser(javaKeyStoreParser, javaKeyStoreStream, uint8ArrayParserInputCompanion, {
12
12
  errorJoinMode: 'all',
13
13
  });
@@ -1,3 +1,5 @@
1
1
  import { type JsonValue } from 'type-fest';
2
2
  import { type Parser } from './parser.js';
3
+ export declare const jsonStringParser: Parser<string, string>;
4
+ export declare const jsonNumberParser: Parser<number, string>;
3
5
  export declare const jsonValueParser: Parser<JsonValue, string>;
@@ -10,6 +10,7 @@ import { createArrayParser } from './arrayParser.js';
10
10
  import { createParserAccessorParser } from './parserAccessorParser.js';
11
11
  import { createElementParser } from './elementParser.js';
12
12
  import { parserCreatorCompose } from './parserCreatorCompose.js';
13
+ import { createSeparatedArrayParser } from './separatedArrayParser.js';
13
14
  const whitespaceParser = createArrayParser(createUnionParser([
14
15
  createExactSequenceParser(' '),
15
16
  createExactSequenceParser('\t'),
@@ -47,11 +48,11 @@ const jsonStringCharacterParser = createDisjunctionParser([
47
48
  return character;
48
49
  })(),
49
50
  ]);
50
- const jsonStringParser = promiseCompose(createTupleParser([
51
+ export const jsonStringParser = promiseCompose(createTupleParser([
51
52
  createExactSequenceParser('"'),
52
53
  promiseCompose(createTerminatedArrayParser(jsonStringCharacterParser, createExactSequenceParser('"')), ([characters]) => characters.join('')),
53
54
  ]), ([, string]) => string);
54
- const jsonNumberParser = parserCreatorCompose(() => createArrayParser(parserCreatorCompose(() => elementParser, character => async (parserContext) => {
55
+ export const jsonNumberParser = parserCreatorCompose(() => createArrayParser(parserCreatorCompose(() => elementParser, character => async (parserContext) => {
55
56
  parserContext.invariant((character === '-'
56
57
  || (character >= '0' && character <= '9')
57
58
  || character === '.'
@@ -113,18 +114,14 @@ const jsonObjectParser = promiseCompose(createTupleParser([
113
114
  const jsonArrayParser = promiseCompose(createTupleParser([
114
115
  createExactSequenceParser('['),
115
116
  whitespaceParser,
116
- promiseCompose(createTerminatedArrayParser(createDisjunctionParser([
117
- promiseCompose(createTupleParser([
118
- createParserAccessorParser(() => jsonValueParser),
119
- whitespaceParser,
120
- createExactSequenceParser(','),
121
- whitespaceParser,
122
- ]), ([value]) => value),
123
- promiseCompose(createTupleParser([
124
- createParserAccessorParser(() => jsonValueParser),
125
- whitespaceParser,
126
- ]), ([value]) => value),
127
- ]), createExactSequenceParser(']')), ([values]) => values),
117
+ createSeparatedArrayParser(createParserAccessorParser(() => jsonValueParser), createTupleParser([
118
+ whitespaceParser,
119
+ createExactSequenceParser(','),
120
+ whitespaceParser,
121
+ ])),
122
+ whitespaceParser,
123
+ createExactSequenceParser(']'),
124
+ whitespaceParser,
128
125
  ]), ([_bracket, _whitespace, values]) => values);
129
126
  export const jsonValueParser = createUnionParser([
130
127
  jsonObjectParser,
@@ -0,0 +1,7 @@
1
+ import { Parser } from "./parser.js";
2
+ export declare const uleb128Parser: Parser<bigint, Uint8Array>;
3
+ export declare const sleb128Parser: Parser<bigint, Uint8Array>;
4
+ export declare const uleb128NumberParser: Parser<number, Uint8Array>;
5
+ export declare const sleb128NumberParser: Parser<number, Uint8Array>;
6
+ export declare const uleb128UnsafeNumberParser: Parser<number, Uint8Array>;
7
+ export declare const sleb128UnsafeNumberParser: Parser<number, Uint8Array>;
@@ -0,0 +1,82 @@
1
+ export const uleb128Parser = async (parserContext) => {
2
+ let leastSignificantValueBitIndex = 0n;
3
+ let value = 0n;
4
+ while (true) {
5
+ const byte = await parserContext.read(0);
6
+ const byteValue = BigInt(byte & 0b01111111);
7
+ const byteNotLast = BigInt(byte & 0b10000000);
8
+ value |= byteValue << leastSignificantValueBitIndex;
9
+ if (byteNotLast) {
10
+ leastSignificantValueBitIndex += 7n;
11
+ continue;
12
+ }
13
+ break;
14
+ }
15
+ return value;
16
+ };
17
+ export const sleb128Parser = async (parserContext) => {
18
+ let value = 0n;
19
+ let leastSignificantValueBitIndex = 0n;
20
+ while (true) {
21
+ const byte = await parserContext.read(0);
22
+ const byteValue = BigInt(byte & 0b01111111);
23
+ const byteNotLast = BigInt(byte & 0b10000000);
24
+ value |= byteValue << leastSignificantValueBitIndex;
25
+ leastSignificantValueBitIndex += 7n;
26
+ if (byteNotLast) {
27
+ continue;
28
+ }
29
+ const mostSignificantInputBit = byte & 0b01000000;
30
+ if (mostSignificantInputBit) {
31
+ value |= (~0n << leastSignificantValueBitIndex);
32
+ }
33
+ break;
34
+ }
35
+ return value;
36
+ };
37
+ export const uleb128NumberParser = async (parserContext) => {
38
+ const value = await uleb128Parser(parserContext);
39
+ parserContext.invariant(Number(value) <= Number.MAX_SAFE_INTEGER, 'Value is too large to be represented as a number: %s', value);
40
+ return Number(value);
41
+ };
42
+ export const sleb128NumberParser = async (parserContext) => {
43
+ const value = await sleb128Parser(parserContext);
44
+ parserContext.invariant(Number(value) >= Number.MIN_SAFE_INTEGER && Number(value) <= Number.MAX_SAFE_INTEGER, 'Value is too large to be represented as a number: %s', value);
45
+ return Number(value);
46
+ };
47
+ export const uleb128UnsafeNumberParser = async (parserContext) => {
48
+ let leastSignificantValueBitIndex = 0;
49
+ let value = 0;
50
+ while (true) {
51
+ const byte = await parserContext.read(0);
52
+ const byteValue = byte & 0b01111111;
53
+ const byteNotLast = byte & 0b10000000;
54
+ value |= byteValue << leastSignificantValueBitIndex;
55
+ if (byteNotLast) {
56
+ leastSignificantValueBitIndex += 7;
57
+ continue;
58
+ }
59
+ break;
60
+ }
61
+ return value;
62
+ };
63
+ export const sleb128UnsafeNumberParser = async (parserContext) => {
64
+ let value = 0;
65
+ let leastSignificantValueBitIndex = 0;
66
+ while (true) {
67
+ const byte = await parserContext.read(0);
68
+ const byteValue = byte & 0b01111111;
69
+ const byteNotLast = byte & 0b10000000;
70
+ value |= byteValue << leastSignificantValueBitIndex;
71
+ leastSignificantValueBitIndex += 7;
72
+ if (byteNotLast) {
73
+ continue;
74
+ }
75
+ const mostSignificantInputBit = byte & 0b01000000;
76
+ if (leastSignificantValueBitIndex < 32 && mostSignificantInputBit) {
77
+ value |= (~0 << leastSignificantValueBitIndex);
78
+ }
79
+ break;
80
+ }
81
+ return value;
82
+ };
@@ -0,0 +1,107 @@
1
+ import { testProp, fc } from '@fast-check/ava';
2
+ import test from 'ava';
3
+ // @ts-expect-error
4
+ import leb128 from 'leb128';
5
+ import { uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
6
+ import { runParser } from './parser.js';
7
+ import { uleb128Parser, sleb128Parser, uleb128NumberParser, sleb128NumberParser } from './leb128Parser.js';
8
+ test('sleb128, uleb128, uleb128p1', async (t) => {
9
+ for (const [input, expectedSleb128, expectedUleb128,] of [
10
+ [Buffer.from('00', 'hex'), 0n, 0n],
11
+ [Buffer.from('01', 'hex'), 1n, 1n],
12
+ [Buffer.from('7f', 'hex'), -1n, 127n],
13
+ [Buffer.from('807f', 'hex'), -128n, 16256n],
14
+ ]) {
15
+ const actualSleb128 = await runParser(sleb128Parser, input, uint8ArrayParserInputCompanion);
16
+ const actualUleb128 = await runParser(uleb128Parser, input, uint8ArrayParserInputCompanion);
17
+ t.is(actualSleb128, expectedSleb128, 'sleb128');
18
+ t.is(actualUleb128, expectedUleb128, 'uleb128');
19
+ }
20
+ for (const [input, expectedUleb128,] of [
21
+ [new Uint8Array([2]), 2n],
22
+ [new Uint8Array([127]), 127n],
23
+ [new Uint8Array([0 + 0x80, 1]), 128n],
24
+ [new Uint8Array([1 + 0x80, 1]), 129n],
25
+ [new Uint8Array([57 + 0x80, 100]), 12857n],
26
+ ]) {
27
+ const actualUleb128 = await runParser(uleb128Parser, input, uint8ArrayParserInputCompanion);
28
+ t.is(actualUleb128, expectedUleb128, 'uleb128');
29
+ }
30
+ for (const [input, expectedSleb128,] of [
31
+ [new Uint8Array([2]), 2n],
32
+ [new Uint8Array([0x7e]), -2n],
33
+ [new Uint8Array([127 + 0x80, 0]), 127n],
34
+ [new Uint8Array([1 + 0x80, 0x7f]), -127n],
35
+ [new Uint8Array([0 + 0x80, 1]), 128n],
36
+ [new Uint8Array([0 + 0x80, 0x7f]), -128n],
37
+ [new Uint8Array([1 + 0x80, 1]), 129n],
38
+ [new Uint8Array([0x7f + 0x80, 0x7e]), -129n],
39
+ ]) {
40
+ const actualSleb128 = await runParser(sleb128Parser, input, uint8ArrayParserInputCompanion);
41
+ t.is(actualSleb128, expectedSleb128, 'sleb128');
42
+ }
43
+ });
44
+ testProp('uleb128NumberParser on small number', [
45
+ fc.nat(),
46
+ ], async (t, natural) => {
47
+ const uleb128 = leb128.unsigned.encode(natural);
48
+ const actualUleb128 = await runParser(uleb128NumberParser, uleb128, uint8ArrayParserInputCompanion);
49
+ t.is(actualUleb128, natural, 'uleb128');
50
+ }, {
51
+ verbose: true,
52
+ });
53
+ testProp('sleb128NumberParser on small number', [
54
+ fc.integer(),
55
+ ], async (t, integer) => {
56
+ const sleb128 = leb128.signed.encode(integer);
57
+ const actualSleb128 = await runParser(sleb128NumberParser, sleb128, uint8ArrayParserInputCompanion);
58
+ t.is(actualSleb128, integer, 'sleb128');
59
+ }, {
60
+ verbose: true,
61
+ });
62
+ // TODO?
63
+ testProp.skip('uleb128NumberParser on large number', [
64
+ fc.maxSafeNat(),
65
+ ], async (t, natural) => {
66
+ const uleb128 = leb128.unsigned.encode(natural);
67
+ if (natural > (2 ** 32) - 1) {
68
+ await t.throwsAsync(() => runParser(uleb128NumberParser, uleb128, uint8ArrayParserInputCompanion));
69
+ return;
70
+ }
71
+ const actualUleb128 = await runParser(uleb128NumberParser, uleb128, uint8ArrayParserInputCompanion);
72
+ t.is(actualUleb128, natural, 'uleb128');
73
+ }, {
74
+ verbose: true,
75
+ });
76
+ // TODO?
77
+ testProp.skip('sleb128NumberParser on large number', [
78
+ fc.maxSafeInteger(),
79
+ ], async (t, integer) => {
80
+ const sleb128 = leb128.signed.encode(integer);
81
+ if (integer > (2 ** 32) - 1 || integer < -(2 ** 32)) {
82
+ await t.throwsAsync(() => runParser(sleb128NumberParser, sleb128, uint8ArrayParserInputCompanion));
83
+ return;
84
+ }
85
+ const actualSleb128 = await runParser(sleb128NumberParser, sleb128, uint8ArrayParserInputCompanion);
86
+ t.is(actualSleb128, integer, 'sleb128');
87
+ }, {
88
+ verbose: true,
89
+ });
90
+ testProp('uleb128Parser on bigint', [
91
+ fc.bigInt({ min: 0n }),
92
+ ], async (t, bigInt) => {
93
+ const uleb128 = leb128.unsigned.encode(bigInt);
94
+ const actualUleb128 = await runParser(uleb128Parser, uleb128, uint8ArrayParserInputCompanion);
95
+ t.is(actualUleb128, bigInt, 'uleb128');
96
+ }, {
97
+ verbose: true,
98
+ });
99
+ testProp('sleb128Parser on bigint', [
100
+ fc.bigInt(),
101
+ ], async (t, bigInt) => {
102
+ const sleb128 = leb128.signed.encode(bigInt);
103
+ const actualSleb128 = await runParser(sleb128Parser, sleb128, uint8ArrayParserInputCompanion);
104
+ t.is(actualSleb128, bigInt, 'sleb128');
105
+ }, {
106
+ verbose: true,
107
+ });
@@ -0,0 +1,2 @@
1
+ import { type Parser } from './parser.js';
2
+ export declare const createLookaheadParser: <Output, Sequence>(childParser: Parser<Output, Sequence>) => Parser<Output, Sequence>;
@@ -0,0 +1,14 @@
1
+ import { getParserName, setParserName } from './parser.js';
2
+ export const createLookaheadParser = (childParser) => {
3
+ const lookaheadParser = async (parserContext) => {
4
+ const childParserContext = parserContext.lookahead();
5
+ try {
6
+ return await childParser(childParserContext);
7
+ }
8
+ finally {
9
+ childParserContext.dispose();
10
+ }
11
+ };
12
+ setParserName(lookaheadParser, `(?=${getParserName(childParser)})`);
13
+ return lookaheadParser;
14
+ };
@@ -1,18 +1,24 @@
1
- import { getParserName } from './parser.js';
1
+ import { getParserName, setParserName } from './parser.js';
2
2
  import { ParserParsingFailedError } from './parserError.js';
3
- export const createNegativeLookaheadParser = (childParser) => async (parserContext) => {
4
- const childParserContext = parserContext.lookahead();
5
- try {
6
- await childParser(childParserContext);
7
- parserContext.invariant(false, 'Negative lookahead assertion failed for child parser %s.', getParserName(childParser));
8
- }
9
- catch (error) {
10
- if (error instanceof ParserParsingFailedError) {
11
- return;
3
+ export const createNegativeLookaheadParser = (childParser) => {
4
+ const negativeLookaheadParser = async (parserContext) => {
5
+ const childParserContext = parserContext.lookahead();
6
+ let childParserSuccess;
7
+ try {
8
+ await childParser(childParserContext);
9
+ childParserSuccess = true;
12
10
  }
13
- throw error;
14
- }
15
- finally {
16
- childParserContext.dispose();
17
- }
11
+ catch (error) {
12
+ if (!(error instanceof ParserParsingFailedError)) {
13
+ throw error;
14
+ }
15
+ childParserSuccess = false;
16
+ }
17
+ finally {
18
+ childParserContext.dispose();
19
+ }
20
+ parserContext.invariant(!childParserSuccess, 'Negative lookahead assertion failed for child parser %s.', getParserName(childParser));
21
+ };
22
+ setParserName(negativeLookaheadParser, `(?!${getParserName(childParser)})`);
23
+ return negativeLookaheadParser;
18
24
  };
@@ -0,0 +1,30 @@
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
+ testProp('negativeLookaheadParser', [
10
+ fc.tuple(fc.string({
11
+ minLength: 1,
12
+ }), fc.string({
13
+ minLength: 1,
14
+ })).filter(([a, b]) => !a.startsWith(b))
15
+ ], async (t, [stringA, stringB]) => {
16
+ const result = await runParser(createTupleParser([
17
+ createNegativeLookaheadParser(createExactSequenceParser(stringB)),
18
+ createExactSequenceParser(stringA + stringB),
19
+ ]), stringA + stringB, stringParserInputCompanion);
20
+ t.deepEqual(result, [undefined, stringA + stringB]);
21
+ await t.throwsAsync(() => runParser(createTupleParser([
22
+ createNegativeLookaheadParser(createExactSequenceParser(stringA)),
23
+ createExactSequenceParser(stringA + stringB),
24
+ ]), stringA + stringB, stringParserInputCompanion), {
25
+ instanceOf: ParserParsingFailedError,
26
+ message: /lookahead/,
27
+ });
28
+ }, {
29
+ verbose: true,
30
+ });
@@ -0,0 +1,2 @@
1
+ import { type Parser } from './parser.js';
2
+ export declare const createNonEmptyArrayParser: <ElementOutput, Sequence>(elementParser: Parser<ElementOutput, Sequence>) => Parser<ElementOutput[], Sequence>;
@@ -0,0 +1,32 @@
1
+ import { getParserName, setParserName } from './parser.js';
2
+ import { ParserParsingFailedError } from './parserError.js';
3
+ export const createNonEmptyArrayParser = (elementParser) => {
4
+ const nonEmptyArrayParser = async (parserContext) => {
5
+ const elements = [];
6
+ while (true) {
7
+ const elementParserContext = parserContext.lookahead();
8
+ const initialPosition = elementParserContext.position;
9
+ try {
10
+ const element = await elementParser(elementParserContext);
11
+ if (elementParserContext.position === initialPosition) {
12
+ break;
13
+ }
14
+ elements.push(element);
15
+ elementParserContext.unlookahead();
16
+ }
17
+ catch (error) {
18
+ if (error instanceof ParserParsingFailedError) {
19
+ break;
20
+ }
21
+ throw error;
22
+ }
23
+ finally {
24
+ elementParserContext.dispose();
25
+ }
26
+ }
27
+ parserContext.invariant(elements.length > 0, 'Expected elementParser (%s) to match at least once', getParserName(elementParser, 'anonymousNonEmptyArrayChild'));
28
+ return elements;
29
+ };
30
+ setParserName(nonEmptyArrayParser, getParserName(elementParser, 'anonymousNonEmptyArrayChild') + '+');
31
+ return nonEmptyArrayParser;
32
+ };
@@ -0,0 +1,16 @@
1
+ import test from 'ava';
2
+ import { createNonEmptyArrayParser } from './nonEmptyArrayParser.js';
3
+ import { runParser } from './parser.js';
4
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
5
+ import { createExactElementParser } from './exactElementParser.js';
6
+ test('empty array does not match', async (t) => {
7
+ const parser = createNonEmptyArrayParser(createExactElementParser('0'));
8
+ await t.throwsAsync(() => runParser(parser, '', stringParserInputCompanion), {
9
+ message: /Expected .* to match at least once/,
10
+ });
11
+ });
12
+ test('non-empty array matches', async (t) => {
13
+ const parser = createNonEmptyArrayParser(createExactElementParser('0'));
14
+ const result = await runParser(parser, '0', stringParserInputCompanion);
15
+ t.deepEqual(result, ['0']);
16
+ });
package/build/parser.d.ts CHANGED
@@ -1,10 +1,19 @@
1
+ import { Class } from 'type-fest';
1
2
  import { type ParserInputCompanion } from './parserInputCompanion.js';
2
3
  import { type ParserContext } from './parserContext.js';
3
4
  import { type DeriveSequenceElement } from './sequence.js';
4
- export type Parser<Output, Sequence, Element = DeriveSequenceElement<Sequence>> = (parserContext: ParserContext<Sequence, Element>) => Promise<Output>;
5
+ export type Parser<Output, Sequence, Element = DeriveSequenceElement<Sequence>> = (parserContext: ParserContext<Sequence, Element>) => Output | Promise<Output>;
5
6
  export declare function getParserName(parser: Parser<any, any, any>, default_?: string): string;
6
7
  export declare function setParserName<Output, Sequence, Element = DeriveSequenceElement<Sequence>>(parser: Parser<Output, Sequence, Element>, name: string): Parser<Output, Sequence, Element>;
8
+ export declare function cloneParser<Output, Sequence, Element = DeriveSequenceElement<Sequence>>(parser: Parser<Output, Sequence, Element>): Parser<Output, Sequence, Element>;
7
9
  export type RunParserOptions<Output, Sequence, Element = DeriveSequenceElement<Sequence>> = {
8
10
  errorJoinMode?: 'none' | 'deepest' | 'furthest' | 'all';
11
+ parserContextClass?: Class<ParserContext<Sequence, Element>>;
9
12
  };
13
+ export type RunParserWithRemainingInputResult<Output, Sequence, Element = DeriveSequenceElement<Sequence>> = {
14
+ output: Output;
15
+ position: number;
16
+ remainingInput: undefined | AsyncIterable<Sequence>;
17
+ };
18
+ export declare function runParserWithRemainingInput<Output, Sequence, Element = DeriveSequenceElement<Sequence>>(parser: Parser<Output, Sequence, Element>, input: AsyncIterator<Sequence> | AsyncIterable<Sequence> | Iterable<Sequence> | Sequence, parserInputCompanion: ParserInputCompanion<Sequence, Element>, options?: RunParserOptions<Output, Sequence, Element>): Promise<RunParserWithRemainingInputResult<Output, Sequence, Element>>;
10
19
  export declare function runParser<Output, Sequence, Element = DeriveSequenceElement<Sequence>>(parser: Parser<Output, Sequence, Element>, input: AsyncIterator<Sequence> | AsyncIterable<Sequence> | Iterable<Sequence> | Sequence, parserInputCompanion: ParserInputCompanion<Sequence, Element>, options?: RunParserOptions<Output, Sequence, Element>): Promise<Output>;
package/build/parser.js CHANGED
@@ -1,6 +1,8 @@
1
- import invariant from 'invariant';
2
1
  import { InputReaderImplementation } from './inputReader.js';
3
2
  import { ParserContextImplementation } from './parserContext.js';
3
+ import { ParserError, ParserUnexpectedRemainingInputError } from './parserError.js';
4
+ import { toAsyncIterator } from './toAsyncIterator.js';
5
+ import { inputReaderStateCompanion } from './inputReaderState.js';
4
6
  export function getParserName(parser, default_ = 'anonymous') {
5
7
  return parser.name || default_;
6
8
  }
@@ -10,44 +12,77 @@ export function setParserName(parser, name) {
10
12
  });
11
13
  return parser;
12
14
  }
13
- function isAsyncIterable(value) {
14
- return value && typeof value[Symbol.asyncIterator] === 'function';
15
- }
16
- function isIterable(value) {
17
- return value && typeof value[Symbol.iterator] === 'function';
18
- }
19
- function isIterator(value) {
20
- return value && typeof value.next === 'function';
21
- }
22
- function iteratorToAsyncIterator(iterator) {
23
- return {
24
- next: async () => iterator.next(),
15
+ const originalParserByClone = new WeakMap();
16
+ export function cloneParser(parser) {
17
+ const originalParser = originalParserByClone.get(parser) ?? parser;
18
+ const clone = (parserContext) => {
19
+ return originalParser(parserContext);
25
20
  };
21
+ setParserName(clone, getParserName(parser));
22
+ originalParserByClone.set(clone, originalParser);
23
+ return clone;
26
24
  }
27
- function toAsyncIterator(value) {
28
- if (typeof value === 'string'
29
- || value instanceof Uint8Array) {
30
- return (async function* () {
31
- yield value;
32
- })();
25
+ async function withEnrichedParserError(parserContext, inputReader, f) {
26
+ try {
27
+ return await f();
33
28
  }
34
- if (isAsyncIterable(value)) {
35
- return value[Symbol.asyncIterator]();
29
+ catch (error) {
30
+ if (error instanceof ParserError) {
31
+ if (error.position === undefined) {
32
+ error.position = parserContext.position;
33
+ }
34
+ if (error.inputReaderSate === undefined) {
35
+ error.inputReaderSate = inputReader.toInputReaderState();
36
+ }
37
+ }
38
+ throw error;
36
39
  }
37
- if (isIterable(value)) {
38
- return iteratorToAsyncIterator(value[Symbol.iterator]());
39
- }
40
- if (isIterator(value)) {
41
- return iteratorToAsyncIterator(value);
42
- }
43
- invariant(false, 'Value must be an async iterator, async iterable, iterable or iterator got %s.', value);
44
40
  }
45
- export async function runParser(parser, input, parserInputCompanion, options = {}) {
41
+ function runParserInternal(parser, input, parserInputCompanion, options = {}) {
46
42
  const inputAsyncIterator = toAsyncIterator(input);
47
43
  const inputReader = new InputReaderImplementation(parserInputCompanion, inputAsyncIterator);
48
- const parserContext = new ParserContextImplementation(parserInputCompanion, inputReader, undefined, {
44
+ const ParserContext = options.parserContextClass ?? ParserContextImplementation;
45
+ const parserContext = new ParserContext(parserInputCompanion, inputReader, undefined, {
49
46
  ...options,
50
47
  debugName: 'root',
51
48
  });
52
- return parser(parserContext);
49
+ const outputPromise = (async () => {
50
+ try {
51
+ return await parser(parserContext);
52
+ }
53
+ finally {
54
+ await parserContext.peek(0);
55
+ }
56
+ })();
57
+ return {
58
+ outputPromise,
59
+ parserContext,
60
+ inputReader,
61
+ };
62
+ }
63
+ export async function runParserWithRemainingInput(parser, input, parserInputCompanion, options = {}) {
64
+ const { outputPromise, parserContext, inputReader, } = runParserInternal(parser, input, parserInputCompanion, options);
65
+ return await withEnrichedParserError(parserContext, inputReader, async () => {
66
+ const output = await outputPromise;
67
+ const inputReaderState = inputReader.toInputReaderState();
68
+ const remainingInput = (inputReaderStateCompanion.isDone(inputReaderState)
69
+ ? undefined
70
+ : inputReaderStateCompanion.toRemainingInputAsyncIterator(inputReaderState));
71
+ return {
72
+ output,
73
+ position: parserContext.position,
74
+ remainingInput,
75
+ };
76
+ });
77
+ }
78
+ export async function runParser(parser, input, parserInputCompanion, options = {}) {
79
+ const { outputPromise, parserContext, inputReader, } = runParserInternal(parser, input, parserInputCompanion, options);
80
+ return await withEnrichedParserError(parserContext, inputReader, async () => {
81
+ const output = await outputPromise;
82
+ const inputReaderState = inputReader.toInputReaderState();
83
+ if (!inputReaderStateCompanion.isDone(inputReaderState)) {
84
+ throw new ParserUnexpectedRemainingInputError('Unexpected remaining input', 0, parserContext.position);
85
+ }
86
+ return output;
87
+ });
53
88
  }