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: relax diagnostics for aggregation which have alternative types #682

Merged
merged 5 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/calm-seas-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@ui5-language-assistant/vscode-ui5-language-assistant-bas-ext": patch
"vscode-ui5-language-assistant": patch
"@ui5-language-assistant/language-server": patch
"@ui5-language-assistant/binding": patch
---

Relax diagnostics for aggregation which have alternative types
136 changes: 91 additions & 45 deletions packages/binding/src/definition/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import { getDocumentation } from "../utils";
import { getFallBackElements } from "./fall-back-definition";
import { getSorterPossibleElement } from "./sorter";
import { getFiltersPossibleElement } from "./filter";
import type {
UI5Aggregation,
UI5TypedefProp,
} from "@ui5-language-assistant/semantic-model-types";

const notAllowedElements: Map<BindingInfoName, BindingInfoName[]> = new Map([
[BindingInfoName.path, [BindingInfoName.parts, BindingInfoName.value]],
Expand Down Expand Up @@ -124,13 +128,13 @@ const sorterMap = new Map([
]);
const getPossibleElement = (param: {
context: BindContext;
aggregation?: boolean;
ui5Aggregation?: UI5Aggregation;
forHover?: boolean;
type: UI5Class;
}): BindingInfoElement[] => {
const result: BindingInfoElement[] = [];
/* istanbul ignore next */
const { aggregation = false, forHover = false, type, context } = param;
const { ui5Aggregation, forHover = false, type, context } = param;
if (type.name === ClassName.Sorter) {
const parameters = type.ctor && type.ctor.parameters;
if (!parameters) {
Expand All @@ -150,7 +154,7 @@ const getPossibleElement = (param: {
type: constParam.type,
name,
collection: false,
aggregation,
ui5Aggregation,
forHover,
reference,
}),
Expand Down Expand Up @@ -190,7 +194,7 @@ const getPossibleElement = (param: {
type: paramType,
name: param.name,
collection: false,
aggregation,
ui5Aggregation,
forHover,
reference,
}),
Expand Down Expand Up @@ -242,20 +246,21 @@ const buildType = (param: {
type: UI5Type;
name: string;
collection?: boolean;
aggregation?: boolean;
ui5Aggregation?: UI5Aggregation;
forHover?: boolean;
reference?: string;
}): PropertyType[] => {
/* istanbul ignore next */
const {
collection = false,
aggregation = false,
ui5Aggregation,
forHover = false,
context,
type,
name,
reference,
} = param;
const aggregation = !!ui5Aggregation;
const propertyType: PropertyType[] = [];
switch (type.kind) {
case "UI5Any": {
Expand Down Expand Up @@ -309,7 +314,7 @@ const buildType = (param: {
notAllowedElements: getFromMap(notAllowedElements, name, aggregation),
possibleElements: reference
? []
: getPossibleElement({ context, aggregation, forHover, type }),
: getPossibleElement({ context, ui5Aggregation, forHover, type }),
possibleValue: {
fixed: false,
values: getPossibleValuesForClass(context, type),
Expand Down Expand Up @@ -338,7 +343,7 @@ const buildType = (param: {
type: unionType.type,
name,
collection: true,
aggregation,
ui5Aggregation,
forHover,
reference,
})
Expand All @@ -350,7 +355,7 @@ const buildType = (param: {
type: unionType,
name,
collection,
aggregation,
ui5Aggregation,
forHover,
reference,
})
Expand All @@ -368,7 +373,7 @@ const buildType = (param: {
type: type.type,
name,
collection: true,
aggregation,
ui5Aggregation,
forHover,
reference,
})
Expand All @@ -378,53 +383,57 @@ const buildType = (param: {
return propertyType;
};

export const getBindingElements = (
context: BindContext,
/* istanbul ignore next */
aggregation = false,
/* istanbul ignore next */
forHover = false
): BindingInfoElement[] => {
const elements: BindingInfoElement[] = [];
const propBinding = aggregation
? context.ui5Model.typedefs[AGGREGATION_BINDING_INFO]
: context.ui5Model.typedefs[PROPERTY_BINDING_INFO];
const getAltTypesPrime = (aggregation?: UI5Aggregation) =>
aggregation?.altTypes?.find((i) => i.kind === "PrimitiveType");

if (!propBinding) {
return getFallBackElements(aggregation);
}
/* istanbul ignore next */
const properties = propBinding.properties ?? [];
const removeDuplicate = (builtType: PropertyType[]): PropertyType[] => {
const result = builtType.reduce(
(previous: PropertyType[], current: PropertyType) => {
const index = previous.findIndex((i) => i.kind === current.kind);
if (index === -1) {
return [...previous, current];
}
// there is duplicate
/* istanbul ignore next */
if (current.possibleValue?.values.length !== 0) {
// has possible value, remove previous - keep current
return [...previous.slice(index), current];
}
/* istanbul ignore next */
if (previous[index].possibleValue?.values.length !== 0) {
// has possible value - keep it
return previous;
}
return [...previous, current];
},
[]
);
return result;
};

const processUI5TypedefProperties = (param: {
properties: UI5TypedefProp[];
context: BindContext;
aggregation?: UI5Aggregation;
forHover?: boolean;
}) => {
const { properties, forHover = false, aggregation, context } = param;
const elements: BindingInfoElement[] = [];
for (const property of properties) {
const { name, type } = property;
if (!type) {
/* istanbul ignore next */
continue;
}
const builtType = buildType({
let builtType = buildType({
context,
type,
name,
collection: false,
aggregation,
ui5Aggregation: aggregation,
forHover,
}).reduce((previous: PropertyType[], current: PropertyType) => {
const index = previous.findIndex((i) => i.kind === current.kind);
if (index !== -1) {
// there is duplicate
/* istanbul ignore next */
if (current.possibleValue?.values.length !== 0) {
// has possible value, remove previous - keep current
return [...previous.slice(index), current];
}
/* istanbul ignore next */
if (previous[index].possibleValue?.values.length !== 0) {
// has possible value - keep it
return previous;
}
}
return [...previous, current];
}, []);
});
builtType = removeDuplicate(builtType);
const FQN = aggregation ? AGGREGATION_BINDING_INFO : PROPERTY_BINDING_INFO;
const data: BindingInfoElement = {
name: name,
Expand All @@ -443,3 +452,40 @@ export const getBindingElements = (
}
return elements;
};
export const getBindingElements = (
context: BindContext,
/* istanbul ignore next */
aggregation: UI5Aggregation | undefined = undefined,
/* istanbul ignore next */
forHover = false
): BindingInfoElement[] => {
const elements: BindingInfoElement[] = [];
const propBinding = aggregation
? context.ui5Model.typedefs[AGGREGATION_BINDING_INFO]
: context.ui5Model.typedefs[PROPERTY_BINDING_INFO];

if (!propBinding) {
return getFallBackElements(!!aggregation);
}
elements.push(
...processUI5TypedefProperties({
context,
forHover,
aggregation,
properties: propBinding.properties,
})
);
const altTypes = getAltTypesPrime(aggregation);
if (altTypes) {
// if `altTypes`, add `PROPERTY_BINDING_INFO` properties too
elements.push(
...processUI5TypedefProperties({
properties: context.ui5Model.typedefs[PROPERTY_BINDING_INFO].properties,
context,
forHover,
})
);
}

return elements;
};
7 changes: 4 additions & 3 deletions packages/binding/src/services/completion/providers/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import { createKeyProperties } from "./create-key-properties";
import { createValue } from "./create-value";
import { createKeyValue } from "./create-key-value";
import { getBindingElements } from "./../../../definition/definition";
import type { UI5Aggregation } from "@ui5-language-assistant/semantic-model-types";

export const getCompletionItems = (
context: BindContext,
binding: BindingTypes.StructureValue,
spaces: BindingTypes.WhiteSpaces[],
/* istanbul ignore next */
aggregation = false,
aggregation: UI5Aggregation | undefined = undefined,
/* istanbul ignore next */
bindingElements = getBindingElements(context, aggregation)
): CompletionItem[] => {
Expand Down Expand Up @@ -80,7 +81,7 @@ export function bindingSuggestions({
if (!ui5Property && !ui5Aggregation) {
return completionItems;
}
const propBinding = getBindingElements(context, !!ui5Aggregation, false);
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);
Expand Down Expand Up @@ -123,7 +124,7 @@ export function bindingSuggestions({
context,
binding,
ast.spaces,
!!ui5Aggregation,
ui5Aggregation,
propBinding
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
positionInside,
isPrimitiveValue,
} from "@ui5-language-assistant/binding-parser";

import type { UI5Aggregation } from "@ui5-language-assistant/semantic-model-types";
import { isParts, typesToValue } from "../../../utils";
import {
BindContext,
Expand Down Expand Up @@ -48,8 +48,7 @@ export const createCollectionValue = (
spaces: BindingTypes.WhiteSpaces[],
valueContext: ValueContext,
bindingElements: BindingInfoElement[],
/* istanbul ignore next */
aggregation = false
aggregation?: UI5Aggregation
): CompletionItem[] => {
const { element } = valueContext;
if (!isCollectionValue(element.value)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import {
import { BindContext, BindingInfoElement, ValueContext } from "../../../types";
import { getBindingElements } from "./../../../api";
import { getCompletionItems } from "./binding";
import type { UI5Aggregation } from "@ui5-language-assistant/semantic-model-types";

export const createStructureValue = (
context: BindContext,
spaces: BindingTypes.WhiteSpaces[],
valueContext: ValueContext,
bindingElements: BindingInfoElement[],
/* istanbul ignore next */
aggregation = false
aggregation?: UI5Aggregation
): CompletionItem[] => {
const { element } = valueContext;
/* istanbul ignore next */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { BindContext, BindingInfoElement, ValueContext } from "../../../types";
import { createDefaultValue } from "./create-default-value";
import { createCollectionValue } from "./create-collection-value";
import { createStructureValue } from "./create-structure-value";
import type { UI5Aggregation } from "@ui5-language-assistant/semantic-model-types";

export const createValue = (
context: BindContext,
spaces: BindingTypes.WhiteSpaces[],
valueContext: ValueContext,
bindingElements: BindingInfoElement[],
/* istanbul ignore next */
aggregation = false
aggregation?: UI5Aggregation
): CompletionItem[] => {
const completionItems: CompletionItem[] = [];
const { element } = valueContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ export function validateBinding(
if (!ui5Property && !ui5Aggregation) {
return issues;
}
const bindingElements = getBindingElements(
context,
!!ui5Aggregation,
false
);
const bindingElements = getBindingElements(context, ui5Aggregation, false);
const properties = bindingElements.map((i) => i.name);
const value = attribute.syntax.value;
/* istanbul ignore next */
Expand Down Expand Up @@ -74,7 +70,7 @@ export function validateBinding(
context,
binding,
errors,
!!ui5Aggregation,
ui5Aggregation,
bindingElements
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { checkComma } from "./check-comma";
import { checkBrackets } from "./check-brackets";
import { t } from "../../../i18n";
import { createMissMatchValueIssue } from "./common";
import type { UI5Aggregation } from "@ui5-language-assistant/semantic-model-types";

/**
* Check collection value
Expand All @@ -33,8 +34,7 @@ export const checkCollectionValue = (
lexer: BindingTypes.LexerError[];
},
bindingElements: BindingInfoElement[],
/* istanbul ignore next */
aggregation = false
aggregation?: UI5Aggregation
): BindingIssue[] => {
const issues: BindingIssue[] = [];
const value = element.value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {
import { BindingParserTypes as BindingTypes } from "@ui5-language-assistant/binding-parser";
import { findRange } from "../../../utils";
import { t } from "../../../i18n";
import type { UI5Aggregation } from "@ui5-language-assistant/semantic-model-types";

/**
* Check if key is a one of supported property binding info
*/
export const checkKey = (
element: BindingTypes.StructureElement,
bindingElements: BindingInfoElement[],
/* istanbul ignore next */
aggregation = false
aggregation?: UI5Aggregation
): BindingIssue[] => {
const issues: BindingIssue[] = [];
if (!element.key) {
Expand Down
Loading