@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
@@ -1,6 +1,10 @@
1
+ import { InputReaderState } from "./inputReaderState.js";
1
2
 
2
3
  export class ParserError extends Error {
3
4
  name = 'ParserError';
5
+
6
+ public position: undefined | number = undefined;
7
+ public inputReaderSate: undefined | InputReaderState<unknown> = undefined;
4
8
  }
5
9
 
6
10
  export class ParserImplementationError extends ParserError {
@@ -18,12 +22,7 @@ export class ParserParsingFailedError extends ParserError {
18
22
  public readonly depth: number,
19
23
  public readonly position: number,
20
24
  ) {
21
- super([
22
- '(position: ',
23
- position,
24
- ') ',
25
- message,
26
- ].join(''));
25
+ super(message);
27
26
  }
28
27
  }
29
28
 
@@ -83,3 +82,7 @@ export class ParserParsingInvariantError extends ParserParsingFailedError {
83
82
  export class ParserUnexpectedEndOfInputError extends ParserParsingFailedError {
84
83
  name = 'ParserUnexpectedEndOfInputError';
85
84
  }
85
+
86
+ export class ParserUnexpectedRemainingInputError extends ParserParsingFailedError {
87
+ name = 'ParserUnexpectedRemainingInputError';
88
+ }
@@ -2,8 +2,13 @@
2
2
  export type ParserInputCompanion<Sequence, Element> = {
3
3
  is(value: unknown): value is Sequence;
4
4
  from(elements: Element[]): Sequence;
5
+ concat(sequences: Sequence[]): Sequence;
5
6
  length(sequence: Sequence): number;
6
7
  at(sequence: Sequence, index: number): Element | undefined;
8
+ subsequence(sequence: Sequence, start: number, end: number): Sequence;
9
+ indexOf(sequence: Sequence, element: Element, fromIndex?: number): number;
10
+ indexOfSubsequence(sequence: Sequence, subsequence: Sequence, fromIndex?: number): number;
11
+ equals(sequenceA: Sequence, sequenceB: Sequence): boolean;
7
12
  };
8
13
 
9
14
  export class StringParserInputCompanion implements ParserInputCompanion<string, string> {
@@ -15,6 +20,10 @@ export class StringParserInputCompanion implements ParserInputCompanion<string,
15
20
  return elements.join('');
16
21
  }
17
22
 
23
+ concat(sequences: string[]): string {
24
+ return sequences.join('');
25
+ }
26
+
18
27
  length(sequence: string): number {
19
28
  return sequence.length;
20
29
  }
@@ -22,6 +31,22 @@ export class StringParserInputCompanion implements ParserInputCompanion<string,
22
31
  at(sequence: string, index: number): string | undefined {
23
32
  return sequence.at(index);
24
33
  }
34
+
35
+ subsequence(sequence: string, start: number, end: number): string {
36
+ return sequence.slice(start, end);
37
+ }
38
+
39
+ indexOf(sequence: string, element: string, fromIndex?: number): number {
40
+ return sequence.indexOf(element, fromIndex);
41
+ }
42
+
43
+ indexOfSubsequence(sequence: string, subsequence: string, fromIndex?: number): number {
44
+ return sequence.indexOf(subsequence, fromIndex);
45
+ }
46
+
47
+ equals(sequenceA: string, sequenceB: string): boolean {
48
+ return sequenceA === sequenceB;
49
+ }
25
50
  }
26
51
 
27
52
  export const stringParserInputCompanion = new StringParserInputCompanion();
@@ -35,6 +60,10 @@ export class Uint8ArrayParserInputCompanion implements ParserInputCompanion<Uint
35
60
  return new Uint8Array(elements);
36
61
  }
37
62
 
63
+ concat(sequences: Uint8Array[]): Uint8Array {
64
+ return new Uint8Array(Buffer.concat(sequences));
65
+ }
66
+
38
67
  length(sequence: Uint8Array): number {
39
68
  return sequence.length;
40
69
  }
@@ -42,6 +71,32 @@ export class Uint8ArrayParserInputCompanion implements ParserInputCompanion<Uint
42
71
  at(sequence: Uint8Array, index: number): number | undefined {
43
72
  return sequence.at(index);
44
73
  }
74
+
75
+ subsequence(sequence: Uint8Array, start: number, end: number): Uint8Array {
76
+ return sequence.subarray(start, end);
77
+ }
78
+
79
+ indexOf(sequence: Uint8Array, element: number, fromIndex?: number): number {
80
+ return sequence.indexOf(element, fromIndex);
81
+ }
82
+
83
+ indexOfSubsequence(sequence: Uint8Array, subsequence: Uint8Array, fromIndex?: number): number {
84
+ return Buffer.from(sequence).indexOf(Buffer.from(subsequence), fromIndex);
85
+ }
86
+
87
+ equals(sequenceA: Uint8Array, sequenceB: Uint8Array): boolean {
88
+ if (sequenceA.length !== sequenceB.length) {
89
+ return false;
90
+ }
91
+
92
+ for (let index = 0; index < sequenceA.length; index++) {
93
+ if (sequenceA[index] !== sequenceB[index]) {
94
+ return false;
95
+ }
96
+ }
97
+
98
+ return true;
99
+ }
45
100
  }
46
101
 
47
102
  export const uint8ArrayParserInputCompanion = new Uint8ArrayParserInputCompanion();
@@ -1,7 +1,21 @@
1
1
 
2
2
  export function promiseCompose<A, B, C>(
3
- f1: (a: A) => Promise<B>,
3
+ f1: (a: A) => B | Promise<B>,
4
4
  f2: (b: B) => C | Promise<C>,
5
- ): (a: A) => Promise<C> {
6
- return async a => f1(a).then(f2);
5
+ ): (a: A) => C | Promise<C> {
6
+ function promiseComposed(a: A) {
7
+ const bOrBPromise = f1(a);
8
+
9
+ if (bOrBPromise instanceof Promise) {
10
+ return bOrBPromise.then(f2);
11
+ }
12
+
13
+ return f2(bOrBPromise);
14
+ };
15
+
16
+ Object.defineProperty(promiseComposed, 'name', {
17
+ value: `promiseCompose(${f1.name}, ${f2.name})`,
18
+ });
19
+
20
+ return promiseComposed;
7
21
  }
@@ -0,0 +1,6 @@
1
+
2
+ export async function promiseSettled<T>(promise: Promise<T>): Promise<PromiseSettledResult<T>> {
3
+ const [ promiseSettledResult ] = await Promise.allSettled([ promise ]);
4
+
5
+ return promiseSettledResult;
6
+ }
@@ -0,0 +1,34 @@
1
+ import test from 'ava';
2
+ import { testProp, fc } from '@fast-check/ava';
3
+ import { createSeparatedArrayParser } from './separatedArrayParser.js';
4
+ import { type Parser, runParser, runParserWithRemainingInput } from './parser.js';
5
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
6
+ import { createExactSequenceParser } from './exactSequenceParser.js';
7
+
8
+ test('does not loop forever with a child parser that does not consume anything', async t => {
9
+ const parser: Parser<undefined[], string> = createSeparatedArrayParser(async () => undefined, () => undefined);
10
+ const { output } = await runParserWithRemainingInput(parser, 'foo', stringParserInputCompanion);
11
+
12
+ t.deepEqual(output, []);
13
+ });
14
+
15
+ testProp(
16
+ 'separatedArray',
17
+ [
18
+ fc.array(fc.constant('element')),
19
+ ],
20
+ async (t, elements) => {
21
+ const separatedArrayParser = createSeparatedArrayParser(
22
+ createExactSequenceParser('element'),
23
+ createExactSequenceParser('separator'),
24
+ );
25
+
26
+ const actual = await runParser(separatedArrayParser, elements.join('separator'), stringParserInputCompanion);
27
+ const expected = elements;
28
+
29
+ t.deepEqual(actual, expected);
30
+ },
31
+ {
32
+ verbose: true,
33
+ },
34
+ );
@@ -0,0 +1,55 @@
1
+ import { getParserName, type Parser, setParserName } from './parser.js';
2
+ import { ParserParsingFailedError } from './parserError.js';
3
+ import { promiseCompose } from './promiseCompose.js';
4
+ import { createTupleParser } from './tupleParser.js';
5
+
6
+ export const createSeparatedArrayParser = <ElementOutput, Sequence>(
7
+ elementParser: Parser<ElementOutput, Sequence>,
8
+ separatorParser: Parser<unknown, Sequence>,
9
+ ): Parser<ElementOutput[], Sequence> => {
10
+ const separatorThenElementParser: Parser<ElementOutput, Sequence> = promiseCompose(
11
+ createTupleParser([
12
+ separatorParser,
13
+ elementParser,
14
+ ]),
15
+ ([ , element ]) => element,
16
+ );
17
+
18
+ const separatedArrayParser: Parser<ElementOutput[], Sequence> = async parserContext => {
19
+ let parser = elementParser;
20
+
21
+ const elements: ElementOutput[] = [];
22
+
23
+ while (true) {
24
+ const elementParserContext = parserContext.lookahead();
25
+ const initialPosition = elementParserContext.position;
26
+
27
+ try {
28
+ const element = await parser(elementParserContext);
29
+
30
+ if (elementParserContext.position === initialPosition) {
31
+ break;
32
+ }
33
+
34
+ elements.push(element);
35
+ elementParserContext.unlookahead();
36
+ } catch (error) {
37
+ if (error instanceof ParserParsingFailedError) {
38
+ break;
39
+ }
40
+
41
+ throw error;
42
+ } finally {
43
+ elementParserContext.dispose();
44
+ }
45
+
46
+ parser = separatorThenElementParser
47
+ }
48
+
49
+ return elements;
50
+ };
51
+
52
+ setParserName(separatedArrayParser, getParserName(elementParser, 'anonymousSeparatedArrayChild') + '*');
53
+
54
+ return separatedArrayParser;
55
+ };
@@ -5,46 +5,116 @@ import { stringParserInputCompanion } from './parserInputCompanion.js';
5
5
  test('sequenceBuffer', t => {
6
6
  const sequenceBuffer = new SequenceBufferImplementation(stringParserInputCompanion);
7
7
 
8
+ t.is(sequenceBuffer.length, 0);
8
9
  t.is(sequenceBuffer.peek(0), undefined);
9
10
 
11
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
12
+ consumedBufferedSequences: [],
13
+ unconsumedBufferedSequences: [],
14
+ });
15
+
10
16
  sequenceBuffer.push('');
11
17
 
18
+ t.is(sequenceBuffer.length, 0);
12
19
  t.is(sequenceBuffer.peek(0), undefined);
13
20
 
21
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
22
+ consumedBufferedSequences: [],
23
+ unconsumedBufferedSequences: [],
24
+ });
25
+
14
26
  sequenceBuffer.push('abc');
15
27
 
28
+ t.is(sequenceBuffer.length, 3);
16
29
  t.is(sequenceBuffer.peek(0), 'a');
17
30
  t.is(sequenceBuffer.peek(1), 'b');
18
31
  t.is(sequenceBuffer.peek(2), 'c');
19
32
  t.is(sequenceBuffer.peek(3), undefined);
20
33
 
34
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
35
+ consumedBufferedSequences: [],
36
+ unconsumedBufferedSequences: ['abc'],
37
+ });
38
+
21
39
  sequenceBuffer.push('def');
22
40
 
41
+ t.is(sequenceBuffer.length, 6);
23
42
  t.is(sequenceBuffer.peek(0), 'a');
24
43
  t.is(sequenceBuffer.peek(3), 'd');
25
44
  t.is(sequenceBuffer.peek(6), undefined);
26
45
 
46
+ t.is(sequenceBuffer.peekSequence(1, 4), 'abcdef'.slice(1, 4), 'bcd');
47
+ t.is(sequenceBuffer.peekSequence(1, 5), 'abcdef'.slice(1, 5), 'bcde');
48
+ t.is(sequenceBuffer.peekSequence(1, 6), 'abcdef'.slice(1, 6), 'bcdef');
49
+ t.is(sequenceBuffer.peekSequence(1, 7), undefined, 'bcdef?');
50
+
51
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
52
+ consumedBufferedSequences: [],
53
+ unconsumedBufferedSequences: ['abc', 'def'],
54
+ });
55
+
27
56
  sequenceBuffer.push('');
28
57
 
58
+ t.is(sequenceBuffer.length, 6);
29
59
  t.is(sequenceBuffer.peek(0), 'a');
30
60
  t.is(sequenceBuffer.peek(3), 'd');
31
61
  t.is(sequenceBuffer.peek(6), undefined);
32
62
 
63
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
64
+ consumedBufferedSequences: [],
65
+ unconsumedBufferedSequences: ['abc', 'def', ''],
66
+ });
67
+
33
68
  sequenceBuffer.skip(1);
34
69
 
70
+ t.is(sequenceBuffer.length, 5);
35
71
  t.is(sequenceBuffer.peek(0), 'b');
36
72
  t.is(sequenceBuffer.peek(3), 'e');
37
73
  t.is(sequenceBuffer.peek(5), undefined);
38
74
 
75
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
76
+ consumedBufferedSequences: ['a'],
77
+ unconsumedBufferedSequences: ['bc', 'def', ''],
78
+ });
79
+
39
80
  sequenceBuffer.skip(3);
40
81
 
82
+ t.is(sequenceBuffer.length, 2);
41
83
  t.is(sequenceBuffer.peek(0), 'e');
42
84
  t.is(sequenceBuffer.peek(2), undefined);
43
85
 
86
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
87
+ consumedBufferedSequences: ['d'],
88
+ unconsumedBufferedSequences: ['ef', ''],
89
+ });
90
+
44
91
  sequenceBuffer.push('gh');
45
92
 
93
+ t.is(sequenceBuffer.length, 4);
46
94
  t.is(sequenceBuffer.peek(0), 'e');
47
95
  t.is(sequenceBuffer.peek(2), 'g');
48
96
  t.is(sequenceBuffer.peek(3), 'h');
49
97
  t.is(sequenceBuffer.peek(4), undefined);
98
+
99
+ t.is(sequenceBuffer.peekSequence(1, 3), 'efgh'.slice(1, 3), 'fg');
100
+ t.is(sequenceBuffer.peekSequence(1, 4), 'efgh'.slice(1, 4), 'fgh');
101
+ t.is(sequenceBuffer.peekSequence(1, 5), undefined, 'fgh?');
102
+
103
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
104
+ consumedBufferedSequences: ['d'],
105
+ unconsumedBufferedSequences: ['ef', '', 'gh'],
106
+ });
107
+ });
108
+
109
+ test('skip more then first sequence length', t => {
110
+ const sequenceBuffer = new SequenceBufferImplementation(stringParserInputCompanion);
111
+
112
+ sequenceBuffer.push('a');
113
+ sequenceBuffer.push('b');
114
+ sequenceBuffer.skip(2);
115
+
116
+ t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
117
+ consumedBufferedSequences: [],
118
+ unconsumedBufferedSequences: [],
119
+ });
50
120
  });
@@ -1,10 +1,18 @@
1
1
  import invariant from 'invariant';
2
2
  import { type ParserInputCompanion } from './parserInputCompanion.js';
3
3
 
4
+ export type SequenceBufferState<Sequence> = {
5
+ consumedBufferedSequences: Sequence[];
6
+ unconsumedBufferedSequences: Sequence[];
7
+ };
8
+
4
9
  export type SequenceBuffer<Sequence, Element> = {
5
10
  push(sequence: Sequence): void;
6
11
  peek(offset: number): Element | undefined;
12
+ peekSequence(start: number, end: number): Sequence | undefined;
7
13
  skip(offset: number): void;
14
+
15
+ toSequenceBufferState(): SequenceBufferState<Sequence>;
8
16
  };
9
17
 
10
18
  export class SequenceBufferImplementation<Sequence, Element> implements SequenceBuffer<Sequence, Element> {
@@ -13,9 +21,14 @@ export class SequenceBufferImplementation<Sequence, Element> implements Sequence
13
21
 
14
22
  constructor(private readonly _parserInputCompanion: ParserInputCompanion<Sequence, Element>) {}
15
23
 
16
- push(sequence: Sequence) {
17
- this._sequences.push(sequence);
24
+ get length() {
25
+ return this._sequences.reduce(
26
+ (sequenceLength, sequence) => sequenceLength + this._parserInputCompanion.length(sequence),
27
+ 0 - this._indexInFirstSequence,
28
+ );
29
+ }
18
30
 
31
+ private _shift() {
19
32
  while (this._sequences.length > 0) {
20
33
  const firstSequence = this._sequences[0];
21
34
  const firstSequenceLength = this._parserInputCompanion.length(firstSequence);
@@ -34,6 +47,12 @@ export class SequenceBufferImplementation<Sequence, Element> implements Sequence
34
47
  }
35
48
  }
36
49
 
50
+ push(sequence: Sequence) {
51
+ this._sequences.push(sequence);
52
+
53
+ this._shift();
54
+ }
55
+
37
56
  peek(offset: number): Element | undefined {
38
57
  invariant(offset >= 0, 'Offset must be non-negative.');
39
58
 
@@ -52,7 +71,74 @@ export class SequenceBufferImplementation<Sequence, Element> implements Sequence
52
71
  return undefined;
53
72
  }
54
73
 
74
+ peekSequence(start: number, end: number): Sequence | undefined {
75
+ invariant(start >= 0, 'Start must be non-negative.');
76
+ invariant(end >= start, 'End must be greater than or equal to start.');
77
+
78
+ let startIndex = this._indexInFirstSequence + start;
79
+ let endIndex = this._indexInFirstSequence + end;
80
+
81
+ const sequences: Sequence[] = [];
82
+
83
+ for (const sequence of this._sequences) {
84
+ const sequenceLength = this._parserInputCompanion.length(sequence);
85
+
86
+ if (startIndex < sequenceLength) {
87
+ const subsequence = this._parserInputCompanion.subsequence(
88
+ sequence,
89
+ Math.max(0, startIndex),
90
+ Math.min(sequenceLength, endIndex),
91
+ )
92
+ sequences.push(subsequence);
93
+ }
94
+
95
+ startIndex -= sequenceLength;
96
+ endIndex -= sequenceLength;
97
+
98
+ if (endIndex <= 0) {
99
+ break;
100
+ }
101
+ }
102
+
103
+ return endIndex > 0 ? undefined : this._parserInputCompanion.concat(sequences);
104
+ }
105
+
55
106
  skip(offset: number) {
56
107
  this._indexInFirstSequence += offset;
108
+
109
+ this._shift();
110
+ }
111
+
112
+ toSequenceBufferState(): SequenceBufferState<Sequence> {
113
+ if (this._sequences.length === 0) {
114
+ return {
115
+ consumedBufferedSequences: [],
116
+ unconsumedBufferedSequences: [],
117
+ };
118
+ }
119
+
120
+ if (this._indexInFirstSequence === 0) {
121
+ return {
122
+ consumedBufferedSequences: [],
123
+ unconsumedBufferedSequences: this._sequences.slice(),
124
+ };
125
+ }
126
+
127
+ const firstSequence = this._sequences[0];
128
+ const firstSequenceLength = this._parserInputCompanion.length(firstSequence);
129
+
130
+ const consumedFirstSequence = this._parserInputCompanion.subsequence(firstSequence, 0, this._indexInFirstSequence);
131
+ const unconsumedFirstSequence = this._parserInputCompanion.subsequence(firstSequence, this._indexInFirstSequence, firstSequenceLength);
132
+
133
+ const unconsumedFirstSequenceLength = this._parserInputCompanion.length(unconsumedFirstSequence);
134
+
135
+ return {
136
+ consumedBufferedSequences: [consumedFirstSequence],
137
+ unconsumedBufferedSequences: (
138
+ unconsumedFirstSequenceLength === 0
139
+ ? this._sequences.slice(1)
140
+ : [unconsumedFirstSequence, ...this._sequences.slice(1)]
141
+ ),
142
+ };
57
143
  }
58
144
  }
@@ -0,0 +1,60 @@
1
+ import * as fc from 'fast-check';
2
+ import { testProp } from '@fast-check/ava';
3
+ import { Parser, runParser } from './parser.js';
4
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
5
+ import { createSequenceTerminatedSequenceParser } from './sequenceTerminatedSequenceParser.js';
6
+
7
+ testProp.serial(
8
+ 'sequenceTerminatedSequenceParser',
9
+ [
10
+ fc.tuple(
11
+ fc
12
+ .string({
13
+ minLength: 1,
14
+ }),
15
+ fc
16
+ .integer({
17
+ min: 1,
18
+ }),
19
+ )
20
+ .map(([ string, terminatorLength ]) => ({
21
+ string,
22
+ terminator: string.slice(-terminatorLength),
23
+ }))
24
+ .filter(({ string, terminator }) => string.split(terminator).length === 2)
25
+ ],
26
+ async (t, { string, terminator }) => {
27
+ const sequenceTerminatedSequenceParser = createSequenceTerminatedSequenceParser<string>(
28
+ terminator,
29
+ );
30
+
31
+ const createTestWrapperParser = (innerParser: typeof sequenceTerminatedSequenceParser): Parser<{
32
+ string: string;
33
+ nextPeek: string | undefined;
34
+ position: number;
35
+ }, string> => async parserContext => {
36
+ const string = await innerParser(parserContext);
37
+
38
+ return {
39
+ string,
40
+ nextPeek: await parserContext.peek(0),
41
+ position: parserContext.position,
42
+ };
43
+ };
44
+
45
+ const actual = await runParser(
46
+ createTestWrapperParser(sequenceTerminatedSequenceParser),
47
+ string,
48
+ stringParserInputCompanion,
49
+ );
50
+
51
+ t.deepEqual(actual, {
52
+ string: string.split(terminator)[0],
53
+ nextPeek: undefined,
54
+ position: string.length,
55
+ });
56
+ },
57
+ {
58
+ verbose: true,
59
+ },
60
+ );
@@ -0,0 +1,62 @@
1
+ import { inspect } from "./inspect.js";
2
+ import { Parser, setParserName } from "./parser.js";
3
+ import { DeriveSequenceElement } from "./sequence.js";
4
+
5
+ function clamp(x: number, min: number, max: number) {
6
+ return Math.max(min, Math.min(x, max));
7
+ }
8
+
9
+ export const createSequenceTerminatedSequenceParser = <Sequence, Element = DeriveSequenceElement<Sequence>>(
10
+ terminatorSequence: Sequence,
11
+ {
12
+ consumeTerminator = true,
13
+ }: {
14
+ consumeTerminator?: boolean;
15
+ } = {},
16
+ ): Parser<Sequence, Sequence, Element> => {
17
+ const elementTerminatedSequenceParser: Parser<Sequence, Sequence, Element> = async parserContext => {
18
+ let window = 1;
19
+ let nonEndOfInputWindow = 0;
20
+
21
+ while (true) {
22
+ const sequence = await parserContext.peekSequence(0, window);
23
+
24
+ if (sequence === undefined) {
25
+ window = clamp(
26
+ Math.floor(window * 0.75),
27
+ nonEndOfInputWindow + 1,
28
+ window - 1,
29
+ );
30
+
31
+ parserContext.invariant(
32
+ window !== nonEndOfInputWindow,
33
+ 'Unexpected end of input without terminated sequence',
34
+ );
35
+
36
+ continue;
37
+ }
38
+
39
+ nonEndOfInputWindow = Math.max(window, nonEndOfInputWindow);
40
+
41
+ const terminatorIndex = parserContext.indexOfSubsequence(sequence, terminatorSequence);
42
+
43
+ if (terminatorIndex === -1) {
44
+ window = window * 2;
45
+
46
+ continue;
47
+ }
48
+
49
+ const sequence_ = await parserContext.readSequence(0, terminatorIndex);
50
+
51
+ if (consumeTerminator) {
52
+ parserContext.skip(parserContext.length(terminatorSequence));
53
+ }
54
+
55
+ return sequence_;
56
+ }
57
+ };
58
+
59
+ setParserName(elementTerminatedSequenceParser, `.*?${inspect(terminatorSequence)}`);
60
+
61
+ return elementTerminatedSequenceParser;
62
+ };
package/src/skipParser.ts CHANGED
@@ -1,12 +1,14 @@
1
- import { type Parser } from './parser.js';
1
+ import { setParserName, type Parser } from './parser.js';
2
2
  import { parserImplementationInvariant } from './parserImplementationInvariant.js';
3
3
 
4
- export const createSkipParser = <Sequence>(length: number): Parser<undefined, Sequence, unknown> => {
4
+ export const createSkipParser = <Sequence>(length: number): Parser<void, Sequence, unknown> => {
5
5
  parserImplementationInvariant(length > 0, 'Length must be positive.');
6
6
 
7
- return async parserContext => {
7
+ const skipParser: Parser<void, Sequence, unknown> = parserContext => {
8
8
  parserContext.skip(length);
9
-
10
- return undefined;
11
9
  };
10
+
11
+ setParserName(skipParser, `createSkipParser(${length})`);
12
+
13
+ return skipParser;
12
14
  };
@@ -0,0 +1,16 @@
1
+ import { Parser, setParserName } from "./parser.js";
2
+ import { parserImplementationInvariant } from './parserImplementationInvariant.js';
3
+
4
+ export const createSkipToParser = (offset: number): Parser<void, Uint8Array> => {
5
+ const skipToParser: Parser<void, Uint8Array> = (parserContext) => {
6
+ const length = offset - parserContext.position;
7
+
8
+ parserImplementationInvariant(length >= 0, 'Skip length must be positive, got %s (position: %s)', length, parserContext.position);
9
+
10
+ parserContext.skip(length);
11
+ };
12
+
13
+ setParserName(skipToParser, `createSkipToParser(${offset})`);
14
+
15
+ return skipToParser;
16
+ };