@futpib/parser 1.0.3 → 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 (262) 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 +89 -0
  20. package/build/bash.js +1 -0
  21. package/build/bashParser.d.ts +6 -0
  22. package/build/bashParser.js +335 -0
  23. package/build/bashParser.test.d.ts +1 -0
  24. package/build/bashParser.test.js +343 -0
  25. package/build/bashParserEdgeCases.test.d.ts +1 -0
  26. package/build/bashParserEdgeCases.test.js +117 -0
  27. package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
  28. package/build/dalvikBytecodeParser/addressConversion.js +334 -0
  29. package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
  30. package/build/dalvikBytecodeParser/formatParsers.js +13 -14
  31. package/build/dalvikBytecodeParser.d.ts +60 -31
  32. package/build/dalvikBytecodeParser.js +92 -35
  33. package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
  34. package/build/dalvikBytecodeParser.test-d.js +268 -0
  35. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
  36. package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
  37. package/build/dalvikBytecodeUnparser.d.ts +2 -2
  38. package/build/dalvikBytecodeUnparser.js +23 -23
  39. package/build/dalvikBytecodeUnparser.test.js +7 -7
  40. package/build/dalvikExecutable.d.ts +3 -3
  41. package/build/dalvikExecutable.test-d.d.ts +1 -0
  42. package/build/dalvikExecutable.test-d.js +59 -0
  43. package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
  44. package/build/dalvikExecutableParser/typedNumbers.js +3 -0
  45. package/build/dalvikExecutableParser.d.ts +2 -1
  46. package/build/dalvikExecutableParser.js +96 -77
  47. package/build/dalvikExecutableParser.test.js +24 -3
  48. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
  49. package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
  50. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
  51. package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
  52. package/build/dalvikExecutableUnparser.d.ts +2 -2
  53. package/build/dalvikExecutableUnparser.test.js +2 -1
  54. package/build/disjunctionParser.d.ts +5 -3
  55. package/build/disjunctionParser.js +79 -17
  56. package/build/disjunctionParser.test-d.d.ts +1 -0
  57. package/build/disjunctionParser.test-d.js +72 -0
  58. package/build/elementSwitchParser.d.ts +4 -0
  59. package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
  60. package/build/elementSwitchParser.test-d.d.ts +1 -0
  61. package/build/elementSwitchParser.test-d.js +44 -0
  62. package/build/exactSequenceParser.d.ts +4 -2
  63. package/build/exactSequenceParser.test-d.d.ts +1 -0
  64. package/build/exactSequenceParser.test-d.js +36 -0
  65. package/build/fetchCid.js +2 -66
  66. package/build/index.d.ts +25 -2
  67. package/build/index.js +23 -1
  68. package/build/index.test.js +16 -1
  69. package/build/inputReader.d.ts +10 -0
  70. package/build/inputReader.js +36 -0
  71. package/build/java.d.ts +502 -0
  72. package/build/java.js +2 -0
  73. package/build/javaKeyStoreParser.js +14 -17
  74. package/build/javaParser.d.ts +51 -0
  75. package/build/javaParser.js +1538 -0
  76. package/build/javaParser.test.d.ts +1 -0
  77. package/build/javaParser.test.js +1287 -0
  78. package/build/javaScript.d.ts +35 -0
  79. package/build/javaScript.js +1 -0
  80. package/build/javaScriptParser.d.ts +9 -0
  81. package/build/javaScriptParser.js +34 -0
  82. package/build/javaScriptUnparser.d.ts +3 -0
  83. package/build/javaScriptUnparser.js +4 -0
  84. package/build/javaScriptUnparser.test.d.ts +1 -0
  85. package/build/javaScriptUnparser.test.js +24 -0
  86. package/build/javaUnparser.d.ts +2 -0
  87. package/build/javaUnparser.js +519 -0
  88. package/build/javaUnparser.test.d.ts +1 -0
  89. package/build/javaUnparser.test.js +24 -0
  90. package/build/javascript.d.ts +35 -0
  91. package/build/javascript.js +1 -0
  92. package/build/javascriptParser.d.ts +9 -0
  93. package/build/javascriptParser.js +34 -0
  94. package/build/javascriptUnparser.d.ts +3 -0
  95. package/build/javascriptUnparser.js +4 -0
  96. package/build/javascriptUnparser.test.d.ts +1 -0
  97. package/build/javascriptUnparser.test.js +24 -0
  98. package/build/jsonParser.js +2 -12
  99. package/build/lazyMessageError.d.ts +3 -0
  100. package/build/lookaheadParser.js +60 -3
  101. package/build/negativeLookaheadParser.js +70 -11
  102. package/build/nonEmptyArrayParser.js +72 -13
  103. package/build/objectParser.d.ts +12 -0
  104. package/build/objectParser.js +31 -0
  105. package/build/objectParser.test-d.d.ts +1 -0
  106. package/build/objectParser.test-d.js +112 -0
  107. package/build/objectParser.test.d.ts +1 -0
  108. package/build/objectParser.test.js +55 -0
  109. package/build/optionalParser.js +69 -10
  110. package/build/parser.d.ts +4 -0
  111. package/build/parser.js +3 -1
  112. package/build/parser.test.js +114 -1
  113. package/build/parserConsumedSequenceParser.js +66 -7
  114. package/build/parserContext.d.ts +6 -0
  115. package/build/parserContext.js +20 -11
  116. package/build/parserError.d.ts +119 -27
  117. package/build/parserError.js +16 -8
  118. package/build/regexpParser.d.ts +2 -0
  119. package/build/regexpParser.js +101 -0
  120. package/build/regexpParser.test.d.ts +1 -0
  121. package/build/regexpParser.test.js +114 -0
  122. package/build/regularExpression.d.ts +63 -0
  123. package/build/regularExpression.js +1 -0
  124. package/build/regularExpressionParser.d.ts +3 -0
  125. package/build/regularExpressionParser.js +600 -0
  126. package/build/regularExpressionParser.test.d.ts +1 -0
  127. package/build/regularExpressionParser.test.js +89 -0
  128. package/build/separatedArrayParser.js +73 -14
  129. package/build/separatedNonEmptyArrayParser.js +73 -14
  130. package/build/sliceBoundedParser.js +62 -5
  131. package/build/smaliParser.d.ts +7 -7
  132. package/build/smaliParser.js +185 -268
  133. package/build/smaliParser.test.js +58 -0
  134. package/build/stringEscapes.d.ts +5 -0
  135. package/build/stringEscapes.js +244 -0
  136. package/build/symbolicExpression.d.ts +29 -0
  137. package/build/symbolicExpression.js +1 -0
  138. package/build/symbolicExpressionParser.d.ts +4 -0
  139. package/build/symbolicExpressionParser.js +123 -0
  140. package/build/symbolicExpressionParser.test.d.ts +1 -0
  141. package/build/symbolicExpressionParser.test.js +289 -0
  142. package/build/terminatedArrayParser.js +113 -38
  143. package/build/terminatedArrayParser.test.js +4 -2
  144. package/build/tupleParser.d.ts +7 -15
  145. package/build/tupleParser.js +1 -0
  146. package/build/unionParser.d.ts +5 -3
  147. package/build/unionParser.js +7 -2
  148. package/build/unionParser.test-d.d.ts +1 -0
  149. package/build/unionParser.test-d.js +72 -0
  150. package/build/unionParser.test.js +10 -11
  151. package/build/zig.d.ts +280 -0
  152. package/build/zig.js +2 -0
  153. package/build/zigParser.d.ts +3 -0
  154. package/build/zigParser.js +1119 -0
  155. package/build/zigParser.test.d.ts +1 -0
  156. package/build/zigParser.test.js +1590 -0
  157. package/build/zigUnparser.d.ts +2 -0
  158. package/build/zigUnparser.js +460 -0
  159. package/build/zigUnparser.test.d.ts +1 -0
  160. package/build/zigUnparser.test.js +24 -0
  161. package/build/zipParser.js +19 -32
  162. package/build/zipUnparser.js +19 -7
  163. package/build/zipUnparser.test.js +1 -1
  164. package/node_modules-@types/s-expression/index.d.ts +5 -0
  165. package/package.json +25 -6
  166. package/src/androidPackageParser.ts +33 -60
  167. package/src/arbitraryDalvikBytecode.ts +39 -31
  168. package/src/arbitraryDalvikExecutable.ts +65 -20
  169. package/src/arbitraryJava.ts +804 -0
  170. package/src/arbitraryJavaScript.ts +410 -0
  171. package/src/arbitraryZig.ts +380 -0
  172. package/src/arrayParser.ts +1 -3
  173. package/src/backsmali.ts +35 -4
  174. package/src/bash.ts +127 -0
  175. package/src/bashParser.test.ts +590 -0
  176. package/src/bashParser.ts +498 -0
  177. package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
  178. package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
  179. package/src/dalvikBytecodeParser.test-d.ts +310 -0
  180. package/src/dalvikBytecodeParser.ts +194 -69
  181. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
  182. package/src/dalvikBytecodeUnparser.test.ts +7 -7
  183. package/src/dalvikBytecodeUnparser.ts +31 -30
  184. package/src/dalvikExecutable.test-d.ts +132 -0
  185. package/src/dalvikExecutable.ts +3 -3
  186. package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
  187. package/src/dalvikExecutableParser.test.ts +37 -3
  188. package/src/dalvikExecutableParser.test.ts.md +163 -2
  189. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  190. package/src/dalvikExecutableParser.ts +121 -139
  191. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
  192. package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
  193. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
  194. package/src/dalvikExecutableUnparser.test.ts +3 -2
  195. package/src/dalvikExecutableUnparser.ts +4 -4
  196. package/src/disjunctionParser.test-d.ts +105 -0
  197. package/src/disjunctionParser.ts +18 -15
  198. package/src/elementSwitchParser.test-d.ts +74 -0
  199. package/src/elementSwitchParser.ts +51 -0
  200. package/src/exactSequenceParser.test-d.ts +43 -0
  201. package/src/exactSequenceParser.ts +13 -8
  202. package/src/fetchCid.ts +2 -76
  203. package/src/index.test.ts +22 -1
  204. package/src/index.ts +119 -2
  205. package/src/inputReader.ts +53 -0
  206. package/src/java.ts +708 -0
  207. package/src/javaKeyStoreParser.ts +18 -32
  208. package/src/javaParser.test.ts +1592 -0
  209. package/src/javaParser.ts +2640 -0
  210. package/src/javaScript.ts +36 -0
  211. package/src/javaScriptParser.ts +57 -0
  212. package/src/javaScriptUnparser.test.ts +37 -0
  213. package/src/javaScriptUnparser.ts +7 -0
  214. package/src/javaUnparser.test.ts +37 -0
  215. package/src/javaUnparser.ts +640 -0
  216. package/src/jsonParser.ts +6 -27
  217. package/src/lookaheadParser.ts +2 -6
  218. package/src/negativeLookaheadParser.ts +1 -3
  219. package/src/nonEmptyArrayParser.ts +1 -3
  220. package/src/objectParser.test-d.ts +152 -0
  221. package/src/objectParser.test.ts +71 -0
  222. package/src/objectParser.ts +69 -0
  223. package/src/optionalParser.ts +1 -3
  224. package/src/parser.test.ts +151 -4
  225. package/src/parser.ts +11 -1
  226. package/src/parserConsumedSequenceParser.ts +2 -4
  227. package/src/parserContext.ts +26 -11
  228. package/src/parserError.ts +17 -3
  229. package/src/regexpParser.test.ts +264 -0
  230. package/src/regexpParser.ts +126 -0
  231. package/src/regularExpression.ts +24 -0
  232. package/src/regularExpressionParser.test.ts +102 -0
  233. package/src/regularExpressionParser.ts +920 -0
  234. package/src/separatedArrayParser.ts +1 -3
  235. package/src/separatedNonEmptyArrayParser.ts +1 -3
  236. package/src/sliceBoundedParser.test.ts +2 -2
  237. package/src/sliceBoundedParser.ts +15 -19
  238. package/src/smaliParser.test.ts +64 -0
  239. package/src/smaliParser.test.ts.md +12 -12
  240. package/src/smaliParser.test.ts.snap +0 -0
  241. package/src/smaliParser.ts +246 -534
  242. package/src/stringEscapes.ts +253 -0
  243. package/src/symbolicExpression.ts +17 -0
  244. package/src/symbolicExpressionParser.test.ts +466 -0
  245. package/src/symbolicExpressionParser.ts +190 -0
  246. package/src/terminatedArrayParser.test.ts +9 -6
  247. package/src/terminatedArrayParser.ts +25 -29
  248. package/src/tupleParser.ts +21 -18
  249. package/src/unionParser.test-d.ts +105 -0
  250. package/src/unionParser.test.ts +18 -17
  251. package/src/unionParser.ts +28 -16
  252. package/src/zig.ts +411 -0
  253. package/src/zigParser.test.ts +1693 -0
  254. package/src/zigParser.ts +1745 -0
  255. package/src/zigUnparser.test.ts +37 -0
  256. package/src/zigUnparser.ts +615 -0
  257. package/src/zipParser.ts +20 -56
  258. package/src/zipUnparser.test.ts +1 -1
  259. package/src/zipUnparser.ts +22 -7
  260. package/tsconfig.json +2 -2
  261. package/build/exactElementSwitchParser.d.ts +0 -3
  262. package/src/exactElementSwitchParser.ts +0 -41
@@ -0,0 +1,410 @@
1
+ import * as fc from 'fast-check';
2
+ import { type JavaScriptProgram, type StripMeta } from './javaScriptParser.js';
3
+ import type * as estree from 'estree';
4
+
5
+ type Expression = StripMeta<estree.Expression>;
6
+ type Statement = StripMeta<estree.Statement>;
7
+ type Identifier = StripMeta<estree.Identifier>;
8
+
9
+ const jsKeywords = new Set([
10
+ 'abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', 'catch',
11
+ 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do',
12
+ 'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final',
13
+ 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import',
14
+ 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new',
15
+ 'null', 'package', 'private', 'protected', 'public', 'return', 'short',
16
+ 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws',
17
+ 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while',
18
+ 'with', 'yield', 'undefined', 'NaN', 'Infinity',
19
+ ]);
20
+
21
+ const arbitraryIdentifierName = fc.stringMatching(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/).filter(
22
+ id => !jsKeywords.has(id),
23
+ );
24
+
25
+ const arbitraryIdentifier: fc.Arbitrary<Identifier> = fc.record({
26
+ type: fc.constant('Identifier' as const),
27
+ name: arbitraryIdentifierName,
28
+ });
29
+
30
+ const arbitraryStringLiteral = fc.record({
31
+ type: fc.constant('Literal' as const),
32
+ value: fc.stringMatching(/^[a-zA-Z0-9 ]*$/),
33
+ });
34
+
35
+ const arbitraryNumberLiteral = fc.record({
36
+ type: fc.constant('Literal' as const),
37
+ value: fc.integer({ min: 0, max: 999 }),
38
+ });
39
+
40
+ const arbitraryBooleanLiteral = fc.record({
41
+ type: fc.constant('Literal' as const),
42
+ value: fc.boolean(),
43
+ });
44
+
45
+ const arbitraryNullLiteral = fc.record({
46
+ type: fc.constant('Literal' as const),
47
+ value: fc.constant(null),
48
+ });
49
+
50
+ const arbitraryThisExpression = fc.record({
51
+ type: fc.constant('ThisExpression' as const),
52
+ });
53
+
54
+ const arbitraryLeafExpression: fc.Arbitrary<Expression> = fc.oneof(
55
+ arbitraryIdentifier as fc.Arbitrary<Expression>,
56
+ arbitraryStringLiteral as fc.Arbitrary<Expression>,
57
+ arbitraryNumberLiteral as fc.Arbitrary<Expression>,
58
+ arbitraryBooleanLiteral as fc.Arbitrary<Expression>,
59
+ arbitraryNullLiteral as fc.Arbitrary<Expression>,
60
+ arbitraryThisExpression as fc.Arbitrary<Expression>,
61
+ );
62
+
63
+ const safeBinaryOperators: Array<estree.BinaryOperator> = [
64
+ '==', '!=', '===', '!==', '<', '<=', '>', '>=',
65
+ '<<', '>>', '>>>',
66
+ '+', '-', '*', '/', '%', '**',
67
+ '|', '^', '&',
68
+ 'instanceof',
69
+ ];
70
+
71
+ const arbitraryBinaryExpression = fc.record({
72
+ type: fc.constant('BinaryExpression' as const),
73
+ operator: fc.oneof(...safeBinaryOperators.map(op => fc.constant(op))),
74
+ left: arbitraryLeafExpression,
75
+ right: arbitraryLeafExpression,
76
+ });
77
+
78
+ const arbitraryLogicalExpression = fc.record({
79
+ type: fc.constant('LogicalExpression' as const),
80
+ operator: fc.oneof(
81
+ fc.constant('||' as const),
82
+ fc.constant('&&' as const),
83
+ fc.constant('??' as const),
84
+ ),
85
+ left: arbitraryLeafExpression,
86
+ right: arbitraryLeafExpression,
87
+ });
88
+
89
+ const safeUnaryOperators: Array<estree.UnaryOperator> = [
90
+ '-', '+', '!', '~', 'typeof', 'void',
91
+ ];
92
+
93
+ const arbitraryUnaryExpression = fc.record({
94
+ type: fc.constant('UnaryExpression' as const),
95
+ operator: fc.oneof(...safeUnaryOperators.map(op => fc.constant(op))),
96
+ prefix: fc.constant(true as const),
97
+ argument: arbitraryLeafExpression,
98
+ });
99
+
100
+ const arbitraryUpdateExpression = fc.record({
101
+ type: fc.constant('UpdateExpression' as const),
102
+ operator: fc.oneof(
103
+ fc.constant('++' as const),
104
+ fc.constant('--' as const),
105
+ ),
106
+ argument: arbitraryIdentifier as fc.Arbitrary<Expression>,
107
+ prefix: fc.boolean(),
108
+ });
109
+
110
+ const arbitraryAssignmentExpression = fc.record({
111
+ type: fc.constant('AssignmentExpression' as const),
112
+ operator: fc.constant('=' as const),
113
+ left: arbitraryIdentifier,
114
+ right: arbitraryLeafExpression,
115
+ });
116
+
117
+ const arbitraryConditionalExpression = fc.record({
118
+ type: fc.constant('ConditionalExpression' as const),
119
+ test: arbitraryLeafExpression,
120
+ consequent: arbitraryLeafExpression,
121
+ alternate: arbitraryLeafExpression,
122
+ });
123
+
124
+ const arbitraryCallExpression = fc.record({
125
+ type: fc.constant('CallExpression' as const),
126
+ callee: arbitraryIdentifier as fc.Arbitrary<Expression>,
127
+ arguments: fc.array(arbitraryLeafExpression, { minLength: 0, maxLength: 3 }),
128
+ optional: fc.constant(false),
129
+ });
130
+
131
+ const arbitraryMemberExpression = fc.record({
132
+ type: fc.constant('MemberExpression' as const),
133
+ object: arbitraryIdentifier as fc.Arbitrary<Expression>,
134
+ property: arbitraryIdentifier as fc.Arbitrary<Expression>,
135
+ computed: fc.constant(false),
136
+ optional: fc.constant(false),
137
+ });
138
+
139
+ const arbitraryArrayExpression = fc.record({
140
+ type: fc.constant('ArrayExpression' as const),
141
+ elements: fc.array(arbitraryLeafExpression, { minLength: 0, maxLength: 3 }),
142
+ });
143
+
144
+ const arbitraryProperty = fc.record({
145
+ type: fc.constant('Property' as const),
146
+ key: arbitraryIdentifier as fc.Arbitrary<Expression>,
147
+ value: arbitraryLeafExpression,
148
+ kind: fc.constant('init' as const),
149
+ method: fc.constant(false),
150
+ shorthand: fc.constant(false),
151
+ computed: fc.constant(false),
152
+ });
153
+
154
+ const arbitraryObjectExpression = fc.record({
155
+ type: fc.constant('ObjectExpression' as const),
156
+ properties: fc.array(arbitraryProperty, { minLength: 0, maxLength: 3 }),
157
+ });
158
+
159
+ const arbitraryNewExpression = fc.record({
160
+ type: fc.constant('NewExpression' as const),
161
+ callee: arbitraryIdentifier as fc.Arbitrary<Expression>,
162
+ arguments: fc.array(arbitraryLeafExpression, { minLength: 0, maxLength: 3 }),
163
+ });
164
+
165
+ const arbitraryExpression: fc.Arbitrary<Expression> = fc.oneof(
166
+ { weight: 5, arbitrary: arbitraryLeafExpression },
167
+ { weight: 2, arbitrary: arbitraryBinaryExpression as fc.Arbitrary<Expression> },
168
+ { weight: 2, arbitrary: arbitraryLogicalExpression as fc.Arbitrary<Expression> },
169
+ { weight: 2, arbitrary: arbitraryUnaryExpression as fc.Arbitrary<Expression> },
170
+ { weight: 1, arbitrary: arbitraryUpdateExpression as fc.Arbitrary<Expression> },
171
+ { weight: 1, arbitrary: arbitraryAssignmentExpression as fc.Arbitrary<Expression> },
172
+ { weight: 1, arbitrary: arbitraryConditionalExpression as fc.Arbitrary<Expression> },
173
+ { weight: 2, arbitrary: arbitraryCallExpression as fc.Arbitrary<Expression> },
174
+ { weight: 1, arbitrary: arbitraryMemberExpression as fc.Arbitrary<Expression> },
175
+ { weight: 1, arbitrary: arbitraryArrayExpression as fc.Arbitrary<Expression> },
176
+ { weight: 1, arbitrary: arbitraryObjectExpression as fc.Arbitrary<Expression> },
177
+ { weight: 1, arbitrary: arbitraryNewExpression as fc.Arbitrary<Expression> },
178
+ );
179
+
180
+ const arbitraryExpressionStatement: fc.Arbitrary<Statement> = arbitraryExpression
181
+ .filter(expr => {
182
+ if (expr.type === 'Literal' && typeof (expr as { value: unknown }).value === 'string') {
183
+ return false;
184
+ }
185
+
186
+ if (expr.type === 'ObjectExpression') {
187
+ return false;
188
+ }
189
+
190
+ return true;
191
+ })
192
+ .map(expression => ({
193
+ type: 'ExpressionStatement' as const,
194
+ expression,
195
+ }));
196
+
197
+ const arbitraryVariableDeclaration: fc.Arbitrary<Statement> = fc.record({
198
+ type: fc.constant('VariableDeclaration' as const),
199
+ kind: fc.constant('var' as const),
200
+ declarations: fc.array(
201
+ fc.record({
202
+ type: fc.constant('VariableDeclarator' as const),
203
+ id: arbitraryIdentifier,
204
+ init: fc.oneof(
205
+ fc.constant(null),
206
+ arbitraryLeafExpression,
207
+ ),
208
+ }),
209
+ { minLength: 1, maxLength: 3 },
210
+ ),
211
+ });
212
+
213
+ const arbitraryReturnStatement: fc.Arbitrary<Statement> = fc.record({
214
+ type: fc.constant('ReturnStatement' as const),
215
+ argument: fc.oneof(
216
+ fc.constant(null),
217
+ arbitraryLeafExpression,
218
+ ),
219
+ });
220
+
221
+ const arbitraryEmptyStatement: fc.Arbitrary<Statement> = fc.record({
222
+ type: fc.constant('EmptyStatement' as const),
223
+ });
224
+
225
+ const arbitraryThrowStatement: fc.Arbitrary<Statement> = fc.record({
226
+ type: fc.constant('ThrowStatement' as const),
227
+ argument: arbitraryLeafExpression,
228
+ });
229
+
230
+ const arbitrarySimpleNonFunctionStatement: fc.Arbitrary<Statement> = fc.oneof(
231
+ { weight: 3, arbitrary: arbitraryExpressionStatement },
232
+ { weight: 2, arbitrary: arbitraryVariableDeclaration },
233
+ { weight: 1, arbitrary: arbitraryEmptyStatement },
234
+ { weight: 1, arbitrary: arbitraryThrowStatement },
235
+ );
236
+
237
+ const arbitrarySimpleBlockStatement = fc.record({
238
+ type: fc.constant('BlockStatement' as const),
239
+ body: fc.array(arbitrarySimpleNonFunctionStatement, { minLength: 0, maxLength: 3 }),
240
+ });
241
+
242
+ const arbitraryFunctionBodyStatement: fc.Arbitrary<Statement> = fc.oneof(
243
+ { weight: 3, arbitrary: arbitraryExpressionStatement },
244
+ { weight: 2, arbitrary: arbitraryVariableDeclaration },
245
+ { weight: 2, arbitrary: arbitraryReturnStatement },
246
+ { weight: 1, arbitrary: arbitraryEmptyStatement },
247
+ { weight: 1, arbitrary: arbitraryThrowStatement },
248
+ );
249
+
250
+ const arbitraryFunctionBodyBlockStatement = fc.record({
251
+ type: fc.constant('BlockStatement' as const),
252
+ body: fc.array(arbitraryFunctionBodyStatement, { minLength: 0, maxLength: 3 }),
253
+ });
254
+
255
+ const arbitraryArrowFunctionExpression = fc.oneof(
256
+ fc.record({
257
+ type: fc.constant('ArrowFunctionExpression' as const),
258
+ id: fc.constant(null),
259
+ params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
260
+ body: arbitraryFunctionBodyBlockStatement,
261
+ expression: fc.constant(false),
262
+ generator: fc.constant(false),
263
+ async: fc.constant(false),
264
+ }),
265
+ fc.record({
266
+ type: fc.constant('ArrowFunctionExpression' as const),
267
+ id: fc.constant(null),
268
+ params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
269
+ body: arbitraryLeafExpression,
270
+ expression: fc.constant(true),
271
+ generator: fc.constant(false),
272
+ async: fc.constant(false),
273
+ }),
274
+ );
275
+
276
+ const arbitraryFunctionExpression = fc.record({
277
+ type: fc.constant('FunctionExpression' as const),
278
+ id: fc.constant(null),
279
+ params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
280
+ body: arbitraryFunctionBodyBlockStatement,
281
+ expression: fc.constant(false),
282
+ generator: fc.constant(false),
283
+ async: fc.constant(false),
284
+ });
285
+
286
+ const arbitraryIfStatement: fc.Arbitrary<Statement> = fc.record({
287
+ type: fc.constant('IfStatement' as const),
288
+ test: arbitraryLeafExpression,
289
+ consequent: arbitrarySimpleBlockStatement as fc.Arbitrary<Statement>,
290
+ alternate: fc.oneof(
291
+ fc.constant(null),
292
+ arbitrarySimpleBlockStatement as fc.Arbitrary<Statement>,
293
+ ),
294
+ });
295
+
296
+ const arbitraryWhileStatement: fc.Arbitrary<Statement> = fc.record({
297
+ type: fc.constant('WhileStatement' as const),
298
+ test: arbitraryLeafExpression,
299
+ body: arbitrarySimpleBlockStatement as fc.Arbitrary<Statement>,
300
+ });
301
+
302
+ const arbitraryForStatement: fc.Arbitrary<Statement> = fc.record({
303
+ type: fc.constant('ForStatement' as const),
304
+ init: fc.oneof(
305
+ fc.constant(null),
306
+ fc.record({
307
+ type: fc.constant('VariableDeclaration' as const),
308
+ kind: fc.constant('let' as const),
309
+ declarations: fc.tuple(
310
+ fc.record({
311
+ type: fc.constant('VariableDeclarator' as const),
312
+ id: arbitraryIdentifier,
313
+ init: fc.oneof(
314
+ fc.constant(null),
315
+ arbitraryNumberLiteral as fc.Arbitrary<Expression>,
316
+ ),
317
+ }),
318
+ ).map(([decl]) => [decl]),
319
+ }),
320
+ ),
321
+ test: fc.oneof(
322
+ fc.constant(null),
323
+ arbitraryLeafExpression,
324
+ ),
325
+ update: fc.oneof(
326
+ fc.constant(null),
327
+ arbitraryLeafExpression,
328
+ ),
329
+ body: arbitrarySimpleBlockStatement as fc.Arbitrary<Statement>,
330
+ });
331
+
332
+ const arbitraryCatchClause = fc.record({
333
+ type: fc.constant('CatchClause' as const),
334
+ param: fc.oneof(
335
+ fc.constant(null),
336
+ arbitraryIdentifier,
337
+ ),
338
+ body: arbitrarySimpleBlockStatement,
339
+ });
340
+
341
+ const arbitraryTryStatement: fc.Arbitrary<Statement> = fc.oneof(
342
+ fc.record({
343
+ type: fc.constant('TryStatement' as const),
344
+ block: arbitrarySimpleBlockStatement,
345
+ handler: arbitraryCatchClause,
346
+ finalizer: fc.oneof(
347
+ fc.constant(null),
348
+ arbitrarySimpleBlockStatement,
349
+ ),
350
+ }),
351
+ fc.record({
352
+ type: fc.constant('TryStatement' as const),
353
+ block: arbitrarySimpleBlockStatement,
354
+ handler: fc.constant(null),
355
+ finalizer: arbitrarySimpleBlockStatement,
356
+ }),
357
+ );
358
+
359
+ const arbitraryFunctionDeclaration: fc.Arbitrary<Statement> = fc.record({
360
+ type: fc.constant('FunctionDeclaration' as const),
361
+ id: arbitraryIdentifier,
362
+ params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
363
+ body: arbitraryFunctionBodyBlockStatement,
364
+ expression: fc.constant(false),
365
+ generator: fc.constant(false),
366
+ async: fc.constant(false),
367
+ });
368
+
369
+ const arbitraryTopLevelExpressionStatement: fc.Arbitrary<Statement> = fc.oneof(
370
+ arbitraryExpression,
371
+ arbitraryArrowFunctionExpression as fc.Arbitrary<Expression>,
372
+ arbitraryFunctionExpression as fc.Arbitrary<Expression>,
373
+ )
374
+ .filter(expr => {
375
+ if (expr.type === 'Literal' && typeof (expr as { value: unknown }).value === 'string') {
376
+ return false;
377
+ }
378
+
379
+ if (expr.type === 'ObjectExpression') {
380
+ return false;
381
+ }
382
+
383
+ if (expr.type === 'FunctionExpression') {
384
+ return false;
385
+ }
386
+
387
+ return true;
388
+ })
389
+ .map(expression => ({
390
+ type: 'ExpressionStatement' as const,
391
+ expression,
392
+ }));
393
+
394
+ const arbitraryStatement: fc.Arbitrary<Statement> = fc.oneof(
395
+ { weight: 3, arbitrary: arbitraryTopLevelExpressionStatement },
396
+ { weight: 2, arbitrary: arbitraryVariableDeclaration },
397
+ { weight: 2, arbitrary: arbitraryIfStatement },
398
+ { weight: 1, arbitrary: arbitraryWhileStatement },
399
+ { weight: 1, arbitrary: arbitraryForStatement },
400
+ { weight: 1, arbitrary: arbitraryEmptyStatement },
401
+ { weight: 1, arbitrary: arbitraryFunctionDeclaration },
402
+ { weight: 1, arbitrary: arbitraryThrowStatement },
403
+ { weight: 1, arbitrary: arbitraryTryStatement },
404
+ );
405
+
406
+ export const arbitraryJavaScriptProgram: fc.Arbitrary<JavaScriptProgram> = fc.record({
407
+ type: fc.constant('Program' as const),
408
+ sourceType: fc.constant('script' as const),
409
+ body: fc.array(arbitraryStatement, { minLength: 0, maxLength: 5 }),
410
+ });