@sun-asterisk/sungen 3.2.6 → 3.2.8
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.
- package/dist/cli/commands/delivery.d.ts +25 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +30 -47
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
- package/dist/dashboard/snapshot-builder.js +28 -6
- package/dist/dashboard/snapshot-builder.js.map +1 -1
- package/dist/dashboard/templates/index.html +20 -20
- package/dist/dashboard/types.d.ts +18 -0
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/exporters/api-catalog-loader.d.ts +18 -0
- package/dist/exporters/api-catalog-loader.d.ts.map +1 -0
- package/dist/exporters/api-catalog-loader.js +77 -0
- package/dist/exporters/api-catalog-loader.js.map +1 -0
- package/dist/exporters/api-testcase-formatter.d.ts.map +1 -1
- package/dist/exporters/api-testcase-formatter.js +80 -4
- package/dist/exporters/api-testcase-formatter.js.map +1 -1
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +6 -1
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/json-exporter.d.ts +10 -1
- package/dist/exporters/json-exporter.d.ts.map +1 -1
- package/dist/exporters/json-exporter.js +34 -2
- package/dist/exporters/json-exporter.js.map +1 -1
- package/dist/exporters/playwright-report-parser.d.ts +14 -0
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +30 -0
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/types.d.ts +5 -0
- package/dist/exporters/types.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.d.ts +18 -17
- package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.js +25 -595
- package/dist/exporters/xlsx-exporter.js.map +1 -1
- package/dist/exporters/xlsx-report-builder.d.ts +196 -0
- package/dist/exporters/xlsx-report-builder.d.ts.map +1 -0
- package/dist/exporters/xlsx-report-builder.js +653 -0
- package/dist/exporters/xlsx-report-builder.js.map +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +2 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +2 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +2 -2
- package/dist/generators/test-generator/step-mapper.d.ts +6 -2
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +10 -6
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-api-design/SKILL.md +8 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +12 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +3 -0
- package/dist/orchestrator/templates/specs-api.d.ts +14 -2
- package/dist/orchestrator/templates/specs-api.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-api.js +38 -14
- package/dist/orchestrator/templates/specs-api.js.map +1 -1
- package/dist/orchestrator/templates/specs-api.ts +43 -14
- package/package.json +3 -3
- package/src/cli/commands/delivery.ts +32 -46
- package/src/dashboard/snapshot-builder.ts +31 -7
- package/src/dashboard/templates/index.html +20 -20
- package/src/dashboard/types.ts +19 -0
- package/src/exporters/api-catalog-loader.ts +44 -0
- package/src/exporters/api-testcase-formatter.ts +77 -4
- package/src/exporters/csv-exporter.ts +6 -1
- package/src/exporters/json-exporter.ts +46 -4
- package/src/exporters/playwright-report-parser.ts +27 -0
- package/src/exporters/types.ts +5 -0
- package/src/exporters/xlsx-exporter.ts +34 -658
- package/src/exporters/xlsx-report-builder.ts +806 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +2 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +2 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +2 -2
- package/src/generators/test-generator/step-mapper.ts +10 -6
- package/src/orchestrator/templates/ai-src/skills/sungen-api-design/SKILL.md +8 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +12 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +3 -0
- package/src/orchestrator/templates/specs-api.ts +43 -14
- package/dist/cli/types.d.ts +0 -9
- package/dist/cli/types.d.ts.map +0 -1
- package/dist/cli/types.js +0 -7
- package/dist/cli/types.js.map +0 -1
- package/dist/generators/gherkin-parser/selector-extractor.d.ts +0 -37
- package/dist/generators/gherkin-parser/selector-extractor.d.ts.map +0 -1
- package/dist/generators/gherkin-parser/selector-extractor.js +0 -108
- package/dist/generators/gherkin-parser/selector-extractor.js.map +0 -1
- package/dist/generators/test-generator/types.d.ts +0 -25
- package/dist/generators/test-generator/types.d.ts.map +0 -1
- package/dist/generators/test-generator/types.js +0 -7
- package/dist/generators/test-generator/types.js.map +0 -1
- package/dist/generators/types.d.ts +0 -119
- package/dist/generators/types.d.ts.map +0 -1
- package/dist/generators/types.js +0 -48
- package/dist/generators/types.js.map +0 -1
- package/dist/orchestrator/figma/node-path-collapser.d.ts +0 -16
- package/dist/orchestrator/figma/node-path-collapser.d.ts.map +0 -1
- package/dist/orchestrator/figma/node-path-collapser.js +0 -37
- package/dist/orchestrator/figma/node-path-collapser.js.map +0 -1
- package/src/cli/types.ts +0 -9
- package/src/generators/gherkin-parser/selector-extractor.ts +0 -142
- package/src/generators/test-generator/types.ts +0 -26
- package/src/generators/types.ts +0 -227
- package/src/orchestrator/figma/node-path-collapser.ts +0 -38
package/dist/generators/types.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Core types for Selector DSL Framework
|
|
4
|
-
* Framework-agnostic types for multi-platform support
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.GeneratorError = exports.UIModelNotFoundError = exports.SelectorNotFoundError = void 0;
|
|
8
|
-
exports.parseElementReference = parseElementReference;
|
|
9
|
-
function parseElementReference(ref) {
|
|
10
|
-
// Parse "[screen.element]" format
|
|
11
|
-
const match = ref.match(/^\[([^.]+)\.([^\]]+)\]$/);
|
|
12
|
-
if (!match)
|
|
13
|
-
return null;
|
|
14
|
-
return {
|
|
15
|
-
elementId: ref,
|
|
16
|
-
screenId: match[1],
|
|
17
|
-
elementName: match[2]
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Error Types
|
|
22
|
-
// ============================================================================
|
|
23
|
-
class SelectorNotFoundError extends Error {
|
|
24
|
-
constructor(elementId, screenId) {
|
|
25
|
-
super(`Selector not found: ${elementId} on screen ${screenId}`);
|
|
26
|
-
this.elementId = elementId;
|
|
27
|
-
this.screenId = screenId;
|
|
28
|
-
this.name = 'SelectorNotFoundError';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
exports.SelectorNotFoundError = SelectorNotFoundError;
|
|
32
|
-
class UIModelNotFoundError extends Error {
|
|
33
|
-
constructor(screenId) {
|
|
34
|
-
super(`UI Model not found for screen: ${screenId}`);
|
|
35
|
-
this.screenId = screenId;
|
|
36
|
-
this.name = 'UIModelNotFoundError';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
exports.UIModelNotFoundError = UIModelNotFoundError;
|
|
40
|
-
class GeneratorError extends Error {
|
|
41
|
-
constructor(message, cause) {
|
|
42
|
-
super(message);
|
|
43
|
-
this.cause = cause;
|
|
44
|
-
this.name = 'GeneratorError';
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
exports.GeneratorError = GeneratorError;
|
|
48
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/generators/types.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA4LH,sDAUC;AAVD,SAAgB,qBAAqB,CAAC,GAAW;IAC/C,kCAAkC;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO;QACL,SAAS,EAAE,GAAG;QACd,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;QAClB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;KACtB,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,MAAa,qBAAsB,SAAQ,KAAK;IAC9C,YAAmB,SAAiB,EAAS,QAAgB;QAC3D,KAAK,CAAC,uBAAuB,SAAS,cAAc,QAAQ,EAAE,CAAC,CAAC;QAD/C,cAAS,GAAT,SAAS,CAAQ;QAAS,aAAQ,GAAR,QAAQ,CAAQ;QAE3D,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AALD,sDAKC;AAED,MAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAmB,QAAgB;QACjC,KAAK,CAAC,kCAAkC,QAAQ,EAAE,CAAC,CAAC;QADnC,aAAQ,GAAR,QAAQ,CAAQ;QAEjC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AALD,oDAKC;AAED,MAAa,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe,EAAS,KAAa;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,UAAK,GAAL,KAAK,CAAQ;QAE/C,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AALD,wCAKC"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure helper: collapse consecutive repeated segments in a Figma node path.
|
|
3
|
-
*
|
|
4
|
-
* Delimiter: " > " (space-angle-space).
|
|
5
|
-
* Collapsed runs use the multiplication sign × (U+00D7).
|
|
6
|
-
*
|
|
7
|
-
* Examples:
|
|
8
|
-
* "A > B > C" → "A > B > C" (unchanged)
|
|
9
|
-
* "A > B > B > C" → "A > B×2 > C"
|
|
10
|
-
* "Container > Container > Container > X" → "Container×3 > X"
|
|
11
|
-
* "A > A > A > A > A > B > C" → "A×5 > B > C"
|
|
12
|
-
* "A" → "A" (single)
|
|
13
|
-
* "" → "" (empty)
|
|
14
|
-
*/
|
|
15
|
-
export declare function collapseNodePath(path: string): string;
|
|
16
|
-
//# sourceMappingURL=node-path-collapser.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node-path-collapser.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/figma/node-path-collapser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBrD"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.collapseNodePath = collapseNodePath;
|
|
4
|
-
/**
|
|
5
|
-
* Pure helper: collapse consecutive repeated segments in a Figma node path.
|
|
6
|
-
*
|
|
7
|
-
* Delimiter: " > " (space-angle-space).
|
|
8
|
-
* Collapsed runs use the multiplication sign × (U+00D7).
|
|
9
|
-
*
|
|
10
|
-
* Examples:
|
|
11
|
-
* "A > B > C" → "A > B > C" (unchanged)
|
|
12
|
-
* "A > B > B > C" → "A > B×2 > C"
|
|
13
|
-
* "Container > Container > Container > X" → "Container×3 > X"
|
|
14
|
-
* "A > A > A > A > A > B > C" → "A×5 > B > C"
|
|
15
|
-
* "A" → "A" (single)
|
|
16
|
-
* "" → "" (empty)
|
|
17
|
-
*/
|
|
18
|
-
function collapseNodePath(path) {
|
|
19
|
-
if (!path)
|
|
20
|
-
return path;
|
|
21
|
-
const DELIMITER = ' > ';
|
|
22
|
-
const segments = path.split(DELIMITER);
|
|
23
|
-
const collapsed = [];
|
|
24
|
-
let i = 0;
|
|
25
|
-
while (i < segments.length) {
|
|
26
|
-
const current = segments[i];
|
|
27
|
-
let count = 1;
|
|
28
|
-
// Count consecutive identical segments
|
|
29
|
-
while (i + count < segments.length && segments[i + count] === current) {
|
|
30
|
-
count++;
|
|
31
|
-
}
|
|
32
|
-
collapsed.push(count > 1 ? `${current}×${count}` : current);
|
|
33
|
-
i += count;
|
|
34
|
-
}
|
|
35
|
-
return collapsed.join(DELIMITER);
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=node-path-collapser.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node-path-collapser.js","sourceRoot":"","sources":["../../../src/orchestrator/figma/node-path-collapser.ts"],"names":[],"mappings":";;AAcA,4CAuBC;AArCD;;;;;;;;;;;;;GAaG;AACH,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,SAAS,GAAG,KAAK,CAAC;IACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEvC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,uCAAuC;QACvC,OAAO,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC;YACtE,KAAK,EAAE,CAAC;QACV,CAAC;QAED,SAAS,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC5D,CAAC,IAAI,KAAK,CAAC;IACb,CAAC;IAED,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC"}
|
package/src/cli/types.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gherkin Selector Extractor
|
|
3
|
-
* Scans Gherkin feature files and extracts all [screen.element] references
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import { glob } from 'glob';
|
|
9
|
-
|
|
10
|
-
export interface ExtractedSelector {
|
|
11
|
-
screenId: string;
|
|
12
|
-
elementId: string;
|
|
13
|
-
fullRef: string; // e.g., "[auth-login.email]"
|
|
14
|
-
occurrences: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface SelectorsByScreen {
|
|
18
|
-
[screenId: string]: {
|
|
19
|
-
[elementId: string]: {
|
|
20
|
-
fullRef: string;
|
|
21
|
-
occurrences: number;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class GherkinSelectorExtractor {
|
|
27
|
-
/**
|
|
28
|
-
* Extract all selector references from Gherkin feature files
|
|
29
|
-
*/
|
|
30
|
-
extractSelectors(featuresDir: string): SelectorsByScreen {
|
|
31
|
-
const featureFiles = glob.sync('**/*.feature', {
|
|
32
|
-
cwd: featuresDir,
|
|
33
|
-
absolute: true,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const selectorsByScreen: SelectorsByScreen = {};
|
|
37
|
-
|
|
38
|
-
for (const filePath of featureFiles) {
|
|
39
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
40
|
-
const selectors = this.extractSelectorsFromContent(content);
|
|
41
|
-
|
|
42
|
-
// Merge into selectorsByScreen
|
|
43
|
-
for (const selector of selectors) {
|
|
44
|
-
if (!selectorsByScreen[selector.screenId]) {
|
|
45
|
-
selectorsByScreen[selector.screenId] = {};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!selectorsByScreen[selector.screenId][selector.elementId]) {
|
|
49
|
-
selectorsByScreen[selector.screenId][selector.elementId] = {
|
|
50
|
-
fullRef: selector.fullRef,
|
|
51
|
-
occurrences: 0,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
selectorsByScreen[selector.screenId][selector.elementId].occurrences++;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return selectorsByScreen;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Extract selectors from feature file content
|
|
64
|
-
*/
|
|
65
|
-
private extractSelectorsFromContent(content: string): ExtractedSelector[] {
|
|
66
|
-
const selectors: ExtractedSelector[] = [];
|
|
67
|
-
|
|
68
|
-
// Regex to match [screen.element] or [screen]
|
|
69
|
-
const selectorRegex = /\[([a-zA-Z0-9_-]+)(?:\.([a-zA-Z0-9_-]+))?\]/g;
|
|
70
|
-
|
|
71
|
-
let match;
|
|
72
|
-
while ((match = selectorRegex.exec(content)) !== null) {
|
|
73
|
-
const fullRef = match[0]; // e.g., "[auth-login.email]"
|
|
74
|
-
const screenId = match[1]; // e.g., "auth-login"
|
|
75
|
-
const elementId = match[2]; // e.g., "email" (undefined for route-only refs)
|
|
76
|
-
|
|
77
|
-
// Only include selectors with both screen and element (skip route-only refs)
|
|
78
|
-
if (elementId) {
|
|
79
|
-
selectors.push({
|
|
80
|
-
screenId,
|
|
81
|
-
elementId,
|
|
82
|
-
fullRef,
|
|
83
|
-
occurrences: 1,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return selectors;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Generate base skeleton YAML structure
|
|
93
|
-
*/
|
|
94
|
-
generateSkeletonYaml(screenId: string, selectors: SelectorsByScreen): string {
|
|
95
|
-
const screenSelectors = selectors[screenId];
|
|
96
|
-
|
|
97
|
-
if (!screenSelectors) {
|
|
98
|
-
return `# No selectors found for screen: ${screenId}\n`;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const lines: string[] = [
|
|
102
|
-
`# Selector skeleton for screen: ${screenId}`,
|
|
103
|
-
`# AI will fill in the selector values based on UI model`,
|
|
104
|
-
`# This file is generated by scanning Gherkin feature files`,
|
|
105
|
-
'',
|
|
106
|
-
];
|
|
107
|
-
|
|
108
|
-
// Sort by element ID for consistency
|
|
109
|
-
const sortedElementIds = Object.keys(screenSelectors).sort();
|
|
110
|
-
|
|
111
|
-
for (const elementId of sortedElementIds) {
|
|
112
|
-
const { fullRef, occurrences } = screenSelectors[elementId];
|
|
113
|
-
|
|
114
|
-
lines.push(`"${fullRef}":`);
|
|
115
|
-
lines.push(` selector: ""`);
|
|
116
|
-
lines.push(` type: ""`);
|
|
117
|
-
lines.push(` description: ""`);
|
|
118
|
-
lines.push(` # Referenced ${occurrences} time(s) in Gherkin`);
|
|
119
|
-
lines.push('');
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return lines.join('\n');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Write skeleton files for all screens
|
|
127
|
-
*/
|
|
128
|
-
writeSkeletonFiles(
|
|
129
|
-
selectors: SelectorsByScreen,
|
|
130
|
-
outputDir: string
|
|
131
|
-
): void {
|
|
132
|
-
// Ensure output directory exists
|
|
133
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
134
|
-
|
|
135
|
-
for (const screenId of Object.keys(selectors)) {
|
|
136
|
-
const skeletonContent = this.generateSkeletonYaml(screenId, selectors);
|
|
137
|
-
const outputPath = path.join(outputDir, `${screenId}.skeleton.yaml`);
|
|
138
|
-
|
|
139
|
-
fs.writeFileSync(outputPath, skeletonContent, 'utf-8');
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test Generator Types
|
|
3
|
-
* Core type definitions for the test generation compiler
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Generated Test Result
|
|
8
|
-
*/
|
|
9
|
-
export interface GeneratedTest {
|
|
10
|
-
featureName: string;
|
|
11
|
-
filePath: string;
|
|
12
|
-
code: string;
|
|
13
|
-
sourceFile?: string;
|
|
14
|
-
stepCount?: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Generation Statistics
|
|
19
|
-
*/
|
|
20
|
-
export interface GenerationStats {
|
|
21
|
-
totalScenarios: number;
|
|
22
|
-
totalSteps: number;
|
|
23
|
-
dictionaryMatched: number;
|
|
24
|
-
todoCount: number;
|
|
25
|
-
generationTime: number;
|
|
26
|
-
}
|
package/src/generators/types.ts
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core types for Selector DSL Framework
|
|
3
|
-
* Framework-agnostic types for multi-platform support
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ============================================================================
|
|
7
|
-
// UI Model Types
|
|
8
|
-
// ============================================================================
|
|
9
|
-
|
|
10
|
-
export interface UIElement {
|
|
11
|
-
key: string; // Unique key within screen (e1, e2, ...)
|
|
12
|
-
tag: string; // HTML/component tag (input, button, View, TextField, ...)
|
|
13
|
-
role?: string; // ARIA role or semantic role
|
|
14
|
-
name?: string; // name attribute
|
|
15
|
-
id?: string; // id/resource-id attribute
|
|
16
|
-
placeholder?: string; // placeholder text
|
|
17
|
-
label?: string; // Associated label text
|
|
18
|
-
text?: string; // Text content
|
|
19
|
-
ariaLabel?: string; // aria-label attribute
|
|
20
|
-
testId?: string; // data-testid / test ID
|
|
21
|
-
source: string; // Source file path
|
|
22
|
-
framework?: string; // Framework-specific type (TextField, EditText, etc.)
|
|
23
|
-
props?: Record<string, any>; // Additional framework-specific props
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface UIModel {
|
|
27
|
-
screenId: string; // Screen identifier (login, dashboard, ...)
|
|
28
|
-
routeId: string; // Route path or identifier
|
|
29
|
-
framework: FrameworkType; // Framework type
|
|
30
|
-
sourceFiles: string[]; // All source files merged
|
|
31
|
-
elements: UIElement[]; // All UI elements on this screen
|
|
32
|
-
metadata?: {
|
|
33
|
-
scannedAt: string; // ISO timestamp
|
|
34
|
-
version: string; // Tool version
|
|
35
|
-
hash: string; // Content hash for cache
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ============================================================================
|
|
40
|
-
// Selector DSL Types
|
|
41
|
-
// ============================================================================
|
|
42
|
-
|
|
43
|
-
export type DiscoveryMethod =
|
|
44
|
-
| 'ai-static-analysis' // Generated by AI from static code analysis
|
|
45
|
-
| 'manual' // Manually written by QA
|
|
46
|
-
| 'runtime'; // Discovered at runtime
|
|
47
|
-
|
|
48
|
-
export type LocatorType =
|
|
49
|
-
| 'css' // CSS selector (web)
|
|
50
|
-
| 'xpath' // XPath selector
|
|
51
|
-
| 'resource-id' // Android resource-id
|
|
52
|
-
| 'accessibility-id' // iOS accessibility identifier
|
|
53
|
-
| 'test-id' // Framework test ID (data-testid, etc.)
|
|
54
|
-
| 'key' // Flutter Key
|
|
55
|
-
| 'text' // Text-based locator
|
|
56
|
-
| 'role'; // ARIA role locator
|
|
57
|
-
|
|
58
|
-
export interface SelectorEntry {
|
|
59
|
-
selector: string; // The actual selector string
|
|
60
|
-
type: string; // Element type (input, button, link, text, ...)
|
|
61
|
-
description: string; // Human-readable description
|
|
62
|
-
discoveryMethod: DiscoveryMethod;
|
|
63
|
-
locatorType?: LocatorType; // Type of locator (for multi-platform)
|
|
64
|
-
confidence?: 'high' | 'medium' | 'low'; // AI confidence level
|
|
65
|
-
alternatives?: string[]; // Alternative selectors (fallbacks)
|
|
66
|
-
metadata?: {
|
|
67
|
-
lastValidated?: string; // ISO timestamp
|
|
68
|
-
validationStatus?: 'valid' | 'invalid' | 'unknown';
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface SelectorDSL {
|
|
73
|
-
[elementId: string]: SelectorEntry;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ============================================================================
|
|
77
|
-
// Framework Types
|
|
78
|
-
// ============================================================================
|
|
79
|
-
|
|
80
|
-
export type FrameworkType =
|
|
81
|
-
| 'react'
|
|
82
|
-
| 'react-nextjs'
|
|
83
|
-
| 'vue'
|
|
84
|
-
| 'angular'
|
|
85
|
-
| 'html'
|
|
86
|
-
| 'flutter'
|
|
87
|
-
| 'jetpack-compose'
|
|
88
|
-
| 'swiftui';
|
|
89
|
-
|
|
90
|
-
export type TargetPlatform =
|
|
91
|
-
| 'web'
|
|
92
|
-
| 'android'
|
|
93
|
-
| 'ios'
|
|
94
|
-
| 'desktop';
|
|
95
|
-
|
|
96
|
-
// ============================================================================
|
|
97
|
-
// Executor Types
|
|
98
|
-
// ============================================================================
|
|
99
|
-
|
|
100
|
-
export type ExecutorType =
|
|
101
|
-
| 'playwright' // Web - Playwright
|
|
102
|
-
| 'puppeteer' // Web - Puppeteer
|
|
103
|
-
| 'selenium' // Web - Selenium
|
|
104
|
-
| 'appium-android' // Android - Appium
|
|
105
|
-
| 'appium-ios' // iOS - Appium
|
|
106
|
-
| 'flutter-driver' // Flutter Driver
|
|
107
|
-
| 'espresso' // Android - Espresso
|
|
108
|
-
| 'xcuitest'; // iOS - XCUITest
|
|
109
|
-
|
|
110
|
-
export interface ExecutorConfig {
|
|
111
|
-
type: ExecutorType;
|
|
112
|
-
platform: TargetPlatform;
|
|
113
|
-
selectorPath: string; // Path to selector DSL files
|
|
114
|
-
overridePath?: string; // Path to override files
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ============================================================================
|
|
118
|
-
// Cache Types
|
|
119
|
-
// ============================================================================
|
|
120
|
-
|
|
121
|
-
export interface CacheEntry {
|
|
122
|
-
screenId: string;
|
|
123
|
-
hash: string; // SHA-256 hash of UI Model + element IDs
|
|
124
|
-
selectors: SelectorDSL;
|
|
125
|
-
metadata: {
|
|
126
|
-
createdAt: string; // ISO timestamp
|
|
127
|
-
aiModel?: string; // AI model used (claude-3-5-sonnet, gemini-2.0-flash, ...)
|
|
128
|
-
tokenCost?: number; // Token usage
|
|
129
|
-
framework: FrameworkType;
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// ============================================================================
|
|
134
|
-
// Generator Config Types
|
|
135
|
-
// ============================================================================
|
|
136
|
-
|
|
137
|
-
export interface GeneratorConfig {
|
|
138
|
-
// AI Provider
|
|
139
|
-
aiProvider: 'anthropic' | 'google' | 'openai';
|
|
140
|
-
aiModel?: string; // Optional: specific model (defaults to best available)
|
|
141
|
-
|
|
142
|
-
// Paths
|
|
143
|
-
sourceRoot: string; // Root directory to scan (e.g., 'app', 'src')
|
|
144
|
-
uiModelPath: string; // Where to save UI models
|
|
145
|
-
selectorPath: string; // Where to save selectors
|
|
146
|
-
cachePath: string; // Cache directory
|
|
147
|
-
|
|
148
|
-
// Framework
|
|
149
|
-
framework: FrameworkType;
|
|
150
|
-
|
|
151
|
-
// Options
|
|
152
|
-
enableCache: boolean;
|
|
153
|
-
cacheExpiry?: number; // Cache expiry in milliseconds
|
|
154
|
-
parallelScans?: number; // Number of parallel scans
|
|
155
|
-
verbose?: boolean;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// ============================================================================
|
|
159
|
-
// CLI Types
|
|
160
|
-
// ============================================================================
|
|
161
|
-
|
|
162
|
-
export interface DiscoverOptions {
|
|
163
|
-
screenId?: string; // Specific screen to discover
|
|
164
|
-
all?: boolean; // Discover all screens
|
|
165
|
-
force?: boolean; // Force re-scan even if cached
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export interface GenerateOptions {
|
|
169
|
-
screenId?: string; // Specific screen to generate
|
|
170
|
-
all?: boolean; // Generate all screens
|
|
171
|
-
force?: boolean; // Force re-generation
|
|
172
|
-
skipCache?: boolean; // Skip cache lookup
|
|
173
|
-
runtimeData?: boolean; // Runtime data loading (default: true). False = compile-time hardcoding.
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
export interface ValidateOptions {
|
|
177
|
-
screenId?: string; // Specific screen to validate
|
|
178
|
-
all?: boolean; // Validate all screens
|
|
179
|
-
executor?: ExecutorType; // Executor to validate against
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// ============================================================================
|
|
183
|
-
// Gherkin Integration Types
|
|
184
|
-
// ============================================================================
|
|
185
|
-
|
|
186
|
-
export interface GherkinElementReference {
|
|
187
|
-
elementId: string; // e.g., "[login.email]"
|
|
188
|
-
screenId: string; // e.g., "login"
|
|
189
|
-
elementName: string; // e.g., "email"
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export function parseElementReference(ref: string): GherkinElementReference | null {
|
|
193
|
-
// Parse "[screen.element]" format
|
|
194
|
-
const match = ref.match(/^\[([^.]+)\.([^\]]+)\]$/);
|
|
195
|
-
if (!match) return null;
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
elementId: ref,
|
|
199
|
-
screenId: match[1],
|
|
200
|
-
elementName: match[2]
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// ============================================================================
|
|
205
|
-
// Error Types
|
|
206
|
-
// ============================================================================
|
|
207
|
-
|
|
208
|
-
export class SelectorNotFoundError extends Error {
|
|
209
|
-
constructor(public elementId: string, public screenId: string) {
|
|
210
|
-
super(`Selector not found: ${elementId} on screen ${screenId}`);
|
|
211
|
-
this.name = 'SelectorNotFoundError';
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export class UIModelNotFoundError extends Error {
|
|
216
|
-
constructor(public screenId: string) {
|
|
217
|
-
super(`UI Model not found for screen: ${screenId}`);
|
|
218
|
-
this.name = 'UIModelNotFoundError';
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
export class GeneratorError extends Error {
|
|
223
|
-
constructor(message: string, public cause?: Error) {
|
|
224
|
-
super(message);
|
|
225
|
-
this.name = 'GeneratorError';
|
|
226
|
-
}
|
|
227
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure helper: collapse consecutive repeated segments in a Figma node path.
|
|
3
|
-
*
|
|
4
|
-
* Delimiter: " > " (space-angle-space).
|
|
5
|
-
* Collapsed runs use the multiplication sign × (U+00D7).
|
|
6
|
-
*
|
|
7
|
-
* Examples:
|
|
8
|
-
* "A > B > C" → "A > B > C" (unchanged)
|
|
9
|
-
* "A > B > B > C" → "A > B×2 > C"
|
|
10
|
-
* "Container > Container > Container > X" → "Container×3 > X"
|
|
11
|
-
* "A > A > A > A > A > B > C" → "A×5 > B > C"
|
|
12
|
-
* "A" → "A" (single)
|
|
13
|
-
* "" → "" (empty)
|
|
14
|
-
*/
|
|
15
|
-
export function collapseNodePath(path: string): string {
|
|
16
|
-
if (!path) return path;
|
|
17
|
-
|
|
18
|
-
const DELIMITER = ' > ';
|
|
19
|
-
const segments = path.split(DELIMITER);
|
|
20
|
-
|
|
21
|
-
const collapsed: string[] = [];
|
|
22
|
-
let i = 0;
|
|
23
|
-
|
|
24
|
-
while (i < segments.length) {
|
|
25
|
-
const current = segments[i];
|
|
26
|
-
let count = 1;
|
|
27
|
-
|
|
28
|
-
// Count consecutive identical segments
|
|
29
|
-
while (i + count < segments.length && segments[i + count] === current) {
|
|
30
|
-
count++;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
collapsed.push(count > 1 ? `${current}×${count}` : current);
|
|
34
|
-
i += count;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return collapsed.join(DELIMITER);
|
|
38
|
-
}
|