fix: diagnose nested partial Profile values in the editor (T-710)
Resolve MR sequence 3 profile_nested_editor_diagnostics_missing with a separate, non-materializing authoring constraint pass. Preserve omission and the persisted evaluation schema, and map nested/imported failures to supplied virtual-source spans. Exercise actual Backend schema in native and regenerated WASM tests for empty/partial values, worker and feature types, unknown fields, imports and composition. Validation: root cargo check; config-source 38; config-source-wasm native/doc; unfiltered yoi-workspace-server 642 lib + 11 bin; worker-runtime 340 lib + 17 per binary; server-api --features typescript 77; focused Deno 39; deno task check; wasm32 release build, wasm-bindgen 0.2.117 + Binaryen 132 -Oz regeneration; cargo fmt/diff checks. Earlier checker failure did not recur: Reviewer independently passed full source suite and exact original baseline checker filter, recorded in MR sequence 3.
This commit is contained in:
@@ -475,19 +475,100 @@ Deno.test("generated WASM authors value-based Profiles using the Backend schema
|
||||
);
|
||||
assertEquals(result.from, cursor - token.length);
|
||||
}
|
||||
const invalidContent = content.replace("profile = {};", "profile = 42;");
|
||||
const invalid = {
|
||||
for (
|
||||
const value of [
|
||||
"{}",
|
||||
"{ worker = {}; }",
|
||||
'{ worker = { mode = "wip"; }; }',
|
||||
"{ feature = { task = {}; }; }",
|
||||
]
|
||||
) {
|
||||
const partialContent = content.replace(
|
||||
"profile = {};",
|
||||
`profile = ${value};`,
|
||||
);
|
||||
assertEquals(
|
||||
analyze_snapshot(tree, "main.dcdl", partialContent),
|
||||
[],
|
||||
value,
|
||||
);
|
||||
}
|
||||
const recipe = "{ worker = { mode = 42; }; }";
|
||||
const analysisTree = {
|
||||
...tree,
|
||||
entries: {
|
||||
"main.dcdl": { ...tree.entries["main.dcdl"], content: invalidContent },
|
||||
...tree.entries,
|
||||
"recipe.dcdl": {
|
||||
path: "recipe.dcdl",
|
||||
content_type: "decodal",
|
||||
content: recipe,
|
||||
content_digest: await digestText(recipe),
|
||||
},
|
||||
},
|
||||
};
|
||||
const diagnostics = analyze_snapshot(
|
||||
invalid,
|
||||
"main.dcdl",
|
||||
undefined,
|
||||
) as Array<
|
||||
unknown
|
||||
>;
|
||||
assertEquals(diagnostics.length > 0, true);
|
||||
for (
|
||||
const [value, field, expectedPath] of [
|
||||
["42", "profile", "main.dcdl"],
|
||||
["{ worker = 42; }", "worker", "main.dcdl"],
|
||||
["{ worker = { mode = 42; }; }", "mode", "main.dcdl"],
|
||||
["{ feature = { task = { enabled = 42; }; }; }", "enabled", "main.dcdl"],
|
||||
['{ worker = { typo = "wip"; }; }', "typo", "main.dcdl"],
|
||||
['import "./recipe.dcdl"', "mode", "recipe.dcdl"],
|
||||
[
|
||||
'(import "./recipe.dcdl") // { worker = { mode = 42; }; }',
|
||||
"mode",
|
||||
"main.dcdl",
|
||||
],
|
||||
]
|
||||
) {
|
||||
const invalidContent = content.replace(
|
||||
"profile = {};",
|
||||
`profile = ${value};`,
|
||||
);
|
||||
const diagnostics = analyze_snapshot(
|
||||
analysisTree,
|
||||
"main.dcdl",
|
||||
invalidContent,
|
||||
) as Array<{
|
||||
path: string;
|
||||
revision: number;
|
||||
kind: string;
|
||||
span: { start_byte: number; end_byte: number };
|
||||
message: string;
|
||||
labels: Array<
|
||||
{ span: { start_byte: number; end_byte: number }; message: string }
|
||||
>;
|
||||
}>;
|
||||
assertEquals(diagnostics.length > 0, true, value);
|
||||
const diagnostic = diagnostics[0];
|
||||
assertEquals(diagnostic.path, expectedPath);
|
||||
assertEquals(diagnostic.revision, tree.revision);
|
||||
assertEquals(
|
||||
["constraint_violation", "type_mismatch"].includes(diagnostic.kind),
|
||||
true,
|
||||
);
|
||||
assertEquals(
|
||||
diagnostic.message.includes(field) ||
|
||||
diagnostic.labels.some((label) => label.message.includes(field)),
|
||||
true,
|
||||
);
|
||||
// New authoring failures must be anchored in the supplied value, not the
|
||||
// much longer schema source, including relative imported recipes.
|
||||
if (value !== "42") {
|
||||
const length = new TextEncoder().encode(
|
||||
expectedPath === "main.dcdl" ? invalidContent : recipe,
|
||||
).length;
|
||||
assertEquals(
|
||||
diagnostic.span.end_byte > diagnostic.span.start_byte &&
|
||||
diagnostic.span.end_byte <= length,
|
||||
true,
|
||||
);
|
||||
assertEquals(
|
||||
diagnostic.labels.every((label) => label.span.end_byte <= length),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
// Neither completion nor diagnostic shape checking changes the saved value.
|
||||
assertEquals(evaluate_snapshot(tree, valueContract), evaluated);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user