Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 1x 1x 5x 1x 1x 3x 3x 3x 3x 3x 5x 5x 5x 1x 1x 1x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x | /**
* `DyE2E_VQA_FindingId_Util` — stable finding-ID generálás (`VQA-<projekt>-<feature>-NNN`).
*
* Az AI agent ezt használja a finding-write-or, hogy a következő szabad
* sorszámot kapjon a feature-en belül. Az existingFindingIds set-jét a bundle
* vagy a projekt BACKLOG.md adja.
*/
export class DyE2E_VQA_FindingId_Util {
/** Következő szabad sorszám (001-tól, padding 3). */
static nextId(
projectSlug: string,
featureSlug: string,
existingFindingIds: string[],
): string {
if (!/^[a-z0-9-]+$/.test(projectSlug)) {
throw new Error(`projectSlug must be lowercase kebab-case: '${projectSlug}'`);
}
if (!/^[a-z0-9-]+$/.test(featureSlug)) {
throw new Error(`featureSlug must be lowercase kebab-case: '${featureSlug}'`);
}
const prefix: string = `VQA-${projectSlug}-${featureSlug}-`;
const usedNums: number[] = existingFindingIds
.filter((id) => id.startsWith(prefix))
.map((id) => parseInt(id.slice(prefix.length), 10))
.filter((n) => !isNaN(n));
const next: number = (usedNums.length === 0 ? 0 : Math.max(...usedNums)) + 1;
return `${prefix}${String(next).padStart(3, '0')}`;
}
/** Parse-back: kibontja a komponenseket egy ID-ből. Null ha nem-konform. */
static parse(findingId: string): { projectSlug: string; featureSlug: string; seq: number } | null {
const match: RegExpMatchArray | null = findingId.match(/^VQA-([a-z0-9-]+?)-([a-z0-9-]+?)-(\d{3,})$/);
if (!match) {
return null;
}
return {
projectSlug: match[1],
featureSlug: match[2],
seq: parseInt(match[3], 10),
};
}
}
|