xi include part 1

This commit is contained in:
2026-08-01 14:30:14 +02:00
parent 656fab349d
commit 429ea367f3
7 changed files with 345 additions and 36 deletions
+38 -30
View File
@@ -115,8 +115,12 @@ export class Ra3Diagnostics {
}
}
// Elements outside the EA asset namespace (e.g. XInclude <xi:include>)
// are not part of the RA3 XSD model; skip their validation entirely.
const isXsdElement = model.isXsdElementName(el.name);
// Unknown element.
if (settings.diagnoseUnknownElements && !el.name.startsWith("xi:")) {
if (settings.diagnoseUnknownElements && isXsdElement) {
const knownType = model.elementTypeName(local);
if (!knownType) {
diags.push(
@@ -131,38 +135,42 @@ export class Ra3Diagnostics {
}
// Attributes.
const elType = resolveElementType(el);
const knownAttrs = model.attributesOfType(elType);
const knownNames = new Set(knownAttrs.map((a) => a.name));
for (const attr of el.attrs) {
const aName = attr.name;
if (aName.startsWith("xmlns") || aName.startsWith("xai:") || aName.startsWith("xi:")) {
continue;
}
if (settings.diagnoseUnknownElements && !knownNames.has(aName)) {
diags.push(
this.diag(
new vscode.Range(
document.positionAt(attr.nameStart),
document.positionAt(attr.nameEnd),
if (isXsdElement) {
const elType = resolveElementType(el);
const knownAttrs = model.attributesOfType(elType);
const knownNames = new Set(knownAttrs.map((a) => a.name));
for (const attr of el.attrs) {
const aName = attr.name;
// Namespace declarations and prefixed attributes (xai:, xi:,
// xlink:, xml:, xsi:, xmlns:*) are not defined by the EA XSD.
if (aName.startsWith("xmlns") || !model.isXsdAttributeName(aName)) {
continue;
}
if (settings.diagnoseUnknownElements && !knownNames.has(aName)) {
diags.push(
this.diag(
new vscode.Range(
document.positionAt(attr.nameStart),
document.positionAt(attr.nameEnd),
),
`Unknown attribute "${aName}" for <${local}>`,
vscode.DiagnosticSeverity.Warning,
"unknown-attribute",
),
`Unknown attribute "${aName}" for <${local}>`,
vscode.DiagnosticSeverity.Warning,
"unknown-attribute",
),
);
}
if (!attr.hasValue) continue;
this.checkValueReferences(
elType,
attr.name,
attr.value,
attr,
document,
idx,
diags,
);
}
if (!attr.hasValue) continue;
this.checkValueReferences(
elType,
attr.name,
attr.value,
attr,
document,
idx,
diags,
);
}
// Include-specific checks.
+24 -3
View File
@@ -29,7 +29,7 @@ export class Ra3HoverProvider implements vscode.HoverProvider {
// Attribute name.
for (const attr of el.attrs) {
if (offset >= attr.nameStart && offset <= attr.nameEnd) {
return this.attributeHover(elType, attr.name);
return this.attributeHover(el, elType, attr.name);
}
}
// Attribute value.
@@ -47,6 +47,14 @@ export class Ra3HoverProvider implements vscode.HoverProvider {
}
private elementHover(name: string): vscode.Hover | null {
if (name.startsWith("xi:")) {
const md = new vscode.MarkdownString();
md.appendCodeblock(`<${name}>`, "xml");
md.appendMarkdown(
"XInclude element (W3C XInclude namespace) — not part of the RA3 XSD model.",
);
return new vscode.Hover(md);
}
const type = model.elementTypeName(name);
const info = type ? model.typeInfo(type) : undefined;
const md = new vscode.MarkdownString();
@@ -68,7 +76,11 @@ export class Ra3HoverProvider implements vscode.HoverProvider {
return new vscode.Hover(md);
}
private attributeHover(elementType: string | null, attrName: string): vscode.Hover | null {
private attributeHover(
el: { name: string },
elementType: string | null,
attrName: string,
): vscode.Hover | null {
const attrs = model.attributesOfType(elementType);
const attr = attrs.find((a) => a.name === attrName);
const md = new vscode.MarkdownString();
@@ -78,6 +90,12 @@ export class Ra3HoverProvider implements vscode.HoverProvider {
md.appendMarkdown(`Namespace/instance attribute.`);
return new vscode.Hover(md);
}
if (!model.isXsdElementName(el.name)) {
md.appendMarkdown(
`XInclude attribute (W3C XInclude namespace) — not part of the RA3 XSD model.`,
);
return new vscode.Hover(md);
}
md.appendMarkdown("Unknown attribute for this element.");
return new vscode.Hover(md);
}
@@ -117,7 +135,10 @@ export class Ra3HoverProvider implements vscode.HoverProvider {
}
// Include source.
if (el.name === "Include" && attrName === "source") {
if (
(el.name === "Include" && attrName === "source") ||
(el.name === "xi:include" && attrName === "href")
) {
const resolved = idx
? resolveSource(
value,