address feedback

This commit is contained in:
Chris Tate
2026-01-12 00:24:22 -06:00
parent 0f7d2946af
commit 21ea2b02bd
+51 -4
View File
@@ -168,14 +168,21 @@ export async function getEnhancedSnapshot(
*/ */
interface RoleNameTracker { interface RoleNameTracker {
counts: Map<string, number>; counts: Map<string, number>;
/** Maps role+name key to array of ref IDs that use it */
refsByKey: Map<string, string[]>;
getKey(role: string, name?: string): string; getKey(role: string, name?: string): string;
getNextIndex(role: string, name?: string): number; getNextIndex(role: string, name?: string): number;
trackRef(role: string, name: string | undefined, ref: string): void;
/** Get all role+name keys that have duplicates */
getDuplicateKeys(): Set<string>;
} }
function createRoleNameTracker(): RoleNameTracker { function createRoleNameTracker(): RoleNameTracker {
const counts = new Map<string, number>(); const counts = new Map<string, number>();
const refsByKey = new Map<string, string[]>();
return { return {
counts, counts,
refsByKey,
getKey(role: string, name?: string): string { getKey(role: string, name?: string): string {
return `${role}:${name ?? ''}`; return `${role}:${name ?? ''}`;
}, },
@@ -185,6 +192,21 @@ function createRoleNameTracker(): RoleNameTracker {
counts.set(key, current + 1); counts.set(key, current + 1);
return current; return current;
}, },
trackRef(role: string, name: string | undefined, ref: string): void {
const key = this.getKey(role, name);
const refs = refsByKey.get(key) ?? [];
refs.push(ref);
refsByKey.set(key, refs);
},
getDuplicateKeys(): Set<string> {
const duplicates = new Set<string>();
for (const [key, refs] of refsByKey) {
if (refs.length > 1) {
duplicates.add(key);
}
}
return duplicates;
},
}; };
} }
@@ -208,23 +230,28 @@ function processAriaTree(ariaTree: string, refs: RefMap, options: SnapshotOption
if (INTERACTIVE_ROLES.has(roleLower)) { if (INTERACTIVE_ROLES.has(roleLower)) {
const ref = nextRef(); const ref = nextRef();
const nth = tracker.getNextIndex(roleLower, name); const nth = tracker.getNextIndex(roleLower, name);
tracker.trackRef(roleLower, name, ref);
refs[ref] = { refs[ref] = {
selector: buildSelector(roleLower, name), selector: buildSelector(roleLower, name),
role: roleLower, role: roleLower,
name, name,
// Only store nth if this is a duplicate (nth > 0) nth, // Always store nth, we'll use it for duplicates
...(nth > 0 ? { nth } : {}),
}; };
let enhanced = `- ${role}`; let enhanced = `- ${role}`;
if (name) enhanced += ` "${name}"`; if (name) enhanced += ` "${name}"`;
enhanced += ` [ref=${ref}]`; enhanced += ` [ref=${ref}]`;
// Only show nth in output if it's > 0 (for readability)
if (nth > 0) enhanced += ` [nth=${nth}]`; if (nth > 0) enhanced += ` [nth=${nth}]`;
if (suffix && suffix.includes('[')) enhanced += suffix; if (suffix && suffix.includes('[')) enhanced += suffix;
result.push(enhanced); result.push(enhanced);
} }
} }
// Post-process: remove nth from refs that don't have duplicates
removeNthFromNonDuplicates(refs, tracker);
return result.join('\n') || '(no interactive elements)'; return result.join('\n') || '(no interactive elements)';
} }
@@ -236,6 +263,9 @@ function processAriaTree(ariaTree: string, refs: RefMap, options: SnapshotOption
} }
} }
// Post-process: remove nth from refs that don't have duplicates
removeNthFromNonDuplicates(refs, tracker);
// If compact mode, remove empty structural elements // If compact mode, remove empty structural elements
if (options.compact) { if (options.compact) {
return compactTree(result.join('\n')); return compactTree(result.join('\n'));
@@ -244,6 +274,22 @@ function processAriaTree(ariaTree: string, refs: RefMap, options: SnapshotOption
return result.join('\n'); return result.join('\n');
} }
/**
* Remove nth from refs that ended up not having duplicates
* This keeps single-element locators simple (no unnecessary .nth(0))
*/
function removeNthFromNonDuplicates(refs: RefMap, tracker: RoleNameTracker): void {
const duplicateKeys = tracker.getDuplicateKeys();
for (const [ref, data] of Object.entries(refs)) {
const key = tracker.getKey(data.role, data.name);
if (!duplicateKeys.has(key)) {
// Not a duplicate, remove nth to keep locator simple
delete refs[ref].nth;
}
}
}
/** /**
* Get indentation level (number of spaces / 2) * Get indentation level (number of spaces / 2)
*/ */
@@ -311,19 +357,20 @@ function processLine(
if (shouldHaveRef) { if (shouldHaveRef) {
const ref = nextRef(); const ref = nextRef();
const nth = tracker.getNextIndex(roleLower, name); const nth = tracker.getNextIndex(roleLower, name);
tracker.trackRef(roleLower, name, ref);
refs[ref] = { refs[ref] = {
selector: buildSelector(roleLower, name), selector: buildSelector(roleLower, name),
role: roleLower, role: roleLower,
name, name,
// Only store nth if this is a duplicate (nth > 0) nth, // Always store nth, we'll clean up non-duplicates later
...(nth > 0 ? { nth } : {}),
}; };
// Build enhanced line with ref // Build enhanced line with ref
let enhanced = `${prefix}${role}`; let enhanced = `${prefix}${role}`;
if (name) enhanced += ` "${name}"`; if (name) enhanced += ` "${name}"`;
enhanced += ` [ref=${ref}]`; enhanced += ` [ref=${ref}]`;
// Only show nth in output if it's > 0 (for readability)
if (nth > 0) enhanced += ` [nth=${nth}]`; if (nth > 0) enhanced += ` [nth=${nth}]`;
if (suffix) enhanced += suffix; if (suffix) enhanced += suffix;