@claudetools/tools 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/cli.js +9 -1
  2. package/dist/codedna/__tests__/examples/mongoose-example.d.ts +6 -0
  3. package/dist/codedna/__tests__/examples/mongoose-example.js +163 -0
  4. package/dist/codedna/__tests__/fixtures/typeorm-production-test.d.ts +1 -0
  5. package/dist/codedna/__tests__/fixtures/typeorm-production-test.js +231 -0
  6. package/dist/codedna/__tests__/fixtures/typeorm-test.d.ts +1 -0
  7. package/dist/codedna/__tests__/fixtures/typeorm-test.js +124 -0
  8. package/dist/codedna/__tests__/laravel-output-review.d.ts +1 -0
  9. package/dist/codedna/__tests__/laravel-output-review.js +249 -0
  10. package/dist/codedna/__tests__/mongoose-output-test.d.ts +1 -0
  11. package/dist/codedna/__tests__/mongoose-output-test.js +178 -0
  12. package/dist/codedna/examples/radix-example.d.ts +2 -0
  13. package/dist/codedna/examples/radix-example.js +259 -0
  14. package/dist/codedna/index.d.ts +5 -3
  15. package/dist/codedna/index.js +6 -3
  16. package/dist/codedna/kappa-ast.d.ts +143 -5
  17. package/dist/codedna/kappa-drizzle-generator.js +8 -5
  18. package/dist/codedna/kappa-gofiber-generator.d.ts +65 -0
  19. package/dist/codedna/kappa-gofiber-generator.js +587 -0
  20. package/dist/codedna/kappa-laravel-generator.d.ts +68 -0
  21. package/dist/codedna/kappa-laravel-generator.js +741 -0
  22. package/dist/codedna/kappa-lexer.d.ts +44 -0
  23. package/dist/codedna/kappa-lexer.js +124 -0
  24. package/dist/codedna/kappa-mantine-generator.d.ts +65 -0
  25. package/dist/codedna/kappa-mantine-generator.js +518 -0
  26. package/dist/codedna/kappa-mongoose-generator.d.ts +44 -0
  27. package/dist/codedna/kappa-mongoose-generator.js +442 -0
  28. package/dist/codedna/kappa-parser.d.ts +43 -1
  29. package/dist/codedna/kappa-parser.js +601 -0
  30. package/dist/codedna/kappa-radix-generator.d.ts +61 -0
  31. package/dist/codedna/kappa-radix-generator.js +566 -0
  32. package/dist/codedna/kappa-typeorm-generator.d.ts +59 -0
  33. package/dist/codedna/kappa-typeorm-generator.js +723 -0
  34. package/dist/codedna/kappa-vitest-generator.d.ts +85 -0
  35. package/dist/codedna/kappa-vitest-generator.js +739 -0
  36. package/dist/codedna/parser.js +26 -1
  37. package/dist/codegen/cloud-client.d.ts +160 -0
  38. package/dist/codegen/cloud-client.js +195 -0
  39. package/dist/codegen/codegen-tool.d.ts +35 -0
  40. package/dist/codegen/codegen-tool.js +312 -0
  41. package/dist/codegen/field-inference.d.ts +24 -0
  42. package/dist/codegen/field-inference.js +101 -0
  43. package/dist/codegen/form-parser.d.ts +13 -0
  44. package/dist/codegen/form-parser.js +186 -0
  45. package/dist/codegen/index.d.ts +2 -0
  46. package/dist/codegen/index.js +4 -0
  47. package/dist/codegen/natural-parser.d.ts +50 -0
  48. package/dist/codegen/natural-parser.js +769 -0
  49. package/dist/handlers/codedna-handlers.d.ts +1 -1
  50. package/dist/handlers/codegen-handlers.d.ts +20 -0
  51. package/dist/handlers/codegen-handlers.js +60 -0
  52. package/dist/handlers/kappa-handlers.d.ts +97 -0
  53. package/dist/handlers/kappa-handlers.js +408 -0
  54. package/dist/handlers/tool-handlers.js +124 -221
  55. package/dist/helpers/api-client.js +48 -3
  56. package/dist/helpers/compact-formatter.d.ts +9 -2
  57. package/dist/helpers/compact-formatter.js +26 -2
  58. package/dist/helpers/config.d.ts +7 -2
  59. package/dist/helpers/config.js +25 -10
  60. package/dist/helpers/session-validation.d.ts +1 -1
  61. package/dist/helpers/session-validation.js +2 -4
  62. package/dist/helpers/tasks.d.ts +21 -0
  63. package/dist/helpers/tasks.js +52 -0
  64. package/dist/helpers/workers.d.ts +1 -1
  65. package/dist/helpers/workers.js +19 -19
  66. package/dist/setup.d.ts +1 -0
  67. package/dist/setup.js +228 -3
  68. package/dist/templates/claude-md.d.ts +1 -1
  69. package/dist/templates/claude-md.js +37 -152
  70. package/dist/templates/orchestrator-prompt.d.ts +2 -2
  71. package/dist/templates/orchestrator-prompt.js +31 -38
  72. package/dist/templates/self-critique.d.ts +50 -0
  73. package/dist/templates/self-critique.js +209 -0
  74. package/dist/templates/worker-prompt.d.ts +3 -3
  75. package/dist/templates/worker-prompt.js +18 -18
  76. package/dist/tools.js +77 -413
  77. package/docs/codedna/generator-testing-summary.md +205 -0
  78. package/docs/codedna/radix-ui-generator.md +478 -0
  79. package/docs/kappa-gofiber-generator.md +274 -0
  80. package/docs/kappa-laravel-fixes.md +172 -0
  81. package/docs/kappa-mongoose-generator.md +322 -0
  82. package/docs/kappa-vitest-generator.md +337 -0
  83. package/package.json +1 -1
  84. package/dist/context/deduplication.test.d.ts +0 -6
  85. package/dist/context/deduplication.test.js +0 -84
@@ -34,6 +34,7 @@ class KappaParser extends CstParser {
34
34
  { ALT: () => this.SUBRULE(this.componentBlock) },
35
35
  { ALT: () => this.SUBRULE(this.formBlock) },
36
36
  { ALT: () => this.SUBRULE(this.designBlock) },
37
+ { ALT: () => this.SUBRULE(this.testBlock) },
37
38
  ]);
38
39
  });
39
40
  });
@@ -1167,6 +1168,261 @@ class KappaParser extends CstParser {
1167
1168
  { ALT: () => this.CONSUME(tokens.StringLiteral) },
1168
1169
  ]);
1169
1170
  });
1171
+ // ---------------------------------------------------------------------------
1172
+ // Test Block
1173
+ // ---------------------------------------------------------------------------
1174
+ // test UserTests {
1175
+ // target: User
1176
+ // framework: vitest
1177
+ // type: unit
1178
+ // describe "User entity" {
1179
+ // it "creates a user" { ... }
1180
+ // }
1181
+ // }
1182
+ testBlock = this.RULE('testBlock', () => {
1183
+ this.CONSUME(tokens.Test);
1184
+ this.CONSUME(tokens.PascalIdentifier); // Test suite name
1185
+ this.CONSUME(tokens.LBrace);
1186
+ this.MANY(() => {
1187
+ this.OR([
1188
+ { ALT: () => this.SUBRULE(this.testProperty) },
1189
+ { ALT: () => this.SUBRULE(this.testSuite) },
1190
+ { ALT: () => this.SUBRULE(this.testMock) },
1191
+ ]);
1192
+ });
1193
+ this.CONSUME(tokens.RBrace);
1194
+ });
1195
+ // target: User, framework: vitest, type: unit, coverage: { ... }
1196
+ testProperty = this.RULE('testProperty', () => {
1197
+ this.OR([
1198
+ {
1199
+ ALT: () => {
1200
+ this.CONSUME(tokens.Target);
1201
+ this.CONSUME(tokens.Colon);
1202
+ this.CONSUME(tokens.PascalIdentifier);
1203
+ },
1204
+ },
1205
+ {
1206
+ ALT: () => {
1207
+ this.CONSUME(tokens.Framework);
1208
+ this.CONSUME2(tokens.Colon);
1209
+ this.OR2([
1210
+ { ALT: () => this.CONSUME(tokens.Vitest) },
1211
+ { ALT: () => this.CONSUME(tokens.Jest) },
1212
+ { ALT: () => this.CONSUME(tokens.Playwright) },
1213
+ { ALT: () => this.CONSUME(tokens.Cypress) },
1214
+ ]);
1215
+ },
1216
+ },
1217
+ {
1218
+ ALT: () => {
1219
+ this.CONSUME(tokens.Identifier); // 'type' keyword
1220
+ this.CONSUME3(tokens.Colon);
1221
+ this.OR3([
1222
+ { ALT: () => this.CONSUME2(tokens.Identifier) }, // unit, integration, e2e
1223
+ ]);
1224
+ },
1225
+ },
1226
+ {
1227
+ ALT: () => {
1228
+ this.CONSUME(tokens.Coverage);
1229
+ this.CONSUME4(tokens.Colon);
1230
+ this.CONSUME(tokens.LBrace);
1231
+ this.MANY(() => {
1232
+ this.SUBRULE(this.coverageProperty);
1233
+ });
1234
+ this.CONSUME(tokens.RBrace);
1235
+ },
1236
+ },
1237
+ ]);
1238
+ });
1239
+ coverageProperty = this.RULE('coverageProperty', () => {
1240
+ this.CONSUME(tokens.Identifier); // statements, branches, functions, lines
1241
+ this.CONSUME(tokens.Colon);
1242
+ this.CONSUME(tokens.IntegerLiteral);
1243
+ });
1244
+ // describe "Suite name" { ... }
1245
+ testSuite = this.RULE('testSuite', () => {
1246
+ this.CONSUME(tokens.Describe);
1247
+ this.CONSUME(tokens.StringLiteral);
1248
+ this.CONSUME(tokens.LBrace);
1249
+ this.MANY(() => {
1250
+ this.OR([
1251
+ { ALT: () => this.SUBRULE(this.testLifecycle) },
1252
+ { ALT: () => this.SUBRULE(this.testCase) },
1253
+ { ALT: () => this.SUBRULE2(this.testSuite) }, // Nested suites
1254
+ { ALT: () => this.SUBRULE2(this.testMock) },
1255
+ ]);
1256
+ });
1257
+ this.CONSUME(tokens.RBrace);
1258
+ });
1259
+ // beforeAll { ... }, afterEach { ... }, etc.
1260
+ testLifecycle = this.RULE('testLifecycle', () => {
1261
+ this.OR([
1262
+ { ALT: () => this.CONSUME(tokens.BeforeAll) },
1263
+ { ALT: () => this.CONSUME(tokens.AfterAll) },
1264
+ { ALT: () => this.CONSUME(tokens.BeforeEach) },
1265
+ { ALT: () => this.CONSUME(tokens.AfterEach) },
1266
+ ]);
1267
+ this.CONSUME(tokens.LBrace);
1268
+ this.MANY(() => {
1269
+ this.CONSUME(tokens.StringLiteral); // Code statements as strings
1270
+ });
1271
+ this.CONSUME(tokens.RBrace);
1272
+ });
1273
+ // mock ModuleName { returns: "value" }
1274
+ testMock = this.RULE('testMock', () => {
1275
+ this.CONSUME(tokens.Mock);
1276
+ this.OR([
1277
+ { ALT: () => this.CONSUME(tokens.PascalIdentifier) },
1278
+ { ALT: () => this.CONSUME(tokens.StringLiteral) },
1279
+ ]);
1280
+ this.OPTION(() => {
1281
+ this.CONSUME(tokens.LBrace);
1282
+ this.MANY(() => {
1283
+ this.SUBRULE(this.mockProperty);
1284
+ });
1285
+ this.CONSUME(tokens.RBrace);
1286
+ });
1287
+ });
1288
+ mockProperty = this.RULE('mockProperty', () => {
1289
+ this.OR([
1290
+ {
1291
+ ALT: () => {
1292
+ this.CONSUME(tokens.Returns);
1293
+ this.CONSUME(tokens.Colon);
1294
+ this.CONSUME(tokens.StringLiteral);
1295
+ },
1296
+ },
1297
+ {
1298
+ ALT: () => {
1299
+ this.CONSUME(tokens.Identifier); // implementation, etc.
1300
+ this.CONSUME2(tokens.Colon);
1301
+ this.CONSUME2(tokens.StringLiteral);
1302
+ },
1303
+ },
1304
+ ]);
1305
+ });
1306
+ // it "test name" { setup: [...], action: "...", expect: [...] }
1307
+ // it "test name", skip { ... }
1308
+ // it "test name", only { ... }
1309
+ testCase = this.RULE('testCase', () => {
1310
+ this.CONSUME(tokens.It);
1311
+ this.CONSUME(tokens.StringLiteral);
1312
+ this.OPTION(() => {
1313
+ this.CONSUME(tokens.Comma);
1314
+ this.OR([
1315
+ { ALT: () => this.CONSUME(tokens.Skip) },
1316
+ { ALT: () => this.CONSUME(tokens.Only) },
1317
+ { ALT: () => this.CONSUME(tokens.Todo) },
1318
+ ]);
1319
+ });
1320
+ this.CONSUME(tokens.LBrace);
1321
+ this.MANY(() => {
1322
+ this.SUBRULE(this.testCaseSection);
1323
+ });
1324
+ this.CONSUME(tokens.RBrace);
1325
+ });
1326
+ testCaseSection = this.RULE('testCaseSection', () => {
1327
+ this.OR([
1328
+ {
1329
+ ALT: () => {
1330
+ this.CONSUME(tokens.Setup);
1331
+ this.CONSUME(tokens.Colon);
1332
+ this.CONSUME(tokens.LBracket);
1333
+ this.MANY_SEP({
1334
+ SEP: tokens.Comma,
1335
+ DEF: () => this.CONSUME(tokens.StringLiteral),
1336
+ });
1337
+ this.CONSUME(tokens.RBracket);
1338
+ },
1339
+ },
1340
+ {
1341
+ ALT: () => {
1342
+ this.CONSUME(tokens.Action);
1343
+ this.CONSUME2(tokens.Colon);
1344
+ this.CONSUME2(tokens.StringLiteral);
1345
+ },
1346
+ },
1347
+ {
1348
+ ALT: () => {
1349
+ this.CONSUME(tokens.Teardown);
1350
+ this.CONSUME3(tokens.Colon);
1351
+ this.CONSUME2(tokens.LBracket);
1352
+ this.MANY_SEP2({
1353
+ SEP: tokens.Comma,
1354
+ DEF: () => this.CONSUME3(tokens.StringLiteral),
1355
+ });
1356
+ this.CONSUME2(tokens.RBracket);
1357
+ },
1358
+ },
1359
+ {
1360
+ ALT: () => {
1361
+ this.CONSUME(tokens.Expect);
1362
+ this.CONSUME4(tokens.Colon);
1363
+ this.CONSUME3(tokens.LBracket);
1364
+ this.MANY_SEP3({
1365
+ SEP: tokens.Comma,
1366
+ DEF: () => this.SUBRULE(this.testAssertion),
1367
+ });
1368
+ this.CONSUME3(tokens.RBracket);
1369
+ },
1370
+ },
1371
+ {
1372
+ ALT: () => {
1373
+ this.CONSUME(tokens.Timeout);
1374
+ this.CONSUME5(tokens.Colon);
1375
+ this.CONSUME(tokens.IntegerLiteral);
1376
+ },
1377
+ },
1378
+ ]);
1379
+ });
1380
+ // { actual: "expr", type: equals, expected: "value" }
1381
+ testAssertion = this.RULE('testAssertion', () => {
1382
+ this.CONSUME(tokens.LBrace);
1383
+ this.MANY_SEP({
1384
+ SEP: tokens.Comma,
1385
+ DEF: () => this.SUBRULE(this.assertionProperty),
1386
+ });
1387
+ this.CONSUME(tokens.RBrace);
1388
+ });
1389
+ assertionProperty = this.RULE('assertionProperty', () => {
1390
+ this.OR([
1391
+ {
1392
+ ALT: () => {
1393
+ this.CONSUME(tokens.Identifier); // actual, expected, message
1394
+ this.CONSUME(tokens.Colon);
1395
+ this.CONSUME(tokens.StringLiteral);
1396
+ },
1397
+ },
1398
+ {
1399
+ ALT: () => {
1400
+ this.CONSUME2(tokens.Identifier); // type
1401
+ this.CONSUME2(tokens.Colon);
1402
+ this.SUBRULE(this.assertionType);
1403
+ },
1404
+ },
1405
+ ]);
1406
+ });
1407
+ assertionType = this.RULE('assertionType', () => {
1408
+ this.OR([
1409
+ { ALT: () => this.CONSUME(tokens.EqualsAssertion) },
1410
+ { ALT: () => this.CONSUME(tokens.NotEquals) },
1411
+ { ALT: () => this.CONSUME(tokens.Contains) },
1412
+ { ALT: () => this.CONSUME(tokens.Matches) },
1413
+ { ALT: () => this.CONSUME(tokens.Throws) },
1414
+ { ALT: () => this.CONSUME(tokens.Resolves) },
1415
+ { ALT: () => this.CONSUME(tokens.Rejects) },
1416
+ { ALT: () => this.CONSUME(tokens.Truthy) },
1417
+ { ALT: () => this.CONSUME(tokens.Falsy) },
1418
+ { ALT: () => this.CONSUME(tokens.Defined) },
1419
+ { ALT: () => this.CONSUME(tokens.Undefined) },
1420
+ { ALT: () => this.CONSUME(tokens.Null) },
1421
+ { ALT: () => this.CONSUME(tokens.InstanceOf) },
1422
+ { ALT: () => this.CONSUME(tokens.LengthOf) },
1423
+ { ALT: () => this.CONSUME(tokens.DeepEquals) },
1424
+ ]);
1425
+ });
1170
1426
  }
1171
1427
  // =============================================================================
1172
1428
  // Parser Instance
@@ -1252,6 +1508,9 @@ class KappaAstBuilder extends BaseCstVisitor {
1252
1508
  : [];
1253
1509
  const forms = ctx.formBlock ? ctx.formBlock.map((f) => this.visit(f)) : [];
1254
1510
  const design = ctx.designBlock ? this.visit(ctx.designBlock) : undefined;
1511
+ const tests = ctx.testBlock
1512
+ ? ctx.testBlock.map((t) => this.visit(t))
1513
+ : [];
1255
1514
  return {
1256
1515
  kind: 'KappaSpec',
1257
1516
  loc: this.getLocation(ctx),
@@ -1264,6 +1523,7 @@ class KappaAstBuilder extends BaseCstVisitor {
1264
1523
  components,
1265
1524
  forms,
1266
1525
  design,
1526
+ tests,
1267
1527
  };
1268
1528
  }
1269
1529
  // Project block visitor
@@ -1545,6 +1805,12 @@ class KappaAstBuilder extends BaseCstVisitor {
1545
1805
  'Time',
1546
1806
  'Text',
1547
1807
  'Primary',
1808
+ // Additional keywords commonly used as field names
1809
+ 'Title',
1810
+ 'Label',
1811
+ 'State',
1812
+ 'Version',
1813
+ 'Color',
1548
1814
  ];
1549
1815
  for (const tokenType of tokenTypes) {
1550
1816
  const token = ctx[tokenType]?.[0];
@@ -2497,6 +2763,341 @@ class KappaAstBuilder extends BaseCstVisitor {
2497
2763
  value = ctx.StringLiteral[0].image.slice(1, -1);
2498
2764
  return { name, value };
2499
2765
  }
2766
+ // ---------------------------------------------------------------------------
2767
+ // Test Block Visitors
2768
+ // ---------------------------------------------------------------------------
2769
+ testBlock(ctx) {
2770
+ const name = (ctx.PascalIdentifier?.[0])?.image ?? '';
2771
+ // Parse properties
2772
+ let target = '';
2773
+ let framework = 'vitest';
2774
+ let type = 'unit';
2775
+ let coverage;
2776
+ if (ctx.testProperty) {
2777
+ for (const prop of ctx.testProperty) {
2778
+ const result = this.visit(prop);
2779
+ if (result.type === 'target')
2780
+ target = result.value;
2781
+ else if (result.type === 'framework')
2782
+ framework = result.value;
2783
+ else if (result.type === 'testType')
2784
+ type = result.value;
2785
+ else if (result.type === 'coverage')
2786
+ coverage = result.value;
2787
+ }
2788
+ }
2789
+ // Parse suites
2790
+ const suites = ctx.testSuite
2791
+ ? ctx.testSuite.map((s) => this.visit(s))
2792
+ : [];
2793
+ // Parse mocks
2794
+ const mocks = ctx.testMock
2795
+ ? ctx.testMock.map((m) => this.visit(m))
2796
+ : [];
2797
+ // Build root suite
2798
+ const rootSuite = {
2799
+ kind: 'TestSuite',
2800
+ loc: this.getLocation(ctx),
2801
+ name,
2802
+ mocks,
2803
+ tests: [],
2804
+ suites,
2805
+ };
2806
+ return {
2807
+ kind: 'TestBlock',
2808
+ loc: this.getLocation(ctx),
2809
+ name,
2810
+ target,
2811
+ framework,
2812
+ type,
2813
+ suite: rootSuite,
2814
+ coverage,
2815
+ };
2816
+ }
2817
+ testProperty(ctx) {
2818
+ if (ctx.Target) {
2819
+ return {
2820
+ type: 'target',
2821
+ value: (ctx.PascalIdentifier?.[0])?.image ?? '',
2822
+ };
2823
+ }
2824
+ if (ctx.Framework) {
2825
+ let fw = 'vitest';
2826
+ if (ctx.Vitest)
2827
+ fw = 'vitest';
2828
+ else if (ctx.Jest)
2829
+ fw = 'jest';
2830
+ else if (ctx.Playwright)
2831
+ fw = 'playwright';
2832
+ else if (ctx.Cypress)
2833
+ fw = 'cypress';
2834
+ return { type: 'framework', value: fw };
2835
+ }
2836
+ if (ctx.Coverage) {
2837
+ const coverageProps = ctx.coverageProperty
2838
+ ? ctx.coverageProperty.map((p) => this.visit(p))
2839
+ : [];
2840
+ const coverage = {};
2841
+ for (const prop of coverageProps) {
2842
+ coverage[prop.name] = prop.value;
2843
+ }
2844
+ return { type: 'coverage', value: coverage };
2845
+ }
2846
+ // Default: type property
2847
+ const identifiers = ctx.Identifier;
2848
+ if (identifiers && identifiers.length >= 2) {
2849
+ return { type: 'testType', value: identifiers[1].image };
2850
+ }
2851
+ return { type: 'testType', value: 'unit' };
2852
+ }
2853
+ coverageProperty(ctx) {
2854
+ return {
2855
+ name: ctx.Identifier?.[0]?.image ?? '',
2856
+ value: parseInt(ctx.IntegerLiteral?.[0]?.image ?? '0', 10),
2857
+ };
2858
+ }
2859
+ testSuite(ctx) {
2860
+ const name = (ctx.StringLiteral?.[0])?.image?.slice(1, -1) ?? '';
2861
+ // Parse lifecycle hooks
2862
+ const lifecycles = ctx.testLifecycle
2863
+ ? ctx.testLifecycle.map((l) => this.visit(l))
2864
+ : [];
2865
+ let beforeAll;
2866
+ let afterAll;
2867
+ let beforeEach;
2868
+ let afterEach;
2869
+ for (const lc of lifecycles) {
2870
+ if (lc.type === 'beforeAll')
2871
+ beforeAll = lc.statements;
2872
+ else if (lc.type === 'afterAll')
2873
+ afterAll = lc.statements;
2874
+ else if (lc.type === 'beforeEach')
2875
+ beforeEach = lc.statements;
2876
+ else if (lc.type === 'afterEach')
2877
+ afterEach = lc.statements;
2878
+ }
2879
+ // Parse test cases
2880
+ const tests = ctx.testCase
2881
+ ? ctx.testCase.map((t) => this.visit(t))
2882
+ : [];
2883
+ // Parse nested suites
2884
+ const suites = ctx.testSuite
2885
+ ? ctx.testSuite.map((s) => this.visit(s))
2886
+ : [];
2887
+ // Parse mocks
2888
+ const mocks = ctx.testMock
2889
+ ? ctx.testMock.map((m) => this.visit(m))
2890
+ : [];
2891
+ return {
2892
+ kind: 'TestSuite',
2893
+ loc: this.getLocation(ctx),
2894
+ name,
2895
+ beforeAll,
2896
+ afterAll,
2897
+ beforeEach,
2898
+ afterEach,
2899
+ mocks,
2900
+ tests,
2901
+ suites,
2902
+ };
2903
+ }
2904
+ testLifecycle(ctx) {
2905
+ let type = 'beforeEach';
2906
+ if (ctx.BeforeAll)
2907
+ type = 'beforeAll';
2908
+ else if (ctx.AfterAll)
2909
+ type = 'afterAll';
2910
+ else if (ctx.BeforeEach)
2911
+ type = 'beforeEach';
2912
+ else if (ctx.AfterEach)
2913
+ type = 'afterEach';
2914
+ const statements = ctx.StringLiteral
2915
+ ? ctx.StringLiteral.map((s) => s.image.slice(1, -1))
2916
+ : [];
2917
+ return { type, statements };
2918
+ }
2919
+ testMock(ctx) {
2920
+ let target = '';
2921
+ if (ctx.PascalIdentifier) {
2922
+ target = (ctx.PascalIdentifier?.[0])?.image ?? '';
2923
+ }
2924
+ else if (ctx.StringLiteral) {
2925
+ target = (ctx.StringLiteral?.[0])?.image?.slice(1, -1) ?? '';
2926
+ }
2927
+ let returns;
2928
+ let implementation;
2929
+ if (ctx.mockProperty) {
2930
+ for (const prop of ctx.mockProperty) {
2931
+ const result = this.visit(prop);
2932
+ if (result.type === 'returns')
2933
+ returns = result.value;
2934
+ else if (result.type === 'implementation')
2935
+ implementation = result.value;
2936
+ }
2937
+ }
2938
+ return {
2939
+ kind: 'TestMock',
2940
+ loc: this.getLocation(ctx),
2941
+ target,
2942
+ returns,
2943
+ implementation,
2944
+ };
2945
+ }
2946
+ mockProperty(ctx) {
2947
+ if (ctx.Returns) {
2948
+ return {
2949
+ type: 'returns',
2950
+ value: (ctx.StringLiteral?.[0])?.image?.slice(1, -1) ?? '',
2951
+ };
2952
+ }
2953
+ // implementation or other property
2954
+ const identifier = (ctx.Identifier?.[0])?.image ?? '';
2955
+ const value = (ctx.StringLiteral?.[0])?.image?.slice(1, -1) ?? '';
2956
+ return { type: identifier, value };
2957
+ }
2958
+ testCase(ctx) {
2959
+ const name = (ctx.StringLiteral?.[0])?.image?.slice(1, -1) ?? '';
2960
+ let skip = false;
2961
+ let only = false;
2962
+ let todo = false;
2963
+ if (ctx.Skip)
2964
+ skip = true;
2965
+ if (ctx.Only)
2966
+ only = true;
2967
+ if (ctx.Todo)
2968
+ todo = true;
2969
+ // Parse sections
2970
+ let setup;
2971
+ let action = '';
2972
+ let teardown;
2973
+ let timeout;
2974
+ const assertions = [];
2975
+ if (ctx.testCaseSection) {
2976
+ for (const section of ctx.testCaseSection) {
2977
+ const result = this.visit(section);
2978
+ if (result.type === 'setup')
2979
+ setup = result.value;
2980
+ else if (result.type === 'action')
2981
+ action = result.value;
2982
+ else if (result.type === 'teardown')
2983
+ teardown = result.value;
2984
+ else if (result.type === 'timeout')
2985
+ timeout = result.value;
2986
+ else if (result.type === 'expect')
2987
+ assertions.push(...result.value);
2988
+ }
2989
+ }
2990
+ return {
2991
+ kind: 'TestCase',
2992
+ loc: this.getLocation(ctx),
2993
+ name,
2994
+ setup,
2995
+ action,
2996
+ assertions,
2997
+ teardown,
2998
+ skip,
2999
+ only,
3000
+ todo,
3001
+ timeout,
3002
+ };
3003
+ }
3004
+ testCaseSection(ctx) {
3005
+ if (ctx.Setup) {
3006
+ const statements = ctx.StringLiteral
3007
+ ? ctx.StringLiteral.map((s) => s.image.slice(1, -1))
3008
+ : [];
3009
+ return { type: 'setup', value: statements };
3010
+ }
3011
+ if (ctx.Action) {
3012
+ const value = (ctx.StringLiteral?.[0])?.image?.slice(1, -1) ?? '';
3013
+ return { type: 'action', value };
3014
+ }
3015
+ if (ctx.Teardown) {
3016
+ const statements = ctx.StringLiteral
3017
+ ? ctx.StringLiteral.map((s) => s.image.slice(1, -1))
3018
+ : [];
3019
+ return { type: 'teardown', value: statements };
3020
+ }
3021
+ if (ctx.Expect) {
3022
+ const assertions = ctx.testAssertion
3023
+ ? ctx.testAssertion.map((a) => this.visit(a))
3024
+ : [];
3025
+ return { type: 'expect', value: assertions };
3026
+ }
3027
+ if (ctx.Timeout) {
3028
+ const value = parseInt((ctx.IntegerLiteral?.[0])?.image ?? '0', 10);
3029
+ return { type: 'timeout', value };
3030
+ }
3031
+ return { type: 'unknown', value: null };
3032
+ }
3033
+ testAssertion(ctx) {
3034
+ let actual = '';
3035
+ let type = 'equals';
3036
+ let expected;
3037
+ let message;
3038
+ if (ctx.assertionProperty) {
3039
+ for (const prop of ctx.assertionProperty) {
3040
+ const result = this.visit(prop);
3041
+ if (result.name === 'actual')
3042
+ actual = result.value;
3043
+ else if (result.name === 'expected')
3044
+ expected = result.value;
3045
+ else if (result.name === 'message')
3046
+ message = result.value;
3047
+ else if (result.name === 'type')
3048
+ type = result.value;
3049
+ }
3050
+ }
3051
+ return {
3052
+ kind: 'TestAssertion',
3053
+ loc: this.getLocation(ctx),
3054
+ actual,
3055
+ type,
3056
+ expected,
3057
+ message,
3058
+ };
3059
+ }
3060
+ assertionProperty(ctx) {
3061
+ const identifier = (ctx.Identifier?.[0])?.image ?? '';
3062
+ if (ctx.assertionType) {
3063
+ return { name: 'type', value: this.visit(ctx.assertionType) };
3064
+ }
3065
+ const value = (ctx.StringLiteral?.[0])?.image?.slice(1, -1) ?? '';
3066
+ return { name: identifier, value };
3067
+ }
3068
+ assertionType(ctx) {
3069
+ if (ctx.EqualsAssertion)
3070
+ return 'equals';
3071
+ if (ctx.NotEquals)
3072
+ return 'notEquals';
3073
+ if (ctx.Contains)
3074
+ return 'contains';
3075
+ if (ctx.Matches)
3076
+ return 'matches';
3077
+ if (ctx.Throws)
3078
+ return 'throws';
3079
+ if (ctx.Resolves)
3080
+ return 'resolves';
3081
+ if (ctx.Rejects)
3082
+ return 'rejects';
3083
+ if (ctx.Truthy)
3084
+ return 'truthy';
3085
+ if (ctx.Falsy)
3086
+ return 'falsy';
3087
+ if (ctx.Defined)
3088
+ return 'defined';
3089
+ if (ctx.Undefined)
3090
+ return 'undefined';
3091
+ if (ctx.Null)
3092
+ return 'null';
3093
+ if (ctx.InstanceOf)
3094
+ return 'instanceOf';
3095
+ if (ctx.LengthOf)
3096
+ return 'lengthOf';
3097
+ if (ctx.DeepEquals)
3098
+ return 'deepEquals';
3099
+ return 'equals';
3100
+ }
2500
3101
  }
2501
3102
  // =============================================================================
2502
3103
  // Parse Function
@@ -0,0 +1,61 @@
1
+ import type { ComponentBlock } from './kappa-ast.js';
2
+ export interface RadixGeneratorOptions {
3
+ /** Add provenance comments (default: true) */
4
+ provenance?: boolean;
5
+ /** Generate TypeScript (default: true) */
6
+ typescript?: boolean;
7
+ /** Base path for components (default: 'components/ui') */
8
+ basePath?: string;
9
+ /** Include accessibility documentation comments (default: true) */
10
+ a11yDocs?: boolean;
11
+ }
12
+ export interface GeneratedRadixComponent {
13
+ /** Component file path */
14
+ path: string;
15
+ /** Component content */
16
+ content: string;
17
+ /** Radix primitive used */
18
+ primitive: RadixPrimitive;
19
+ }
20
+ export interface GeneratedRadixComponents {
21
+ /** Generated component files */
22
+ components: GeneratedRadixComponent[];
23
+ /** Required Radix UI dependencies */
24
+ dependencies: string[];
25
+ }
26
+ export type RadixPrimitive = 'Dialog' | 'Popover' | 'Select' | 'Checkbox' | 'RadioGroup' | 'Switch' | 'Slider' | 'Tabs' | 'Accordion' | 'DropdownMenu' | 'ContextMenu' | 'HoverCard' | 'Tooltip' | 'AlertDialog' | 'AspectRatio' | 'Avatar' | 'Collapsible' | 'Label' | 'Progress' | 'ScrollArea' | 'Separator' | 'Toggle' | 'ToggleGroup';
27
+ export declare class KappaRadixGenerator {
28
+ private provenance;
29
+ private typescript;
30
+ private basePath;
31
+ private a11yDocs;
32
+ private usedDependencies;
33
+ constructor(options?: RadixGeneratorOptions);
34
+ /**
35
+ * Generate Radix UI component files from ComponentBlock AST nodes
36
+ */
37
+ generate(components: ComponentBlock[]): GeneratedRadixComponents;
38
+ private detectPrimitive;
39
+ private generateRadixComponent;
40
+ private generateRadixImports;
41
+ private getUsedRadixParts;
42
+ private mapCompoundPartToRadix;
43
+ private generateSimpleRadixComponent;
44
+ private generateRadixPropsInterface;
45
+ private generateRadixStructureJSX;
46
+ private mapStructureToRadixComponent;
47
+ private generateCompoundRadixComponent;
48
+ private generateRadixCompoundPart;
49
+ private generateSimpleComponent;
50
+ private getSimpleDestructuredProps;
51
+ private getVariantClassName;
52
+ private getElementType;
53
+ private getElementTag;
54
+ private getDestructuredProps;
55
+ private mapPropType;
56
+ private toKebabCase;
57
+ }
58
+ /**
59
+ * Generate Radix UI component files from Kappa ComponentBlock nodes
60
+ */
61
+ export declare function generateRadixComponents(components: ComponentBlock[], options?: RadixGeneratorOptions): GeneratedRadixComponents;