@diegovelasquezweb/a11y-engine 0.11.32 → 0.11.33
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/package.json +1 -1
- package/src/fixes/apply-finding-fix.mjs +61 -12
package/package.json
CHANGED
|
@@ -167,15 +167,56 @@ function buildPatternAiInput({ finding, candidate }) {
|
|
|
167
167
|
};
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
// Layout file name patterns for page-level fixes (e.g. bypass/skip-link).
|
|
171
|
+
// Ordered by priority: more specific names first.
|
|
172
|
+
const LAYOUT_FILE_PATTERNS = [
|
|
173
|
+
/^app[\/\\]layout\.[jt]sx?$/i,
|
|
174
|
+
/^src[\/\\]app[\/\\]layout\.[jt]sx?$/i,
|
|
175
|
+
/^pages[\/\\]_app\.[jt]sx?$/i,
|
|
176
|
+
/^pages[\/\\]_document\.[jt]sx?$/i,
|
|
177
|
+
/^src[\/\\]pages[\/\\]_app\.[jt]sx?$/i,
|
|
178
|
+
/^src[\/\\]pages[\/\\]_document\.[jt]sx?$/i,
|
|
179
|
+
/layouts[\/\\]default\.vue$/i,
|
|
180
|
+
/layouts[\/\\][^\/\\]+\.vue$/i,
|
|
181
|
+
/\+layout\.svelte$/i,
|
|
182
|
+
/app\.component\.html$/i,
|
|
183
|
+
/layouts[\/\\][^\/\\]+\.astro$/i,
|
|
184
|
+
/layout[\/\\]theme\.liquid$/i,
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
function getLayoutCandidates(projectDir, files) {
|
|
188
|
+
const byPattern = [];
|
|
189
|
+
for (const { abs, rel, content } of files) {
|
|
190
|
+
const normalRel = rel.replace(/\\/g, "/");
|
|
191
|
+
for (let i = 0; i < LAYOUT_FILE_PATTERNS.length; i++) {
|
|
192
|
+
if (LAYOUT_FILE_PATTERNS[i].test(normalRel)) {
|
|
193
|
+
byPattern.push({ abs, rel, content, score: LAYOUT_FILE_PATTERNS.length - i });
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return byPattern.sort((a, b) => b.score - a.score).slice(0, MAX_CANDIDATE_FILES);
|
|
199
|
+
}
|
|
200
|
+
|
|
170
201
|
function getCandidateFiles(projectDir, finding) {
|
|
171
|
-
const
|
|
202
|
+
const allFiles = listFilesRecursive(projectDir).map((abs) => {
|
|
203
|
+
const content = fs.readFileSync(abs, "utf8");
|
|
204
|
+
const rel = path.relative(projectDir, abs);
|
|
205
|
+
return { abs, rel, content };
|
|
206
|
+
});
|
|
207
|
+
|
|
172
208
|
const tokens = selectorTokens(finding.selector);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
209
|
+
|
|
210
|
+
if (tokens.length === 0) {
|
|
211
|
+
// Selector has no useful tokens (e.g. "html", "body") — target layout files directly.
|
|
212
|
+
const layoutCandidates = getLayoutCandidates(projectDir, allFiles);
|
|
213
|
+
if (layoutCandidates.length > 0) return layoutCandidates;
|
|
214
|
+
// Fallback: return all files with equal weight so Claude gets the full picture.
|
|
215
|
+
return allFiles.slice(0, MAX_CANDIDATE_FILES).map((f) => ({ ...f, score: 1 }));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const ranked = allFiles
|
|
219
|
+
.map((f) => ({ ...f, score: scoreFile(f.rel, f.content, tokens) }))
|
|
179
220
|
.filter((item) => item.score > 0)
|
|
180
221
|
.sort((a, b) => b.score - a.score)
|
|
181
222
|
.slice(0, MAX_CANDIDATE_FILES);
|
|
@@ -216,11 +257,19 @@ function groupFindingsByFile(domFindings, projectDir) {
|
|
|
216
257
|
|
|
217
258
|
for (const finding of domFindings) {
|
|
218
259
|
const tokens = selectorTokens(finding.selector);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
260
|
+
let ranked;
|
|
261
|
+
if (tokens.length === 0) {
|
|
262
|
+
const layoutCandidates = getLayoutCandidates(projectDir, allFiles);
|
|
263
|
+
ranked = layoutCandidates.length > 0
|
|
264
|
+
? layoutCandidates
|
|
265
|
+
: allFiles.slice(0, MAX_CANDIDATE_FILES).map((f) => ({ ...f, score: 1 }));
|
|
266
|
+
} else {
|
|
267
|
+
ranked = allFiles
|
|
268
|
+
.map((f) => ({ ...f, score: scoreFile(f.rel, f.content, tokens) }))
|
|
269
|
+
.filter((f) => f.score > 0)
|
|
270
|
+
.sort((a, b) => b.score - a.score)
|
|
271
|
+
.slice(0, MAX_CANDIDATE_FILES);
|
|
272
|
+
}
|
|
224
273
|
|
|
225
274
|
const key = ranked.length > 0 ? ranked[0].rel : `__no_candidates_${finding.id}`;
|
|
226
275
|
if (!initialGroups.has(key)) {
|