@sun-asterisk/sungen 2.6.0 → 2.6.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.
- package/dist/cli/commands/dashboard.d.ts +10 -0
- package/dist/cli/commands/dashboard.d.ts.map +1 -0
- package/dist/cli/commands/dashboard.js +171 -0
- package/dist/cli/commands/dashboard.js.map +1 -0
- package/dist/cli/index.js +4 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/history-store.d.ts +27 -0
- package/dist/dashboard/history-store.d.ts.map +1 -0
- package/dist/dashboard/history-store.js +112 -0
- package/dist/dashboard/history-store.js.map +1 -0
- package/dist/dashboard/html-renderer.d.ts +30 -0
- package/dist/dashboard/html-renderer.d.ts.map +1 -0
- package/dist/dashboard/html-renderer.js +111 -0
- package/dist/dashboard/html-renderer.js.map +1 -0
- package/dist/dashboard/snapshot-builder.d.ts +30 -0
- package/dist/dashboard/snapshot-builder.d.ts.map +1 -0
- package/dist/dashboard/snapshot-builder.js +263 -0
- package/dist/dashboard/snapshot-builder.js.map +1 -0
- package/dist/dashboard/templates/index.html +287 -0
- package/dist/dashboard/types.d.ts +122 -0
- package/dist/dashboard/types.d.ts.map +1 -0
- package/dist/dashboard/types.js +11 -0
- package/dist/dashboard/types.js.map +1 -0
- package/dist/exporters/json-exporter.d.ts +25 -0
- package/dist/exporters/json-exporter.d.ts.map +1 -0
- package/dist/exporters/json-exporter.js +135 -0
- package/dist/exporters/json-exporter.js.map +1 -0
- package/dist/exporters/playwright-report-parser.d.ts +2 -1
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +12 -5
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/spec-parser.d.ts.map +1 -1
- package/dist/exporters/spec-parser.js +8 -3
- package/dist/exporters/spec-parser.js.map +1 -1
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +15 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +2 -0
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/scenario.hbs +20 -1
- package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +84 -4
- package/dist/generators/test-generator/code-generator.d.ts +1 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +76 -6
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.js +22 -3
- package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/navigation-patterns.js +8 -3
- package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts +13 -0
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +1 -1
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +3 -1
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +70 -10
- package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +23 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +70 -10
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +23 -0
- package/dist/orchestrator/templates/playwright.config.d.ts.map +1 -1
- package/dist/orchestrator/templates/playwright.config.js +9 -1
- package/dist/orchestrator/templates/playwright.config.js.map +1 -1
- package/dist/orchestrator/templates/playwright.config.ts +11 -1
- package/dist/orchestrator/templates/specs-base.d.ts +3 -4
- package/dist/orchestrator/templates/specs-base.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-base.js +53 -39
- package/dist/orchestrator/templates/specs-base.js.map +1 -1
- package/dist/orchestrator/templates/specs-base.ts +55 -45
- package/dist/orchestrator/templates/specs-test-data.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-test-data.js +43 -0
- package/dist/orchestrator/templates/specs-test-data.js.map +1 -1
- package/dist/orchestrator/templates/specs-test-data.ts +47 -0
- package/package.json +4 -3
- package/src/cli/commands/dashboard.ts +158 -0
- package/src/cli/index.ts +4 -2
- package/src/dashboard/history-store.ts +86 -0
- package/src/dashboard/html-renderer.ts +90 -0
- package/src/dashboard/snapshot-builder.ts +273 -0
- package/src/dashboard/templates/index.html +287 -0
- package/src/dashboard/types.ts +148 -0
- package/src/exporters/json-exporter.ts +162 -0
- package/src/exporters/playwright-report-parser.ts +12 -5
- package/src/exporters/spec-parser.ts +8 -3
- package/src/generators/test-generator/adapters/adapter-interface.ts +6 -1
- package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/scenario.hbs +20 -1
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +84 -4
- package/src/generators/test-generator/code-generator.ts +88 -7
- package/src/generators/test-generator/patterns/interaction-patterns.ts +25 -3
- package/src/generators/test-generator/patterns/navigation-patterns.ts +8 -3
- package/src/generators/test-generator/template-engine.ts +5 -2
- package/src/orchestrator/screen-manager.ts +3 -1
- package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +70 -10
- package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +23 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +70 -10
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +23 -0
- package/src/orchestrator/templates/playwright.config.ts +11 -1
- package/src/orchestrator/templates/specs-base.ts +55 -45
- package/src/orchestrator/templates/specs-test-data.ts +47 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sungen dashboard` CLI command.
|
|
3
|
+
*
|
|
4
|
+
* Builds qa/dashboard/index.html — a single-file, share-ready test report —
|
|
5
|
+
* from existing Gherkin features, compiled .spec.ts files, and Playwright
|
|
6
|
+
* results. Snapshots are persisted under qa/dashboard/history/ (max 20).
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
export declare function registerDashboardCommand(program: Command): void;
|
|
10
|
+
//# sourceMappingURL=dashboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwDpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiF/D"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `sungen dashboard` CLI command.
|
|
4
|
+
*
|
|
5
|
+
* Builds qa/dashboard/index.html — a single-file, share-ready test report —
|
|
6
|
+
* from existing Gherkin features, compiled .spec.ts files, and Playwright
|
|
7
|
+
* results. Snapshots are persisted under qa/dashboard/history/ (max 20).
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.registerDashboardCommand = registerDashboardCommand;
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const child_process_1 = require("child_process");
|
|
47
|
+
const snapshot_builder_1 = require("../../dashboard/snapshot-builder");
|
|
48
|
+
const history_store_1 = require("../../dashboard/history-store");
|
|
49
|
+
const html_renderer_1 = require("../../dashboard/html-renderer");
|
|
50
|
+
const COLOR = {
|
|
51
|
+
reset: '\x1b[0m',
|
|
52
|
+
gray: '\x1b[90m',
|
|
53
|
+
green: '\x1b[32m',
|
|
54
|
+
red: '\x1b[31m',
|
|
55
|
+
yellow: '\x1b[33m',
|
|
56
|
+
cyan: '\x1b[36m',
|
|
57
|
+
bold: '\x1b[1m',
|
|
58
|
+
};
|
|
59
|
+
function log(msg) { console.log(msg); }
|
|
60
|
+
function getEnvironment(cwd) {
|
|
61
|
+
let baseURL = '';
|
|
62
|
+
let projectName = 'chromium';
|
|
63
|
+
const configPath = path.join(cwd, 'playwright.config.ts');
|
|
64
|
+
if (fs.existsSync(configPath)) {
|
|
65
|
+
const c = fs.readFileSync(configPath, 'utf-8');
|
|
66
|
+
const baseMatch = c.match(/baseURL:\s*['"]([^'"]+)['"]/);
|
|
67
|
+
if (baseMatch)
|
|
68
|
+
baseURL = baseMatch[1];
|
|
69
|
+
const projMatch = c.match(/name:\s*['"]([^'"]+)['"]/);
|
|
70
|
+
if (projMatch)
|
|
71
|
+
projectName = projMatch[1];
|
|
72
|
+
}
|
|
73
|
+
let executor = process.env.CI_USER || process.env.USER || '';
|
|
74
|
+
try {
|
|
75
|
+
const gitUser = (0, child_process_1.execSync)('git config user.name', { cwd, encoding: 'utf-8' }).trim();
|
|
76
|
+
if (gitUser)
|
|
77
|
+
executor = gitUser;
|
|
78
|
+
}
|
|
79
|
+
catch { /* ignore */ }
|
|
80
|
+
return { baseURL, projectName, executor };
|
|
81
|
+
}
|
|
82
|
+
function registerDashboardCommand(program) {
|
|
83
|
+
program
|
|
84
|
+
.command('dashboard')
|
|
85
|
+
.description('Build a single-file HTML dashboard summarising all test cases & results')
|
|
86
|
+
.argument('[names...]', 'Specific screen or flow names. Omit to include all.')
|
|
87
|
+
.option('--no-history', 'Do not persist this run under qa/dashboard/history/')
|
|
88
|
+
.option('--max-history <n>', `Cap retained history files (default: ${history_store_1.DEFAULT_MAX_HISTORY})`)
|
|
89
|
+
.option('--open', 'Open the rendered HTML in the default browser when done')
|
|
90
|
+
.action(async (names, options) => {
|
|
91
|
+
try {
|
|
92
|
+
const cwd = process.cwd();
|
|
93
|
+
// 1. Scope detection
|
|
94
|
+
let targets;
|
|
95
|
+
if (names && names.length > 0) {
|
|
96
|
+
targets = names.map((n) => (0, snapshot_builder_1.resolveTargetType)(cwd, n));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
targets = (0, snapshot_builder_1.listDashboardTargets)(cwd);
|
|
100
|
+
if (targets.length === 0) {
|
|
101
|
+
console.error(`${COLOR.red}No screens or flows found in qa/screens/ or qa/flows/${COLOR.reset}`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const labels = targets.map((t) => t.isFlow ? `flow/${t.name}` : t.name);
|
|
106
|
+
log(`${COLOR.bold}sungen dashboard${COLOR.reset} — building report for ${targets.length} target(s): ${labels.join(', ')}`);
|
|
107
|
+
// 2. Build snapshot
|
|
108
|
+
const env = getEnvironment(cwd);
|
|
109
|
+
const snapshot = (0, snapshot_builder_1.buildDashboardSnapshot)({
|
|
110
|
+
cwd,
|
|
111
|
+
targets,
|
|
112
|
+
env,
|
|
113
|
+
continueOnError: true,
|
|
114
|
+
});
|
|
115
|
+
log(`\n${COLOR.bold}Snapshot${COLOR.reset} ${snapshot.runId} ` +
|
|
116
|
+
`${COLOR.gray}(${snapshot.screens.length} screens, ${snapshot.summary.total} TCs)${COLOR.reset}`);
|
|
117
|
+
// 3. Persist history (unless disabled)
|
|
118
|
+
if (!options.noHistory) {
|
|
119
|
+
const max = options.maxHistory ? Math.max(1, parseInt(options.maxHistory, 10) || history_store_1.DEFAULT_MAX_HISTORY) : history_store_1.DEFAULT_MAX_HISTORY;
|
|
120
|
+
const result = (0, history_store_1.writeSnapshotToHistory)(cwd, snapshot, max);
|
|
121
|
+
log(` ${COLOR.green}✓${COLOR.reset} history ${path.relative(cwd, result.written)}`);
|
|
122
|
+
if (result.pruned.length > 0) {
|
|
123
|
+
log(` ${COLOR.gray} pruned ${result.pruned.length} older snapshot(s)${COLOR.reset}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// 4. Render HTML
|
|
127
|
+
const payload = (0, html_renderer_1.buildPayload)(cwd, snapshot);
|
|
128
|
+
const rendered = (0, html_renderer_1.renderDashboardHtml)(cwd, payload);
|
|
129
|
+
log(` ${COLOR.green}✓${COLOR.reset} html ${path.relative(cwd, rendered.outputPath)} ${COLOR.gray}(${(rendered.bytes / 1024 / 1024).toFixed(2)} MB)${COLOR.reset}`);
|
|
130
|
+
// 5. Print quick summary
|
|
131
|
+
const s = snapshot.summary;
|
|
132
|
+
log('');
|
|
133
|
+
log(` ${COLOR.bold}Summary${COLOR.reset}`);
|
|
134
|
+
log(` Total: ${s.total}`);
|
|
135
|
+
log(` ${COLOR.green}Passed${COLOR.reset}: ${s.passed}`);
|
|
136
|
+
log(` ${COLOR.red}Failed${COLOR.reset}: ${s.failed}`);
|
|
137
|
+
log(` Pending: ${s.pending}`);
|
|
138
|
+
log(` N/A: ${s.na}`);
|
|
139
|
+
if (s.notCompiled > 0) {
|
|
140
|
+
log(` ${COLOR.yellow}Not compiled${COLOR.reset}: ${s.notCompiled}`);
|
|
141
|
+
}
|
|
142
|
+
const passRatePct = (s.passRate * 100).toFixed(1);
|
|
143
|
+
log(` Pass rate: ${passRatePct}% ${COLOR.gray}(of executed)${COLOR.reset}`);
|
|
144
|
+
log('');
|
|
145
|
+
// 6. Optionally open in browser
|
|
146
|
+
if (options.open) {
|
|
147
|
+
openInBrowser(rendered.outputPath);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.error(`${COLOR.red}Fatal:${COLOR.reset} ${err instanceof Error ? err.message : err}`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function openInBrowser(filePath) {
|
|
157
|
+
const fileUrl = `file://${filePath}`;
|
|
158
|
+
const platform = process.platform;
|
|
159
|
+
try {
|
|
160
|
+
if (platform === 'darwin')
|
|
161
|
+
(0, child_process_1.execSync)(`open "${fileUrl}"`);
|
|
162
|
+
else if (platform === 'win32')
|
|
163
|
+
(0, child_process_1.execSync)(`start "" "${fileUrl}"`);
|
|
164
|
+
else
|
|
165
|
+
(0, child_process_1.execSync)(`xdg-open "${fileUrl}"`);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// ignore — user can open manually
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/cli/commands/dashboard.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -14,16 +14,17 @@ const update_1 = require("./commands/update");
|
|
|
14
14
|
const delivery_1 = require("./commands/delivery");
|
|
15
15
|
const figma_1 = require("./commands/figma");
|
|
16
16
|
const add_flow_1 = require("./commands/add-flow");
|
|
17
|
+
const dashboard_1 = require("./commands/dashboard");
|
|
17
18
|
async function main() {
|
|
18
19
|
const program = new commander_1.Command();
|
|
19
20
|
program
|
|
20
21
|
.name('sungen')
|
|
21
22
|
.description('Deterministic E2E Test Compiler — Gherkin + Selectors → Playwright')
|
|
22
|
-
.version('2.6.
|
|
23
|
+
.version('2.6.2');
|
|
23
24
|
// Global options
|
|
24
25
|
program
|
|
25
26
|
.option('-v, --verbose', 'Enable verbose logging');
|
|
26
|
-
// Register commands (
|
|
27
|
+
// Register commands (9)
|
|
27
28
|
(0, init_1.registerInitCommand)(program);
|
|
28
29
|
(0, add_1.registerAddCommand)(program);
|
|
29
30
|
(0, generate_1.registerGenerateCommand)(program);
|
|
@@ -32,6 +33,7 @@ async function main() {
|
|
|
32
33
|
(0, delivery_1.registerDeliveryCommand)(program);
|
|
33
34
|
(0, figma_1.registerFigmaCommand)(program);
|
|
34
35
|
(0, add_flow_1.registerAddFlowCommand)(program);
|
|
36
|
+
(0, dashboard_1.registerDashboardCommand)(program);
|
|
35
37
|
await program.parseAsync(process.argv);
|
|
36
38
|
}
|
|
37
39
|
main().catch((error) => {
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;AACA;;;GAGG;;AAEH,yCAAoC;AACpC,0CAAsD;AACtD,wCAAoD;AACpD,kDAA8D;AAC9D,kDAA8D;AAC9D,8CAA0D;AAC1D,kDAA8D;AAC9D,4CAAwD;AACxD,kDAA6D;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;AACA;;;GAGG;;AAEH,yCAAoC;AACpC,0CAAsD;AACtD,wCAAoD;AACpD,kDAA8D;AAC9D,kDAA8D;AAC9D,8CAA0D;AAC1D,kDAA8D;AAC9D,4CAAwD;AACxD,kDAA6D;AAC7D,oDAAgE;AAEhE,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CAAC,oEAAoE,CAAC;SACjF,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,iBAAiB;IACjB,OAAO;SACJ,MAAM,CAAC,eAAe,EAAE,wBAAwB,CAAC,CAAC;IAErD,wBAAwB;IACxB,IAAA,0BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,wBAAkB,EAAC,OAAO,CAAC,CAAC;IAC5B,IAAA,kCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,kCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,kCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,4BAAoB,EAAC,OAAO,CAAC,CAAC;IAC9B,IAAA,iCAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,oCAAwB,EAAC,OAAO,CAAC,CAAC;IAElC,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persist dashboard snapshots under qa/dashboard/history/ and prune to a fixed
|
|
3
|
+
* max count (oldest by mtime are deleted). Used by `sungen dashboard` to
|
|
4
|
+
* accumulate runs for Trends / Compare views.
|
|
5
|
+
*/
|
|
6
|
+
import { DashboardSnapshot } from './types';
|
|
7
|
+
export declare const DEFAULT_MAX_HISTORY = 20;
|
|
8
|
+
export interface HistoryWriteResult {
|
|
9
|
+
written: string;
|
|
10
|
+
pruned: string[];
|
|
11
|
+
retained: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare function historyDir(cwd: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Write `snapshot` as <runId>.json and prune older files until at most `max`
|
|
16
|
+
* files remain. Files are sorted by mtime so manual edits (rare) still work.
|
|
17
|
+
*/
|
|
18
|
+
export declare function writeSnapshotToHistory(cwd: string, snapshot: DashboardSnapshot, max?: number): HistoryWriteResult;
|
|
19
|
+
/**
|
|
20
|
+
* Return absolute paths of every JSON file under history/, sorted newest → oldest.
|
|
21
|
+
*/
|
|
22
|
+
export declare function listHistoryFiles(dir: string): string[];
|
|
23
|
+
/**
|
|
24
|
+
* Read every history JSON, oldest → newest. Skips files that fail to parse.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readHistory(cwd: string): DashboardSnapshot[];
|
|
27
|
+
//# sourceMappingURL=history-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-store.d.ts","sourceRoot":"","sources":["../../src/dashboard/history-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,iBAAiB,EAC3B,GAAG,GAAE,MAA4B,GAChC,kBAAkB,CAYpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAMtD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAa5D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Persist dashboard snapshots under qa/dashboard/history/ and prune to a fixed
|
|
4
|
+
* max count (oldest by mtime are deleted). Used by `sungen dashboard` to
|
|
5
|
+
* accumulate runs for Trends / Compare views.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.DEFAULT_MAX_HISTORY = void 0;
|
|
42
|
+
exports.historyDir = historyDir;
|
|
43
|
+
exports.writeSnapshotToHistory = writeSnapshotToHistory;
|
|
44
|
+
exports.listHistoryFiles = listHistoryFiles;
|
|
45
|
+
exports.readHistory = readHistory;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
exports.DEFAULT_MAX_HISTORY = 20;
|
|
49
|
+
function historyDir(cwd) {
|
|
50
|
+
return path.join(cwd, 'qa', 'dashboard', 'history');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Write `snapshot` as <runId>.json and prune older files until at most `max`
|
|
54
|
+
* files remain. Files are sorted by mtime so manual edits (rare) still work.
|
|
55
|
+
*/
|
|
56
|
+
function writeSnapshotToHistory(cwd, snapshot, max = exports.DEFAULT_MAX_HISTORY) {
|
|
57
|
+
const dir = historyDir(cwd);
|
|
58
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
59
|
+
const filename = `${snapshot.runId}.json`;
|
|
60
|
+
const target = path.join(dir, filename);
|
|
61
|
+
fs.writeFileSync(target, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
62
|
+
const pruned = pruneHistory(dir, max);
|
|
63
|
+
const retained = listHistoryFiles(dir);
|
|
64
|
+
return { written: target, pruned, retained };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Return absolute paths of every JSON file under history/, sorted newest → oldest.
|
|
68
|
+
*/
|
|
69
|
+
function listHistoryFiles(dir) {
|
|
70
|
+
if (!fs.existsSync(dir))
|
|
71
|
+
return [];
|
|
72
|
+
return fs.readdirSync(dir)
|
|
73
|
+
.filter((f) => f.endsWith('.json'))
|
|
74
|
+
.map((f) => path.join(dir, f))
|
|
75
|
+
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Read every history JSON, oldest → newest. Skips files that fail to parse.
|
|
79
|
+
*/
|
|
80
|
+
function readHistory(cwd) {
|
|
81
|
+
const dir = historyDir(cwd);
|
|
82
|
+
const files = listHistoryFiles(dir).reverse(); // oldest → newest
|
|
83
|
+
const out = [];
|
|
84
|
+
for (const f of files) {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(fs.readFileSync(f, 'utf-8'));
|
|
87
|
+
out.push(parsed);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// ignore malformed
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Delete oldest files in `dir` until at most `max` remain.
|
|
97
|
+
* Returns the absolute paths removed.
|
|
98
|
+
*/
|
|
99
|
+
function pruneHistory(dir, max) {
|
|
100
|
+
const files = listHistoryFiles(dir); // newest first
|
|
101
|
+
if (files.length <= max)
|
|
102
|
+
return [];
|
|
103
|
+
const toRemove = files.slice(max);
|
|
104
|
+
for (const f of toRemove) {
|
|
105
|
+
try {
|
|
106
|
+
fs.unlinkSync(f);
|
|
107
|
+
}
|
|
108
|
+
catch { /* ignore */ }
|
|
109
|
+
}
|
|
110
|
+
return toRemove;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=history-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-store.js","sourceRoot":"","sources":["../../src/dashboard/history-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inject a DashboardPayload into the pre-built single-file HTML template,
|
|
3
|
+
* then write the result to qa/dashboard/index.html.
|
|
4
|
+
*
|
|
5
|
+
* The template lives at src/dashboard/templates/index.html (built by
|
|
6
|
+
* dashboard/, then copied during `npm run build`). It must contain
|
|
7
|
+
* the placeholder line:
|
|
8
|
+
*
|
|
9
|
+
* <script id="__SUNGEN_DASHBOARD__" type="application/json">{}</script>
|
|
10
|
+
*
|
|
11
|
+
* The renderer replaces the JSON content with the payload — no other
|
|
12
|
+
* mutation. This keeps the template itself fully static, so opening it
|
|
13
|
+
* directly (without running the CLI) shows an empty-state dashboard.
|
|
14
|
+
*/
|
|
15
|
+
import { DashboardPayload, DashboardSnapshot } from './types';
|
|
16
|
+
/**
|
|
17
|
+
* Locate the bundled template. Looks first in dist/ (production), then src/
|
|
18
|
+
* (when running via tsx in dev).
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveTemplatePath(): string;
|
|
21
|
+
export declare function buildPayload(cwd: string, current: DashboardSnapshot): DashboardPayload;
|
|
22
|
+
export interface RenderResult {
|
|
23
|
+
outputPath: string;
|
|
24
|
+
bytes: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Render `payload` into the template and write to qa/dashboard/index.html.
|
|
28
|
+
*/
|
|
29
|
+
export declare function renderDashboardHtml(cwd: string, payload: DashboardPayload): RenderResult;
|
|
30
|
+
//# sourceMappingURL=html-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-renderer.d.ts","sourceRoot":"","sources":["../../src/dashboard/html-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAM9D;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAe5C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAKtF;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAaxF"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Inject a DashboardPayload into the pre-built single-file HTML template,
|
|
4
|
+
* then write the result to qa/dashboard/index.html.
|
|
5
|
+
*
|
|
6
|
+
* The template lives at src/dashboard/templates/index.html (built by
|
|
7
|
+
* dashboard/, then copied during `npm run build`). It must contain
|
|
8
|
+
* the placeholder line:
|
|
9
|
+
*
|
|
10
|
+
* <script id="__SUNGEN_DASHBOARD__" type="application/json">{}</script>
|
|
11
|
+
*
|
|
12
|
+
* The renderer replaces the JSON content with the payload — no other
|
|
13
|
+
* mutation. This keeps the template itself fully static, so opening it
|
|
14
|
+
* directly (without running the CLI) shows an empty-state dashboard.
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.resolveTemplatePath = resolveTemplatePath;
|
|
51
|
+
exports.buildPayload = buildPayload;
|
|
52
|
+
exports.renderDashboardHtml = renderDashboardHtml;
|
|
53
|
+
const fs = __importStar(require("fs"));
|
|
54
|
+
const path = __importStar(require("path"));
|
|
55
|
+
const history_store_1 = require("./history-store");
|
|
56
|
+
const PAYLOAD_TAG_OPEN = '<script id="__SUNGEN_DASHBOARD__" type="application/json">';
|
|
57
|
+
const PAYLOAD_TAG_CLOSE = '</script>';
|
|
58
|
+
/**
|
|
59
|
+
* Locate the bundled template. Looks first in dist/ (production), then src/
|
|
60
|
+
* (when running via tsx in dev).
|
|
61
|
+
*/
|
|
62
|
+
function resolveTemplatePath() {
|
|
63
|
+
const candidates = [
|
|
64
|
+
// Compiled package: dist/dashboard/templates/index.html (copy-templates)
|
|
65
|
+
path.join(__dirname, 'templates', 'index.html'),
|
|
66
|
+
// Dev: src/dashboard/templates/index.html
|
|
67
|
+
path.join(__dirname, '..', '..', 'src', 'dashboard', 'templates', 'index.html'),
|
|
68
|
+
];
|
|
69
|
+
for (const c of candidates) {
|
|
70
|
+
if (fs.existsSync(c))
|
|
71
|
+
return c;
|
|
72
|
+
}
|
|
73
|
+
throw new Error('Dashboard HTML template not found. Build it via:\n' +
|
|
74
|
+
' cd dashboard && npm install && npm run build\n' +
|
|
75
|
+
'then copy dashboard/dist/index.html → src/dashboard/templates/index.html');
|
|
76
|
+
}
|
|
77
|
+
function buildPayload(cwd, current) {
|
|
78
|
+
const all = (0, history_store_1.readHistory)(cwd);
|
|
79
|
+
// Exclude `current` from history if it's been written there already.
|
|
80
|
+
const history = all.filter((s) => s.runId !== current.runId);
|
|
81
|
+
return { current, history };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Render `payload` into the template and write to qa/dashboard/index.html.
|
|
85
|
+
*/
|
|
86
|
+
function renderDashboardHtml(cwd, payload) {
|
|
87
|
+
const templatePath = resolveTemplatePath();
|
|
88
|
+
const template = fs.readFileSync(templatePath, 'utf-8');
|
|
89
|
+
const json = JSON.stringify(payload);
|
|
90
|
+
const replaced = injectPayload(template, json);
|
|
91
|
+
const outDir = path.join(cwd, 'qa', 'dashboard');
|
|
92
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
93
|
+
const outputPath = path.join(outDir, 'index.html');
|
|
94
|
+
fs.writeFileSync(outputPath, replaced, 'utf-8');
|
|
95
|
+
return { outputPath, bytes: Buffer.byteLength(replaced, 'utf-8') };
|
|
96
|
+
}
|
|
97
|
+
function injectPayload(template, json) {
|
|
98
|
+
const start = template.indexOf(PAYLOAD_TAG_OPEN);
|
|
99
|
+
if (start === -1) {
|
|
100
|
+
throw new Error(`Template is missing the payload placeholder ${PAYLOAD_TAG_OPEN}…${PAYLOAD_TAG_CLOSE}`);
|
|
101
|
+
}
|
|
102
|
+
const contentStart = start + PAYLOAD_TAG_OPEN.length;
|
|
103
|
+
const contentEnd = template.indexOf(PAYLOAD_TAG_CLOSE, contentStart);
|
|
104
|
+
if (contentEnd === -1) {
|
|
105
|
+
throw new Error('Template payload placeholder is unterminated');
|
|
106
|
+
}
|
|
107
|
+
// Escape </script> inside JSON to prevent breaking the surrounding script tag.
|
|
108
|
+
const safe = json.replace(/<\/script>/gi, '<\\/script>');
|
|
109
|
+
return template.slice(0, contentStart) + safe + template.slice(contentEnd);
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=html-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-renderer.js","sourceRoot":"","sources":["../../src/dashboard/html-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrate dashboard snapshot construction across all screens/flows.
|
|
3
|
+
*
|
|
4
|
+
* Inputs are read from the same on-disk sources used by `sungen delivery`:
|
|
5
|
+
* qa/screens/<name>/... feature, test-data, selectors, requirements
|
|
6
|
+
* qa/flows/<name>/...
|
|
7
|
+
* specs/generated/<...>/... compiled .spec.ts + per-target test-result.json
|
|
8
|
+
* test-results/results.json global fallback
|
|
9
|
+
*
|
|
10
|
+
* Output is a DashboardSnapshot ready to be embedded in HTML or written as
|
|
11
|
+
* a history entry under qa/dashboard/history/<runId>.json.
|
|
12
|
+
*/
|
|
13
|
+
import { EnvironmentInfo } from '../exporters/types';
|
|
14
|
+
import { DashboardSnapshot, ScenarioSnapshot } from './types';
|
|
15
|
+
export interface DashboardTarget {
|
|
16
|
+
name: string;
|
|
17
|
+
isFlow: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface BuildSnapshotOptions {
|
|
20
|
+
cwd: string;
|
|
21
|
+
targets: DashboardTarget[];
|
|
22
|
+
env: EnvironmentInfo;
|
|
23
|
+
/** Skip targets where the .feature/.spec.ts pair fails to parse. */
|
|
24
|
+
continueOnError?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function buildDashboardSnapshot(options: BuildSnapshotOptions): DashboardSnapshot;
|
|
27
|
+
export declare function listDashboardTargets(cwd: string): DashboardTarget[];
|
|
28
|
+
export declare function resolveTargetType(cwd: string, name: string): DashboardTarget;
|
|
29
|
+
export type { ScenarioSnapshot };
|
|
30
|
+
//# sourceMappingURL=snapshot-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-builder.d.ts","sourceRoot":"","sources":["../../src/dashboard/snapshot-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,EAGjB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,GAAG,EAAE,eAAe,CAAC;IACrB,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,oBAAoB,GAAG,iBAAiB,CAwBvF;AAkHD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,EAAE,CAkBnE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAK5E;AAgED,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
|