qfai 1.4.36 → 1.4.37
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/cli/index.cjs +275 -14
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +275 -14
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.cjs +201 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.mjs +200 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -1589,8 +1589,8 @@ var import_promises7 = require("fs/promises");
|
|
|
1589
1589
|
var import_node_path8 = __toESM(require("path"), 1);
|
|
1590
1590
|
var import_node_url2 = require("url");
|
|
1591
1591
|
async function resolveToolVersion() {
|
|
1592
|
-
if ("1.4.
|
|
1593
|
-
return "1.4.
|
|
1592
|
+
if ("1.4.37".length > 0) {
|
|
1593
|
+
return "1.4.37";
|
|
1594
1594
|
}
|
|
1595
1595
|
try {
|
|
1596
1596
|
const packagePath = resolvePackageJsonPath();
|
|
@@ -3541,6 +3541,7 @@ async function crawlRoutesAndCollectFoundLabels(baseUrl, routes) {
|
|
|
3541
3541
|
status: "failed",
|
|
3542
3542
|
httpStatus: null,
|
|
3543
3543
|
labels: [],
|
|
3544
|
+
markers: [],
|
|
3544
3545
|
error: `invalid baseUrl or route: baseUrl=${baseUrl}, route=${route}`
|
|
3545
3546
|
});
|
|
3546
3547
|
continue;
|
|
@@ -3556,11 +3557,13 @@ async function crawlRoutesAndCollectFoundLabels(baseUrl, routes) {
|
|
|
3556
3557
|
clearTimeout(timeoutId);
|
|
3557
3558
|
const html = await response.text();
|
|
3558
3559
|
const labels = extractDomLabels(html);
|
|
3560
|
+
const markers = extractDomMarkers(html);
|
|
3559
3561
|
results.push({
|
|
3560
3562
|
route,
|
|
3561
3563
|
status: response.ok ? "ok" : "failed",
|
|
3562
3564
|
httpStatus: response.status,
|
|
3563
3565
|
labels,
|
|
3566
|
+
markers,
|
|
3564
3567
|
...response.ok ? {} : { error: `http status ${response.status} for ${targetUrl}` }
|
|
3565
3568
|
});
|
|
3566
3569
|
} finally {
|
|
@@ -3572,6 +3575,7 @@ async function crawlRoutesAndCollectFoundLabels(baseUrl, routes) {
|
|
|
3572
3575
|
status: "failed",
|
|
3573
3576
|
httpStatus: null,
|
|
3574
3577
|
labels: [],
|
|
3578
|
+
markers: [],
|
|
3575
3579
|
error: formatError4(error2)
|
|
3576
3580
|
});
|
|
3577
3581
|
}
|
|
@@ -3644,6 +3648,16 @@ function buildUiFidelityScreens(expectedScreens, crawledRoutes, mockPathResults)
|
|
|
3644
3648
|
const hasPass = mockPath?.entries.some(
|
|
3645
3649
|
(entry) => entry.status.toLowerCase() === "pass"
|
|
3646
3650
|
) ?? false;
|
|
3651
|
+
const expectedMarkers = screen.labels.map(
|
|
3652
|
+
(label) => `${screen.uiContractId}:${label}`
|
|
3653
|
+
);
|
|
3654
|
+
const crawledMarkers = crawl?.markers ?? [];
|
|
3655
|
+
const foundMarkers = expectedMarkers.filter(
|
|
3656
|
+
(marker) => crawledMarkers.includes(marker)
|
|
3657
|
+
);
|
|
3658
|
+
const missingMarkers = expectedMarkers.filter(
|
|
3659
|
+
(marker) => !crawledMarkers.includes(marker)
|
|
3660
|
+
);
|
|
3647
3661
|
return {
|
|
3648
3662
|
route: screen.route,
|
|
3649
3663
|
uiContractId: screen.uiContractId,
|
|
@@ -3653,10 +3667,12 @@ function buildUiFidelityScreens(expectedScreens, crawledRoutes, mockPathResults)
|
|
|
3653
3667
|
labels: screen.labels
|
|
3654
3668
|
},
|
|
3655
3669
|
found: {
|
|
3656
|
-
labels: coverage.found
|
|
3670
|
+
labels: coverage.found,
|
|
3671
|
+
markers: foundMarkers
|
|
3657
3672
|
},
|
|
3658
3673
|
missing: {
|
|
3659
|
-
labels: coverage.missing
|
|
3674
|
+
labels: coverage.missing,
|
|
3675
|
+
markers: missingMarkers
|
|
3660
3676
|
},
|
|
3661
3677
|
coverage: coverage.coverage,
|
|
3662
3678
|
observed: {
|
|
@@ -3899,16 +3915,31 @@ function extractDomLabels(html) {
|
|
|
3899
3915
|
}
|
|
3900
3916
|
}
|
|
3901
3917
|
}
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
const
|
|
3906
|
-
|
|
3907
|
-
|
|
3918
|
+
if (process.env.QFAI_AUTOGEN_BODY_TOKENS === "1") {
|
|
3919
|
+
const rawBodyText = document.body?.textContent ?? "";
|
|
3920
|
+
const bodyTokens = rawBodyText.split(/\s{2,}|\n+/);
|
|
3921
|
+
for (const token of bodyTokens) {
|
|
3922
|
+
const trimmed = normalizeDomLabel(token);
|
|
3923
|
+
if (trimmed) {
|
|
3924
|
+
labels.push(trimmed);
|
|
3925
|
+
}
|
|
3908
3926
|
}
|
|
3909
3927
|
}
|
|
3910
3928
|
return dedupeLabels(labels);
|
|
3911
3929
|
}
|
|
3930
|
+
function extractDomMarkers(html) {
|
|
3931
|
+
const dom = new import_jsdom.JSDOM(html);
|
|
3932
|
+
const document = dom.window.document;
|
|
3933
|
+
const markers = [];
|
|
3934
|
+
for (const element of document.querySelectorAll("[data-qfai]")) {
|
|
3935
|
+
const value = element.getAttribute("data-qfai") ?? "";
|
|
3936
|
+
const trimmed = value.trim();
|
|
3937
|
+
if (trimmed.length > 0) {
|
|
3938
|
+
markers.push(trimmed);
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3941
|
+
return Array.from(new Set(markers)).sort((a, b) => a.localeCompare(b));
|
|
3942
|
+
}
|
|
3912
3943
|
function normalizeDomLabel(value) {
|
|
3913
3944
|
const normalized = value.replace(/\s+/g, " ").trim();
|
|
3914
3945
|
if (normalized.length === 0) {
|
|
@@ -3926,7 +3957,7 @@ function hasLabelMatch(foundLabels, expectedLabel) {
|
|
|
3926
3957
|
}
|
|
3927
3958
|
return foundLabels.some((label) => {
|
|
3928
3959
|
const normalizedFound = normalizeComparableText(label);
|
|
3929
|
-
return normalizedFound === normalizedExpected
|
|
3960
|
+
return normalizedFound === normalizedExpected;
|
|
3930
3961
|
});
|
|
3931
3962
|
}
|
|
3932
3963
|
function normalizeComparableText(value) {
|
|
@@ -3992,9 +4023,35 @@ var DEFAULT_EVIDENCE_PATH = ".qfai/evidence/prototyping.json";
|
|
|
3992
4023
|
async function runPrototyping(options) {
|
|
3993
4024
|
const autogenEnabled = options.autogenUiFidelity || process.env[ENV_AUTOGEN] === "1";
|
|
3994
4025
|
if (!autogenEnabled) {
|
|
4026
|
+
if (options.autogenOnly) {
|
|
4027
|
+
error(
|
|
4028
|
+
`prototyping: --autogen-only \u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059\u304C --autogen-ui-fidelity / ${ENV_AUTOGEN}=1 \u304C\u3042\u308A\u307E\u305B\u3093\u3002`
|
|
4029
|
+
);
|
|
4030
|
+
return 2;
|
|
4031
|
+
}
|
|
3995
4032
|
info(
|
|
3996
4033
|
`prototyping: --autogen-ui-fidelity or ${ENV_AUTOGEN}=1 \u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u4F55\u3082\u5B9F\u884C\u3057\u307E\u305B\u3093\u3002`
|
|
3997
4034
|
);
|
|
4035
|
+
const evidencePath2 = resolveEvidencePath(options.root, options.evidenceOut);
|
|
4036
|
+
const toolVersion2 = await resolveToolVersion();
|
|
4037
|
+
let existingEvidence2 = {};
|
|
4038
|
+
try {
|
|
4039
|
+
const raw = await (0, import_promises14.readFile)(evidencePath2, "utf-8");
|
|
4040
|
+
const parsed = JSON.parse(raw);
|
|
4041
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4042
|
+
existingEvidence2 = parsed;
|
|
4043
|
+
}
|
|
4044
|
+
} catch {
|
|
4045
|
+
}
|
|
4046
|
+
const skippedEvidence = emitUiFidelity({
|
|
4047
|
+
evidence: existingEvidence2,
|
|
4048
|
+
toolVersion: toolVersion2,
|
|
4049
|
+
command: "qfai prototyping",
|
|
4050
|
+
baseUrl: "",
|
|
4051
|
+
status: "skipped",
|
|
4052
|
+
reason: "autogen not enabled (--autogen-ui-fidelity or env not set)"
|
|
4053
|
+
});
|
|
4054
|
+
await writeEvidence(evidencePath2, skippedEvidence);
|
|
3998
4055
|
return 0;
|
|
3999
4056
|
}
|
|
4000
4057
|
const baseUrl = resolveBaseUrl(options);
|
|
@@ -4017,9 +4074,15 @@ async function runPrototyping(options) {
|
|
|
4017
4074
|
}
|
|
4018
4075
|
} catch {
|
|
4019
4076
|
}
|
|
4077
|
+
const routeHints = extractRouteHintsFromEvidence(existingEvidence);
|
|
4020
4078
|
let result;
|
|
4021
4079
|
try {
|
|
4022
|
-
result = await autogenerateUiFidelity(
|
|
4080
|
+
result = await autogenerateUiFidelity(
|
|
4081
|
+
options.root,
|
|
4082
|
+
config,
|
|
4083
|
+
baseUrl,
|
|
4084
|
+
routeHints
|
|
4085
|
+
);
|
|
4023
4086
|
} catch (err) {
|
|
4024
4087
|
const reason = err instanceof Error ? err.message : String(err);
|
|
4025
4088
|
warn(`prototyping: autogen failed - ${reason}`);
|
|
@@ -4098,6 +4161,45 @@ async function writeEvidence(filePath, evidence) {
|
|
|
4098
4161
|
await (0, import_promises14.mkdir)(import_node_path17.default.dirname(filePath), { recursive: true });
|
|
4099
4162
|
await (0, import_promises14.writeFile)(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
|
|
4100
4163
|
}
|
|
4164
|
+
function extractRouteHintsFromEvidence(evidence) {
|
|
4165
|
+
const routes = /* @__PURE__ */ new Set();
|
|
4166
|
+
const runtimeGate = evidence.runtimeGate;
|
|
4167
|
+
if (runtimeGate && typeof runtimeGate === "object" && !Array.isArray(runtimeGate)) {
|
|
4168
|
+
const gate = runtimeGate;
|
|
4169
|
+
const uiRows = gate.ui;
|
|
4170
|
+
if (Array.isArray(uiRows)) {
|
|
4171
|
+
for (const row of uiRows) {
|
|
4172
|
+
if (row && typeof row === "object" && !Array.isArray(row)) {
|
|
4173
|
+
const r = row;
|
|
4174
|
+
if (typeof r.route === "string" && r.route.trim().length > 0) {
|
|
4175
|
+
routes.add(r.route.trim());
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4181
|
+
const specs = evidence.specs;
|
|
4182
|
+
if (Array.isArray(specs)) {
|
|
4183
|
+
for (const spec of specs) {
|
|
4184
|
+
if (spec && typeof spec === "object" && !Array.isArray(spec)) {
|
|
4185
|
+
const s = spec;
|
|
4186
|
+
const missing = s.missing;
|
|
4187
|
+
if (missing && typeof missing === "object" && !Array.isArray(missing)) {
|
|
4188
|
+
const m = missing;
|
|
4189
|
+
const uiRoutes = m.uiRoutes;
|
|
4190
|
+
if (Array.isArray(uiRoutes)) {
|
|
4191
|
+
for (const route of uiRoutes) {
|
|
4192
|
+
if (typeof route === "string" && route.trim().length > 0) {
|
|
4193
|
+
routes.add(route.trim());
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
return Array.from(routes).sort((a, b) => a.localeCompare(b));
|
|
4202
|
+
}
|
|
4101
4203
|
|
|
4102
4204
|
// src/cli/commands/report.ts
|
|
4103
4205
|
var import_promises42 = require("fs/promises");
|
|
@@ -11577,6 +11679,82 @@ async function validateUiFidelity(root, config, evidenceJsonPath, evidence) {
|
|
|
11577
11679
|
)
|
|
11578
11680
|
);
|
|
11579
11681
|
}
|
|
11682
|
+
const screensWithMissingLabels = uiFidelity.screens.filter(
|
|
11683
|
+
(screen) => screen.expected.labels && screen.expected.labels.length > 0 && screen.missing?.labels && screen.missing.labels.length > 0
|
|
11684
|
+
);
|
|
11685
|
+
if (screensWithMissingLabels.length > 0) {
|
|
11686
|
+
const details = screensWithMissingLabels.map((screen) => {
|
|
11687
|
+
const missing = screen.missing?.labels ?? [];
|
|
11688
|
+
return `${screen.route}:${screen.uiContractId}(missing_labels=${missing.join("|")})`;
|
|
11689
|
+
}).sort((a, b) => a.localeCompare(b));
|
|
11690
|
+
const refs = collectLabelMismatchRefs(screensWithMissingLabels);
|
|
11691
|
+
issues.push(
|
|
11692
|
+
issue(
|
|
11693
|
+
"QFAI-PROT-241",
|
|
11694
|
+
`QFAI-PROT-241: uiFidelity screens have missing labels. ${details.join("; ")}`,
|
|
11695
|
+
"error",
|
|
11696
|
+
evidenceJsonPath,
|
|
11697
|
+
"prototypingEvidence.uiFidelityMissingLabels",
|
|
11698
|
+
refs,
|
|
11699
|
+
"change",
|
|
11700
|
+
[
|
|
11701
|
+
"contracts/ui \u306E elements[].label \u3092\u753B\u9762\u306B\u3059\u3079\u3066\u63CF\u753B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
11702
|
+
"\u63CF\u753B\u304C\u96E3\u3057\u3044\u8981\u7D20\u306F data-qfai \u30DE\u30FC\u30AB\u30FC\u3067\u4EE3\u66FF\u3057\u3001autogen \u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
11703
|
+
].join("\n")
|
|
11704
|
+
)
|
|
11705
|
+
);
|
|
11706
|
+
}
|
|
11707
|
+
const screensWithMissingMarkers = uiFidelity.screens.filter(
|
|
11708
|
+
(screen) => screen.expected.elements > 0 && screen.missing?.markers && screen.missing.markers.length > 0
|
|
11709
|
+
);
|
|
11710
|
+
if (screensWithMissingMarkers.length > 0) {
|
|
11711
|
+
const details = screensWithMissingMarkers.map((screen) => {
|
|
11712
|
+
const missing = screen.missing?.markers ?? [];
|
|
11713
|
+
return `${screen.route}:${screen.uiContractId}(missing_markers=${missing.join("|")})`;
|
|
11714
|
+
}).sort((a, b) => a.localeCompare(b));
|
|
11715
|
+
const refs = collectMarkerMismatchRefs(screensWithMissingMarkers);
|
|
11716
|
+
issues.push(
|
|
11717
|
+
issue(
|
|
11718
|
+
"QFAI-PROT-242",
|
|
11719
|
+
`QFAI-PROT-242: uiFidelity screens have missing markers. ${details.join("; ")}`,
|
|
11720
|
+
"error",
|
|
11721
|
+
evidenceJsonPath,
|
|
11722
|
+
"prototypingEvidence.uiFidelityMissingMarkers",
|
|
11723
|
+
refs,
|
|
11724
|
+
"change",
|
|
11725
|
+
[
|
|
11726
|
+
'\u753B\u9762\u306E\u5404\u8981\u7D20\u306B data-qfai="CONTRACT_ID:ELEMENT_LABEL" \u30DE\u30FC\u30AB\u30FC\u3092\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002',
|
|
11727
|
+
"autogen \u3092\u518D\u5B9F\u884C\u3057\u3001missing.markers \u304C\u7A7A\u306B\u306A\u308B\u3053\u3068\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
11728
|
+
].join("\n")
|
|
11729
|
+
)
|
|
11730
|
+
);
|
|
11731
|
+
}
|
|
11732
|
+
const placeholderScreens = uiFidelity.screens.filter((screen) => {
|
|
11733
|
+
if (!screen.found?.labels) return false;
|
|
11734
|
+
const expectedElements = screen.expected.elements;
|
|
11735
|
+
const observedElements = screen.observed.elementsPlaced;
|
|
11736
|
+
const foundLabels = screen.found.labels.length;
|
|
11737
|
+
return expectedElements > 2 && observedElements <= 1 && foundLabels <= 1;
|
|
11738
|
+
});
|
|
11739
|
+
if (placeholderScreens.length > 0) {
|
|
11740
|
+
const details = placeholderScreens.map(
|
|
11741
|
+
(screen) => `${screen.route}:${screen.uiContractId}(expected=${screen.expected.elements},observed=${screen.observed.elementsPlaced})`
|
|
11742
|
+
).sort((a, b) => a.localeCompare(b));
|
|
11743
|
+
issues.push(
|
|
11744
|
+
issue(
|
|
11745
|
+
"QFAI-PROT-243",
|
|
11746
|
+
`QFAI-PROT-243: placeholder/single-text pages detected. ${details.join("; ")}`,
|
|
11747
|
+
"warning",
|
|
11748
|
+
evidenceJsonPath,
|
|
11749
|
+
"prototypingEvidence.placeholderPages",
|
|
11750
|
+
placeholderScreens.map(
|
|
11751
|
+
(screen) => `${screen.uiContractId}|${screen.route}`
|
|
11752
|
+
),
|
|
11753
|
+
"change",
|
|
11754
|
+
"\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u30DA\u30FC\u30B8\u3092\u691C\u51FA\u3057\u307E\u3057\u305F\u3002contracts/ui \u306E\u5168\u8981\u7D20\u3092\u753B\u9762\u306B\u914D\u7F6E\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
11755
|
+
)
|
|
11756
|
+
);
|
|
11757
|
+
}
|
|
11580
11758
|
const hasMockPaths = uiFidelity.screens.some(
|
|
11581
11759
|
(screen) => screen.mockPaths.length > 0
|
|
11582
11760
|
);
|
|
@@ -11647,6 +11825,40 @@ function collectUiFidelityMismatchRefs(mismatches) {
|
|
|
11647
11825
|
}
|
|
11648
11826
|
return Array.from(refs).sort((left, right) => left.localeCompare(right));
|
|
11649
11827
|
}
|
|
11828
|
+
function collectLabelMismatchRefs(screens) {
|
|
11829
|
+
const refs = /* @__PURE__ */ new Set();
|
|
11830
|
+
for (const screen of screens) {
|
|
11831
|
+
refs.add(`contract_id=${screen.uiContractId}`);
|
|
11832
|
+
refs.add(`route=${screen.route}`);
|
|
11833
|
+
refs.add(`contract_route=${screen.uiContractId}|${screen.route}`);
|
|
11834
|
+
const missingLabels = screen.missing?.labels ?? [];
|
|
11835
|
+
if (missingLabels.length > 0) {
|
|
11836
|
+
const labels = missingLabels.sort((a, b) => a.localeCompare(b)).join("|");
|
|
11837
|
+
refs.add(`missing_labels=${labels}`);
|
|
11838
|
+
refs.add(
|
|
11839
|
+
`missing_labels_by_contract_route=${screen.uiContractId}|${screen.route}:${labels}`
|
|
11840
|
+
);
|
|
11841
|
+
}
|
|
11842
|
+
}
|
|
11843
|
+
return Array.from(refs).sort((l, r) => l.localeCompare(r));
|
|
11844
|
+
}
|
|
11845
|
+
function collectMarkerMismatchRefs(screens) {
|
|
11846
|
+
const refs = /* @__PURE__ */ new Set();
|
|
11847
|
+
for (const screen of screens) {
|
|
11848
|
+
refs.add(`contract_id=${screen.uiContractId}`);
|
|
11849
|
+
refs.add(`route=${screen.route}`);
|
|
11850
|
+
refs.add(`contract_route=${screen.uiContractId}|${screen.route}`);
|
|
11851
|
+
const missingMarkers = screen.missing?.markers ?? [];
|
|
11852
|
+
if (missingMarkers.length > 0) {
|
|
11853
|
+
const markers = missingMarkers.sort((a, b) => a.localeCompare(b)).join("|");
|
|
11854
|
+
refs.add(`missing_markers=${markers}`);
|
|
11855
|
+
refs.add(
|
|
11856
|
+
`missing_markers_by_contract_route=${screen.uiContractId}|${screen.route}:${markers}`
|
|
11857
|
+
);
|
|
11858
|
+
}
|
|
11859
|
+
}
|
|
11860
|
+
return Array.from(refs).sort((l, r) => l.localeCompare(r));
|
|
11861
|
+
}
|
|
11650
11862
|
async function collectUiContractScreens(contractIndex) {
|
|
11651
11863
|
const result = /* @__PURE__ */ new Map();
|
|
11652
11864
|
for (const [contractId, fileSet] of contractIndex.idToFiles.entries()) {
|
|
@@ -11799,6 +12011,9 @@ function normalizeUiFidelityScreen(value) {
|
|
|
11799
12011
|
route: value.route.trim(),
|
|
11800
12012
|
uiContractId: value.uiContractId.trim().toUpperCase(),
|
|
11801
12013
|
expected: expected.value,
|
|
12014
|
+
...normalizeOptionalFoundBlock(value.found),
|
|
12015
|
+
...normalizeOptionalMissingBlock(value.missing),
|
|
12016
|
+
...typeof value.coverage === "number" ? { coverage: value.coverage } : {},
|
|
11802
12017
|
observed: observed.value,
|
|
11803
12018
|
mockPaths: mockPaths.value
|
|
11804
12019
|
}
|
|
@@ -11817,11 +12032,13 @@ function normalizeUiFidelityExpected(value) {
|
|
|
11817
12032
|
reason: "`uiFidelity.screens[].expected` requires non-negative integers for elements/actions"
|
|
11818
12033
|
};
|
|
11819
12034
|
}
|
|
12035
|
+
const labels = toOptionalStringArray(value.labels);
|
|
11820
12036
|
return {
|
|
11821
12037
|
ok: true,
|
|
11822
12038
|
value: {
|
|
11823
12039
|
elements: value.elements,
|
|
11824
|
-
actions: value.actions
|
|
12040
|
+
actions: value.actions,
|
|
12041
|
+
...labels ? { labels } : {}
|
|
11825
12042
|
}
|
|
11826
12043
|
};
|
|
11827
12044
|
}
|
|
@@ -11979,6 +12196,47 @@ function toStringArray2(value) {
|
|
|
11979
12196
|
}
|
|
11980
12197
|
return value.map((item) => item.trim()).filter((item) => item.length > 0);
|
|
11981
12198
|
}
|
|
12199
|
+
function toOptionalStringArray(value) {
|
|
12200
|
+
if (value === void 0 || value === null) {
|
|
12201
|
+
return void 0;
|
|
12202
|
+
}
|
|
12203
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
12204
|
+
return void 0;
|
|
12205
|
+
}
|
|
12206
|
+
return value.map((item) => item.trim()).filter((item) => item.length > 0);
|
|
12207
|
+
}
|
|
12208
|
+
function normalizeOptionalFoundBlock(value) {
|
|
12209
|
+
if (!isRecord5(value)) {
|
|
12210
|
+
return {};
|
|
12211
|
+
}
|
|
12212
|
+
const labels = toOptionalStringArray(value.labels);
|
|
12213
|
+
const markers = toOptionalStringArray(value.markers);
|
|
12214
|
+
if (!labels && !markers) {
|
|
12215
|
+
return {};
|
|
12216
|
+
}
|
|
12217
|
+
return {
|
|
12218
|
+
found: {
|
|
12219
|
+
...labels ? { labels } : {},
|
|
12220
|
+
...markers ? { markers } : {}
|
|
12221
|
+
}
|
|
12222
|
+
};
|
|
12223
|
+
}
|
|
12224
|
+
function normalizeOptionalMissingBlock(value) {
|
|
12225
|
+
if (!isRecord5(value)) {
|
|
12226
|
+
return {};
|
|
12227
|
+
}
|
|
12228
|
+
const labels = toOptionalStringArray(value.labels);
|
|
12229
|
+
const markers = toOptionalStringArray(value.markers);
|
|
12230
|
+
if (!labels && !markers) {
|
|
12231
|
+
return {};
|
|
12232
|
+
}
|
|
12233
|
+
return {
|
|
12234
|
+
missing: {
|
|
12235
|
+
...labels ? { labels } : {},
|
|
12236
|
+
...markers ? { markers } : {}
|
|
12237
|
+
}
|
|
12238
|
+
};
|
|
12239
|
+
}
|
|
11982
12240
|
function isRecord5(value) {
|
|
11983
12241
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
11984
12242
|
}
|
|
@@ -14728,7 +14986,10 @@ var ISSUE_EXPECTED_BY_CODE = {
|
|
|
14728
14986
|
"QFAI-PROT-114": "Per-spec DB checks satisfy declared object counts and leave no unresolved DB objects.",
|
|
14729
14987
|
"QFAI-PROT-231": "Interactive prototyping evidence includes uiFidelity with required screen-level fields.",
|
|
14730
14988
|
"QFAI-PROT-232": "uiFidelity screen observations satisfy referenced UI contract elements/actions coverage.",
|
|
14731
|
-
"QFAI-PROT-233": "Interactive uiFidelity records at least one mockPaths status=pass entry (warning in v1.4.
|
|
14989
|
+
"QFAI-PROT-233": "Interactive uiFidelity records at least one mockPaths status=pass entry (warning in v1.4.37).",
|
|
14990
|
+
"QFAI-PROT-241": "uiFidelity screens must have no missing labels when expected.labels is present.",
|
|
14991
|
+
"QFAI-PROT-242": "uiFidelity screens must have no missing markers when expected.elements > 0 and markers are tracked.",
|
|
14992
|
+
"QFAI-PROT-243": "Placeholder/single-text pages are detected when expected elements > 2, observed <= 1, and found.labels <= 1 (warning in v1.4.37).",
|
|
14732
14993
|
"QFAI-CONTRACT-030": "Contract index references must match declared contract IDs in .qfai/contracts/**."
|
|
14733
14994
|
};
|
|
14734
14995
|
function resolveIssueTarget(issue2) {
|