@futpib/parser 1.0.4 → 1.0.6

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 (250) hide show
  1. package/.claude/settings.local.json +24 -0
  2. package/.github/workflows/main.yml +1 -0
  3. package/build/androidPackageParser.js +30 -32
  4. package/build/arbitraryDalvikBytecode.d.ts +3 -3
  5. package/build/arbitraryDalvikBytecode.js +33 -27
  6. package/build/arbitraryDalvikExecutable.js +55 -17
  7. package/build/arbitraryJava.d.ts +31 -0
  8. package/build/arbitraryJava.js +532 -0
  9. package/build/arbitraryJavaScript.d.ts +3 -0
  10. package/build/arbitraryJavaScript.js +263 -0
  11. package/build/arbitraryJavascript.d.ts +3 -0
  12. package/build/arbitraryJavascript.js +263 -0
  13. package/build/arbitraryZig.d.ts +3 -0
  14. package/build/arbitraryZig.js +240 -0
  15. package/build/arbitraryZipStream.d.ts +1 -1
  16. package/build/arrayParser.js +72 -13
  17. package/build/backsmali.d.ts +4 -3
  18. package/build/backsmali.js +26 -6
  19. package/build/bash.d.ts +6 -1
  20. package/build/bashParser.js +131 -90
  21. package/build/bashParser.test.js +162 -0
  22. package/build/bashParserEdgeCases.test.d.ts +1 -0
  23. package/build/bashParserEdgeCases.test.js +117 -0
  24. package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
  25. package/build/dalvikBytecodeParser/addressConversion.js +334 -0
  26. package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
  27. package/build/dalvikBytecodeParser/formatParsers.js +13 -14
  28. package/build/dalvikBytecodeParser.d.ts +60 -31
  29. package/build/dalvikBytecodeParser.js +92 -35
  30. package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
  31. package/build/dalvikBytecodeParser.test-d.js +268 -0
  32. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
  33. package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
  34. package/build/dalvikBytecodeUnparser.d.ts +2 -2
  35. package/build/dalvikBytecodeUnparser.js +23 -23
  36. package/build/dalvikBytecodeUnparser.test.js +7 -7
  37. package/build/dalvikExecutable.d.ts +3 -3
  38. package/build/dalvikExecutable.test-d.d.ts +1 -0
  39. package/build/dalvikExecutable.test-d.js +59 -0
  40. package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
  41. package/build/dalvikExecutableParser/typedNumbers.js +3 -0
  42. package/build/dalvikExecutableParser.d.ts +2 -1
  43. package/build/dalvikExecutableParser.js +96 -77
  44. package/build/dalvikExecutableParser.test.js +24 -3
  45. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
  46. package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
  47. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
  48. package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
  49. package/build/dalvikExecutableUnparser.d.ts +2 -2
  50. package/build/dalvikExecutableUnparser.test.js +2 -1
  51. package/build/disjunctionParser.d.ts +5 -3
  52. package/build/disjunctionParser.js +79 -17
  53. package/build/disjunctionParser.test-d.d.ts +1 -0
  54. package/build/disjunctionParser.test-d.js +72 -0
  55. package/build/elementSwitchParser.d.ts +4 -0
  56. package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
  57. package/build/elementSwitchParser.test-d.d.ts +1 -0
  58. package/build/elementSwitchParser.test-d.js +44 -0
  59. package/build/exactSequenceParser.d.ts +4 -2
  60. package/build/exactSequenceParser.test-d.d.ts +1 -0
  61. package/build/exactSequenceParser.test-d.js +36 -0
  62. package/build/fetchCid.js +2 -66
  63. package/build/index.d.ts +3 -2
  64. package/build/index.js +2 -1
  65. package/build/index.test.js +16 -1
  66. package/build/inputReader.d.ts +10 -0
  67. package/build/inputReader.js +36 -0
  68. package/build/java.d.ts +502 -0
  69. package/build/java.js +2 -0
  70. package/build/javaKeyStoreParser.js +14 -17
  71. package/build/javaParser.d.ts +51 -0
  72. package/build/javaParser.js +1538 -0
  73. package/build/javaParser.test.d.ts +1 -0
  74. package/build/javaParser.test.js +1287 -0
  75. package/build/javaScript.d.ts +35 -0
  76. package/build/javaScript.js +1 -0
  77. package/build/javaScriptParser.d.ts +9 -0
  78. package/build/javaScriptParser.js +34 -0
  79. package/build/javaScriptUnparser.d.ts +3 -0
  80. package/build/javaScriptUnparser.js +4 -0
  81. package/build/javaScriptUnparser.test.d.ts +1 -0
  82. package/build/javaScriptUnparser.test.js +24 -0
  83. package/build/javaUnparser.d.ts +2 -0
  84. package/build/javaUnparser.js +519 -0
  85. package/build/javaUnparser.test.d.ts +1 -0
  86. package/build/javaUnparser.test.js +24 -0
  87. package/build/javascript.d.ts +35 -0
  88. package/build/javascript.js +1 -0
  89. package/build/javascriptParser.d.ts +9 -0
  90. package/build/javascriptParser.js +34 -0
  91. package/build/javascriptUnparser.d.ts +3 -0
  92. package/build/javascriptUnparser.js +4 -0
  93. package/build/javascriptUnparser.test.d.ts +1 -0
  94. package/build/javascriptUnparser.test.js +24 -0
  95. package/build/jsonParser.js +2 -12
  96. package/build/lazyMessageError.d.ts +3 -0
  97. package/build/lookaheadParser.js +60 -3
  98. package/build/negativeLookaheadParser.js +70 -11
  99. package/build/nonEmptyArrayParser.js +72 -13
  100. package/build/objectParser.d.ts +12 -0
  101. package/build/objectParser.js +31 -0
  102. package/build/objectParser.test-d.d.ts +1 -0
  103. package/build/objectParser.test-d.js +112 -0
  104. package/build/objectParser.test.d.ts +1 -0
  105. package/build/objectParser.test.js +55 -0
  106. package/build/optionalParser.js +69 -10
  107. package/build/parser.d.ts +4 -0
  108. package/build/parser.js +3 -1
  109. package/build/parser.test.js +114 -1
  110. package/build/parserConsumedSequenceParser.js +66 -7
  111. package/build/parserContext.d.ts +6 -0
  112. package/build/parserContext.js +20 -11
  113. package/build/parserError.d.ts +119 -27
  114. package/build/parserError.js +16 -8
  115. package/build/regexpParser.js +33 -3
  116. package/build/regexpParser.test.js +31 -0
  117. package/build/regularExpressionParser.js +35 -15
  118. package/build/separatedArrayParser.js +73 -14
  119. package/build/separatedNonEmptyArrayParser.js +73 -14
  120. package/build/sliceBoundedParser.js +62 -5
  121. package/build/smaliParser.d.ts +7 -7
  122. package/build/smaliParser.js +185 -268
  123. package/build/smaliParser.test.js +58 -0
  124. package/build/stringEscapes.d.ts +5 -0
  125. package/build/stringEscapes.js +244 -0
  126. package/build/symbolicExpression.d.ts +29 -0
  127. package/build/symbolicExpression.js +1 -0
  128. package/build/symbolicExpressionParser.d.ts +4 -0
  129. package/build/symbolicExpressionParser.js +123 -0
  130. package/build/symbolicExpressionParser.test.d.ts +1 -0
  131. package/build/symbolicExpressionParser.test.js +289 -0
  132. package/build/terminatedArrayParser.js +113 -38
  133. package/build/terminatedArrayParser.test.js +4 -2
  134. package/build/tupleParser.d.ts +7 -15
  135. package/build/tupleParser.js +1 -0
  136. package/build/unionParser.d.ts +5 -3
  137. package/build/unionParser.js +7 -2
  138. package/build/unionParser.test-d.d.ts +1 -0
  139. package/build/unionParser.test-d.js +72 -0
  140. package/build/unionParser.test.js +10 -11
  141. package/build/zig.d.ts +280 -0
  142. package/build/zig.js +2 -0
  143. package/build/zigParser.d.ts +3 -0
  144. package/build/zigParser.js +1119 -0
  145. package/build/zigParser.test.d.ts +1 -0
  146. package/build/zigParser.test.js +1590 -0
  147. package/build/zigUnparser.d.ts +2 -0
  148. package/build/zigUnparser.js +460 -0
  149. package/build/zigUnparser.test.d.ts +1 -0
  150. package/build/zigUnparser.test.js +24 -0
  151. package/build/zipParser.js +19 -32
  152. package/build/zipUnparser.js +19 -7
  153. package/build/zipUnparser.test.js +1 -1
  154. package/node_modules-@types/s-expression/index.d.ts +5 -0
  155. package/package.json +24 -6
  156. package/src/androidPackageParser.ts +33 -60
  157. package/src/arbitraryDalvikBytecode.ts +39 -31
  158. package/src/arbitraryDalvikExecutable.ts +65 -20
  159. package/src/arbitraryJava.ts +804 -0
  160. package/src/arbitraryJavaScript.ts +410 -0
  161. package/src/arbitraryZig.ts +380 -0
  162. package/src/arrayParser.ts +1 -3
  163. package/src/backsmali.ts +35 -4
  164. package/src/bash.ts +8 -1
  165. package/src/bashParser.test.ts +258 -0
  166. package/src/bashParser.ts +180 -143
  167. package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
  168. package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
  169. package/src/dalvikBytecodeParser.test-d.ts +310 -0
  170. package/src/dalvikBytecodeParser.ts +194 -69
  171. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
  172. package/src/dalvikBytecodeUnparser.test.ts +7 -7
  173. package/src/dalvikBytecodeUnparser.ts +31 -30
  174. package/src/dalvikExecutable.test-d.ts +132 -0
  175. package/src/dalvikExecutable.ts +3 -3
  176. package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
  177. package/src/dalvikExecutableParser.test.ts +37 -3
  178. package/src/dalvikExecutableParser.test.ts.md +163 -2
  179. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  180. package/src/dalvikExecutableParser.ts +121 -139
  181. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
  182. package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
  183. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
  184. package/src/dalvikExecutableUnparser.test.ts +3 -2
  185. package/src/dalvikExecutableUnparser.ts +4 -4
  186. package/src/disjunctionParser.test-d.ts +105 -0
  187. package/src/disjunctionParser.ts +18 -15
  188. package/src/elementSwitchParser.test-d.ts +74 -0
  189. package/src/elementSwitchParser.ts +51 -0
  190. package/src/exactSequenceParser.test-d.ts +43 -0
  191. package/src/exactSequenceParser.ts +13 -8
  192. package/src/fetchCid.ts +2 -76
  193. package/src/index.test.ts +22 -1
  194. package/src/index.ts +7 -1
  195. package/src/inputReader.ts +53 -0
  196. package/src/java.ts +708 -0
  197. package/src/javaKeyStoreParser.ts +18 -32
  198. package/src/javaParser.test.ts +1592 -0
  199. package/src/javaParser.ts +2640 -0
  200. package/src/javaScript.ts +36 -0
  201. package/src/javaScriptParser.ts +57 -0
  202. package/src/javaScriptUnparser.test.ts +37 -0
  203. package/src/javaScriptUnparser.ts +7 -0
  204. package/src/javaUnparser.test.ts +37 -0
  205. package/src/javaUnparser.ts +640 -0
  206. package/src/jsonParser.ts +6 -27
  207. package/src/lookaheadParser.ts +2 -6
  208. package/src/negativeLookaheadParser.ts +1 -3
  209. package/src/nonEmptyArrayParser.ts +1 -3
  210. package/src/objectParser.test-d.ts +152 -0
  211. package/src/objectParser.test.ts +71 -0
  212. package/src/objectParser.ts +69 -0
  213. package/src/optionalParser.ts +1 -3
  214. package/src/parser.test.ts +151 -4
  215. package/src/parser.ts +11 -1
  216. package/src/parserConsumedSequenceParser.ts +2 -4
  217. package/src/parserContext.ts +26 -11
  218. package/src/parserError.ts +17 -3
  219. package/src/regexpParser.test.ts +78 -0
  220. package/src/regexpParser.ts +35 -3
  221. package/src/regularExpressionParser.ts +36 -37
  222. package/src/separatedArrayParser.ts +1 -3
  223. package/src/separatedNonEmptyArrayParser.ts +1 -3
  224. package/src/sliceBoundedParser.test.ts +2 -2
  225. package/src/sliceBoundedParser.ts +15 -19
  226. package/src/smaliParser.test.ts +64 -0
  227. package/src/smaliParser.test.ts.md +12 -12
  228. package/src/smaliParser.test.ts.snap +0 -0
  229. package/src/smaliParser.ts +246 -534
  230. package/src/stringEscapes.ts +253 -0
  231. package/src/symbolicExpression.ts +17 -0
  232. package/src/symbolicExpressionParser.test.ts +466 -0
  233. package/src/symbolicExpressionParser.ts +190 -0
  234. package/src/terminatedArrayParser.test.ts +9 -6
  235. package/src/terminatedArrayParser.ts +25 -29
  236. package/src/tupleParser.ts +21 -18
  237. package/src/unionParser.test-d.ts +105 -0
  238. package/src/unionParser.test.ts +18 -17
  239. package/src/unionParser.ts +28 -16
  240. package/src/zig.ts +411 -0
  241. package/src/zigParser.test.ts +1693 -0
  242. package/src/zigParser.ts +1745 -0
  243. package/src/zigUnparser.test.ts +37 -0
  244. package/src/zigUnparser.ts +615 -0
  245. package/src/zipParser.ts +20 -56
  246. package/src/zipUnparser.test.ts +1 -1
  247. package/src/zipUnparser.ts +22 -7
  248. package/tsconfig.json +2 -2
  249. package/build/exactElementSwitchParser.d.ts +0 -3
  250. package/src/exactElementSwitchParser.ts +0 -41
@@ -1,29 +1,91 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  import { getParserName, setParserName } from './parser.js';
2
54
  import { isParserParsingFailedError } from './parserError.js';
3
55
  import { parserImplementationInvariant } from './parserImplementationInvariant.js';
4
56
  import { promiseSettled } from './promiseSettled.js';
5
- export const createDisjunctionParser = (childParsers) => {
57
+ export function createDisjunctionParser(childParsers) {
6
58
  parserImplementationInvariant(childParsers.length > 0, 'Disjunction parser must have at least one child parser.');
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
60
  const disjunctionParser = async (parserContext) => {
8
61
  const parserParsingFailedErrors = [];
9
62
  for (const childParser of childParsers) {
10
- const childParserContext = parserContext.lookahead({
11
- debugName: getParserName(childParser, 'anonymousDisjunctionChild'),
12
- });
13
- const childParserResult = await promiseSettled(childParser(childParserContext));
14
- if (childParserResult.status === 'fulfilled') {
15
- const successfulParserOutput = childParserResult.value;
16
- childParserContext.unlookahead();
17
- childParserContext.dispose();
18
- return successfulParserOutput;
63
+ const env_1 = { stack: [], error: void 0, hasError: false };
64
+ try {
65
+ const childParserContext = __addDisposableResource(env_1, parserContext.lookahead({
66
+ debugName: getParserName(childParser, 'anonymousDisjunctionChild'),
67
+ }), false);
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ const childParserResult = await promiseSettled(childParser(childParserContext));
70
+ if (childParserResult.status === 'fulfilled') {
71
+ const successfulParserOutput = childParserResult.value;
72
+ childParserContext.unlookahead();
73
+ return successfulParserOutput;
74
+ }
75
+ const error = childParserResult.reason;
76
+ if (isParserParsingFailedError(error)) {
77
+ parserParsingFailedErrors.push(error);
78
+ }
79
+ else {
80
+ throw error;
81
+ }
19
82
  }
20
- childParserContext.dispose();
21
- const error = childParserResult.reason;
22
- if (isParserParsingFailedError(error)) {
23
- parserParsingFailedErrors.push(error);
83
+ catch (e_1) {
84
+ env_1.error = e_1;
85
+ env_1.hasError = true;
24
86
  }
25
- else {
26
- throw error;
87
+ finally {
88
+ __disposeResources(env_1);
27
89
  }
28
90
  }
29
91
  return parserContext.invariantJoin(false, parserParsingFailedErrors, 'No disjunction child parser succeeded.');
@@ -34,4 +96,4 @@ export const createDisjunctionParser = (childParsers) => {
34
96
  ')',
35
97
  ].join('');
36
98
  return setParserName(disjunctionParser, name);
37
- };
99
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ import { expectAssignable } from 'tsd';
2
+ import { createDisjunctionParser } from './disjunctionParser.js';
3
+ import { createExactSequenceParser } from './exactSequenceParser.js';
4
+ import { createExactElementParser } from './exactElementParser.js';
5
+ import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
6
+ // Test: basic disjunction of string parsers - output inferred as string
7
+ {
8
+ const parser = createDisjunctionParser([
9
+ createExactElementParser('a'),
10
+ createExactElementParser('b'),
11
+ ]);
12
+ expectAssignable(null);
13
+ expectAssignable(null);
14
+ }
15
+ // Test: disjunction preserves literal types when parsers have explicit literal output types
16
+ {
17
+ const parserA = async () => 'a';
18
+ const parserB = async () => 'b';
19
+ const parser = createDisjunctionParser([parserA, parserB]);
20
+ // Output should be 'a' | 'b', not string
21
+ expectAssignable(null);
22
+ expectAssignable(null);
23
+ }
24
+ // Test: disjunction of parsers with different output types
25
+ {
26
+ const stringParser = createFixedLengthSequenceParser(3);
27
+ const numberParser = () => 42;
28
+ const parser = createDisjunctionParser([
29
+ stringParser,
30
+ numberParser,
31
+ ]);
32
+ // Output should be string | number
33
+ expectAssignable(null);
34
+ expectAssignable(null);
35
+ }
36
+ // Test: nested disjunctions
37
+ {
38
+ const inner = createDisjunctionParser([
39
+ createExactElementParser('a'),
40
+ createExactElementParser('b'),
41
+ ]);
42
+ const parser = createDisjunctionParser([
43
+ inner,
44
+ createExactElementParser('c'),
45
+ ]);
46
+ expectAssignable(null);
47
+ expectAssignable(null);
48
+ }
49
+ // Test: sequence type inferred from child parsers
50
+ {
51
+ const parser = createDisjunctionParser([
52
+ createExactSequenceParser('hello'),
53
+ createExactSequenceParser('world'),
54
+ ]);
55
+ // Parser should be for string sequences, output is string (widened from literals)
56
+ expectAssignable(null);
57
+ }
58
+ // Test: single parser in disjunction
59
+ {
60
+ const parser = createDisjunctionParser([
61
+ createExactSequenceParser('only'),
62
+ ]);
63
+ // Output is string (widened from literal 'only')
64
+ expectAssignable(null);
65
+ }
66
+ // Test: disjunction of object-producing parsers
67
+ {
68
+ const parser1 = async () => ({ type: 'a', value: 1 });
69
+ const parser2 = async () => ({ type: 'b', name: 'test' });
70
+ const parser = createDisjunctionParser([parser1, parser2]);
71
+ expectAssignable(null);
72
+ }
@@ -0,0 +1,4 @@
1
+ import { Parser, ParserOutput, ParserSequence } from "./parser.js";
2
+ type ElementSwitchOutput<ChildParser extends Parser<any, any, any>, DefaultParser extends Parser<any, any, any> | undefined> = ParserOutput<ChildParser> | (DefaultParser extends undefined ? never : ParserOutput<NonNullable<DefaultParser>>);
3
+ export declare function createElementSwitchParser<Element, ChildParser extends Parser<any, any, Element>, DefaultParser extends Parser<any, any, Element> | undefined = undefined>(childParsers: Map<Element, ChildParser>, defaultParser?: DefaultParser): Parser<ElementSwitchOutput<ChildParser, DefaultParser>, ParserSequence<ChildParser>, Element>;
4
+ export {};
@@ -1,7 +1,7 @@
1
1
  import invariant from "invariant";
2
2
  import { getParserName, setParserName } from "./parser.js";
3
3
  import { parserImplementationInvariant } from "./parserImplementationInvariant.js";
4
- export const createElementSwitchParser = (childParsers, defaultParser) => {
4
+ export function createElementSwitchParser(childParsers, defaultParser) {
5
5
  parserImplementationInvariant(childParsers.size > 0, 'Element switch parser must have at least one child parser.');
6
6
  const elementSwitchParser = async (parserContext) => {
7
7
  const currentElement = await parserContext.peek(0);
@@ -9,8 +9,7 @@ export const createElementSwitchParser = (childParsers, defaultParser) => {
9
9
  invariant(currentElement !== undefined, 'Unexpected end of input.');
10
10
  const childParser = childParsers.get(currentElement) ?? defaultParser;
11
11
  parserContext.invariant(childParser, `No child parser found for element: ${String(currentElement)}`);
12
- const childParserOutput = await childParser(parserContext);
13
- return childParserOutput;
12
+ return childParser(parserContext);
14
13
  };
15
14
  const name = [
16
15
  'elementSwitch(',
@@ -19,4 +18,4 @@ export const createElementSwitchParser = (childParsers, defaultParser) => {
19
18
  ')',
20
19
  ].join('');
21
20
  return setParserName(elementSwitchParser, name);
22
- };
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ import { expectAssignable, expectType } from 'tsd';
2
+ import { createElementSwitchParser } from './elementSwitchParser.js';
3
+ // Test: basic element switch with inferred output type
4
+ {
5
+ const parserA = async () => 'a';
6
+ const parserB = async () => 'b';
7
+ const parser = createElementSwitchParser(new Map([
8
+ ['x', parserA],
9
+ ['y', parserB],
10
+ ]));
11
+ // Output should be 'a' | 'b'
12
+ expectAssignable(null);
13
+ expectAssignable(null);
14
+ }
15
+ // Test: element switch with default parser
16
+ {
17
+ const parserA = async () => 'a';
18
+ const defaultParser = async () => 'default';
19
+ const parser = createElementSwitchParser(new Map([
20
+ ['x', parserA],
21
+ ]), defaultParser);
22
+ // Output should be 'a' | 'default'
23
+ expectAssignable(null);
24
+ expectAssignable(null);
25
+ }
26
+ // Test: element switch with number keys (Uint8Array sequence)
27
+ {
28
+ const parser1 = async () => ({ type: 'one' });
29
+ const parser2 = async () => ({ type: 'two' });
30
+ const parser = createElementSwitchParser(new Map([
31
+ [1, parser1],
32
+ [2, parser2],
33
+ ]));
34
+ expectAssignable(null);
35
+ }
36
+ // Test: element switch without default parser has no 'never' in output
37
+ {
38
+ const parserA = async () => 'result';
39
+ const parser = createElementSwitchParser(new Map([
40
+ ['key', parserA],
41
+ ]));
42
+ // Output should just be string, not string | never
43
+ expectType(null);
44
+ }
@@ -1,3 +1,5 @@
1
1
  import { type Parser } from './parser.js';
2
- export declare const createExactSequenceNaiveParser: <Sequence>(sequence: Sequence) => Parser<Sequence, Sequence, unknown>;
3
- export declare const createExactSequenceParser: <Sequence>(expectedSequence: Sequence) => Parser<Sequence, Sequence, unknown>;
2
+ type DeriveBaseSequence<T> = T extends string ? string : T extends Uint8Array ? Uint8Array : T;
3
+ export declare const createExactSequenceNaiveParser: <const Output>(sequence: Output) => Parser<Output, DeriveBaseSequence<Output>, unknown>;
4
+ export declare const createExactSequenceParser: <const Output>(expectedSequence: Output) => Parser<Output, DeriveBaseSequence<Output>, unknown>;
5
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ import { expectType, expectAssignable } from 'tsd';
2
+ import { createExactSequenceParser, createExactSequenceNaiveParser } from './exactSequenceParser.js';
3
+ // Test: string literal output type is preserved, sequence type is string
4
+ {
5
+ const parser = createExactSequenceParser('foo');
6
+ expectType(parser);
7
+ }
8
+ // Test: string literal with 'as const' also works
9
+ {
10
+ const parser = createExactSequenceParser('bar');
11
+ expectType(parser);
12
+ }
13
+ // Test: plain string variable widens to string
14
+ {
15
+ const value = 'baz';
16
+ const parser = createExactSequenceParser(value);
17
+ expectType(parser);
18
+ }
19
+ // Test: Uint8Array sequence type is preserved
20
+ {
21
+ const bytes = new Uint8Array([1, 2, 3]);
22
+ const parser = createExactSequenceParser(bytes);
23
+ // Output is the specific Uint8Array instance type, Sequence is Uint8Array
24
+ expectAssignable(parser);
25
+ }
26
+ // Test: naive parser has same type behavior
27
+ {
28
+ const parser = createExactSequenceNaiveParser('hello');
29
+ expectType(parser);
30
+ }
31
+ // Test: naive parser with Uint8Array
32
+ {
33
+ const bytes = new Uint8Array([0xff]);
34
+ const parser = createExactSequenceNaiveParser(bytes);
35
+ expectAssignable(parser);
36
+ }
package/build/fetchCid.js CHANGED
@@ -1,8 +1,5 @@
1
1
  import fsPromises from 'node:fs/promises';
2
- import path from 'node:path';
3
- import pMemoize from 'p-memoize';
4
- import envPaths from 'env-paths';
5
- const paths = envPaths('parser.futpib.github.io');
2
+ import { fetchCid as fetchCidFromIpfs } from '@futpib/fetch-cid';
6
3
  function readableWebStreamOnFinish(readableWebStream, onFinish) {
7
4
  const reader = readableWebStream.getReader();
8
5
  const stream = new ReadableStream({
@@ -29,65 +26,6 @@ function readableWebStreamOnFinish(readableWebStream, onFinish) {
29
26
  });
30
27
  return stream;
31
28
  }
32
- class FsCache {
33
- get _basePath() {
34
- return path.join(paths.cache, 'fetchCid');
35
- }
36
- _getKeyPath(key) {
37
- return path.join(this._basePath, key.replaceAll('/', '_'));
38
- }
39
- async get(key) {
40
- try {
41
- const file = await fsPromises.open(this._getKeyPath(key), 'r');
42
- const stream = file.readableWebStream();
43
- const streamWithClose = readableWebStreamOnFinish(stream, () => {
44
- file.close();
45
- });
46
- return [streamWithClose, undefined];
47
- }
48
- catch (error) {
49
- if (error.code === 'ENOENT') {
50
- return undefined;
51
- }
52
- throw error;
53
- }
54
- }
55
- async has(key) {
56
- const streams = await this.get(key);
57
- try {
58
- return streams !== undefined;
59
- }
60
- finally {
61
- for (const stream of streams ?? []) {
62
- await stream?.cancel();
63
- }
64
- }
65
- }
66
- async set(key, [_, value]) {
67
- await fsPromises.mkdir(this._basePath, {
68
- recursive: true,
69
- });
70
- const file = await fsPromises.open(this._getKeyPath(key), 'w');
71
- try {
72
- for await (const chunk of value) {
73
- await file.write(chunk);
74
- }
75
- }
76
- finally {
77
- await file.close();
78
- }
79
- }
80
- async delete(key) {
81
- await fsPromises.unlink(this._getKeyPath(key));
82
- }
83
- }
84
- async function reallyFetchCid(cid) {
85
- const response = await fetch('https://ipfs.io/ipfs/' + cid);
86
- return response.body.tee();
87
- }
88
- const cachedReallyFetchCid = pMemoize(reallyFetchCid, {
89
- cache: new FsCache(),
90
- });
91
29
  export async function fetchCid(cidOrPath) {
92
30
  if (cidOrPath.includes('/')) {
93
31
  const file = await fsPromises.open(cidOrPath, 'r');
@@ -97,7 +35,5 @@ export async function fetchCid(cidOrPath) {
97
35
  });
98
36
  return streamWithClose;
99
37
  }
100
- const [readable, unused] = await cachedReallyFetchCid(cidOrPath);
101
- await unused?.cancel();
102
- return readable;
38
+ return fetchCidFromIpfs(cidOrPath);
103
39
  }
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { type Parser, runParser, runParserWithRemainingInput, setParserName, getParserName, cloneParser, type RunParserOptions, type RunParserWithRemainingInputResult, } from './parser.js';
1
+ export { type Parser, type ParserOutput, type ParserSequence, runParser, runParserWithRemainingInput, setParserName, getParserName, cloneParser, type RunParserOptions, type RunParserWithRemainingInputResult, } from './parser.js';
2
2
  export type { ParserContext, } from './parserContext.js';
3
3
  export { type ParserInputCompanion, StringParserInputCompanion, stringParserInputCompanion, Uint8ArrayParserInputCompanion, uint8ArrayParserInputCompanion, } from './parserInputCompanion.js';
4
4
  export { type UnparserOutputCompanion, StringUnparserOutputCompanion, stringUnparserOutputCompanion, Uint8ArrayUnparserOutputCompanion, uint8ArrayUnparserOutputCompanion, } from './unparserOutputCompanion.js';
@@ -7,6 +7,7 @@ export { parserCreatorCompose, parserCreatorComposeMem, } from './parserCreatorC
7
7
  export { promiseCompose, } from './promiseCompose.js';
8
8
  export type { DeriveSequenceElement, } from './sequence.js';
9
9
  export { createTupleParser, } from './tupleParser.js';
10
+ export { createObjectParser, } from './objectParser.js';
10
11
  export { createExactSequenceParser, } from './exactSequenceParser.js';
11
12
  export { createFixedLengthSequenceParser, } from './fixedLengthSequenceParser.js';
12
13
  export { createArrayParser, } from './arrayParser.js';
@@ -34,7 +35,7 @@ export { createSequenceTerminatedSequenceParser, } from './sequenceTerminatedSeq
34
35
  export { createQuantifierParser, } from './quantifierParser.js';
35
36
  export { createSkipToParser, } from './skipToParser.js';
36
37
  export { createDebugLogInputParser, } from './debugLogInputParser.js';
37
- export { createElementSwitchParser, } from './exactElementSwitchParser.js';
38
+ export { createElementSwitchParser, } from './elementSwitchParser.js';
38
39
  export { createParserConsumedSequenceParser, } from './parserConsumedSequenceParser.js';
39
40
  export { type Unparser, type UnparserResult, runUnparser, } from './unparser.js';
40
41
  export { type UnparserContext, WriteLater, WriteEarlier, UnparserContextImplementation, } from './unparserContext.js';
package/build/index.js CHANGED
@@ -5,6 +5,7 @@ export { isParserError, isParserParsingFailedError, isParserParsingJoinError, no
5
5
  export { parserCreatorCompose, parserCreatorComposeMem, } from './parserCreatorCompose.js';
6
6
  export { promiseCompose, } from './promiseCompose.js';
7
7
  export { createTupleParser, } from './tupleParser.js';
8
+ export { createObjectParser, } from './objectParser.js';
8
9
  export { createExactSequenceParser, } from './exactSequenceParser.js';
9
10
  export { createFixedLengthSequenceParser, } from './fixedLengthSequenceParser.js';
10
11
  export { createArrayParser, } from './arrayParser.js';
@@ -32,7 +33,7 @@ export { createSequenceTerminatedSequenceParser, } from './sequenceTerminatedSeq
32
33
  export { createQuantifierParser, } from './quantifierParser.js';
33
34
  export { createSkipToParser, } from './skipToParser.js';
34
35
  export { createDebugLogInputParser, } from './debugLogInputParser.js';
35
- export { createElementSwitchParser, } from './exactElementSwitchParser.js';
36
+ export { createElementSwitchParser, } from './elementSwitchParser.js';
36
37
  export { createParserConsumedSequenceParser, } from './parserConsumedSequenceParser.js';
37
38
  export { runUnparser, } from './unparser.js';
38
39
  export { WriteLater, WriteEarlier, UnparserContextImplementation, } from './unparserContext.js';
@@ -1,2 +1,17 @@
1
1
  import test from 'ava';
2
- test.todo('TODO');
2
+ import { runParser, createExactSequenceParser, createTupleParser, stringParserInputCompanion, } from './index.js';
3
+ test('exports main parser functions', async (t) => {
4
+ // Test that runParser is exported and works
5
+ const parser = createExactSequenceParser('hello');
6
+ const result = await runParser(parser, 'hello', stringParserInputCompanion);
7
+ t.is(result, 'hello');
8
+ });
9
+ test('exports parser combinators', async (t) => {
10
+ // Test that createTupleParser is exported and works
11
+ const tupleParser = createTupleParser([
12
+ createExactSequenceParser('a'),
13
+ createExactSequenceParser('b'),
14
+ ]);
15
+ const result = await runParser(tupleParser, 'ab', stringParserInputCompanion);
16
+ t.deepEqual(result, ['a', 'b']);
17
+ });
@@ -2,9 +2,13 @@ import { type ParserInputCompanion } from './parserInputCompanion.js';
2
2
  import { type InputReaderState } from './inputReaderState.js';
3
3
  export type InputReader<Sequence, Element> = {
4
4
  get position(): number;
5
+ get furthestReadPosition(): number;
6
+ get furthestPeekedPosition(): number;
5
7
  peek(offset: number): Promise<Element | undefined>;
6
8
  peekSequence(start: number, end: number): Promise<Sequence | undefined>;
7
9
  skip(offset: number): void;
10
+ updateFurthestReadPosition(position: number): void;
11
+ updateFurthestPeekedPosition(position: number): void;
8
12
  lookahead(): InputReader<Sequence, Element>;
9
13
  toInputReaderState(): InputReaderState<Sequence>;
10
14
  };
@@ -13,6 +17,8 @@ export declare class InputReaderImplementation<Sequence, Element> implements Inp
13
17
  private readonly _inputAsyncIterator;
14
18
  private readonly _id;
15
19
  private _position;
20
+ private _furthestReadPosition;
21
+ private _furthestPeekedPosition;
16
22
  private _uncommitedSkipOffset;
17
23
  private _inputAsyncIteratorDone;
18
24
  private readonly _promiseMutex;
@@ -20,6 +26,10 @@ export declare class InputReaderImplementation<Sequence, Element> implements Inp
20
26
  constructor(_parserInputCompanion: ParserInputCompanion<Sequence, Element>, _inputAsyncIterator: AsyncIterator<Sequence>);
21
27
  get [Symbol.toStringTag](): string;
22
28
  get position(): number;
29
+ get furthestReadPosition(): number;
30
+ get furthestPeekedPosition(): number;
31
+ updateFurthestReadPosition(position: number): void;
32
+ updateFurthestPeekedPosition(position: number): void;
23
33
  peek(offset: number): Promise<Element | undefined>;
24
34
  peekSequence(start: number, end: number): Promise<Sequence | undefined>;
25
35
  skip(offset: number): void;
@@ -8,6 +8,8 @@ export class InputReaderImplementation {
8
8
  _inputAsyncIterator;
9
9
  _id = inputReaderId++;
10
10
  _position = 0;
11
+ _furthestReadPosition = 0;
12
+ _furthestPeekedPosition = 0;
11
13
  _uncommitedSkipOffset = 0;
12
14
  _inputAsyncIteratorDone = false;
13
15
  _promiseMutex = new PromiseMutex();
@@ -27,8 +29,21 @@ export class InputReaderImplementation {
27
29
  get position() {
28
30
  return this._position;
29
31
  }
32
+ get furthestReadPosition() {
33
+ return this._furthestReadPosition;
34
+ }
35
+ get furthestPeekedPosition() {
36
+ return this._furthestPeekedPosition;
37
+ }
38
+ updateFurthestReadPosition(position) {
39
+ this._furthestReadPosition = Math.max(this._furthestReadPosition, position);
40
+ }
41
+ updateFurthestPeekedPosition(position) {
42
+ this._furthestPeekedPosition = Math.max(this._furthestPeekedPosition, position);
43
+ }
30
44
  async peek(offset) {
31
45
  parserImplementationInvariant(offset >= 0, 'offset >= 0');
46
+ this.updateFurthestPeekedPosition(this._position + offset);
32
47
  offset += this._uncommitedSkipOffset;
33
48
  const element = this._sequenceBuffer.peek(offset);
34
49
  if (element !== undefined) {
@@ -59,6 +74,9 @@ export class InputReaderImplementation {
59
74
  parserImplementationInvariant(end >= start, 'end (%s) >= start (%s)', start, end);
60
75
  parserImplementationInvariant(Number.isSafeInteger(start), 'start (%s) is not a safe integer', start);
61
76
  parserImplementationInvariant(Number.isSafeInteger(end), 'end (%s) is not a safe integer', end);
77
+ if (end > start) {
78
+ this.updateFurthestPeekedPosition(this._position + end - 1);
79
+ }
62
80
  start += this._uncommitedSkipOffset;
63
81
  end += this._uncommitedSkipOffset;
64
82
  const sequence = this._sequenceBuffer.peekSequence(start, end);
@@ -74,6 +92,7 @@ export class InputReaderImplementation {
74
92
  skip(offset) {
75
93
  parserImplementationInvariant(offset >= 0, 'offset >= 0');
76
94
  this._position += offset;
95
+ this.updateFurthestReadPosition(this._position);
77
96
  if (this._promiseMutex.isLocked) {
78
97
  this._uncommitedSkipOffset += offset;
79
98
  }
@@ -113,21 +132,38 @@ class InputReaderLookaheadImplementation {
113
132
  get position() {
114
133
  return this._initialInputReaderPosition + this._offset;
115
134
  }
135
+ get furthestReadPosition() {
136
+ return this._inputReader.furthestReadPosition;
137
+ }
138
+ get furthestPeekedPosition() {
139
+ return this._inputReader.furthestPeekedPosition;
140
+ }
141
+ updateFurthestReadPosition(position) {
142
+ this._inputReader.updateFurthestReadPosition(position);
143
+ }
144
+ updateFurthestPeekedPosition(position) {
145
+ this._inputReader.updateFurthestPeekedPosition(position);
146
+ }
116
147
  async peek(offset) {
117
148
  const inputReaderMovedForward = this._inputReader.position - this._initialInputReaderPosition;
118
149
  this._initialInputReaderPosition = this._inputReader.position;
119
150
  this._offset -= inputReaderMovedForward;
151
+ this.updateFurthestPeekedPosition(this.position + offset);
120
152
  return this._inputReader.peek(this._offset + offset);
121
153
  }
122
154
  async peekSequence(start, end) {
123
155
  const inputReaderMovedForward = this._inputReader.position - this._initialInputReaderPosition;
124
156
  this._initialInputReaderPosition = this._inputReader.position;
125
157
  this._offset -= inputReaderMovedForward;
158
+ if (end > start) {
159
+ this.updateFurthestPeekedPosition(this.position + end - 1);
160
+ }
126
161
  return this._inputReader.peekSequence(this._offset + start, this._offset + end);
127
162
  }
128
163
  skip(offset) {
129
164
  parserImplementationInvariant(offset >= 0, 'offset >= 0');
130
165
  this._offset += offset;
166
+ this.updateFurthestReadPosition(this.position);
131
167
  }
132
168
  lookahead() {
133
169
  const lookahead = new InputReaderLookaheadImplementation(this._inputReader);