@ia-qa/self-healing 0.2.1 → 0.3.1
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/browser/contract.d.ts +6 -1
- package/dist/browser/contract.js +64 -1
- package/dist/browser/contract.js.map +1 -1
- package/dist/cli/diff.d.ts +7 -4
- package/dist/cli/diff.js +161 -5
- package/dist/cli/diff.js.map +1 -1
- package/dist/cli/fix.d.ts +9 -8
- package/dist/cli/fix.js +132 -8
- package/dist/cli/fix.js.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/map.d.ts +3 -0
- package/dist/cli/map.js +118 -0
- package/dist/cli/map.js.map +1 -1
- package/dist/config.d.ts +27 -0
- package/dist/config.js +11 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +54 -0
- package/dist/layout.js +183 -0
- package/dist/layout.js.map +1 -0
- package/dist/markdown.d.ts +9 -3
- package/dist/markdown.js +16 -3
- package/dist/markdown.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/map.d.ts
CHANGED
|
@@ -5,5 +5,8 @@
|
|
|
5
5
|
* see `resolveSecret`), launches headless Chromium, logs in if configured,
|
|
6
6
|
* then visits each target page and writes a compressed accessibility mapping
|
|
7
7
|
* to `.ia-qa/mapping/<page-name>.json`.
|
|
8
|
+
*
|
|
9
|
+
* After all pages are mapped, if `config.layouts` is defined, extracts shared
|
|
10
|
+
* elements into `_layouts/<name>.json` and strips them from per-page mappings.
|
|
8
11
|
*/
|
|
9
12
|
export declare function runMap(pageNameArg?: string): Promise<void>;
|
package/dist/cli/map.js
CHANGED
|
@@ -39,6 +39,8 @@ const launcher_1 = require("../launcher");
|
|
|
39
39
|
const config_1 = require("../config");
|
|
40
40
|
const aom_1 = require("../aom");
|
|
41
41
|
const markdown_1 = require("../markdown");
|
|
42
|
+
const layout_1 = require("../layout");
|
|
43
|
+
const markdown_2 = require("../markdown");
|
|
42
44
|
/**
|
|
43
45
|
* `ia-qa-heal map [pageName]` — scraping & DOM compression engine.
|
|
44
46
|
*
|
|
@@ -46,6 +48,9 @@ const markdown_1 = require("../markdown");
|
|
|
46
48
|
* see `resolveSecret`), launches headless Chromium, logs in if configured,
|
|
47
49
|
* then visits each target page and writes a compressed accessibility mapping
|
|
48
50
|
* to `.ia-qa/mapping/<page-name>.json`.
|
|
51
|
+
*
|
|
52
|
+
* After all pages are mapped, if `config.layouts` is defined, extracts shared
|
|
53
|
+
* elements into `_layouts/<name>.json` and strips them from per-page mappings.
|
|
49
54
|
*/
|
|
50
55
|
async function runMap(pageNameArg) {
|
|
51
56
|
const config = (0, config_1.loadConfig)();
|
|
@@ -86,6 +91,119 @@ async function runMap(pageNameArg) {
|
|
|
86
91
|
finally {
|
|
87
92
|
await browser.close();
|
|
88
93
|
}
|
|
94
|
+
// Post-mapping: detect & extract layout components (only when mapping all pages)
|
|
95
|
+
if (!pageNameArg) {
|
|
96
|
+
// Step 1: auto-layout — detect shared elements across ALL pages
|
|
97
|
+
if (config.autoLayout) {
|
|
98
|
+
await extractAutoLayout(config);
|
|
99
|
+
}
|
|
100
|
+
// Step 2: explicit layouts — per-layout-group detection
|
|
101
|
+
if (config.layouts) {
|
|
102
|
+
await extractAndSaveLayouts(config);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* After all pages are mapped, detect shared layout elements, extract them into
|
|
108
|
+
* `_layouts/<name>.json`, strip them from per-page mappings, and re-save.
|
|
109
|
+
*/
|
|
110
|
+
async function extractAndSaveLayouts(config) {
|
|
111
|
+
const layouts = config.layouts;
|
|
112
|
+
for (const [layoutName, layoutCfg] of Object.entries(layouts)) {
|
|
113
|
+
const threshold = layoutCfg.threshold ?? 0.9;
|
|
114
|
+
const layoutPageNames = config.pages
|
|
115
|
+
.filter((p) => p.layout === layoutName)
|
|
116
|
+
.map((p) => p.name);
|
|
117
|
+
if (layoutPageNames.length === 0) {
|
|
118
|
+
console.log(`\n📐 Layout "${layoutName}": no pages reference it — skipping.`);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
// Load the freshly-mapped pages
|
|
122
|
+
const pages = [];
|
|
123
|
+
for (const name of layoutPageNames) {
|
|
124
|
+
try {
|
|
125
|
+
pages.push((0, aom_1.loadMapping)(name));
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
console.log(` ⚠ Could not load mapping for "${name}" — skipping.`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (pages.length === 0)
|
|
132
|
+
continue;
|
|
133
|
+
const layoutMapping = (0, layout_1.extractLayout)(layoutName, pages, threshold, layoutCfg.description);
|
|
134
|
+
console.log(`\n📐 Layout "${layoutName}": ${layoutMapping.elements.length} elements shared across ≥${Math.floor(threshold * pages.length)}/${pages.length} pages`);
|
|
135
|
+
if (layoutMapping.elements.length === 0)
|
|
136
|
+
continue;
|
|
137
|
+
// Save the layout
|
|
138
|
+
const layoutFile = (0, layout_1.saveLayout)(layoutMapping);
|
|
139
|
+
const layoutMd = (0, markdown_2.saveLayoutMarkdown)(layoutMapping);
|
|
140
|
+
console.log(` ✔ layout → ${path.relative(process.cwd(), layoutFile)} + ${path.relative(process.cwd(), layoutMd)}`);
|
|
141
|
+
// Strip layout elements from each page and re-save
|
|
142
|
+
const stripped = (0, layout_1.stripLayoutFromPages)(pages, layoutMapping);
|
|
143
|
+
const layoutInfo = { count: layoutMapping.elements.length, name: layoutName };
|
|
144
|
+
for (const slim of stripped) {
|
|
145
|
+
(0, aom_1.saveMapping)(slim);
|
|
146
|
+
(0, markdown_1.saveMarkdown)(slim, (0, config_1.mappingDir)(), layoutInfo);
|
|
147
|
+
}
|
|
148
|
+
console.log(` ✔ stripped ${layoutMapping.elements.length} layout elements from ${stripped.length} page mappings`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Auto-detect shared layout elements across ALL mapped pages (no manual layout
|
|
153
|
+
* config required). Controlled by `config.autoLayout` and `config.layoutThreshold`.
|
|
154
|
+
*
|
|
155
|
+
* Algorithm:
|
|
156
|
+
* 1. Load every freshly-mapped page from `.ia-qa/mapping/`
|
|
157
|
+
* 2. Count how many pages each `(role, name, selector)` tuple appears on
|
|
158
|
+
* 3. Any tuple on ≥ `threshold` fraction of pages is promoted to layout
|
|
159
|
+
* 4. Save `_layouts/shell.json` + `_layouts/shell.md`
|
|
160
|
+
* 5. Strip layout elements from each page `.json` + `.md`, and add a banner
|
|
161
|
+
* to each `.md` pointing at `_layouts/shell.md`
|
|
162
|
+
*
|
|
163
|
+
* Single-page `map <page>` never triggers this — only `map` (all pages).
|
|
164
|
+
*/
|
|
165
|
+
async function extractAutoLayout(config) {
|
|
166
|
+
const threshold = config.layoutThreshold ?? 0.85;
|
|
167
|
+
// Load every page mapping we just wrote
|
|
168
|
+
const pages = [];
|
|
169
|
+
for (const target of config.pages) {
|
|
170
|
+
try {
|
|
171
|
+
pages.push((0, aom_1.loadMapping)(target.name));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// page failed to map — skip it for layout detection
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (pages.length < 2) {
|
|
178
|
+
console.log('\n📐 Auto-layout: need ≥2 pages to detect shared elements — skipping.');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const layoutMapping = (0, layout_1.extractLayout)('shell', pages, threshold, 'Auto-detected shared elements (navbar, footer, search, cookies…)');
|
|
182
|
+
const minPages = Math.ceil(threshold * pages.length);
|
|
183
|
+
console.log(`\n📐 Auto-layout: ${layoutMapping.elements.length} shared elements ` +
|
|
184
|
+
`(≥${minPages}/${pages.length} pages, threshold ${threshold}) → _layouts/shell.json`);
|
|
185
|
+
if (layoutMapping.elements.length === 0)
|
|
186
|
+
return;
|
|
187
|
+
// Save the layout
|
|
188
|
+
const layoutFile = (0, layout_1.saveLayout)(layoutMapping);
|
|
189
|
+
const layoutMd = (0, markdown_2.saveLayoutMarkdown)(layoutMapping);
|
|
190
|
+
console.log(` ✔ layout → ${path.relative(process.cwd(), layoutFile)} + ${path.relative(process.cwd(), layoutMd)}`);
|
|
191
|
+
// Strip layout elements from each page and re-save with banner
|
|
192
|
+
const stripped = (0, layout_1.stripLayoutFromPages)(pages, layoutMapping);
|
|
193
|
+
const layoutInfo = { count: layoutMapping.elements.length, name: 'shell' };
|
|
194
|
+
const dir = (0, config_1.mappingDir)();
|
|
195
|
+
for (const slim of stripped) {
|
|
196
|
+
(0, aom_1.saveMapping)(slim, dir);
|
|
197
|
+
(0, markdown_1.saveMarkdown)(slim, dir, layoutInfo);
|
|
198
|
+
}
|
|
199
|
+
// Per-page summary
|
|
200
|
+
const strippedMap = new Map(stripped.map((s) => [s.page, s]));
|
|
201
|
+
for (const original of pages) {
|
|
202
|
+
const slim = strippedMap.get(original.page);
|
|
203
|
+
const layoutCount = original.elements.length - (slim?.elements.length ?? 0);
|
|
204
|
+
console.log(` ✔ ${original.page.padEnd(20)} ${slim?.elements.length ?? '?'} éléments ` +
|
|
205
|
+
`(${layoutCount} dans le layout)`);
|
|
206
|
+
}
|
|
89
207
|
}
|
|
90
208
|
async function login(page, config) {
|
|
91
209
|
const auth = config.auth;
|
package/dist/cli/map.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map.js","sourceRoot":"","sources":["../../src/cli/map.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../../src/cli/map.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -14,11 +14,21 @@ export interface SecretRef {
|
|
|
14
14
|
/** AWS region — required when source is `aws-ssm`. */
|
|
15
15
|
region?: string;
|
|
16
16
|
}
|
|
17
|
+
export interface LayoutConfig {
|
|
18
|
+
/** Human-readable description of this layout group. */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Optional CSS selector to scope layout extraction. Auto-detection is the primary path. */
|
|
21
|
+
selector?: string;
|
|
22
|
+
/** Fraction of pages (0-1) an element must appear on to be promoted to layout. Default 0.9. */
|
|
23
|
+
threshold?: number;
|
|
24
|
+
}
|
|
17
25
|
export interface PageTarget {
|
|
18
26
|
/** Logical page name — becomes the mapping filename (`.ia-qa/mapping/<name>.json`). */
|
|
19
27
|
name: string;
|
|
20
28
|
/** Path or absolute URL, resolved against `baseUrl`. */
|
|
21
29
|
url: string;
|
|
30
|
+
/** Reference to a layout key in `config.layouts`. Layout elements are stripped from this page's mapping. */
|
|
31
|
+
layout?: string;
|
|
22
32
|
}
|
|
23
33
|
export interface AuthConfig {
|
|
24
34
|
loginUrl: string;
|
|
@@ -37,12 +47,29 @@ export interface IaQaConfig {
|
|
|
37
47
|
secrets: Record<string, SecretRef>;
|
|
38
48
|
auth?: AuthConfig;
|
|
39
49
|
pages: PageTarget[];
|
|
50
|
+
/** Layout groups — shared elements auto-detected across pages. */
|
|
51
|
+
layouts?: Record<string, LayoutConfig>;
|
|
52
|
+
/**
|
|
53
|
+
* Auto-detect shared layout elements across ALL mapped pages.
|
|
54
|
+
* When true, any element appearing on ≥ `layoutThreshold` fraction of pages
|
|
55
|
+
* is promoted to `_layouts/shell.json` and stripped from per-page mappings.
|
|
56
|
+
* Default false (backward-compatible).
|
|
57
|
+
*/
|
|
58
|
+
autoLayout?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Fraction of pages (0-1) an element must appear on to be auto-promoted to
|
|
61
|
+
* layout. Default 0.85. Only used when `autoLayout` is true.
|
|
62
|
+
*/
|
|
63
|
+
layoutThreshold?: number;
|
|
40
64
|
}
|
|
41
65
|
export declare const CONFIG_DIR = ".ia-qa";
|
|
42
66
|
export declare const MAPPING_DIRNAME = "mapping";
|
|
43
67
|
export declare function configPath(cwd?: string): string;
|
|
44
68
|
export declare function mappingDir(cwd?: string): string;
|
|
69
|
+
export declare const LAYOUT_DIRNAME = "_layouts";
|
|
45
70
|
export declare function mappingPath(pageName: string, dir?: string): string;
|
|
71
|
+
export declare function layoutDir(cwd?: string): string;
|
|
72
|
+
export declare function layoutPath(layoutName: string, dir?: string): string;
|
|
46
73
|
export declare function loadConfig(cwd?: string): IaQaConfig;
|
|
47
74
|
export declare function saveConfig(config: IaQaConfig, cwd?: string): string;
|
|
48
75
|
/**
|
package/dist/config.js
CHANGED
|
@@ -33,10 +33,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.MAPPING_DIRNAME = exports.CONFIG_DIR = void 0;
|
|
36
|
+
exports.LAYOUT_DIRNAME = exports.MAPPING_DIRNAME = exports.CONFIG_DIR = void 0;
|
|
37
37
|
exports.configPath = configPath;
|
|
38
38
|
exports.mappingDir = mappingDir;
|
|
39
39
|
exports.mappingPath = mappingPath;
|
|
40
|
+
exports.layoutDir = layoutDir;
|
|
41
|
+
exports.layoutPath = layoutPath;
|
|
40
42
|
exports.loadConfig = loadConfig;
|
|
41
43
|
exports.saveConfig = saveConfig;
|
|
42
44
|
exports.resolveSecret = resolveSecret;
|
|
@@ -50,10 +52,18 @@ function configPath(cwd = process.cwd()) {
|
|
|
50
52
|
function mappingDir(cwd = process.cwd()) {
|
|
51
53
|
return path.join(cwd, exports.CONFIG_DIR, exports.MAPPING_DIRNAME);
|
|
52
54
|
}
|
|
55
|
+
exports.LAYOUT_DIRNAME = '_layouts';
|
|
53
56
|
function mappingPath(pageName, dir = mappingDir()) {
|
|
54
57
|
const safe = pageName.replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
55
58
|
return path.join(dir, `${safe}.json`);
|
|
56
59
|
}
|
|
60
|
+
function layoutDir(cwd = process.cwd()) {
|
|
61
|
+
return path.join(cwd, exports.CONFIG_DIR, exports.MAPPING_DIRNAME, exports.LAYOUT_DIRNAME);
|
|
62
|
+
}
|
|
63
|
+
function layoutPath(layoutName, dir = layoutDir()) {
|
|
64
|
+
const safe = layoutName.replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
65
|
+
return path.join(dir, `${safe}.json`);
|
|
66
|
+
}
|
|
57
67
|
function loadConfig(cwd = process.cwd()) {
|
|
58
68
|
const file = configPath(cwd);
|
|
59
69
|
if (!fs.existsSync(file)) {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,5 +8,7 @@ export { launchBrowser } from './launcher';
|
|
|
8
8
|
export type { BrowserChoice, LaunchedBrowser } from './launcher';
|
|
9
9
|
export type { MapUrlOptions, MapUrlResult } from './mapUrl';
|
|
10
10
|
export { computeRewrites, applyRewrites, collectFiles, replaceQuoted } from './fixEngine';
|
|
11
|
-
export { loadConfig, resolveSecret } from './config';
|
|
12
|
-
export type { IaQaConfig, SecretRef, PageTarget, AuthConfig } from './config';
|
|
11
|
+
export { loadConfig, resolveSecret, layoutDir, layoutPath, LAYOUT_DIRNAME } from './config';
|
|
12
|
+
export type { IaQaConfig, SecretRef, PageTarget, AuthConfig, LayoutConfig } from './config';
|
|
13
|
+
export { extractLayout, stripLayoutFromPages } from './layout';
|
|
14
|
+
export type { LayoutMapping } from './layout';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveSecret = exports.loadConfig = exports.replaceQuoted = exports.collectFiles = exports.applyRewrites = exports.computeRewrites = exports.launchBrowser = exports.pageNameFromUrl = exports.mapUrl = exports.markdownPath = exports.saveMarkdown = exports.renderPageContract = exports.saveMapping = exports.loadMapping = exports.extractInteractiveElements = exports.llmResolverStub = exports.aiFill = exports.aiClick = void 0;
|
|
3
|
+
exports.stripLayoutFromPages = exports.extractLayout = exports.LAYOUT_DIRNAME = exports.layoutPath = exports.layoutDir = exports.resolveSecret = exports.loadConfig = exports.replaceQuoted = exports.collectFiles = exports.applyRewrites = exports.computeRewrites = exports.launchBrowser = exports.pageNameFromUrl = exports.mapUrl = exports.markdownPath = exports.saveMarkdown = exports.renderPageContract = exports.saveMapping = exports.loadMapping = exports.extractInteractiveElements = exports.llmResolverStub = exports.aiFill = exports.aiClick = void 0;
|
|
4
4
|
var healer_1 = require("./playwright/healer");
|
|
5
5
|
Object.defineProperty(exports, "aiClick", { enumerable: true, get: function () { return healer_1.aiClick; } });
|
|
6
6
|
Object.defineProperty(exports, "aiFill", { enumerable: true, get: function () { return healer_1.aiFill; } });
|
|
@@ -26,4 +26,10 @@ Object.defineProperty(exports, "replaceQuoted", { enumerable: true, get: functio
|
|
|
26
26
|
var config_1 = require("./config");
|
|
27
27
|
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
|
|
28
28
|
Object.defineProperty(exports, "resolveSecret", { enumerable: true, get: function () { return config_1.resolveSecret; } });
|
|
29
|
+
Object.defineProperty(exports, "layoutDir", { enumerable: true, get: function () { return config_1.layoutDir; } });
|
|
30
|
+
Object.defineProperty(exports, "layoutPath", { enumerable: true, get: function () { return config_1.layoutPath; } });
|
|
31
|
+
Object.defineProperty(exports, "LAYOUT_DIRNAME", { enumerable: true, get: function () { return config_1.LAYOUT_DIRNAME; } });
|
|
32
|
+
var layout_1 = require("./layout");
|
|
33
|
+
Object.defineProperty(exports, "extractLayout", { enumerable: true, get: function () { return layout_1.extractLayout; } });
|
|
34
|
+
Object.defineProperty(exports, "stripLayoutFromPages", { enumerable: true, get: function () { return layout_1.stripLayoutFromPages; } });
|
|
29
35
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8CAAuE;AAA9D,iGAAA,OAAO,OAAA;AAAE,gGAAA,MAAM,OAAA;AAAE,yGAAA,eAAe,OAAA;AAEzC,6BAA6E;AAApE,iHAAA,0BAA0B,OAAA;AAAE,kGAAA,WAAW,OAAA;AAAE,kGAAA,WAAW,OAAA;AAE7D,uCAA4E;AAAnE,8GAAA,kBAAkB,OAAA;AAAE,wGAAA,YAAY,OAAA;AAAE,wGAAA,YAAY,OAAA;AACvD,mCAAmD;AAA1C,gGAAA,MAAM,OAAA;AAAE,yGAAA,eAAe,OAAA;AAChC,uCAA2C;AAAlC,yGAAA,aAAa,OAAA;AAGtB,yCAA0F;AAAjF,4GAAA,eAAe,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,yGAAA,YAAY,OAAA;AAAE,0GAAA,aAAa,OAAA;AACpE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8CAAuE;AAA9D,iGAAA,OAAO,OAAA;AAAE,gGAAA,MAAM,OAAA;AAAE,yGAAA,eAAe,OAAA;AAEzC,6BAA6E;AAApE,iHAAA,0BAA0B,OAAA;AAAE,kGAAA,WAAW,OAAA;AAAE,kGAAA,WAAW,OAAA;AAE7D,uCAA4E;AAAnE,8GAAA,kBAAkB,OAAA;AAAE,wGAAA,YAAY,OAAA;AAAE,wGAAA,YAAY,OAAA;AACvD,mCAAmD;AAA1C,gGAAA,MAAM,OAAA;AAAE,yGAAA,eAAe,OAAA;AAChC,uCAA2C;AAAlC,yGAAA,aAAa,OAAA;AAGtB,yCAA0F;AAAjF,4GAAA,eAAe,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,yGAAA,YAAY,OAAA;AAAE,0GAAA,aAAa,OAAA;AACpE,mCAA4F;AAAnF,oGAAA,UAAU,OAAA;AAAE,uGAAA,aAAa,OAAA;AAAE,mGAAA,SAAS,OAAA;AAAE,oGAAA,UAAU,OAAA;AAAE,wGAAA,cAAc,OAAA;AAEzE,mCAA+D;AAAtD,uGAAA,aAAa,OAAA;AAAE,8GAAA,oBAAoB,OAAA"}
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { MappedElement, PageMapping } from './aom';
|
|
2
|
+
/**
|
|
3
|
+
* Layout detection & extraction engine.
|
|
4
|
+
*
|
|
5
|
+
* A "layout" is a set of interactive elements that appear on many pages (navbar,
|
|
6
|
+
* footer, cookie consent, search, etc.). Rather than storing 34 copies of the
|
|
7
|
+
* same footer across 47 page mappings, we detect them once, extract them into
|
|
8
|
+
* `_layouts/<name>.json`, and strip them from individual page mappings.
|
|
9
|
+
*
|
|
10
|
+
* The driving metric is `threshold`: an element is promoted to layout when it
|
|
11
|
+
* appears — same role, name, and selector — on ≥ threshold fraction of pages.
|
|
12
|
+
*/
|
|
13
|
+
export interface LayoutMapping {
|
|
14
|
+
layout: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
capturedAt: string;
|
|
17
|
+
sourcePages: number;
|
|
18
|
+
elements: MappedElement[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract layout elements from a set of page mappings.
|
|
22
|
+
*
|
|
23
|
+
* For each element, count how many pages it appears on. Any element above
|
|
24
|
+
* `threshold * totalPages` (rounded down) is promoted to layout.
|
|
25
|
+
*
|
|
26
|
+
* Returns the layout mapping. Does NOT modify the page mappings — call
|
|
27
|
+
* `stripLayoutFromPages` separately to produce lean page mappings.
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractLayout(layoutName: string, pages: PageMapping[], threshold: number, description?: string): LayoutMapping;
|
|
30
|
+
/**
|
|
31
|
+
* Remove layout elements from each page mapping. Returns new page mappings
|
|
32
|
+
* (the originals are not mutated).
|
|
33
|
+
*/
|
|
34
|
+
export declare function stripLayoutFromPages(pages: PageMapping[], layout: LayoutMapping): PageMapping[];
|
|
35
|
+
/**
|
|
36
|
+
* Save a layout mapping to `_layouts/<name>.json`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function saveLayout(mapping: LayoutMapping, dir?: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Load a layout mapping from disk.
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadLayout(layoutName: string, dir?: string): LayoutMapping;
|
|
43
|
+
/**
|
|
44
|
+
* Build a set of element fingerprints from all loaded layouts for fast lookup.
|
|
45
|
+
*/
|
|
46
|
+
export declare function layoutFingerprintSet(layouts: LayoutMapping[]): Set<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Load all layouts referenced by a config. Returns a Map of layoutName → LayoutMapping.
|
|
49
|
+
*/
|
|
50
|
+
export declare function loadAllLayouts(layoutNames: string[], dir?: string): Map<string, LayoutMapping>;
|
|
51
|
+
/**
|
|
52
|
+
* Walk `.ia-qa/mapping/` and collect all page mappings (skip `_layouts/` and non-JSON).
|
|
53
|
+
*/
|
|
54
|
+
export declare function collectPageMappings(dir?: string): PageMapping[];
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.extractLayout = extractLayout;
|
|
37
|
+
exports.stripLayoutFromPages = stripLayoutFromPages;
|
|
38
|
+
exports.saveLayout = saveLayout;
|
|
39
|
+
exports.loadLayout = loadLayout;
|
|
40
|
+
exports.layoutFingerprintSet = layoutFingerprintSet;
|
|
41
|
+
exports.loadAllLayouts = loadAllLayouts;
|
|
42
|
+
exports.collectPageMappings = collectPageMappings;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const config_1 = require("./config");
|
|
46
|
+
/** Fingerprint an element by its role + name + selector. All three must match for the element to be "the same" across pages. */
|
|
47
|
+
function fingerprint(el) {
|
|
48
|
+
return `${el.role}||${el.name}||${el.selector}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Extract layout elements from a set of page mappings.
|
|
52
|
+
*
|
|
53
|
+
* For each element, count how many pages it appears on. Any element above
|
|
54
|
+
* `threshold * totalPages` (rounded down) is promoted to layout.
|
|
55
|
+
*
|
|
56
|
+
* Returns the layout mapping. Does NOT modify the page mappings — call
|
|
57
|
+
* `stripLayoutFromPages` separately to produce lean page mappings.
|
|
58
|
+
*/
|
|
59
|
+
function extractLayout(layoutName, pages, threshold, description) {
|
|
60
|
+
if (pages.length === 0) {
|
|
61
|
+
return {
|
|
62
|
+
layout: layoutName,
|
|
63
|
+
description,
|
|
64
|
+
capturedAt: new Date().toISOString(),
|
|
65
|
+
sourcePages: 0,
|
|
66
|
+
elements: [],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// Count pages each element fingerprint appears on
|
|
70
|
+
const counts = new Map();
|
|
71
|
+
for (const page of pages) {
|
|
72
|
+
for (const el of page.elements) {
|
|
73
|
+
const fp = fingerprint(el);
|
|
74
|
+
let entry = counts.get(fp);
|
|
75
|
+
if (!entry) {
|
|
76
|
+
entry = { el, pages: new Set() };
|
|
77
|
+
counts.set(fp, entry);
|
|
78
|
+
}
|
|
79
|
+
entry.pages.add(page.page);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Promote elements that appear on ≥ minPages
|
|
83
|
+
const layoutElements = [];
|
|
84
|
+
for (const [, entry] of counts) {
|
|
85
|
+
if (entry.pages.size / pages.length >= threshold) {
|
|
86
|
+
layoutElements.push(entry.el);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Sort by role then name for stable output
|
|
90
|
+
layoutElements.sort((a, b) => {
|
|
91
|
+
const rc = a.role.localeCompare(b.role);
|
|
92
|
+
if (rc !== 0)
|
|
93
|
+
return rc;
|
|
94
|
+
return a.name.localeCompare(b.name);
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
layout: layoutName,
|
|
98
|
+
description,
|
|
99
|
+
capturedAt: new Date().toISOString(),
|
|
100
|
+
sourcePages: pages.length,
|
|
101
|
+
elements: layoutElements,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Remove layout elements from each page mapping. Returns new page mappings
|
|
106
|
+
* (the originals are not mutated).
|
|
107
|
+
*/
|
|
108
|
+
function stripLayoutFromPages(pages, layout) {
|
|
109
|
+
const fpSet = new Set(layout.elements.map(fingerprint));
|
|
110
|
+
return pages.map((page) => ({
|
|
111
|
+
...page,
|
|
112
|
+
elements: page.elements.filter((el) => !fpSet.has(fingerprint(el))),
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Save a layout mapping to `_layouts/<name>.json`.
|
|
117
|
+
*/
|
|
118
|
+
function saveLayout(mapping, dir = (0, config_1.layoutDir)()) {
|
|
119
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
120
|
+
const file = (0, config_1.layoutPath)(mapping.layout, dir);
|
|
121
|
+
fs.writeFileSync(file, JSON.stringify(mapping, null, 2) + '\n', 'utf8');
|
|
122
|
+
return file;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Load a layout mapping from disk.
|
|
126
|
+
*/
|
|
127
|
+
function loadLayout(layoutName, dir = (0, config_1.layoutDir)()) {
|
|
128
|
+
const file = (0, config_1.layoutPath)(layoutName, dir);
|
|
129
|
+
if (!fs.existsSync(file)) {
|
|
130
|
+
throw new Error(`No layout found for "${layoutName}" (${file}).`);
|
|
131
|
+
}
|
|
132
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build a set of element fingerprints from all loaded layouts for fast lookup.
|
|
136
|
+
*/
|
|
137
|
+
function layoutFingerprintSet(layouts) {
|
|
138
|
+
const fpSet = new Set();
|
|
139
|
+
for (const layout of layouts) {
|
|
140
|
+
for (const el of layout.elements) {
|
|
141
|
+
fpSet.add(fingerprint(el));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return fpSet;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Load all layouts referenced by a config. Returns a Map of layoutName → LayoutMapping.
|
|
148
|
+
*/
|
|
149
|
+
function loadAllLayouts(layoutNames, dir = (0, config_1.layoutDir)()) {
|
|
150
|
+
const map = new Map();
|
|
151
|
+
for (const name of layoutNames) {
|
|
152
|
+
const file = (0, config_1.layoutPath)(name, dir);
|
|
153
|
+
if (fs.existsSync(file)) {
|
|
154
|
+
map.set(name, JSON.parse(fs.readFileSync(file, 'utf8')));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return map;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Walk `.ia-qa/mapping/` and collect all page mappings (skip `_layouts/` and non-JSON).
|
|
161
|
+
*/
|
|
162
|
+
function collectPageMappings(dir = (0, config_1.mappingDir)()) {
|
|
163
|
+
const pages = [];
|
|
164
|
+
if (!fs.existsSync(dir))
|
|
165
|
+
return pages;
|
|
166
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
167
|
+
for (const entry of entries) {
|
|
168
|
+
if (entry.isFile() && entry.name.endsWith('.json') && !entry.name.startsWith('.')) {
|
|
169
|
+
const abs = path.join(dir, entry.name);
|
|
170
|
+
try {
|
|
171
|
+
const raw = JSON.parse(fs.readFileSync(abs, 'utf8'));
|
|
172
|
+
if (raw && Array.isArray(raw.elements) && typeof raw.page === 'string') {
|
|
173
|
+
pages.push(raw);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
/* skip unparseable */
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return pages;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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"}
|
package/dist/markdown.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { PageMapping } from './aom';
|
|
2
|
-
import {
|
|
2
|
+
import { LayoutMapping } from './layout';
|
|
3
|
+
import { renderPageContract, renderLayoutContract } from './browser/contract';
|
|
3
4
|
/**
|
|
4
5
|
* Node-side file I/O for the page contract. The rendering itself lives in
|
|
5
6
|
* `browser/contract.js` (pure JS) so the CLI and ia-qa.com produce identical
|
|
6
7
|
* `.md` output from the same mapping.
|
|
7
8
|
*/
|
|
8
|
-
export { renderPageContract };
|
|
9
|
+
export { renderPageContract, renderLayoutContract };
|
|
9
10
|
export declare function markdownPath(pageName: string, dir?: string): string;
|
|
10
|
-
export declare function
|
|
11
|
+
export declare function layoutMdPath(layoutName: string, dir?: string): string;
|
|
12
|
+
export declare function saveMarkdown(mapping: PageMapping, dir?: string, layoutInfo?: {
|
|
13
|
+
count: number;
|
|
14
|
+
name: string;
|
|
15
|
+
}): string;
|
|
16
|
+
export declare function saveLayoutMarkdown(mapping: LayoutMapping, dir?: string): string;
|
package/dist/markdown.js
CHANGED
|
@@ -33,22 +33,35 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.renderPageContract = void 0;
|
|
36
|
+
exports.renderLayoutContract = exports.renderPageContract = void 0;
|
|
37
37
|
exports.markdownPath = markdownPath;
|
|
38
|
+
exports.layoutMdPath = layoutMdPath;
|
|
38
39
|
exports.saveMarkdown = saveMarkdown;
|
|
40
|
+
exports.saveLayoutMarkdown = saveLayoutMarkdown;
|
|
39
41
|
const fs = __importStar(require("fs"));
|
|
40
42
|
const path = __importStar(require("path"));
|
|
41
43
|
const config_1 = require("./config");
|
|
42
44
|
const contract_1 = require("./browser/contract");
|
|
43
45
|
Object.defineProperty(exports, "renderPageContract", { enumerable: true, get: function () { return contract_1.renderPageContract; } });
|
|
46
|
+
Object.defineProperty(exports, "renderLayoutContract", { enumerable: true, get: function () { return contract_1.renderLayoutContract; } });
|
|
44
47
|
function markdownPath(pageName, dir = (0, config_1.mappingDir)()) {
|
|
45
48
|
const safe = pageName.replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
46
49
|
return path.join(dir, `${safe}.md`);
|
|
47
50
|
}
|
|
48
|
-
function
|
|
51
|
+
function layoutMdPath(layoutName, dir = (0, config_1.layoutDir)()) {
|
|
52
|
+
const safe = layoutName.replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
53
|
+
return path.join(dir, `${safe}.md`);
|
|
54
|
+
}
|
|
55
|
+
function saveMarkdown(mapping, dir = (0, config_1.mappingDir)(), layoutInfo) {
|
|
49
56
|
fs.mkdirSync(dir, { recursive: true });
|
|
50
57
|
const file = markdownPath(mapping.page, dir);
|
|
51
|
-
fs.writeFileSync(file, (0, contract_1.renderPageContract)(mapping), 'utf8');
|
|
58
|
+
fs.writeFileSync(file, (0, contract_1.renderPageContract)(mapping, layoutInfo), 'utf8');
|
|
59
|
+
return file;
|
|
60
|
+
}
|
|
61
|
+
function saveLayoutMarkdown(mapping, dir = (0, config_1.layoutDir)()) {
|
|
62
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
63
|
+
const file = layoutMdPath(mapping.layout, dir);
|
|
64
|
+
fs.writeFileSync(file, (0, contract_1.renderLayoutContract)(mapping), 'utf8');
|
|
52
65
|
return file;
|
|
53
66
|
}
|
|
54
67
|
//# sourceMappingURL=markdown.js.map
|
package/dist/markdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,oCAGC;AAED,oCAGC;AAED,oCASC;AAED,gDAKC;AAzCD,uCAAyB;AACzB,2CAA6B;AAG7B,qCAAiD;AACjD,iDAA8E;AAQrE,mGARA,6BAAkB,OAQA;AAAE,qGARA,+BAAoB,OAQA;AAEjD,SAAgB,YAAY,CAAC,QAAgB,EAAE,MAAc,IAAA,mBAAU,GAAE;IACvE,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;AACtC,CAAC;AAED,SAAgB,YAAY,CAAC,UAAkB,EAAE,MAAc,IAAA,kBAAS,GAAE;IACxE,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;AACtC,CAAC;AAED,SAAgB,YAAY,CAC1B,OAAoB,EACpB,MAAc,IAAA,mBAAU,GAAE,EAC1B,UAA4C;IAE5C,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC7C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAA,6BAAkB,EAAC,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IACxE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAAsB,EAAE,MAAc,IAAA,kBAAS,GAAE;IAClF,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAA,+BAAoB,EAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ia-qa/self-healing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Local-first self-healing for UI tests: a local MCP server + CLI that map your app's pages to a role/name/selector contract, diff selector drift (PASS/FIX/BLOCK), and apply deterministic fixes to Cypress/Playwright/Selenium tests. Runs on your machine — nothing leaves it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"self-healing",
|