@diegovelasquezweb/a11y-engine 0.11.28 → 0.11.29
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
CHANGED
|
@@ -316,16 +316,22 @@ function parseJsonBlock(text) {
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
async function callClaudeForPatch({ apiKey, model, aiInput }) {
|
|
319
|
+
const isMulti = Array.isArray(aiInput.findings);
|
|
319
320
|
const system = [
|
|
320
321
|
"You are an accessibility fix engine.",
|
|
321
322
|
"Return JSON only.",
|
|
322
323
|
"Generate deterministic text replacements for provided files.",
|
|
323
|
-
"Use finding.fixDescription and
|
|
324
|
+
"Use finding.fixDescription and constraints.must as guidance for what to fix and how.",
|
|
324
325
|
"For insertions (new element that does not yet exist in the file), use the nearest existing parent element as the search anchor. The replace value must include that anchor plus the new content.",
|
|
325
326
|
"Do not create files. Do not modify paths outside provided filePath values.",
|
|
327
|
+
isMulti
|
|
328
|
+
? "You are fixing MULTIPLE findings at once. Generate at least one change per finding. Set findingId on each change to the exact finding ID it addresses."
|
|
329
|
+
: "",
|
|
326
330
|
"Schema:",
|
|
327
|
-
|
|
328
|
-
|
|
331
|
+
isMulti
|
|
332
|
+
? "{\"changes\":[{\"findingId\":\"...(required: exact finding id)\",\"filePath\":\"...\",\"search\":\"...\",\"replace\":\"...\"}],\"notes\":\"...\"}"
|
|
333
|
+
: "{\"changes\":[{\"filePath\":\"...\",\"search\":\"...\",\"replace\":\"...\"}],\"notes\":\"...\"}",
|
|
334
|
+
].filter(Boolean).join("\n");
|
|
329
335
|
|
|
330
336
|
const userMessage = JSON.stringify(aiInput, null, 2);
|
|
331
337
|
|
|
@@ -388,6 +394,7 @@ function validateAiPatchOutput(output, projectDir, fileSet) {
|
|
|
388
394
|
function applyChanges(projectDir, changes) {
|
|
389
395
|
const changedFiles = [];
|
|
390
396
|
const patchParts = [];
|
|
397
|
+
const succeededFindingIds = new Set();
|
|
391
398
|
|
|
392
399
|
for (const change of changes) {
|
|
393
400
|
const rel = change.filePath;
|
|
@@ -401,6 +408,9 @@ function applyChanges(projectDir, changes) {
|
|
|
401
408
|
fs.writeFileSync(abs, updated, "utf8");
|
|
402
409
|
changedFiles.push(rel);
|
|
403
410
|
patchParts.push(`--- ${rel}\n+++ ${rel}\n@@\n-${change.search}\n+${change.replace}`);
|
|
411
|
+
if (typeof change.findingId === "string" && change.findingId.trim()) {
|
|
412
|
+
succeededFindingIds.add(change.findingId.trim());
|
|
413
|
+
}
|
|
404
414
|
}
|
|
405
415
|
|
|
406
416
|
if (changedFiles.length === 0) return { ok: false, reason: "No effective changes were applied" };
|
|
@@ -409,6 +419,7 @@ function applyChanges(projectDir, changes) {
|
|
|
409
419
|
ok: true,
|
|
410
420
|
changedFiles: [...new Set(changedFiles)],
|
|
411
421
|
patch: patchParts.join("\n"),
|
|
422
|
+
succeededFindingIds,
|
|
412
423
|
};
|
|
413
424
|
}
|
|
414
425
|
|
|
@@ -661,8 +672,8 @@ export async function applyFindingFix(input) {
|
|
|
661
672
|
message: "Patch applied successfully.",
|
|
662
673
|
changedFiles: applied.changedFiles,
|
|
663
674
|
patch: applied.patch,
|
|
664
|
-
verifyRule:
|
|
665
|
-
verifyRoute:
|
|
675
|
+
verifyRule: execution.verify.ruleId,
|
|
676
|
+
verifyRoute: execution.verify.route,
|
|
666
677
|
findingTitle: finding.title || "",
|
|
667
678
|
branchSlug: slugify(`${findingId}-${ruleId}`),
|
|
668
679
|
usage: claudeUsage,
|
|
@@ -867,19 +878,30 @@ export async function applyFindingsFix(input) {
|
|
|
867
878
|
const perInput = Math.round(claudeUsage.input_tokens / n);
|
|
868
879
|
const perOutput = Math.round(claudeUsage.output_tokens / n);
|
|
869
880
|
|
|
881
|
+
// If Claude tagged changes with findingId, use those for per-finding success tracking.
|
|
882
|
+
// If no findingId tags were emitted, fall back to group-level success for all findings.
|
|
883
|
+
const hasFindingIdTracking = applied.succeededFindingIds.size > 0;
|
|
884
|
+
|
|
870
885
|
for (const finding of withRules) {
|
|
871
886
|
const ruleId = typeof finding.rule_id === "string" ? finding.rule_id.trim() : "";
|
|
872
887
|
const intelligenceRule = intelligenceRules[ruleId] || {};
|
|
873
888
|
const execution = buildExecution(ruleId, intelligenceRule, finding);
|
|
889
|
+
|
|
890
|
+
const findingApplied = hasFindingIdTracking
|
|
891
|
+
? applied.succeededFindingIds.has(finding.id)
|
|
892
|
+
: true;
|
|
893
|
+
|
|
874
894
|
resultMap.set(
|
|
875
895
|
finding.id,
|
|
876
896
|
makeResult(finding.id, {
|
|
877
|
-
applied:
|
|
878
|
-
reason: "",
|
|
879
|
-
message:
|
|
897
|
+
applied: findingApplied,
|
|
898
|
+
reason: findingApplied ? "" : FIX_ERROR_CODES.PATCH_APPLY_FAILED,
|
|
899
|
+
message: findingApplied
|
|
900
|
+
? "Patch applied successfully."
|
|
901
|
+
: "The change for this finding could not be applied (search block not found).",
|
|
880
902
|
changedFiles: applied.changedFiles,
|
|
881
903
|
patch: applied.patch,
|
|
882
|
-
verifyRule:
|
|
904
|
+
verifyRule: execution.verify.ruleId,
|
|
883
905
|
verifyRoute: execution.verify.route,
|
|
884
906
|
findingTitle: finding.title || "",
|
|
885
907
|
branchSlug: slugify(`${finding.id}-${ruleId}`),
|
|
@@ -605,8 +605,11 @@ async function analyzeRoute(
|
|
|
605
605
|
const builder = new AxeBuilder({ page });
|
|
606
606
|
|
|
607
607
|
if (onlyRule) {
|
|
608
|
-
|
|
609
|
-
|
|
608
|
+
const rules = onlyRule.includes(",")
|
|
609
|
+
? onlyRule.split(",").map((r) => r.trim()).filter(Boolean)
|
|
610
|
+
: [onlyRule];
|
|
611
|
+
log.info(`Targeted Audit: Only checking rules "${rules.join(", ")}"`);
|
|
612
|
+
builder.withRules(rules);
|
|
610
613
|
} else {
|
|
611
614
|
const tagsToUse = axeTags || AXE_TAGS;
|
|
612
615
|
builder.withTags(tagsToUse);
|