@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
@@ -0,0 +1,804 @@
1
+ import * as fc from 'fast-check';
2
+
3
+ const javaKeywords = new Set([
4
+ 'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch', 'char',
5
+ 'class', 'const', 'continue', 'default', 'do', 'double', 'else', 'enum',
6
+ 'extends', 'final', 'finally', 'float', 'for', 'goto', 'if', 'implements',
7
+ 'import', 'instanceof', 'int', 'interface', 'long', 'native', 'new',
8
+ 'package', 'private', 'protected', 'public', 'return', 'short', 'static',
9
+ 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws',
10
+ 'transient', 'try', 'void', 'volatile', 'while', 'true', 'false', 'null',
11
+ 'sealed', 'non-sealed', 'record', 'yield', 'var',
12
+ ]);
13
+
14
+ const arbitraryJavaIdentifier = fc.stringMatching(/^[a-zA-Z_][a-zA-Z0-9_]*$/).filter(
15
+ id => !javaKeywords.has(id),
16
+ );
17
+
18
+ const arbitrarySimpleName = fc.record({
19
+ type: fc.constant('SimpleName' as const),
20
+ identifier: arbitraryJavaIdentifier,
21
+ });
22
+
23
+ const arbitraryName: fc.Arbitrary<{ type: 'Name'; identifier: string; qualifier?: unknown }> = fc.nat({ max: 2 }).chain(depth => {
24
+ if (depth === 0) {
25
+ return fc.record({
26
+ type: fc.constant('Name' as const),
27
+ identifier: arbitraryJavaIdentifier,
28
+ });
29
+ }
30
+
31
+ return arbitraryJavaIdentifier.chain(identifier => {
32
+ const buildQualifier = (d: number): fc.Arbitrary<{ type: 'Name'; identifier: string; qualifier?: unknown }> => {
33
+ if (d === 0) {
34
+ return fc.record({
35
+ type: fc.constant('Name' as const),
36
+ identifier: arbitraryJavaIdentifier,
37
+ });
38
+ }
39
+
40
+ return fc.record({
41
+ type: fc.constant('Name' as const),
42
+ identifier: arbitraryJavaIdentifier,
43
+ qualifier: buildQualifier(d - 1),
44
+ });
45
+ };
46
+
47
+ return fc.record({
48
+ type: fc.constant('Name' as const),
49
+ identifier: fc.constant(identifier),
50
+ qualifier: buildQualifier(depth - 1),
51
+ });
52
+ });
53
+ });
54
+
55
+ // Types
56
+
57
+ const arbitraryPrimitiveType = fc.record({
58
+ type: fc.constant('PrimitiveType' as const),
59
+ type_: fc.oneof(
60
+ fc.constant('BOOLEAN' as const),
61
+ fc.constant('BYTE' as const),
62
+ fc.constant('CHAR' as const),
63
+ fc.constant('DOUBLE' as const),
64
+ fc.constant('FLOAT' as const),
65
+ fc.constant('INT' as const),
66
+ fc.constant('LONG' as const),
67
+ fc.constant('SHORT' as const),
68
+ ),
69
+ annotations: fc.constant([] as unknown[]),
70
+ });
71
+
72
+ const arbitraryVoidType = fc.record({
73
+ type: fc.constant('VoidType' as const),
74
+ annotations: fc.constant([] as unknown[]),
75
+ });
76
+
77
+ const arbitraryAnnotation = fc.record({
78
+ type: fc.constant('MarkerAnnotationExpr' as const),
79
+ name: arbitraryName,
80
+ });
81
+
82
+ type ClassOrInterfaceTypeShape = {
83
+ type: 'ClassOrInterfaceType';
84
+ name: { type: 'SimpleName'; identifier: string };
85
+ scope?: ClassOrInterfaceTypeShape;
86
+ typeArguments?: unknown[];
87
+ annotations: unknown[];
88
+ };
89
+
90
+ const arbitraryClassOrInterfaceType: fc.Arbitrary<ClassOrInterfaceTypeShape> = fc.nat({ max: 1 }).chain(depth => {
91
+ const buildType = (d: number): fc.Arbitrary<ClassOrInterfaceTypeShape> => {
92
+ if (d === 0) {
93
+ return fc.record({
94
+ type: fc.constant('ClassOrInterfaceType' as const),
95
+ name: arbitrarySimpleName,
96
+ annotations: fc.constant([] as unknown[]),
97
+ });
98
+ }
99
+
100
+ return fc.record({
101
+ type: fc.constant('ClassOrInterfaceType' as const),
102
+ scope: buildType(d - 1),
103
+ name: arbitrarySimpleName,
104
+ annotations: fc.constant([] as unknown[]),
105
+ });
106
+ };
107
+
108
+ return buildType(depth);
109
+ });
110
+
111
+ // ClassOrInterfaceType with optional type arguments (for extends/implements)
112
+ const arbitraryClassOrInterfaceTypeWithTypeArgs: fc.Arbitrary<ClassOrInterfaceTypeShape> = fc.nat({ max: 1 }).chain(depth => {
113
+ const buildType = (d: number): fc.Arbitrary<ClassOrInterfaceTypeShape> => {
114
+ const baseFields = {
115
+ type: fc.constant('ClassOrInterfaceType' as const),
116
+ name: arbitrarySimpleName,
117
+ annotations: fc.constant([] as unknown[]),
118
+ };
119
+
120
+ if (d === 0) {
121
+ return fc.oneof(
122
+ fc.record(baseFields),
123
+ fc.record({
124
+ ...baseFields,
125
+ typeArguments: fc.array(
126
+ fc.oneof(
127
+ arbitraryPrimitiveType,
128
+ fc.record({
129
+ type: fc.constant('ClassOrInterfaceType' as const),
130
+ name: arbitrarySimpleName,
131
+ annotations: fc.constant([] as unknown[]),
132
+ }),
133
+ fc.record({
134
+ type: fc.constant('WildcardType' as const),
135
+ annotations: fc.constant([] as unknown[]),
136
+ }),
137
+ ),
138
+ { minLength: 1, maxLength: 2 },
139
+ ),
140
+ }),
141
+ );
142
+ }
143
+
144
+ return fc.record({
145
+ ...baseFields,
146
+ scope: buildType(d - 1),
147
+ });
148
+ };
149
+
150
+ return buildType(depth);
151
+ });
152
+
153
+ type JavaTypeShape = {
154
+ type: string;
155
+ [key: string]: unknown;
156
+ };
157
+
158
+ const arbitraryNonArrayType: fc.Arbitrary<JavaTypeShape> = fc.oneof(
159
+ arbitraryPrimitiveType,
160
+ arbitraryClassOrInterfaceType,
161
+ );
162
+
163
+ const arbitraryType: fc.Arbitrary<JavaTypeShape> = fc.oneof(
164
+ { weight: 3, arbitrary: arbitraryNonArrayType },
165
+ {
166
+ weight: 1,
167
+ arbitrary: arbitraryNonArrayType.map(componentType => ({
168
+ type: 'ArrayType' as const,
169
+ componentType,
170
+ origin: 'TYPE' as const,
171
+ annotations: [],
172
+ })),
173
+ },
174
+ );
175
+
176
+ const arbitraryReturnType: fc.Arbitrary<JavaTypeShape> = fc.oneof(
177
+ { weight: 3, arbitrary: arbitraryType },
178
+ { weight: 1, arbitrary: arbitraryVoidType },
179
+ );
180
+
181
+ // Leaf expressions (used as operands in compound expressions to avoid precedence issues)
182
+
183
+ const arbitraryNameExpr = fc.record({
184
+ type: fc.constant('NameExpr' as const),
185
+ name: arbitrarySimpleName,
186
+ });
187
+
188
+ const arbitraryStringLiteralExpr = fc.record({
189
+ type: fc.constant('StringLiteralExpr' as const),
190
+ value: fc.oneof(
191
+ fc.stringMatching(/^[a-zA-Z0-9 ]*$/),
192
+ fc.constantFrom('hello\nworld', 'tab\there', 'back\\slash', 'quote\ttab\nnewline'),
193
+ ),
194
+ });
195
+
196
+ const arbitraryIntegerLiteralExpr = fc.record({
197
+ type: fc.constant('IntegerLiteralExpr' as const),
198
+ value: fc.nat({ max: 999 }).map(n => String(n)),
199
+ });
200
+
201
+ const arbitraryNullLiteralExpr = fc.record({
202
+ type: fc.constant('NullLiteralExpr' as const),
203
+ });
204
+
205
+ const arbitraryBooleanLiteralExpr = fc.record({
206
+ type: fc.constant('BooleanLiteralExpr' as const),
207
+ value: fc.boolean(),
208
+ });
209
+
210
+ const arbitraryThisExpr = fc.record({
211
+ type: fc.constant('ThisExpr' as const),
212
+ });
213
+
214
+ const arbitraryLeafExpression: fc.Arbitrary<unknown> = fc.oneof(
215
+ arbitraryNameExpr,
216
+ arbitraryStringLiteralExpr,
217
+ arbitraryIntegerLiteralExpr,
218
+ arbitraryNullLiteralExpr,
219
+ arbitraryBooleanLiteralExpr,
220
+ arbitraryThisExpr,
221
+ );
222
+
223
+ // Compound expressions (only use leaf operands)
224
+
225
+ const arbitraryMethodCallExpr: fc.Arbitrary<unknown> = fc.oneof(
226
+ // Without scope
227
+ fc.record({
228
+ type: fc.constant('MethodCallExpr' as const),
229
+ name: arbitrarySimpleName,
230
+ arguments: fc.array(arbitraryLeafExpression, { maxLength: 2 }),
231
+ }),
232
+ // With scope
233
+ fc.record({
234
+ type: fc.constant('MethodCallExpr' as const),
235
+ scope: arbitraryLeafExpression,
236
+ name: arbitrarySimpleName,
237
+ arguments: fc.array(arbitraryLeafExpression, { maxLength: 2 }),
238
+ }),
239
+ );
240
+
241
+ const arbitraryFieldAccessExpr: fc.Arbitrary<unknown> = fc.record({
242
+ type: fc.constant('FieldAccessExpr' as const),
243
+ scope: arbitraryLeafExpression,
244
+ name: arbitrarySimpleName,
245
+ });
246
+
247
+ const arbitraryEnclosedExpr: fc.Arbitrary<unknown> = fc.record({
248
+ type: fc.constant('EnclosedExpr' as const),
249
+ inner: arbitraryLeafExpression,
250
+ });
251
+
252
+ const arbitraryArrayAccessExpr: fc.Arbitrary<unknown> = fc.record({
253
+ type: fc.constant('ArrayAccessExpr' as const),
254
+ name: arbitraryLeafExpression,
255
+ index: arbitraryLeafExpression,
256
+ });
257
+
258
+ const arbitraryObjectCreationExpr: fc.Arbitrary<unknown> = fc.oneof(
259
+ fc.record({
260
+ type: fc.constant('ObjectCreationExpr' as const),
261
+ type_: arbitraryClassOrInterfaceType,
262
+ arguments: fc.array(arbitraryLeafExpression, { maxLength: 2 }),
263
+ }),
264
+ // With diamond operator (empty typeArguments)
265
+ fc.record({
266
+ type: fc.constant('ObjectCreationExpr' as const),
267
+ type_: arbitraryClassOrInterfaceType.map(t => ({
268
+ ...t,
269
+ typeArguments: [] as unknown[],
270
+ })),
271
+ arguments: fc.array(arbitraryLeafExpression, { maxLength: 2 }),
272
+ }),
273
+ );
274
+
275
+ const arbitraryPrimaryExpression: fc.Arbitrary<unknown> = fc.oneof(
276
+ arbitraryLeafExpression,
277
+ arbitraryMethodCallExpr,
278
+ arbitraryFieldAccessExpr,
279
+ arbitraryEnclosedExpr,
280
+ arbitraryArrayAccessExpr,
281
+ arbitraryObjectCreationExpr,
282
+ );
283
+
284
+ const arbitraryBinaryOperator = fc.oneof(
285
+ fc.constant('PLUS'),
286
+ fc.constant('MINUS'),
287
+ fc.constant('MULTIPLY'),
288
+ fc.constant('DIVIDE'),
289
+ fc.constant('REMAINDER'),
290
+ fc.constant('LESS'),
291
+ fc.constant('GREATER'),
292
+ fc.constant('LESS_EQUALS'),
293
+ fc.constant('GREATER_EQUALS'),
294
+ fc.constant('EQUALS'),
295
+ fc.constant('NOT_EQUALS'),
296
+ fc.constant('AND'),
297
+ fc.constant('OR'),
298
+ );
299
+
300
+ const arbitraryBinaryExpr: fc.Arbitrary<unknown> = fc.record({
301
+ type: fc.constant('BinaryExpr' as const),
302
+ left: arbitraryLeafExpression,
303
+ right: arbitraryLeafExpression,
304
+ operator: arbitraryBinaryOperator,
305
+ });
306
+
307
+ // UnaryExpr in parser output has NO prefix field - operator encodes prefix/postfix
308
+ const arbitraryUnaryExpr: fc.Arbitrary<unknown> = fc.record({
309
+ type: fc.constant('UnaryExpr' as const),
310
+ operator: fc.oneof(
311
+ fc.constant('PREFIX_INCREMENT'),
312
+ fc.constant('PREFIX_DECREMENT'),
313
+ fc.constant('POSTFIX_INCREMENT'),
314
+ fc.constant('POSTFIX_DECREMENT'),
315
+ fc.constant('MINUS'),
316
+ fc.constant('PLUS'),
317
+ fc.constant('LOGICAL_COMPLEMENT'),
318
+ ),
319
+ expression: arbitraryLeafExpression,
320
+ });
321
+
322
+ const arbitraryAssignOperator = fc.oneof(
323
+ fc.constant('ASSIGN'),
324
+ fc.constant('PLUS'),
325
+ fc.constant('MINUS'),
326
+ fc.constant('MULTIPLY'),
327
+ fc.constant('DIVIDE'),
328
+ );
329
+
330
+ const arbitraryAssignExpr: fc.Arbitrary<unknown> = fc.record({
331
+ type: fc.constant('AssignExpr' as const),
332
+ target: arbitraryNameExpr,
333
+ value: arbitraryLeafExpression,
334
+ operator: arbitraryAssignOperator,
335
+ });
336
+
337
+ const arbitraryConditionalExpr: fc.Arbitrary<unknown> = fc.record({
338
+ type: fc.constant('ConditionalExpr' as const),
339
+ condition: arbitraryLeafExpression,
340
+ thenExpr: arbitraryLeafExpression,
341
+ elseExpr: arbitraryLeafExpression,
342
+ });
343
+
344
+ const arbitraryCastExpr: fc.Arbitrary<unknown> = fc.record({
345
+ type: fc.constant('CastExpr' as const),
346
+ type_: arbitraryType,
347
+ expression: arbitraryPrimaryExpression,
348
+ });
349
+
350
+ const arbitraryInstanceOfExpr: fc.Arbitrary<unknown> = fc.record({
351
+ type: fc.constant('InstanceOfExpr' as const),
352
+ expression: arbitraryLeafExpression,
353
+ type_: fc.oneof(
354
+ arbitraryClassOrInterfaceType as fc.Arbitrary<JavaTypeShape>,
355
+ arbitraryNonArrayType.map(componentType => ({
356
+ type: 'ArrayType' as const,
357
+ componentType,
358
+ origin: 'TYPE' as const,
359
+ annotations: [] as unknown[],
360
+ })),
361
+ ),
362
+ });
363
+
364
+ // Lambda expressions
365
+ const arbitraryLambdaExpr: fc.Arbitrary<unknown> = fc.oneof(
366
+ // With parenthesized params
367
+ fc.record({
368
+ type: fc.constant('LambdaExpr' as const),
369
+ parameters: fc.array(
370
+ fc.record({
371
+ type: fc.constant('Parameter' as const),
372
+ annotations: fc.constant([]),
373
+ modifiers: fc.constant([]),
374
+ isVarArgs: fc.constant(false),
375
+ varArgsAnnotations: fc.constant([]),
376
+ name: arbitrarySimpleName,
377
+ type_: fc.constant({ type: 'UnknownType', annotations: [] }),
378
+ }),
379
+ { maxLength: 2 },
380
+ ),
381
+ body: fc.oneof(
382
+ // Expression body (wrapped in ExpressionStmt)
383
+ arbitraryLeafExpression.map(expr => ({
384
+ type: 'ExpressionStmt' as const,
385
+ expression: expr,
386
+ })),
387
+ // Block body
388
+ fc.constant({ type: 'BlockStmt' as const, statements: [] }),
389
+ ),
390
+ isEnclosingParameters: fc.constant(true),
391
+ }),
392
+ // Single unparenthesized param
393
+ fc.record({
394
+ type: fc.constant('LambdaExpr' as const),
395
+ parameters: arbitrarySimpleName.map(name => ([{
396
+ type: 'Parameter' as const,
397
+ annotations: [],
398
+ modifiers: [],
399
+ isVarArgs: false,
400
+ varArgsAnnotations: [],
401
+ name,
402
+ type_: { type: 'UnknownType', annotations: [] },
403
+ }])),
404
+ body: fc.oneof(
405
+ arbitraryLeafExpression.map(expr => ({
406
+ type: 'ExpressionStmt' as const,
407
+ expression: expr,
408
+ })),
409
+ fc.constant({ type: 'BlockStmt' as const, statements: [] }),
410
+ ),
411
+ isEnclosingParameters: fc.constant(false),
412
+ }),
413
+ );
414
+
415
+ const arbitraryExpression: fc.Arbitrary<unknown> = fc.oneof(
416
+ { weight: 4, arbitrary: arbitraryLeafExpression },
417
+ { weight: 1, arbitrary: arbitraryBinaryExpr },
418
+ { weight: 1, arbitrary: arbitraryUnaryExpr },
419
+ { weight: 1, arbitrary: arbitraryAssignExpr },
420
+ { weight: 1, arbitrary: arbitraryConditionalExpr },
421
+ { weight: 1, arbitrary: arbitraryCastExpr },
422
+ { weight: 1, arbitrary: arbitraryEnclosedExpr },
423
+ { weight: 1, arbitrary: arbitraryMethodCallExpr },
424
+ { weight: 1, arbitrary: arbitraryFieldAccessExpr },
425
+ { weight: 1, arbitrary: arbitraryObjectCreationExpr },
426
+ { weight: 1, arbitrary: arbitraryArrayAccessExpr },
427
+ { weight: 1, arbitrary: arbitraryInstanceOfExpr },
428
+ { weight: 1, arbitrary: arbitraryLambdaExpr },
429
+ );
430
+
431
+ // Variable declarations
432
+
433
+ const arbitraryVariableDeclarator: fc.Arbitrary<unknown> = fc.record({
434
+ type: fc.constant('VariableDeclarator' as const),
435
+ name: arbitrarySimpleName,
436
+ type_: arbitraryType,
437
+ }).chain(base =>
438
+ fc.oneof(
439
+ fc.constant(base),
440
+ arbitraryLeafExpression.map(init => ({
441
+ ...base,
442
+ initializer: init,
443
+ })),
444
+ ),
445
+ );
446
+
447
+ const arbitraryVariableDeclarationExpr: fc.Arbitrary<unknown> = arbitraryType.chain(type_ =>
448
+ fc.record({
449
+ type: fc.constant('VariableDeclarationExpr' as const),
450
+ modifiers: fc.constant([]),
451
+ annotations: fc.constant([]),
452
+ variables: fc.array(
453
+ fc.record({
454
+ type: fc.constant('VariableDeclarator' as const),
455
+ name: arbitrarySimpleName,
456
+ type_: fc.constant(type_),
457
+ }).chain(base =>
458
+ fc.oneof(
459
+ fc.constant(base),
460
+ arbitraryLeafExpression.map(init => ({
461
+ ...base,
462
+ initializer: init,
463
+ })),
464
+ ),
465
+ ),
466
+ { minLength: 1, maxLength: 2 },
467
+ ),
468
+ }),
469
+ );
470
+
471
+ // Statements
472
+
473
+ const arbitraryBlockStmt: fc.Arbitrary<unknown> = fc.record({
474
+ type: fc.constant('BlockStmt' as const),
475
+ statements: fc.constant([]),
476
+ });
477
+
478
+ const arbitraryExpressionStmt: fc.Arbitrary<unknown> = fc.record({
479
+ type: fc.constant('ExpressionStmt' as const),
480
+ expression: arbitraryExpression,
481
+ });
482
+
483
+ const arbitraryReturnStmt: fc.Arbitrary<unknown> = fc.oneof(
484
+ fc.constant({ type: 'ReturnStmt' as const }),
485
+ fc.record({
486
+ type: fc.constant('ReturnStmt' as const),
487
+ expression: arbitraryExpression,
488
+ }),
489
+ );
490
+
491
+ const arbitraryThrowStmt: fc.Arbitrary<unknown> = fc.record({
492
+ type: fc.constant('ThrowStmt' as const),
493
+ expression: arbitraryExpression,
494
+ });
495
+
496
+ const arbitraryIfStmt: fc.Arbitrary<unknown> = fc.oneof(
497
+ fc.record({
498
+ type: fc.constant('IfStmt' as const),
499
+ condition: arbitraryExpression,
500
+ thenStmt: arbitraryBlockStmt,
501
+ }),
502
+ fc.record({
503
+ type: fc.constant('IfStmt' as const),
504
+ condition: arbitraryExpression,
505
+ thenStmt: arbitraryBlockStmt,
506
+ elseStmt: arbitraryBlockStmt,
507
+ }),
508
+ );
509
+
510
+ const arbitraryForStmt: fc.Arbitrary<unknown> = fc.oneof(
511
+ // Empty for
512
+ fc.record({
513
+ type: fc.constant('ForStmt' as const),
514
+ initialization: fc.constant([]),
515
+ update: fc.constant([]),
516
+ body: arbitraryBlockStmt,
517
+ }),
518
+ // For with init and compare
519
+ fc.record({
520
+ type: fc.constant('ForStmt' as const),
521
+ initialization: fc.array(arbitraryVariableDeclarationExpr, { minLength: 1, maxLength: 1 }),
522
+ compare: arbitraryExpression,
523
+ update: fc.array(arbitraryExpression, { maxLength: 2 }),
524
+ body: arbitraryBlockStmt,
525
+ }),
526
+ );
527
+
528
+ const arbitraryForEachStmt: fc.Arbitrary<unknown> = fc.record({
529
+ type: fc.constant('ForEachStmt' as const),
530
+ variable: arbitraryVariableDeclarationExpr,
531
+ iterable: arbitraryExpression,
532
+ body: arbitraryBlockStmt,
533
+ });
534
+
535
+ const arbitraryParameter: fc.Arbitrary<unknown> = fc.record({
536
+ type: fc.constant('Parameter' as const),
537
+ modifiers: fc.constant([]),
538
+ annotations: fc.constant([]),
539
+ type_: arbitraryType,
540
+ isVarArgs: fc.constant(false),
541
+ varArgsAnnotations: fc.constant([]),
542
+ name: arbitrarySimpleName,
543
+ });
544
+
545
+ const arbitraryCatchClause: fc.Arbitrary<unknown> = fc.record({
546
+ type: fc.constant('CatchClause' as const),
547
+ parameter: arbitraryParameter,
548
+ body: fc.record({
549
+ type: fc.constant('BlockStmt' as const),
550
+ statements: fc.constant([]),
551
+ }),
552
+ });
553
+
554
+ const arbitraryTryStmt: fc.Arbitrary<unknown> = fc.oneof(
555
+ // try-catch
556
+ fc.record({
557
+ type: fc.constant('TryStmt' as const),
558
+ resources: fc.constant([]),
559
+ tryBlock: fc.record({
560
+ type: fc.constant('BlockStmt' as const),
561
+ statements: fc.constant([]),
562
+ }),
563
+ catchClauses: fc.array(arbitraryCatchClause, { minLength: 1, maxLength: 2 }),
564
+ }),
565
+ // try-catch-finally
566
+ fc.record({
567
+ type: fc.constant('TryStmt' as const),
568
+ resources: fc.constant([]),
569
+ tryBlock: fc.record({
570
+ type: fc.constant('BlockStmt' as const),
571
+ statements: fc.constant([]),
572
+ }),
573
+ catchClauses: fc.array(arbitraryCatchClause, { maxLength: 1 }),
574
+ finallyBlock: fc.record({
575
+ type: fc.constant('BlockStmt' as const),
576
+ statements: fc.constant([]),
577
+ }),
578
+ }),
579
+ // try-with-resources
580
+ fc.record({
581
+ type: fc.constant('TryStmt' as const),
582
+ resources: fc.array(arbitraryVariableDeclarationExpr, { minLength: 1, maxLength: 1 }),
583
+ tryBlock: fc.record({
584
+ type: fc.constant('BlockStmt' as const),
585
+ statements: fc.constant([]),
586
+ }),
587
+ catchClauses: fc.constant([]),
588
+ }),
589
+ );
590
+
591
+ const arbitrarySwitchEntry: fc.Arbitrary<unknown> = fc.oneof(
592
+ // case
593
+ fc.record({
594
+ type: fc.constant('SwitchEntry' as const),
595
+ isDefault: fc.constant(false),
596
+ labels: fc.array(arbitraryExpression, { minLength: 1, maxLength: 1 }),
597
+ statements: fc.constant([]),
598
+ type_: fc.constant('STATEMENT_GROUP' as const),
599
+ }),
600
+ // default
601
+ fc.record({
602
+ type: fc.constant('SwitchEntry' as const),
603
+ isDefault: fc.constant(true),
604
+ labels: fc.constant([]),
605
+ statements: fc.constant([]),
606
+ type_: fc.constant('STATEMENT_GROUP' as const),
607
+ }),
608
+ );
609
+
610
+ const arbitrarySwitchStmt: fc.Arbitrary<unknown> = fc.record({
611
+ type: fc.constant('SwitchStmt' as const),
612
+ selector: arbitraryExpression,
613
+ entries: fc.array(arbitrarySwitchEntry, { maxLength: 3 }),
614
+ });
615
+
616
+ const arbitraryExplicitConstructorInvocationStmt: fc.Arbitrary<unknown> = fc.record({
617
+ type: fc.constant('ExplicitConstructorInvocationStmt' as const),
618
+ isThis: fc.boolean(),
619
+ arguments: fc.array(arbitraryLeafExpression, { maxLength: 2 }),
620
+ });
621
+
622
+ const arbitraryLocalVarDeclStmt: fc.Arbitrary<unknown> = fc.record({
623
+ type: fc.constant('ExpressionStmt' as const),
624
+ expression: arbitraryVariableDeclarationExpr,
625
+ });
626
+
627
+ const arbitraryStatement: fc.Arbitrary<unknown> = fc.oneof(
628
+ { weight: 2, arbitrary: arbitraryBlockStmt },
629
+ { weight: 2, arbitrary: arbitraryExpressionStmt },
630
+ { weight: 2, arbitrary: arbitraryReturnStmt },
631
+ { weight: 1, arbitrary: arbitraryThrowStmt },
632
+ { weight: 1, arbitrary: arbitraryIfStmt },
633
+ { weight: 1, arbitrary: arbitraryForStmt },
634
+ { weight: 1, arbitrary: arbitraryForEachStmt },
635
+ { weight: 1, arbitrary: arbitraryTryStmt },
636
+ { weight: 1, arbitrary: arbitrarySwitchStmt },
637
+ { weight: 1, arbitrary: arbitraryExplicitConstructorInvocationStmt },
638
+ { weight: 1, arbitrary: arbitraryLocalVarDeclStmt },
639
+ );
640
+
641
+ // Body declarations
642
+
643
+ const arbitraryModifier = fc.record({
644
+ type: fc.constant('Modifier' as const),
645
+ keyword: fc.oneof(
646
+ fc.constant('PUBLIC' as const),
647
+ fc.constant('PROTECTED' as const),
648
+ fc.constant('PRIVATE' as const),
649
+ fc.constant('STATIC' as const),
650
+ fc.constant('FINAL' as const),
651
+ fc.constant('ABSTRACT' as const),
652
+ ),
653
+ });
654
+
655
+ const arbitraryFieldDeclaration: fc.Arbitrary<unknown> = arbitraryType.chain(type_ =>
656
+ fc.record({
657
+ type: fc.constant('FieldDeclaration' as const),
658
+ modifiers: fc.array(arbitraryModifier, { maxLength: 2 }),
659
+ annotations: fc.array(arbitraryAnnotation, { maxLength: 1 }),
660
+ variables: fc.array(
661
+ fc.record({
662
+ type: fc.constant('VariableDeclarator' as const),
663
+ name: arbitrarySimpleName,
664
+ type_: fc.constant(type_),
665
+ }).chain(base =>
666
+ fc.oneof(
667
+ fc.constant(base),
668
+ arbitraryLeafExpression.map(init => ({
669
+ ...base,
670
+ initializer: init,
671
+ })),
672
+ ),
673
+ ),
674
+ { minLength: 1, maxLength: 2 },
675
+ ),
676
+ }),
677
+ );
678
+
679
+ const arbitraryMethodDeclaration: fc.Arbitrary<unknown> = fc.oneof(
680
+ // Method with body
681
+ fc.record({
682
+ type: fc.constant('MethodDeclaration' as const),
683
+ modifiers: fc.array(arbitraryModifier, { maxLength: 2 }),
684
+ annotations: fc.array(arbitraryAnnotation, { maxLength: 1 }),
685
+ typeParameters: fc.constant([]),
686
+ type_: arbitraryReturnType,
687
+ name: arbitrarySimpleName,
688
+ parameters: fc.array(arbitraryParameter, { maxLength: 2 }),
689
+ thrownExceptions: fc.constant([]),
690
+ body: fc.record({
691
+ type: fc.constant('BlockStmt' as const),
692
+ statements: fc.array(arbitraryStatement, { maxLength: 2 }),
693
+ }),
694
+ }),
695
+ // Abstract method (no body)
696
+ fc.record({
697
+ type: fc.constant('MethodDeclaration' as const),
698
+ modifiers: fc.array(arbitraryModifier, { maxLength: 2 }),
699
+ annotations: fc.array(arbitraryAnnotation, { maxLength: 1 }),
700
+ typeParameters: fc.constant([]),
701
+ type_: arbitraryReturnType,
702
+ name: arbitrarySimpleName,
703
+ parameters: fc.array(arbitraryParameter, { maxLength: 2 }),
704
+ thrownExceptions: fc.constant([]),
705
+ }),
706
+ );
707
+
708
+ const arbitraryConstructorDeclaration: fc.Arbitrary<unknown> = fc.record({
709
+ type: fc.constant('ConstructorDeclaration' as const),
710
+ modifiers: fc.array(arbitraryModifier, { maxLength: 1 }),
711
+ annotations: fc.constant([]),
712
+ typeParameters: fc.constant([]),
713
+ name: arbitrarySimpleName,
714
+ parameters: fc.array(arbitraryParameter, { maxLength: 2 }),
715
+ thrownExceptions: fc.constant([]),
716
+ body: fc.record({
717
+ type: fc.constant('BlockStmt' as const),
718
+ statements: fc.array(arbitraryStatement, { maxLength: 2 }),
719
+ }),
720
+ });
721
+
722
+ const arbitraryBodyDeclaration: fc.Arbitrary<unknown> = fc.oneof(
723
+ { weight: 2, arbitrary: arbitraryFieldDeclaration },
724
+ { weight: 2, arbitrary: arbitraryMethodDeclaration },
725
+ { weight: 1, arbitrary: arbitraryConstructorDeclaration },
726
+ );
727
+
728
+ // Type declarations
729
+
730
+ const arbitraryEnumDeclaration: fc.Arbitrary<unknown> = fc.record({
731
+ type: fc.constant('EnumDeclaration' as const),
732
+ modifiers: fc.array(arbitraryModifier, { maxLength: 2 }),
733
+ annotations: fc.array(arbitraryAnnotation, { maxLength: 1 }),
734
+ name: arbitrarySimpleName,
735
+ implementedTypes: fc.constant([]),
736
+ entries: fc.constant([]),
737
+ members: fc.constant([]),
738
+ });
739
+
740
+ const arbitraryClassOrInterfaceDeclaration: fc.Arbitrary<unknown> = fc.boolean().chain(isInterface =>
741
+ fc.record({
742
+ type: fc.constant('ClassOrInterfaceDeclaration' as const),
743
+ modifiers: fc.array(arbitraryModifier, { maxLength: 2 }),
744
+ annotations: fc.array(arbitraryAnnotation, { maxLength: 1 }),
745
+ name: arbitrarySimpleName,
746
+ isInterface: fc.constant(isInterface),
747
+ typeParameters: fc.oneof(
748
+ fc.constant([]),
749
+ fc.array(
750
+ fc.record({
751
+ type: fc.constant('TypeParameter' as const),
752
+ annotations: fc.constant([]),
753
+ name: arbitrarySimpleName,
754
+ typeBound: fc.constant([]),
755
+ }),
756
+ { minLength: 1, maxLength: 2 },
757
+ ),
758
+ ),
759
+ extendedTypes: fc.oneof(
760
+ fc.constant([]),
761
+ fc.array(arbitraryClassOrInterfaceTypeWithTypeArgs, { minLength: 1, maxLength: 1 }),
762
+ ),
763
+ // Interfaces always have implementedTypes: [] (parser outputs empty array for interfaces)
764
+ implementedTypes: isInterface
765
+ ? fc.constant([])
766
+ : fc.oneof(
767
+ fc.constant([]),
768
+ fc.array(arbitraryClassOrInterfaceTypeWithTypeArgs, { minLength: 1, maxLength: 2 }),
769
+ ),
770
+ permittedTypes: fc.constant([]),
771
+ members: fc.array(arbitraryBodyDeclaration, { maxLength: 3 }),
772
+ }),
773
+ );
774
+
775
+ const arbitraryTypeDeclaration: fc.Arbitrary<unknown> = fc.oneof(
776
+ { weight: 3, arbitrary: arbitraryClassOrInterfaceDeclaration },
777
+ { weight: 1, arbitrary: arbitraryEnumDeclaration },
778
+ );
779
+
780
+ // Import declaration
781
+
782
+ const arbitraryImportDeclaration = fc.record({
783
+ type: fc.constant('ImportDeclaration' as const),
784
+ isStatic: fc.boolean(),
785
+ isAsterisk: fc.boolean(),
786
+ name: arbitraryName,
787
+ });
788
+
789
+ // Package declaration
790
+
791
+ const arbitraryPackageDeclaration = fc.record({
792
+ type: fc.constant('PackageDeclaration' as const),
793
+ annotations: fc.array(arbitraryAnnotation, { maxLength: 1 }),
794
+ name: arbitraryName,
795
+ });
796
+
797
+ // Compilation unit
798
+
799
+ export const arbitraryJavaCompilationUnit = fc.record({
800
+ type: fc.constant('CompilationUnit' as const),
801
+ packageDeclaration: fc.option(arbitraryPackageDeclaration, { nil: undefined }),
802
+ imports: fc.array(arbitraryImportDeclaration, { maxLength: 2 }),
803
+ types: fc.array(arbitraryTypeDeclaration, { minLength: 1, maxLength: 2 }),
804
+ });