@tayo-dev/rtl 1.0.0

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 (150) hide show
  1. package/README.md +250 -0
  2. package/dist/analyzer/mocks/detector.d.ts +59 -0
  3. package/dist/analyzer/mocks/detector.d.ts.map +1 -0
  4. package/dist/analyzer/mocks/detector.js +264 -0
  5. package/dist/analyzer/mocks/detector.js.map +1 -0
  6. package/dist/analyzer/mocks/target-analyzer.d.ts +92 -0
  7. package/dist/analyzer/mocks/target-analyzer.d.ts.map +1 -0
  8. package/dist/analyzer/mocks/target-analyzer.js +305 -0
  9. package/dist/analyzer/mocks/target-analyzer.js.map +1 -0
  10. package/dist/analyzer/visual/element-analyzer.d.ts +44 -0
  11. package/dist/analyzer/visual/element-analyzer.d.ts.map +1 -0
  12. package/dist/analyzer/visual/element-analyzer.js +176 -0
  13. package/dist/analyzer/visual/element-analyzer.js.map +1 -0
  14. package/dist/analyzer/visual/inspector.d.ts +49 -0
  15. package/dist/analyzer/visual/inspector.d.ts.map +1 -0
  16. package/dist/analyzer/visual/inspector.js +109 -0
  17. package/dist/analyzer/visual/inspector.js.map +1 -0
  18. package/dist/cli/commands/generate.d.ts +13 -0
  19. package/dist/cli/commands/generate.d.ts.map +1 -0
  20. package/dist/cli/commands/generate.js +417 -0
  21. package/dist/cli/commands/generate.js.map +1 -0
  22. package/dist/core/generator.d.ts +32 -0
  23. package/dist/core/generator.d.ts.map +1 -0
  24. package/dist/core/generator.js +173 -0
  25. package/dist/core/generator.js.map +1 -0
  26. package/dist/core/js-parser.d.ts +48 -0
  27. package/dist/core/js-parser.d.ts.map +1 -0
  28. package/dist/core/js-parser.js +244 -0
  29. package/dist/core/js-parser.js.map +1 -0
  30. package/dist/core/mock-intelligence.d.ts +14 -0
  31. package/dist/core/mock-intelligence.d.ts.map +1 -0
  32. package/dist/core/mock-intelligence.js +140 -0
  33. package/dist/core/mock-intelligence.js.map +1 -0
  34. package/dist/core/orchestrator.d.ts +49 -0
  35. package/dist/core/orchestrator.d.ts.map +1 -0
  36. package/dist/core/orchestrator.js +315 -0
  37. package/dist/core/orchestrator.js.map +1 -0
  38. package/dist/core/parser.d.ts +9 -0
  39. package/dist/core/parser.d.ts.map +1 -0
  40. package/dist/core/parser.js +120 -0
  41. package/dist/core/parser.js.map +1 -0
  42. package/dist/core/recording-intelligence.d.ts +15 -0
  43. package/dist/core/recording-intelligence.d.ts.map +1 -0
  44. package/dist/core/recording-intelligence.js +178 -0
  45. package/dist/core/recording-intelligence.js.map +1 -0
  46. package/dist/core/resolver.d.ts +58 -0
  47. package/dist/core/resolver.d.ts.map +1 -0
  48. package/dist/core/resolver.js +291 -0
  49. package/dist/core/resolver.js.map +1 -0
  50. package/dist/core/scanner.d.ts +51 -0
  51. package/dist/core/scanner.d.ts.map +1 -0
  52. package/dist/core/scanner.js +310 -0
  53. package/dist/core/scanner.js.map +1 -0
  54. package/dist/core/scorer.d.ts +8 -0
  55. package/dist/core/scorer.d.ts.map +1 -0
  56. package/dist/core/scorer.js +76 -0
  57. package/dist/core/scorer.js.map +1 -0
  58. package/dist/core/validator.d.ts +134 -0
  59. package/dist/core/validator.d.ts.map +1 -0
  60. package/dist/core/validator.js +44 -0
  61. package/dist/core/validator.js.map +1 -0
  62. package/dist/core/verifier.d.ts +10 -0
  63. package/dist/core/verifier.d.ts.map +1 -0
  64. package/dist/core/verifier.js +30 -0
  65. package/dist/core/verifier.js.map +1 -0
  66. package/dist/core/writer.d.ts +15 -0
  67. package/dist/core/writer.d.ts.map +1 -0
  68. package/dist/core/writer.js +43 -0
  69. package/dist/core/writer.js.map +1 -0
  70. package/dist/generator/mocks/builder.d.ts +47 -0
  71. package/dist/generator/mocks/builder.d.ts.map +1 -0
  72. package/dist/generator/mocks/builder.js +335 -0
  73. package/dist/generator/mocks/builder.js.map +1 -0
  74. package/dist/generator/transforms/dialog-transform.d.ts +35 -0
  75. package/dist/generator/transforms/dialog-transform.d.ts.map +1 -0
  76. package/dist/generator/transforms/dialog-transform.js +293 -0
  77. package/dist/generator/transforms/dialog-transform.js.map +1 -0
  78. package/dist/index.d.ts +7 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +18 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/learner/analyzer.d.ts +13 -0
  83. package/dist/learner/analyzer.d.ts.map +1 -0
  84. package/dist/learner/analyzer.js +484 -0
  85. package/dist/learner/analyzer.js.map +1 -0
  86. package/dist/learner/index.d.ts +66 -0
  87. package/dist/learner/index.d.ts.map +1 -0
  88. package/dist/learner/index.js +247 -0
  89. package/dist/learner/index.js.map +1 -0
  90. package/dist/learner/storage.d.ts +68 -0
  91. package/dist/learner/storage.d.ts.map +1 -0
  92. package/dist/learner/storage.js +201 -0
  93. package/dist/learner/storage.js.map +1 -0
  94. package/dist/learner/types.d.ts +41 -0
  95. package/dist/learner/types.d.ts.map +1 -0
  96. package/dist/learner/types.js +31 -0
  97. package/dist/learner/types.js.map +1 -0
  98. package/dist/parser/recorder-parser.d.ts +40 -0
  99. package/dist/parser/recorder-parser.d.ts.map +1 -0
  100. package/dist/parser/recorder-parser.js +139 -0
  101. package/dist/parser/recorder-parser.js.map +1 -0
  102. package/dist/parser/steps/deduplicator.d.ts +19 -0
  103. package/dist/parser/steps/deduplicator.d.ts.map +1 -0
  104. package/dist/parser/steps/deduplicator.js +75 -0
  105. package/dist/parser/steps/deduplicator.js.map +1 -0
  106. package/dist/parser/steps/dialog-detector.d.ts +38 -0
  107. package/dist/parser/steps/dialog-detector.d.ts.map +1 -0
  108. package/dist/parser/steps/dialog-detector.js +290 -0
  109. package/dist/parser/steps/dialog-detector.js.map +1 -0
  110. package/dist/parser/steps/noise-filter.d.ts +21 -0
  111. package/dist/parser/steps/noise-filter.d.ts.map +1 -0
  112. package/dist/parser/steps/noise-filter.js +138 -0
  113. package/dist/parser/steps/noise-filter.js.map +1 -0
  114. package/dist/scorer/index.d.ts +43 -0
  115. package/dist/scorer/index.d.ts.map +1 -0
  116. package/dist/scorer/index.js +82 -0
  117. package/dist/scorer/index.js.map +1 -0
  118. package/dist/scorer/post-verify.d.ts +17 -0
  119. package/dist/scorer/post-verify.d.ts.map +1 -0
  120. package/dist/scorer/post-verify.js +163 -0
  121. package/dist/scorer/post-verify.js.map +1 -0
  122. package/dist/scorer/pre-audit.d.ts +32 -0
  123. package/dist/scorer/pre-audit.d.ts.map +1 -0
  124. package/dist/scorer/pre-audit.js +99 -0
  125. package/dist/scorer/pre-audit.js.map +1 -0
  126. package/dist/scorer/quality-gates.d.ts +17 -0
  127. package/dist/scorer/quality-gates.d.ts.map +1 -0
  128. package/dist/scorer/quality-gates.js +304 -0
  129. package/dist/scorer/quality-gates.js.map +1 -0
  130. package/dist/scorer/types.d.ts +27 -0
  131. package/dist/scorer/types.d.ts.map +1 -0
  132. package/dist/scorer/types.js +5 -0
  133. package/dist/scorer/types.js.map +1 -0
  134. package/dist/templates/test-template.d.ts +21 -0
  135. package/dist/templates/test-template.d.ts.map +1 -0
  136. package/dist/templates/test-template.js +92 -0
  137. package/dist/templates/test-template.js.map +1 -0
  138. package/dist/types/conventions.d.ts +49 -0
  139. package/dist/types/conventions.d.ts.map +1 -0
  140. package/dist/types/conventions.js +13 -0
  141. package/dist/types/conventions.js.map +1 -0
  142. package/dist/types/recording.d.ts +143 -0
  143. package/dist/types/recording.d.ts.map +1 -0
  144. package/dist/types/recording.js +5 -0
  145. package/dist/types/recording.js.map +1 -0
  146. package/dist/types/score.d.ts +18 -0
  147. package/dist/types/score.d.ts.map +1 -0
  148. package/dist/types/score.js +2 -0
  149. package/dist/types/score.js.map +1 -0
  150. package/package.json +51 -0
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Codebase convention scanner
3
+ * Scans project for test file conventions and persists to .taro/conventions.json
4
+ */
5
+ import { readdir, readFile, mkdir, writeFile, access } from 'node:fs/promises';
6
+ import { join, extname, relative, isAbsolute } from 'node:path';
7
+ import pc from 'picocolors';
8
+ import { DEFAULT_CONVENTIONS } from '../types/conventions.js';
9
+ const SKIP_DIRS = new Set([
10
+ 'node_modules',
11
+ '.git',
12
+ 'dist',
13
+ '.taro',
14
+ 'coverage',
15
+ '.next',
16
+ '.nuxt',
17
+ ]);
18
+ const TEST_FILE_REGEX = /\.(test|spec)\.(ts|tsx|js|jsx)$/;
19
+ /**
20
+ * Recursively find all test files in a directory
21
+ * @param root - Root directory to scan
22
+ * @returns Array of absolute paths to test files
23
+ */
24
+ export async function findTestFiles(root) {
25
+ const results = [];
26
+ async function walk(dir) {
27
+ let entries;
28
+ try {
29
+ entries = await readdir(dir, { withFileTypes: true });
30
+ }
31
+ catch {
32
+ // Skip directories we can't read
33
+ return;
34
+ }
35
+ for (const entry of entries) {
36
+ const fullPath = join(dir, entry.name);
37
+ if (entry.isDirectory()) {
38
+ if (!SKIP_DIRS.has(entry.name)) {
39
+ await walk(fullPath);
40
+ }
41
+ }
42
+ else if (entry.isFile() && TEST_FILE_REGEX.test(entry.name)) {
43
+ results.push(fullPath);
44
+ }
45
+ }
46
+ }
47
+ await walk(root);
48
+ return results;
49
+ }
50
+ /**
51
+ * Load discovered test files with content for downstream analyzers.
52
+ */
53
+ export async function readTestFiles(root) {
54
+ const files = await findTestFiles(root);
55
+ const loaded = await Promise.all(files.map(async (path) => {
56
+ try {
57
+ const content = await readFile(path, 'utf-8');
58
+ return { path, content };
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ }));
64
+ return loaded.filter((entry) => entry !== null);
65
+ }
66
+ /**
67
+ * Analyze a single test file to detect its conventions
68
+ * @param filePath - Absolute path to the test file
69
+ * @returns ConventionFile with detected conventions
70
+ */
71
+ async function analyzeTestFile(filePath) {
72
+ let content;
73
+ try {
74
+ content = await readFile(filePath, 'utf-8');
75
+ }
76
+ catch {
77
+ // If we can't read the file, return defaults
78
+ return {
79
+ path: filePath,
80
+ importStyle: 'esm',
81
+ hasDescribeBlock: false,
82
+ mockPattern: 'none',
83
+ hasHelperWithExpect: false,
84
+ };
85
+ }
86
+ // Detect import style: require() indicates CJS
87
+ const importStyle = content.includes('require(') ? 'cjs' : 'esm';
88
+ // Detect describe block
89
+ const hasDescribeBlock = content.includes('describe(');
90
+ // Detect mock pattern
91
+ let mockPattern = 'none';
92
+ if (content.includes('vi.mock(')) {
93
+ mockPattern = 'vi.mock';
94
+ }
95
+ else if (content.includes('jest.mock(')) {
96
+ mockPattern = 'jest.mock';
97
+ }
98
+ // Detect helper functions with expect() - simplified heuristic
99
+ // Look for function declarations that contain expect( but are not in it/test/describe blocks
100
+ const hasHelperWithExpect = detectHelperWithExpect(content);
101
+ return {
102
+ path: filePath,
103
+ importStyle,
104
+ hasDescribeBlock,
105
+ mockPattern,
106
+ hasHelperWithExpect,
107
+ };
108
+ }
109
+ /**
110
+ * Detect if file has helper functions containing expect()
111
+ * Uses simple heuristic: has expect( and a function declaration
112
+ */
113
+ function detectHelperWithExpect(content) {
114
+ // If no expect at all, return false
115
+ if (!content.includes('expect(')) {
116
+ return false;
117
+ }
118
+ // Simple heuristic: has function declaration/arrow function AND expect
119
+ // This catches most helper patterns
120
+ const hasFunction = /function\s+\w+|const\s+\w+\s*=\s*(?:async\s+)?\(|const\s+\w+\s*:\s*(?:Promise<)?\w+>?\s*=\s*(?:async\s+)?\(/.test(content);
121
+ return hasFunction && content.includes('expect(');
122
+ }
123
+ /**
124
+ * Derive conventions from analyzed files
125
+ * @param files - Array of analyzed ConventionFile objects
126
+ * @param projectRoot - Root directory of the project
127
+ * @returns ConventionsSchema with derived conventions
128
+ */
129
+ export function deriveConventions(files, projectRoot) {
130
+ if (files.length === 0) {
131
+ return {
132
+ ...DEFAULT_CONVENTIONS,
133
+ scannedAt: new Date().toISOString(),
134
+ projectRoot,
135
+ };
136
+ }
137
+ // Majority vote for import style
138
+ const esmCount = files.filter((f) => f.importStyle === 'esm').length;
139
+ const cjsCount = files.filter((f) => f.importStyle === 'cjs').length;
140
+ const importStyle = cjsCount > esmCount ? 'cjs' : 'esm';
141
+ // Mock pattern: any vi.mock wins, then jest.mock, else none
142
+ const hasViMock = files.some((f) => f.mockPattern === 'vi.mock');
143
+ const hasJestMock = files.some((f) => f.mockPattern === 'jest.mock');
144
+ let mockPattern = 'none';
145
+ if (hasViMock) {
146
+ mockPattern = 'vi.mock';
147
+ }
148
+ else if (hasJestMock) {
149
+ mockPattern = 'jest.mock';
150
+ }
151
+ // Folder pattern detection
152
+ const folderPattern = detectFolderPattern(files, projectRoot);
153
+ // File extension majority
154
+ const fileExtension = detectFileExtension(files);
155
+ return {
156
+ scannedAt: new Date().toISOString(),
157
+ projectRoot,
158
+ importStyle,
159
+ mockPattern,
160
+ testFiles: files,
161
+ folderPattern,
162
+ fileExtension,
163
+ };
164
+ }
165
+ /**
166
+ * Detect folder pattern from test files
167
+ */
168
+ function detectFolderPattern(files, projectRoot) {
169
+ if (files.length === 0) {
170
+ return 'unknown';
171
+ }
172
+ let hasColocated = false;
173
+ let hasTestsDir = false;
174
+ for (const file of files) {
175
+ const relativePath = relative(projectRoot, file.path);
176
+ if (relativePath.includes('__tests__') || relativePath.includes('__test__')) {
177
+ hasTestsDir = true;
178
+ }
179
+ else {
180
+ hasColocated = true;
181
+ }
182
+ }
183
+ if (hasColocated && hasTestsDir) {
184
+ return 'mixed';
185
+ }
186
+ else if (hasTestsDir) {
187
+ return '__tests__';
188
+ }
189
+ else {
190
+ return 'colocated';
191
+ }
192
+ }
193
+ /**
194
+ * Detect majority file extension
195
+ */
196
+ function detectFileExtension(files) {
197
+ const extensions = files.map((f) => {
198
+ const ext = extname(f.path).slice(1); // remove leading dot
199
+ if (ext === 'ts' || ext === 'tsx') {
200
+ return 'ts'; // normalize to ts
201
+ }
202
+ return 'js'; // normalize to js
203
+ });
204
+ const tsCount = extensions.filter((e) => e === 'ts').length;
205
+ const jsCount = extensions.filter((e) => e === 'js').length;
206
+ if (tsCount === 0 && jsCount > 0) {
207
+ return 'js';
208
+ }
209
+ if (jsCount === 0 && tsCount > 0) {
210
+ return 'ts';
211
+ }
212
+ if (tsCount > 0 && jsCount > 0) {
213
+ return 'mixed';
214
+ }
215
+ return 'ts'; // default
216
+ }
217
+ /**
218
+ * Read conventions from .taro/conventions.json
219
+ * @param projectRoot - Root directory of the project
220
+ * @returns ConventionsSchema or null if not found
221
+ */
222
+ export async function readConventions(projectRoot) {
223
+ const conventionsPath = join(projectRoot, '.taro', 'conventions.json');
224
+ try {
225
+ await access(conventionsPath);
226
+ const content = await readFile(conventionsPath, 'utf-8');
227
+ return JSON.parse(content);
228
+ }
229
+ catch {
230
+ // File doesn't exist or can't be read
231
+ return null;
232
+ }
233
+ }
234
+ /**
235
+ * Scan project for test conventions
236
+ * @param projectRoot - Root directory of the project
237
+ * @returns ConventionsSchema with detected conventions
238
+ */
239
+ export async function scanConventions(projectRoot) {
240
+ // Step 1: Find all test files
241
+ const files = await findTestFiles(projectRoot);
242
+ // Step 2: If no files found, return defaults
243
+ if (files.length === 0) {
244
+ const conventions = {
245
+ ...DEFAULT_CONVENTIONS,
246
+ scannedAt: new Date().toISOString(),
247
+ projectRoot,
248
+ testFiles: [],
249
+ };
250
+ // Log warning
251
+ console.log(pc.yellow('[taro] CTX: No test files found — using defaults'));
252
+ // Persist defaults
253
+ await persistConventions(projectRoot, conventions);
254
+ return conventions;
255
+ }
256
+ // Step 3: Analyze all test files
257
+ const analyzed = await Promise.all(files.map(analyzeTestFile));
258
+ // Step 4: Derive conventions from analyzed files
259
+ const conventions = deriveConventions(analyzed, projectRoot);
260
+ // Step 5: Emit TEST-02 warnings for helpers with expect()
261
+ for (const file of analyzed) {
262
+ if (file.hasHelperWithExpect) {
263
+ console.log(pc.yellow(`[taro] TEST-02: Helper function with expect() found in ${relative(projectRoot, file.path)}`));
264
+ }
265
+ }
266
+ // Step 6: Persist conventions
267
+ await persistConventions(projectRoot, conventions);
268
+ return conventions;
269
+ }
270
+ /**
271
+ * Persist conventions to .taro/conventions.json
272
+ */
273
+ export async function persistConventions(projectRoot, conventions) {
274
+ const taroDir = join(projectRoot, '.taro');
275
+ // Ensure .taro directory exists
276
+ await mkdir(taroDir, { recursive: true });
277
+ // Write conventions.json
278
+ const conventionsPath = join(taroDir, 'conventions.json');
279
+ await writeFile(conventionsPath, JSON.stringify(conventions, null, 2), 'utf-8');
280
+ }
281
+ /**
282
+ * Merge new file conventions into the persisted conventions store.
283
+ */
284
+ export async function mergeConventions(projectRoot, newPatterns) {
285
+ const existing = await readConventions(projectRoot);
286
+ if (!existing) {
287
+ await scanConventions(projectRoot);
288
+ return;
289
+ }
290
+ const normalizedPatterns = {
291
+ ...newPatterns,
292
+ path: isAbsolute(newPatterns.path)
293
+ ? newPatterns.path
294
+ : join(projectRoot, newPatterns.path),
295
+ };
296
+ const mergedFiles = existing.testFiles.filter((file) => file.path !== normalizedPatterns.path);
297
+ mergedFiles.push(normalizedPatterns);
298
+ const conventions = deriveConventions(mergedFiles, projectRoot);
299
+ await persistConventions(projectRoot, conventions);
300
+ }
301
+ /**
302
+ * Analyze a single test file without rescanning the whole project.
303
+ */
304
+ export async function analyzeSingleTestFile(projectRoot, filePath) {
305
+ const normalizedPath = isAbsolute(filePath)
306
+ ? filePath
307
+ : join(projectRoot, filePath);
308
+ return analyzeTestFile(normalizedPath);
309
+ }
310
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { QueryResult } from '../types/recording.js';
2
+ import type { ScoreDimensions, ScoreResult } from '../types/score.js';
3
+ export declare function calculateQueryScore(queryResults: QueryResult[]): number;
4
+ export declare function calculateAssertionScore(code: string): number;
5
+ export declare function calculateStructureScore(code: string): number;
6
+ export declare function calculateAggregateScore(dimensions: ScoreDimensions): Pick<ScoreResult, 'total' | 'grade'>;
7
+ export declare function scoreGeneratedTest(code: string, queryResults?: QueryResult[]): ScoreResult;
8
+ //# sourceMappingURL=scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../../src/core/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAiBrE,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,CAUvE;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW5D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmB5D;AAED,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,eAAe,GAC1B,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAAC,CAwBtC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,WAAW,EAAO,GAC/B,WAAW,CAWb"}
@@ -0,0 +1,76 @@
1
+ const QUERY_WEIGHTS = {
2
+ getByRole: 1.0,
3
+ getByLabelText: 0.8,
4
+ getByText: 0.6,
5
+ getByPlaceholderText: 0.5,
6
+ getByTestId: 0.2,
7
+ };
8
+ const STRONG_ASSERTION_REGEX = /\.toHaveValue\(|\.toBeChecked\(|\.toHaveTextContent\(|\.toBeVisible\(/g;
9
+ const WEAK_ASSERTION_REGEX = /\.toBeInTheDocument\(/g;
10
+ function clampScore(score) {
11
+ return Math.min(100, Math.max(0, Math.round(score)));
12
+ }
13
+ export function calculateQueryScore(queryResults) {
14
+ if (queryResults.length === 0) {
15
+ return 100;
16
+ }
17
+ const totalWeight = queryResults.reduce((sum, queryResult) => {
18
+ return sum + (QUERY_WEIGHTS[queryResult.method] ?? 0.2);
19
+ }, 0);
20
+ return clampScore((totalWeight / queryResults.length) * 100);
21
+ }
22
+ export function calculateAssertionScore(code) {
23
+ const strongAssertions = code.match(STRONG_ASSERTION_REGEX)?.length ?? 0;
24
+ const weakAssertions = code.match(WEAK_ASSERTION_REGEX)?.length ?? 0;
25
+ const totalAssertions = strongAssertions + weakAssertions;
26
+ if (totalAssertions === 0) {
27
+ return 0;
28
+ }
29
+ const weightedScore = strongAssertions + weakAssertions * 0.3;
30
+ return clampScore((weightedScore / totalAssertions) * 100);
31
+ }
32
+ export function calculateStructureScore(code) {
33
+ const describeCount = code.match(/\bdescribe\s*\(/g)?.length ?? 0;
34
+ const itCount = code.match(/\b(?:it|test)\s*\(/g)?.length ?? 0;
35
+ let score = 50;
36
+ if (describeCount > 0) {
37
+ score += 20;
38
+ }
39
+ if (itCount > 1) {
40
+ score += Math.min((itCount - 1) * 15, 30);
41
+ }
42
+ if (itCount === 1 && code.length > 2000) {
43
+ score -= 20;
44
+ }
45
+ return clampScore(score);
46
+ }
47
+ export function calculateAggregateScore(dimensions) {
48
+ const total = clampScore(dimensions.queryQuality * 0.4 +
49
+ dimensions.assertionSpecificity * 0.35 +
50
+ dimensions.testStructure * 0.25);
51
+ if (total >= 90) {
52
+ return { total, grade: 'A' };
53
+ }
54
+ if (total >= 80) {
55
+ return { total, grade: 'B' };
56
+ }
57
+ if (total >= 70) {
58
+ return { total, grade: 'C' };
59
+ }
60
+ if (total >= 60) {
61
+ return { total, grade: 'D' };
62
+ }
63
+ return { total, grade: 'F' };
64
+ }
65
+ export function scoreGeneratedTest(code, queryResults = []) {
66
+ const dimensions = {
67
+ queryQuality: calculateQueryScore(queryResults),
68
+ assertionSpecificity: calculateAssertionScore(code),
69
+ testStructure: calculateStructureScore(code),
70
+ };
71
+ return {
72
+ ...calculateAggregateScore(dimensions),
73
+ dimensions,
74
+ };
75
+ }
76
+ //# sourceMappingURL=scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/core/scorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Input schema validation using Zod
3
+ * Validates Chrome Recorder export structure before processing,
4
+ * returning structured errors rather than throwing.
5
+ */
6
+ import { z } from 'zod';
7
+ export declare const chromeRecorderSchema: z.ZodObject<{
8
+ title: z.ZodOptional<z.ZodString>;
9
+ steps: z.ZodArray<z.ZodObject<{
10
+ type: z.ZodString;
11
+ target: z.ZodOptional<z.ZodString>;
12
+ selectors: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>;
13
+ value: z.ZodOptional<z.ZodString>;
14
+ key: z.ZodOptional<z.ZodString>;
15
+ url: z.ZodOptional<z.ZodString>;
16
+ assertedEvents: z.ZodOptional<z.ZodArray<z.ZodObject<{
17
+ type: z.ZodString;
18
+ url: z.ZodOptional<z.ZodString>;
19
+ title: z.ZodOptional<z.ZodString>;
20
+ }, "strip", z.ZodTypeAny, {
21
+ type: string;
22
+ url?: string | undefined;
23
+ title?: string | undefined;
24
+ }, {
25
+ type: string;
26
+ url?: string | undefined;
27
+ title?: string | undefined;
28
+ }>, "many">>;
29
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
30
+ type: z.ZodString;
31
+ target: z.ZodOptional<z.ZodString>;
32
+ selectors: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>;
33
+ value: z.ZodOptional<z.ZodString>;
34
+ key: z.ZodOptional<z.ZodString>;
35
+ url: z.ZodOptional<z.ZodString>;
36
+ assertedEvents: z.ZodOptional<z.ZodArray<z.ZodObject<{
37
+ type: z.ZodString;
38
+ url: z.ZodOptional<z.ZodString>;
39
+ title: z.ZodOptional<z.ZodString>;
40
+ }, "strip", z.ZodTypeAny, {
41
+ type: string;
42
+ url?: string | undefined;
43
+ title?: string | undefined;
44
+ }, {
45
+ type: string;
46
+ url?: string | undefined;
47
+ title?: string | undefined;
48
+ }>, "many">>;
49
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
50
+ type: z.ZodString;
51
+ target: z.ZodOptional<z.ZodString>;
52
+ selectors: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>;
53
+ value: z.ZodOptional<z.ZodString>;
54
+ key: z.ZodOptional<z.ZodString>;
55
+ url: z.ZodOptional<z.ZodString>;
56
+ assertedEvents: z.ZodOptional<z.ZodArray<z.ZodObject<{
57
+ type: z.ZodString;
58
+ url: z.ZodOptional<z.ZodString>;
59
+ title: z.ZodOptional<z.ZodString>;
60
+ }, "strip", z.ZodTypeAny, {
61
+ type: string;
62
+ url?: string | undefined;
63
+ title?: string | undefined;
64
+ }, {
65
+ type: string;
66
+ url?: string | undefined;
67
+ title?: string | undefined;
68
+ }>, "many">>;
69
+ }, z.ZodTypeAny, "passthrough">>, "many">;
70
+ settings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
71
+ }, "strip", z.ZodTypeAny, {
72
+ steps: z.objectOutputType<{
73
+ type: z.ZodString;
74
+ target: z.ZodOptional<z.ZodString>;
75
+ selectors: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>;
76
+ value: z.ZodOptional<z.ZodString>;
77
+ key: z.ZodOptional<z.ZodString>;
78
+ url: z.ZodOptional<z.ZodString>;
79
+ assertedEvents: z.ZodOptional<z.ZodArray<z.ZodObject<{
80
+ type: z.ZodString;
81
+ url: z.ZodOptional<z.ZodString>;
82
+ title: z.ZodOptional<z.ZodString>;
83
+ }, "strip", z.ZodTypeAny, {
84
+ type: string;
85
+ url?: string | undefined;
86
+ title?: string | undefined;
87
+ }, {
88
+ type: string;
89
+ url?: string | undefined;
90
+ title?: string | undefined;
91
+ }>, "many">>;
92
+ }, z.ZodTypeAny, "passthrough">[];
93
+ title?: string | undefined;
94
+ settings?: Record<string, unknown> | undefined;
95
+ }, {
96
+ steps: z.objectInputType<{
97
+ type: z.ZodString;
98
+ target: z.ZodOptional<z.ZodString>;
99
+ selectors: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>;
100
+ value: z.ZodOptional<z.ZodString>;
101
+ key: z.ZodOptional<z.ZodString>;
102
+ url: z.ZodOptional<z.ZodString>;
103
+ assertedEvents: z.ZodOptional<z.ZodArray<z.ZodObject<{
104
+ type: z.ZodString;
105
+ url: z.ZodOptional<z.ZodString>;
106
+ title: z.ZodOptional<z.ZodString>;
107
+ }, "strip", z.ZodTypeAny, {
108
+ type: string;
109
+ url?: string | undefined;
110
+ title?: string | undefined;
111
+ }, {
112
+ type: string;
113
+ url?: string | undefined;
114
+ title?: string | undefined;
115
+ }>, "many">>;
116
+ }, z.ZodTypeAny, "passthrough">[];
117
+ title?: string | undefined;
118
+ settings?: Record<string, unknown> | undefined;
119
+ }>;
120
+ export type ValidatedRecording = z.infer<typeof chromeRecorderSchema>;
121
+ export interface ValidationError {
122
+ path: string;
123
+ message: string;
124
+ }
125
+ export type ValidationResult = {
126
+ valid: true;
127
+ data: ValidatedRecording;
128
+ } | {
129
+ valid: false;
130
+ errors: ValidationError[];
131
+ };
132
+ export declare function validateRecording(data: unknown): ValidationResult;
133
+ export declare function formatValidationErrors(errors: ValidationError[]): string;
134
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAoBvB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI/B,CAAA;AAEF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAErE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,GACzC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CAAA;AAS/C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,CAMjE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAExE"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Input schema validation using Zod
3
+ * Validates Chrome Recorder export structure before processing,
4
+ * returning structured errors rather than throwing.
5
+ */
6
+ import { z } from 'zod';
7
+ const assertedEventSchema = z.object({
8
+ type: z.string(),
9
+ url: z.string().optional(),
10
+ title: z.string().optional(),
11
+ });
12
+ const recordingStepSchema = z
13
+ .object({
14
+ type: z.string(),
15
+ target: z.string().optional(),
16
+ selectors: z.array(z.array(z.string())).optional(),
17
+ value: z.string().optional(),
18
+ key: z.string().optional(),
19
+ url: z.string().optional(),
20
+ assertedEvents: z.array(assertedEventSchema).optional(),
21
+ })
22
+ .passthrough();
23
+ export const chromeRecorderSchema = z.object({
24
+ title: z.string().optional(),
25
+ steps: z.array(recordingStepSchema),
26
+ settings: z.record(z.unknown()).optional(),
27
+ });
28
+ function formatErrors(zodError) {
29
+ return zodError.errors.map((issue) => ({
30
+ path: issue.path.length > 0 ? issue.path.join('.') : '(root)',
31
+ message: issue.message,
32
+ }));
33
+ }
34
+ export function validateRecording(data) {
35
+ const result = chromeRecorderSchema.safeParse(data);
36
+ if (result.success) {
37
+ return { valid: true, data: result.data };
38
+ }
39
+ return { valid: false, errors: formatErrors(result.error) };
40
+ }
41
+ export function formatValidationErrors(errors) {
42
+ return errors.map((e) => ` • ${e.path}: ${e.message}`).join('\n');
43
+ }
44
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAA;AAEF,MAAM,mBAAmB,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;IAClD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,QAAQ,EAAE;CACxD,CAAC;KACD,WAAW,EAAE,CAAA;AAEhB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IACnC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC3C,CAAC,CAAA;AAaF,SAAS,YAAY,CAAC,QAAoB;IACxC,OAAO,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ;QAC7D,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC,CAAC,CAAA;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC7C,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACnD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAA;IAC3C,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;AAC7D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAyB;IAC9D,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpE,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Post-write syntax verification using Babel parser.
3
+ * Ensures generated files parse successfully before reporting completion.
4
+ */
5
+ export interface VerificationResult {
6
+ valid: boolean;
7
+ error?: string;
8
+ }
9
+ export declare function verifySyntax(code: string, filePath: string): VerificationResult;
10
+ //# sourceMappingURL=verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../src/core/verifier.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAcD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAcpB"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Post-write syntax verification using Babel parser.
3
+ * Ensures generated files parse successfully before reporting completion.
4
+ */
5
+ import * as babelParser from '@babel/parser';
6
+ function getPlugins(filePath) {
7
+ if (filePath.endsWith('.tsx')) {
8
+ return ['typescript', 'jsx'];
9
+ }
10
+ if (filePath.endsWith('.ts')) {
11
+ return ['typescript'];
12
+ }
13
+ return ['jsx'];
14
+ }
15
+ export function verifySyntax(code, filePath) {
16
+ try {
17
+ babelParser.parse(code, {
18
+ sourceType: 'module',
19
+ plugins: getPlugins(filePath),
20
+ });
21
+ return { valid: true };
22
+ }
23
+ catch (error) {
24
+ return {
25
+ valid: false,
26
+ error: error instanceof Error ? error.message : 'Unknown parse error',
27
+ };
28
+ }
29
+ }
30
+ //# sourceMappingURL=verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../src/core/verifier.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,WAAW,MAAM,eAAe,CAAA;AAO5C,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,YAAY,CAAC,CAAA;IACvB,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,QAAgB;IAEhB,IAAI,CAAC;QACH,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE;YACtB,UAAU,EAAE,QAAQ;YACpB,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC;SAC9B,CAAC,CAAA;QAEF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB;SACtE,CAAA;IACH,CAAC;AACH,CAAC"}