Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: no code completion or diagnostic for contextPath or metaPath of ... #689

Merged
merged 7 commits into from
Jan 10, 2024
7 changes: 7 additions & 0 deletions .changeset/brown-cows-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@ui5-language-assistant/vscode-ui5-language-assistant-bas-ext": patch
"vscode-ui5-language-assistant": patch
"@ui5-language-assistant/binding": patch
---

No code completion or diagnostic for contextPath or metaPath of macros namespace
125 changes: 69 additions & 56 deletions packages/binding/src/services/completion/providers/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import {

import { BindContext } from "../../../types";
import { createInitialSnippet } from "./create-initial-snippet";
import { getCursorContext } from "../../../utils";
import {
getCursorContext,
getLogger,
isMacrosMetaContextPath,
} from "../../../utils";
import { createAllSupportedElements } from "./create-all-supported-elements";
import { createKeyProperties } from "./create-key-properties";
import { createValue } from "./create-value";
Expand Down Expand Up @@ -70,64 +74,73 @@ export function bindingSuggestions({
context,
}: AttributeValueCompletionOptions<BindContext>): CompletionItem[] {
const completionItems: CompletionItem[] = [];
const ui5Property = getUI5PropertyByXMLAttributeKey(
attribute,
context.ui5Model
);
const ui5Aggregation = getUI5AggregationByXMLAttributeKey(
attribute,
context.ui5Model
);
if (!ui5Property && !ui5Aggregation) {
return completionItems;
}
const propBinding = getBindingElements(context, ui5Aggregation, false);
const properties = propBinding.map((i) => i.name);
const value = attribute.syntax.value;
const startChar = value && value.image.charAt(0);
context.doubleQuotes = startChar === '"';
/* istanbul ignore next */
const text = attribute.value ?? "";
const extractedBindings = extractBindingSyntax(text);
for (const bindingSyntax of extractedBindings) {
const { expression, startIndex } = bindingSyntax;
if (isBindingExpression(expression)) {
continue;
}
/* istanbul ignore next */
const position: Position = {
character: (value?.startColumn ?? 0) + startIndex,
line: value?.startLine ? value.startLine - 1 : 0, // zero based index
};
const { ast, errors } = parseBinding(expression, position);
const input = expression;
if (input.trim() === "") {
completionItems.push(...createInitialSnippet());
continue;
try {
// `metaPath` and `contextPath` of 'sap.fe.macros' is static
if (isMacrosMetaContextPath(attribute)) {
return completionItems;
}
/* istanbul ignore next */
const cursorPos = context.textDocumentPosition?.position;
const binding = ast.bindings.find(
(b) =>
cursorPos &&
b.range &&
rangeContained(b.range, { start: cursorPos, end: cursorPos })
const ui5Property = getUI5PropertyByXMLAttributeKey(
attribute,
context.ui5Model
);
if (!binding) {
continue;
const ui5Aggregation = getUI5AggregationByXMLAttributeKey(
attribute,
context.ui5Model
);
if (!ui5Property && !ui5Aggregation) {
return completionItems;
}
if (!isBindingAllowed(text, binding, errors, properties)) {
continue;
const propBinding = getBindingElements(context, ui5Aggregation, false);
const properties = propBinding.map((i) => i.name);
const value = attribute.syntax.value;
const startChar = value && value.image.charAt(0);
context.doubleQuotes = startChar === '"';
/* istanbul ignore next */
const text = attribute.value ?? "";
const extractedBindings = extractBindingSyntax(text);
for (const bindingSyntax of extractedBindings) {
const { expression, startIndex } = bindingSyntax;
if (isBindingExpression(expression)) {
continue;
}
/* istanbul ignore next */
const position: Position = {
character: (value?.startColumn ?? 0) + startIndex,
line: value?.startLine ? value.startLine - 1 : 0, // zero based index
};
const { ast, errors } = parseBinding(expression, position);
const input = expression;
if (input.trim() === "") {
completionItems.push(...createInitialSnippet());
continue;
}
/* istanbul ignore next */
const cursorPos = context.textDocumentPosition?.position;
const binding = ast.bindings.find(
(b) =>
cursorPos &&
b.range &&
rangeContained(b.range, { start: cursorPos, end: cursorPos })
);
if (!binding) {
continue;
}
if (!isBindingAllowed(text, binding, errors, properties)) {
continue;
}
completionItems.push(
...getCompletionItems(
context,
binding,
ast.spaces,
ui5Aggregation,
propBinding
)
);
}
completionItems.push(
...getCompletionItems(
context,
binding,
ast.spaces,
ui5Aggregation,
propBinding
)
);
return completionItems;
} catch (error) {
getLogger().debug("bindingSuggestions failed:", error);
return completionItems;
}
return completionItems;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from "@ui5-language-assistant/logic-utils";
import { BindingIssue } from "../../../types";
import { BINDING_ISSUE_TYPE } from "../../../constant";
import { getLogger } from "../../../utils";
import { getLogger, isMacrosMetaContextPath } from "../../../utils";
import { Position } from "vscode-languageserver-types";
import {
parseBinding,
Expand All @@ -25,6 +25,9 @@ export function validateBinding(
): BindingIssue[] {
const issues: BindingIssue[] = [];
try {
if (isMacrosMetaContextPath(attribute)) {
return issues;
}
const ui5Property = getUI5PropertyByXMLAttributeKey(
attribute,
context.ui5Model
Expand Down
17 changes: 17 additions & 0 deletions packages/binding/src/utils/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "@ui5-language-assistant/binding-parser";
import { PARTS } from "../constant";
import { Range } from "vscode-languageserver-types";
import type { XMLAttribute } from "@xml-tools/ast";
const isNumber = (input: number | undefined): input is number => {
return input !== undefined;
};
Expand Down Expand Up @@ -129,3 +130,19 @@ export const getPropertyTypeWithPossibleValue = (

return undefined;
};

/**
* Return turn if it is `metaPath` or `contextPath` of `macros` namespace
*/
export const isMacrosMetaContextPath = (attribute: XMLAttribute): boolean => {
if (!attribute.key) {
return false;
}
if (
["metaPath", "contextPath"].includes(attribute.key) &&
attribute.parent.ns === "macros"
) {
return true;
}
return false;
};
1 change: 1 addition & 0 deletions packages/binding/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export {
findRange,
defaultRange,
getPropertyTypeWithPossibleValue,
isMacrosMetaContextPath,
} from "./element";

export { getCursorContext } from "./cursor";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -718,5 +718,17 @@ describe("index", () => {
});
});
});
describe("macros static property", () => {
it("no CC for metaPath", async () => {
const snippet = `<macros:Chart metaPath="${CURSOR_ANCHOR}"></macros:Chart>`;
const result = await getCompletionResult(snippet);
expect(result).toStrictEqual([]);
});
it("no CC for contextPath", async () => {
const snippet = `<macros:Chart contextPath="${CURSOR_ANCHOR}"></macros:Chart>`;
const result = await getCompletionResult(snippet);
expect(result).toStrictEqual([]);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -900,4 +900,16 @@ describe("property-binding-info-validator", () => {
});
});
});
describe("macros static property", () => {
it("no diagnostic for metaPath", async () => {
const snippet = `<macros:Chart metaPath="{path: 'dynamic-path', wrong: true}"></macros:Chart>`;
const result = await validateView(snippet);
expect(result).toStrictEqual([]);
});
it("no diagnostic for contextPath", async () => {
const snippet = `<macros:Chart contextPath="{path: 'dynamic-path', wrong: true}"></macros:Chart>`;
const result = await validateView(snippet);
expect(result).toStrictEqual([]);
});
});
});