From d4a33ddb8664e68bf8fb5fe2300f833d829ceddf Mon Sep 17 00:00:00 2001 From: Maruf Rasully Date: Thu, 25 Apr 2024 06:54:26 +0200 Subject: [PATCH] fix: support cc for absolute path in meta path --- .../completion/providers/context-path.ts | 236 +++---- .../completion/providers/meta-path.ts | 382 +++++------ .../services/completion/providers/utils.ts | 139 ++++ packages/fe/src/types/completion.ts | 24 + packages/fe/src/types/index.ts | 12 + packages/fe/src/utils/metadata.ts | 21 +- packages/fe/src/utils/misc.ts | 81 ++- packages/fe/src/utils/path.ts | 22 + .../completion/providers/context-path.test.ts | 222 +++---- .../completion/providers/meta-path.test.ts | 607 +++++++++++++----- .../validators/wrong-filterbar-id.test.ts | 2 +- 11 files changed, 1127 insertions(+), 621 deletions(-) create mode 100644 packages/fe/src/services/completion/providers/utils.ts diff --git a/packages/fe/src/services/completion/providers/context-path.ts b/packages/fe/src/services/completion/providers/context-path.ts index 52da27e17..b71109617 100644 --- a/packages/fe/src/services/completion/providers/context-path.ts +++ b/packages/fe/src/services/completion/providers/context-path.ts @@ -1,37 +1,17 @@ import { getUI5PropertyByXMLAttributeKey } from "@ui5-language-assistant/logic-utils"; -import { - getPathConstraintsForControl, - getNextPossibleContextPathTargets, - getRootElements, - resolvePathTarget, -} from "../../../utils"; +import { getPathConstraintsForControl } from "../../../utils"; import { AnnotationTargetInXMLAttributeValueCompletion, SAP_FE_MACROS, } from "../../../types"; import { UI5AttributeValueCompletionOptions } from "./index"; +import { CompletionSuggestion } from "../../../types/completion"; import { - EntityContainer, - EntitySet, - EntityType, - NavigationProperty, - Singleton, -} from "@sap-ux/vocabularies-types"; -import { getAffectedRange } from "../utils"; -import { AnnotationTargetInXMLAttributeValueTypeName } from "../../../types/completion"; - -type ApplicableMetadataElement = - | EntityContainer - | EntitySet - | EntityType - | Singleton - | NavigationProperty; - -interface CompletionSuggestion { - element: ApplicableMetadataElement; - isLastSegment: boolean; -} + getNavigationSuggestion, + getRootElementSuggestions, + suggestionToTargetCompletion, +} from "./utils"; /** * Suggests values for macros contextPath @@ -46,150 +26,84 @@ export function contextPathSuggestions({ attribute, context.ui5Model ); + if (!ui5Property) { + return []; + } + const metaPathStartsWithAbsolutePath = element.attributes.find( + (i) => i.key === "metaPath" && i.value?.startsWith("/") + ); + // no CC for contextPath if metaPath starts with absolute path + if (metaPathStartsWithAbsolutePath) { + return []; + } if ( - ui5Property?.library === SAP_FE_MACROS && - ui5Property.parent?.name === "Chart" && - ui5Property.name === "contextPath" + !["contextPath"].includes(ui5Property.name) || + ui5Property?.library !== SAP_FE_MACROS || + ui5Property.parent?.name !== "Chart" ) { - const mainServicePath = context.manifestDetails.mainServicePath; - const service = mainServicePath - ? context.services[mainServicePath] - : undefined; - if (!service) { - return []; - } - const metadata = service.convertedMetadata; - const { expectedAnnotations, expectedTypes } = getPathConstraintsForControl( - element.name, - ui5Property - ); - const isPropertyPath = expectedTypes.includes("Property"); - const suggestions: CompletionSuggestion[] = []; - const segments = (attribute.value || "").split("/"); - const precedingSegments = (prefix || "").split("/"); - const completionSegmentIndex = precedingSegments.length - 1; - precedingSegments.pop(); - const completionSegmentOffset = - precedingSegments.join("/").length + (precedingSegments.length ? 1 : 0); - const isAbsolutePath = segments.length > 1 && !segments[0]; - if (!isAbsolutePath && completionSegmentIndex > 0) { - // relative paths are not supported - return []; - } - if (expectedAnnotations.length + expectedTypes.length === 0) { - return []; - } + return []; + } - const isNextSegmentPossible = ( - currentTarget: EntitySet | EntityType | Singleton | EntityContainer, - milestones: string[] = [] - ): boolean => { - return ( - getNextPossibleContextPathTargets( - service.convertedMetadata, - currentTarget, - { - allowedTerms: expectedAnnotations, - allowedTargets: expectedTypes, - isPropertyPath, - }, - [...milestones, currentTarget.fullyQualifiedName] - ).length > 0 - ); - }; + const mainServicePath = context.manifestDetails.mainServicePath; + const service = mainServicePath + ? context.services[mainServicePath] + : undefined; + if (!service) { + return []; + } + const metadata = service.convertedMetadata; + const { expectedAnnotations, expectedTypes } = getPathConstraintsForControl( + element.name, + ui5Property + ); + if (expectedAnnotations.length + expectedTypes.length === 0) { + return []; + } + const isPropertyPath = expectedTypes.includes("Property"); + const suggestions: CompletionSuggestion[] = []; + const segments = (attribute.value || "").split("/"); + const precedingSegments = (prefix || "").split("/"); + const completionSegmentIndex = precedingSegments.length - 1; + precedingSegments.pop(); + const completionSegmentOffset = + precedingSegments.join("/").length + (precedingSegments.length ? 1 : 0); + const isAbsolutePath = segments.length > 1 && !segments[0]; + if (!isAbsolutePath && completionSegmentIndex > 0) { + // relative paths are not supported + return []; + } - if (completionSegmentIndex < 2) { - // completion for root element - const roots = getRootElements( + if (completionSegmentIndex < 2) { + // completion for root element + suggestions.push( + ...getRootElementSuggestions( metadata, expectedAnnotations, expectedTypes, isPropertyPath - ); - suggestions.push( - ...roots.map((root) => ({ - element: root, - isLastSegment: !isNextSegmentPossible(root), - })) - ); - } else { - // completion for navigation property segment - const precedingPath = segments.slice(0, completionSegmentIndex).join("/"); - const { target, isCollection, milestones } = resolvePathTarget( - service.convertedMetadata, - precedingPath - ); - if (!target) { - // target not resolved or path leads to collection - no further segments possible - return []; - } else if (target._type === "Property") { - // no further segments possible after entity property, container is not supported - return []; - } else { - const possibleTargets = getNextPossibleContextPathTargets( - service.convertedMetadata, - target, - { - allowedTerms: expectedAnnotations, - allowedTargets: expectedTypes, - isPropertyPath, - isCollection: isCollection ? false : undefined, - }, - milestones - ); - suggestions.push( - ...possibleTargets.map((t) => { - const entityType = - t._type === "NavigationProperty" ? t.targetType : t.entityType; - return { - element: t, - isLastSegment: !isNextSegmentPossible(entityType, milestones), - }; - }) - ); - } - } - - const sortMap: Record = { - EntityContainer: "Z", - EntityType: "A", - EntitySet: "B", - Singleton: "C", - NavigationProperty: "N", - }; - - const getSuggestionText = (suggestion: CompletionSuggestion): string => { - const isFullyQualifiedName = [ - "EntityContainer", - "EntitySet", - "Singleton", - ].includes(suggestion.element._type); - return `${completionSegmentIndex === 0 ? "/" : ""}${ - isFullyQualifiedName && completionSegmentIndex < 2 - ? suggestion.element.fullyQualifiedName - : suggestion.element.name - }`; + ) + ); + } else { + // completion for navigation property segment + const precedingPath = segments.slice(0, completionSegmentIndex).join("/"); + const options = { + allowedTerms: expectedAnnotations, + allowedTargets: expectedTypes, + isPropertyPath, }; - - return suggestions.map((suggestion) => { - const text = getSuggestionText(suggestion); - return { - type: AnnotationTargetInXMLAttributeValueTypeName, - node: { - kind: suggestion.element._type, - name: text, - text, - affectedRange: getAffectedRange( - attribute.syntax.value, - completionSegmentOffset - ), - commitCharacters: suggestion.isLastSegment ? [] : ["/"], - commitCharactersRequired: true, - sortText: sortMap[suggestion.element._type] + text, - }, - }; - }); + suggestions.push( + ...getNavigationSuggestion( + service.convertedMetadata, + precedingPath, + options + ) + ); } - return []; + return suggestionToTargetCompletion( + attribute, + suggestions, + completionSegmentIndex, + completionSegmentOffset + ); } diff --git a/packages/fe/src/services/completion/providers/meta-path.ts b/packages/fe/src/services/completion/providers/meta-path.ts index 5dd719946..ebc27f36d 100644 --- a/packages/fe/src/services/completion/providers/meta-path.ts +++ b/packages/fe/src/services/completion/providers/meta-path.ts @@ -6,12 +6,12 @@ import { getNextPossiblePathTargets, resolvePathTarget, normalizePath, - getContextPath, + ResolvedPathTargetType, + resolveContextPath, } from "../../../utils"; import type { UI5AttributeValueCompletionOptions } from "./index"; import type { - EntityContainer, EntitySet, Singleton, EntityType, @@ -20,15 +20,22 @@ import type { } from "@sap-ux/vocabularies-types"; import { AnnotationPathInXMLAttributeValueCompletion, - PropertyPathInXMLAttributeValueCompletion, + ContextPathOrigin, SAP_FE_MACROS, } from "../../../types"; import { Range } from "vscode-languageserver-types"; import { getAffectedRange } from "../utils"; import { AnnotationPathInXMLAttributeValueTypeName, + AnnotationTargetInXMLAttributeValueTypeName, + MetaPathSuggestion, PropertyPathInXMLAttributeValueTypeName, } from "../../../types/completion"; +import { + getRootElementSuggestions, + sortMap, + suggestionToTargetCompletion, +} from "./utils"; export interface CompletionItem { name: string; @@ -45,14 +52,8 @@ export function metaPathSuggestions({ attribute, context, prefix, -}: UI5AttributeValueCompletionOptions): ( - | AnnotationPathInXMLAttributeValueCompletion - | PropertyPathInXMLAttributeValueCompletion -)[] { - const result: ( - | AnnotationPathInXMLAttributeValueCompletion - | PropertyPathInXMLAttributeValueCompletion - )[] = []; +}: UI5AttributeValueCompletionOptions): MetaPathSuggestion[] { + const result: MetaPathSuggestion[] = []; const ui5Property = getUI5PropertyByXMLAttributeKey( attribute, context.ui5Model @@ -64,7 +65,6 @@ export function metaPathSuggestions({ return []; } const contextPathAttr = getElementAttributeValue(element, "contextPath"); - let contextPath = getContextPath(contextPathAttr, context); const mainServicePath = context.manifestDetails.mainServicePath; const service = mainServicePath @@ -74,206 +74,220 @@ export function metaPathSuggestions({ return []; } - const entitySet = - context.manifestDetails.customViews[context.customViewId || ""] - ?.entitySet ?? ""; - const metadata = service.convertedMetadata; let baseType: EntityType | undefined; - let base: - | EntityContainer - | EntitySet - | EntityType - | Singleton - | Property - | undefined; - let isNavSegmentsAllowed = true; + let base: ResolvedPathTargetType | undefined; + // navigation is only allowed when contextPath in xml attribute is undefined + const isNavSegmentsAllowed = typeof contextPathAttr === "undefined"; + const segments = (attribute.value || "").split("/"); + const precedingSegments = (prefix || "").split("/"); + const completionSegmentIndex = precedingSegments.length - 1; + precedingSegments.pop(); + const completionSegmentOffset = + precedingSegments.join("/").length + (precedingSegments.length ? 1 : 0); + const isAbsolutePath = segments.length > 1 && !segments[0]; + const { expectedAnnotations, expectedTypes } = getPathConstraintsForControl( + element.name, + ui5Property + ); + if (expectedAnnotations.length + expectedTypes.length === 0) { + return []; + } + const precedingPath = segments.slice(0, completionSegmentIndex).join("/"); - if (typeof contextPath === "string") { - if (!contextPath.startsWith("/")) { - return []; - } - ({ target: base, targetStructuredType: baseType } = resolvePathTarget( + const isPropertiesAllowed = expectedTypes.includes("Property"); + + // no CC if contextPath is defined in xml and CC is request after absolute path e.g `/` + if (contextPathAttr && isAbsolutePath && completionSegmentIndex === 1) { + return []; + } + const resolvedContext = resolveContextPath( + context, + element, + isAbsolutePath, + precedingPath + ); + + if ( + (!contextPathAttr && isAbsolutePath && completionSegmentIndex === 1) || + !resolvedContext + ) { + // for first absolute segment e.g / + const suggestions = getRootElementSuggestions( metadata, - normalizePath(contextPath) - )); - isNavSegmentsAllowed = typeof contextPathAttr === "undefined"; - } else { - contextPath = `/${entitySet}`; + expectedAnnotations, + expectedTypes, + isPropertiesAllowed + ); + const targetSuggestion = suggestionToTargetCompletion( + attribute, + suggestions, + completionSegmentIndex, + completionSegmentOffset + ); + return targetSuggestion; + } + const { contextPath, origin } = resolvedContext; + if (origin === ContextPathOrigin.entitySetInManifest) { base = service.convertedMetadata.entitySets.find( - (e) => e.name === entitySet + (e) => `/${e.name}` === contextPath ); baseType = base?.entityType; } + let isCollection; - if (baseType) { - const { expectedAnnotations, expectedTypes } = getPathConstraintsForControl( - element.name, - ui5Property - ); - const isPropertiesAllowed = expectedTypes.includes("Property"); - const segments = (attribute.value || "").split("/"); - const precedingSegments = (prefix || "").split("/"); - const completionSegmentIndex = precedingSegments.length - 1; - precedingSegments.pop(); - const completionSegmentOffset = - precedingSegments.join("/").length + (precedingSegments.length ? 1 : 0); - const isAbsolutePath = segments.length > 1 && !segments[0]; + // for (navigation) property segment or annotation term + if (!isAbsolutePath && completionSegmentIndex > 0) { + const contextToConsider = [contextPath, precedingPath].join("/"); - if (isAbsolutePath && completionSegmentIndex > 0) { - // absolute paths are not supported in metaPath + if (!isNavSegmentsAllowed) { return []; } - if (!isNavSegmentsAllowed && completionSegmentIndex > 0) { - return []; - } - if (expectedAnnotations.length + expectedTypes.length === 0) { + + ({ + target: base, + targetStructuredType: baseType, + isCollection: isCollection, + } = resolvePathTarget(metadata, contextToConsider, baseType)); + if (!base) { + // target not resolved e.g. for wrong nav segment - no further segments possible return []; } + } - // completion for (navigation) property segment or annotation term - const precedingPath = segments.slice(0, completionSegmentIndex).join("/"); - const { target, isCollection, targetStructuredType } = - completionSegmentIndex === 0 - ? { - target: base, - targetStructuredType: baseType, - isCollection: undefined, - } - : resolvePathTarget(service.convertedMetadata, precedingPath, baseType); - if (!target) { - // target not resolved - no further segments possible - return []; - } else if (isPropertiesAllowed && target._type === "Property") { - // no further segments possible after entity property - return []; - } else { - // Calculate completion range considering that value region includes quotes - const affectedRange: Range | undefined = getAffectedRange( - attribute.syntax.value, - completionSegmentOffset - ); + if (!base) { + ({ + target: base, + targetStructuredType: baseType, + isCollection: isCollection, + } = resolvePathTarget(metadata, normalizePath(contextPath))); + } - let possibleTargets: ( - | EntitySet - | Singleton - | NavigationProperty - | Property - )[] = []; - if (target._type === "Property" || target._type === "EntityContainer") { - return []; - } - // collect existing terms - const annotationList = collectAnnotationsForElement( - expectedAnnotations, - target - ); - if (["EntitySet", "Singleton"].includes(target._type)) { - // for first path segment completion, where current base can be entity set or singleton, - // we collect also terms applied on their structural entity type + if (!base) { + // target not resolved - no further segments possible + return []; + } - // targetStructuredType is never undefined in this context - annotationList.push( - ...collectAnnotationsForElement( - expectedAnnotations, - targetStructuredType - ) - ); - } - result.push( - ...annotationList.map((annotation) => { - const fullPath = `@${ - annotation.qualifier - ? `${annotation.term}#${annotation.qualifier}` - : annotation.term - }`; - return { - type: AnnotationPathInXMLAttributeValueTypeName, - node: { - kind: "Term", - name: fullPath, - text: fullPath, - affectedRange, - }, - } as AnnotationPathInXMLAttributeValueCompletion; - }) - ); + if (base._type === "Property") { + // no further segments possible after entity property + return []; + } + + // Calculate completion range considering that value region includes quotes + const affectedRange: Range | undefined = getAffectedRange( + attribute.syntax.value, + completionSegmentOffset + ); - // collect possible properties or navigation segments - possibleTargets = getNextPossiblePathTargets( - service.convertedMetadata, - target, - false, - { - allowedTerms: expectedAnnotations, - allowedTargets: expectedTypes, - isPropertyPath: isPropertiesAllowed, - isCollection: isCollection ? false : undefined, + let possibleTargets: ( + | EntitySet + | Singleton + | NavigationProperty + | Property + )[] = []; + + // collect existing terms + const annotationList = collectAnnotationsForElement( + expectedAnnotations, + base + ); + if (["EntitySet", "Singleton"].includes(base._type)) { + // for first path segment completion, where current base can be entity set or singleton, + // we collect also terms applied on their structural entity type + + // targetStructuredType is never undefined in this context + annotationList.push( + ...collectAnnotationsForElement(expectedAnnotations, baseType) + ); + } + result.push( + ...annotationList.map((annotation) => { + const fullPath = `@${ + annotation.qualifier + ? `${annotation.term}#${annotation.qualifier}` + : annotation.term + }`; + return { + type: AnnotationPathInXMLAttributeValueTypeName, + node: { + kind: "Term", + name: fullPath, + text: fullPath, + affectedRange, }, - [target.fullyQualifiedName] - ); + } as AnnotationPathInXMLAttributeValueCompletion; + }) + ); - result.push( - ...convertTargetsToCompletionItems( - possibleTargets, - isNavSegmentsAllowed, - isPropertiesAllowed, - affectedRange - ) - ); - } + // collect possible properties or navigation segments + possibleTargets = getNextPossiblePathTargets( + service.convertedMetadata, + base, + false, + { + allowedTerms: expectedAnnotations, + allowedTargets: expectedTypes, + isPropertyPath: isPropertiesAllowed, + isCollection: isCollection ? false : undefined, + }, + [base.fullyQualifiedName] + ); + if (!isNavSegmentsAllowed) { + // filter out Property + possibleTargets = possibleTargets.filter((i) => i._type === "Property"); + } + result.push( + ...convertTargetsToCompletionItems( + possibleTargets, + isPropertiesAllowed, + base._type === "EntityContainer", + affectedRange + ) + ); + + // only if contextPath is not defined in xml and CC is request for initial segment + if (!contextPathAttr && completionSegmentIndex === 0) { + const suggestions = getRootElementSuggestions( + metadata, + expectedAnnotations, + expectedTypes, + isPropertiesAllowed + ); + const targetSuggestion = suggestionToTargetCompletion( + attribute, + suggestions, + completionSegmentIndex, + completionSegmentOffset + ); + result.push(...targetSuggestion); } return result; } function convertTargetsToCompletionItems( targets: (EntitySet | Singleton | Property | NavigationProperty)[], - isNavSegmentsAllowed: boolean, isPropertyPath: boolean, + isEntityContainer: boolean, affectedRange: Range | undefined -): ( - | AnnotationPathInXMLAttributeValueCompletion - | PropertyPathInXMLAttributeValueCompletion -)[] { - const applicableTargets: (NavigationProperty | Property)[] = targets.reduce( - (acc, t) => { - if ( - t._type === "Property" || - (isNavSegmentsAllowed && t._type === "NavigationProperty") - ) { - acc.push(t); - } - return acc; - }, - [] as (NavigationProperty | Property)[] - ); - - return applicableTargets.map((t) => { - if (t._type === "Property") { - return { - type: PropertyPathInXMLAttributeValueTypeName, - node: { - kind: t._type, - name: t.name, - text: t.name, - affectedRange, - sortText: "A" + t.name, - }, - } as PropertyPathInXMLAttributeValueCompletion; - } else { - return { - type: isPropertyPath - ? PropertyPathInXMLAttributeValueTypeName - : AnnotationPathInXMLAttributeValueTypeName, - node: { - kind: t._type, - name: t.name, - text: t.name, - affectedRange, - commitCharacters: ["/"], - sortText: "B" + t.name, - }, - } as AnnotationPathInXMLAttributeValueCompletion; +): MetaPathSuggestion[] { + return targets.map((t) => { + let type = PropertyPathInXMLAttributeValueTypeName; + if (!isPropertyPath) { + type = AnnotationPathInXMLAttributeValueTypeName; + } + if (isEntityContainer) { + type = AnnotationTargetInXMLAttributeValueTypeName; } + return { + type, + node: { + kind: t._type, + name: t.name, + text: t.name, + affectedRange, + commitCharacters: ["/"], + sortText: sortMap[t._type] + t.name, + }, + } as MetaPathSuggestion; }); } diff --git a/packages/fe/src/services/completion/providers/utils.ts b/packages/fe/src/services/completion/providers/utils.ts new file mode 100644 index 000000000..0dcaa2423 --- /dev/null +++ b/packages/fe/src/services/completion/providers/utils.ts @@ -0,0 +1,139 @@ +import { XMLAttribute } from "@xml-tools/ast"; +import { + AnnotationTargetInXMLAttributeValueCompletion, + AnnotationTargetInXMLAttributeValueTypeName, + CompletionSuggestion, +} from "../../../types/completion"; +import { getAffectedRange } from "../utils"; +import { + getNextPossibleContextPathTargets, + getRootElements, + resolvePathTarget, + AllowedTargetType, + isNextSegmentPossible, +} from "../../../utils"; +import { ConvertedMetadata } from "@sap-ux/vocabularies-types"; +import { AnnotationTerm } from "src/types"; + +const getSuggestionText = ( + suggestion: CompletionSuggestion, + completionSegmentIndex: number +): string => { + const isFullyQualifiedName = [ + "EntityContainer", + "EntitySet", + "Singleton", + ].includes(suggestion.element._type); + return `${completionSegmentIndex === 0 ? "/" : ""}${ + isFullyQualifiedName && completionSegmentIndex < 2 + ? suggestion.element.fullyQualifiedName + : suggestion.element.name + }`; +}; + +export const sortMap: Record = { + Property: "A", + NavigationProperty: "B", + Term: "C", + EntityType: "D", + EntitySet: "E", + Singleton: "F", + EntityContainer: "Z", +}; + +export function suggestionToTargetCompletion( + attribute: XMLAttribute, + suggestions: CompletionSuggestion[], + completionIndex: number, + completionOffset: number +): AnnotationTargetInXMLAttributeValueCompletion[] { + return suggestions.map((suggestion) => { + const text = getSuggestionText(suggestion, completionIndex); + return { + type: AnnotationTargetInXMLAttributeValueTypeName, + node: { + kind: suggestion.element._type, + name: text, + text, + affectedRange: getAffectedRange( + attribute.syntax.value, + completionOffset + ), + commitCharacters: suggestion.isLastSegment ? [] : ["/"], + commitCharactersRequired: true, + sortText: sortMap[suggestion.element._type] + text, + }, + }; + }); +} + +export function getRootElementSuggestions( + metadata: ConvertedMetadata, + expectedAnnotations: AnnotationTerm[], + expectedTypes: AllowedTargetType[], + isPropertyPath: boolean +): CompletionSuggestion[] { + const roots = getRootElements( + metadata, + expectedAnnotations, + expectedTypes, + isPropertyPath + ); + return roots.map((root) => ({ + element: root, + isLastSegment: !isNextSegmentPossible(metadata, root, {}), + })); +} + +/** + * Any suggestion after root segment + */ +export function getNavigationSuggestion( + metadata: ConvertedMetadata, + precedingPath: string, + options: { + isPropertyPath?: boolean; + allowedTerms?: AnnotationTerm[]; + allowedTargets?: AllowedTargetType[]; + isCollection?: boolean; + } +): CompletionSuggestion[] { + const { target, isCollection, milestones } = resolvePathTarget( + metadata, + precedingPath + ); + if (!target) { + // target not resolved or path leads to collection - no further segments possible + return []; + } + if (target._type === "Property") { + // no further segments possible after entity property, container is not supported + return []; + } + + options = { ...options, isCollection: isCollection ? false : undefined }; + + const possibleTargets = getNextPossibleContextPathTargets( + metadata, + target, + options, + milestones + ); + const suggestions: CompletionSuggestion[] = []; + suggestions.push( + ...possibleTargets.map((t) => { + const entityType = + t._type === "NavigationProperty" ? t.targetType : t.entityType; + return { + element: t, + isLastSegment: !isNextSegmentPossible( + metadata, + entityType, + options, + milestones + ), + }; + }) + ); + return suggestions; +} diff --git a/packages/fe/src/types/completion.ts b/packages/fe/src/types/completion.ts index 950d158a2..f762d8002 100644 --- a/packages/fe/src/types/completion.ts +++ b/packages/fe/src/types/completion.ts @@ -1,4 +1,11 @@ import { MarkupContent, Range } from "vscode-languageserver-types"; +import { + EntityContainer, + EntitySet, + EntityType, + NavigationProperty, + Singleton, +} from "@sap-ux/vocabularies-types"; export type CompletionItemKind = | "Term" @@ -123,3 +130,20 @@ export interface FilterBarIdInXMLAttributeValueCompletion extends BaseXMLViewAnnotationCompletion { type: typeof FilterBarIdInXMLAttributeValueTypeName; } + +export type ApplicableMetadataElement = + | EntityContainer + | EntitySet + | EntityType + | Singleton + | NavigationProperty; + +export interface CompletionSuggestion { + element: ApplicableMetadataElement; + isLastSegment: boolean; +} + +export type MetaPathSuggestion = + | AnnotationPathInXMLAttributeValueCompletion + | PropertyPathInXMLAttributeValueCompletion + | AnnotationTargetInXMLAttributeValueCompletion; diff --git a/packages/fe/src/types/index.ts b/packages/fe/src/types/index.ts index 446a95acb..580354908 100644 --- a/packages/fe/src/types/index.ts +++ b/packages/fe/src/types/index.ts @@ -15,3 +15,15 @@ export type AnnotationBase = { term: string; qualifier: string; }; + +export enum ContextPathOrigin { + xmlAttributeInContextPath = "xml-attribute-in-context-path", + xmlAttributeInMetaPath = "xml-attribute-in-meta-path", + contextPathInManifest = "context-path-in-manifest", + entitySetInManifest = "entitySet-in-manifest", +} + +export interface ResolveContextPath { + contextPath: string; + origin: ContextPathOrigin; +} diff --git a/packages/fe/src/utils/metadata.ts b/packages/fe/src/utils/metadata.ts index c51844e6e..ada008b3a 100644 --- a/packages/fe/src/utils/metadata.ts +++ b/packages/fe/src/utils/metadata.ts @@ -101,7 +101,7 @@ export function getRootElements( export function collectAnnotationsForElement( allowedTerms: AnnotationTerm[], - element: EntityType | EntitySet | Singleton | undefined, + element: EntityContainer | EntityType | EntitySet | Singleton | undefined, property?: string, navigationProperty?: string ): AnnotationBase[] { @@ -110,20 +110,25 @@ export function collectAnnotationsForElement( if (!element) { return []; } - const type: EntityType = getEntityTypeForElement(element); let target: + | EntityContainer | EntityType | EntitySet | Singleton | Property | NavigationProperty | undefined; - if (property) { - target = type.entityProperties.find((p) => p.name === property); - } else if (navigationProperty) { - target = type.navigationProperties.find( - (p) => p.name === navigationProperty - ); + if (element._type !== "EntityContainer") { + const type: EntityType = getEntityTypeForElement(element); + if (property) { + target = type.entityProperties.find((p) => p.name === property); + } else if (navigationProperty) { + target = type.navigationProperties.find( + (p) => p.name === navigationProperty + ); + } else { + target = element; + } } else { target = element; } diff --git a/packages/fe/src/utils/misc.ts b/packages/fe/src/utils/misc.ts index 63d0c801b..5bb490949 100644 --- a/packages/fe/src/utils/misc.ts +++ b/packages/fe/src/utils/misc.ts @@ -2,7 +2,11 @@ import { UI5Prop } from "@ui5-language-assistant/semantic-model-types"; import { Context } from "@ui5-language-assistant/context"; import { XMLElement } from "@xml-tools/ast"; import i18next, { TFunction } from "i18next"; -import type { AnnotationTerm } from "../types"; +import { + ContextPathOrigin, + type AnnotationTerm, + type ResolveContextPath, +} from "../types"; import { AllowedTargetType } from "./metadata"; import { BuildingBlockPathConstraints, @@ -72,7 +76,9 @@ export const t: TFunction = (key: string, ...args) => { }; /** - * Returns context path for completion and diagnostics services + * Returns context path for completion and diagnostics services. Context path defined in xml attribute wins over + * context path defined in manifest.json file. + * * @param attributeValue - current element contextPath attribute value * @param context - global context object * @returns - context path @@ -82,9 +88,76 @@ export function getContextPath( context: Context ): AttributeValueType { const contextPathInManifest: string | undefined = - context.manifestDetails?.customViews?.[context.customViewId || ""] - ?.contextPath; + getManifestContextPath(context); return typeof attributeValue !== "undefined" ? attributeValue : contextPathInManifest || undefined; } + +/** + * Get context path defined in manifest.json file. + * + * @param context + * @returns + */ +export function getManifestContextPath(context: Context): string | undefined { + return context.manifestDetails?.customViews?.[context.customViewId || ""] + ?.contextPath; +} + +/** + * Resolve context path. Context path can be defined + * - as xml attribute + * - as contextPath in manifest.json file + * - in meta path if path is starting as absolute + * - as entity set of view defined in manifest.json file + * + * @param context context + * @param element xml element + * @param isAbsolutePath path started as absolute + * @param precedingPath proceeding path segment + * @returns context path with its origin + */ +export function resolveContextPath( + context: Context, + element: XMLElement, + isAbsolutePath: boolean, + precedingPath: string +): ResolveContextPath | undefined { + const contextPathAttr = getElementAttributeValue(element, "contextPath"); + if (contextPathAttr) { + return { + contextPath: contextPathAttr, + origin: ContextPathOrigin.xmlAttributeInContextPath, + }; + } + + // if not absolute path and context path is not defined in xml, take it from manifest.json + const contextPath = getManifestContextPath(context); + if (!isAbsolutePath && contextPath) { + return { + contextPath, + origin: ContextPathOrigin.contextPathInManifest, + }; + } + + // context path is preceding path if it started as absolute path + if (isAbsolutePath && precedingPath.length > 0) { + return { + contextPath: precedingPath, + origin: ContextPathOrigin.xmlAttributeInMetaPath, + }; + } + + const entitySet = + context.manifestDetails.customViews[context.customViewId || ""] + ?.entitySet ?? ""; + + if (entitySet) { + // context path is entity set + return { + contextPath: `/${entitySet}`, + origin: ContextPathOrigin.entitySetInManifest, + }; + } +} diff --git a/packages/fe/src/utils/path.ts b/packages/fe/src/utils/path.ts index 38afb4807..70ef8bfbd 100644 --- a/packages/fe/src/utils/path.ts +++ b/packages/fe/src/utils/path.ts @@ -13,6 +13,7 @@ import { getEntityTypeForElement, } from "./metadata"; import { AnnotationTerm } from "./spec"; +import { ApplicableMetadataElement } from "../types/completion"; export type ResolvedPathTargetType = | EntityContainer @@ -272,3 +273,24 @@ export function getNextPossiblePathTargets( return result; } + +export const isNextSegmentPossible = ( + convertedMetadata: ConvertedMetadata, + currentTarget: Exclude, + options: { + isPropertyPath?: boolean; + allowedTerms?: AnnotationTerm[]; + allowedTargets?: AllowedTargetType[]; + isCollection?: boolean; + }, + milestones: string[] = [] +): boolean => { + return ( + getNextPossibleContextPathTargets( + convertedMetadata, + currentTarget, + options, + [...milestones, currentTarget.fullyQualifiedName] + ).length > 0 + ); +}; diff --git a/packages/fe/test/unit/services/completion/providers/context-path.test.ts b/packages/fe/test/unit/services/completion/providers/context-path.test.ts index 599495ab4..690941c6c 100644 --- a/packages/fe/test/unit/services/completion/providers/context-path.test.ts +++ b/packages/fe/test/unit/services/completion/providers/context-path.test.ts @@ -113,54 +113,54 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:/; sort:Z", - "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/HighestTotal; text: /TravelService.EntityContainer/HighestTotal; kind:2; commit:; sort:B", - "label: /TravelService.EntityContainer/Currencies; text: /TravelService.EntityContainer/Currencies; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/TravelStatus; text: /TravelService.EntityContainer/TravelStatus; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/TravelAgency; text: /TravelService.EntityContainer/TravelAgency; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Passenger; text: /TravelService.EntityContainer/Passenger; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Countries; text: /TravelService.EntityContainer/Countries; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/BookingStatus; text: /TravelService.EntityContainer/BookingStatus; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Airline; text: /TravelService.EntityContainer/Airline; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Flight; text: /TravelService.EntityContainer/Flight; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Supplement; text: /TravelService.EntityContainer/Supplement; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/FlightConnection; text: /TravelService.EntityContainer/FlightConnection; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/SupplementType; text: /TravelService.EntityContainer/SupplementType; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Airport; text: /TravelService.EntityContainer/Airport; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Currencies_texts; text: /TravelService.EntityContainer/Currencies_texts; kind:2; commit:; sort:B", - "label: /TravelService.EntityContainer/TravelStatus_texts; text: /TravelService.EntityContainer/TravelStatus_texts; kind:2; commit:; sort:B", - "label: /TravelService.EntityContainer/Countries_texts; text: /TravelService.EntityContainer/Countries_texts; kind:2; commit:; sort:B", - "label: /TravelService.EntityContainer/BookingStatus_texts; text: /TravelService.EntityContainer/BookingStatus_texts; kind:2; commit:; sort:B", - "label: /TravelService.EntityContainer/Supplement_texts; text: /TravelService.EntityContainer/Supplement_texts; kind:2; commit:; sort:B", - "label: /TravelService.EntityContainer/SupplementType_texts; text: /TravelService.EntityContainer/SupplementType_texts; kind:2; commit:; sort:B", - "label: /Travel; text: /Travel; kind:7; commit:/; sort:A", - "label: /HighestTotal; text: /HighestTotal; kind:7; commit:; sort:A", - "label: /Currencies; text: /Currencies; kind:7; commit:/; sort:A", - "label: /TravelStatus; text: /TravelStatus; kind:7; commit:/; sort:A", - "label: /TravelAgency; text: /TravelAgency; kind:7; commit:/; sort:A", - "label: /Passenger; text: /Passenger; kind:7; commit:/; sort:A", - "label: /Booking; text: /Booking; kind:7; commit:/; sort:A", - "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:A", - "label: /Countries; text: /Countries; kind:7; commit:/; sort:A", - "label: /BookingStatus; text: /BookingStatus; kind:7; commit:/; sort:A", - "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:A", - "label: /Airline; text: /Airline; kind:7; commit:/; sort:A", - "label: /Flight; text: /Flight; kind:7; commit:/; sort:A", - "label: /Supplement; text: /Supplement; kind:7; commit:/; sort:A", - "label: /FlightConnection; text: /FlightConnection; kind:7; commit:/; sort:A", - "label: /SupplementType; text: /SupplementType; kind:7; commit:/; sort:A", - "label: /Airport; text: /Airport; kind:7; commit:/; sort:A", - "label: /DraftAdministrativeData; text: /DraftAdministrativeData; kind:7; commit:; sort:A", - "label: /Currencies_texts; text: /Currencies_texts; kind:7; commit:; sort:A", - "label: /TravelStatus_texts; text: /TravelStatus_texts; kind:7; commit:; sort:A", - "label: /Countries_texts; text: /Countries_texts; kind:7; commit:; sort:A", - "label: /BookingStatus_texts; text: /BookingStatus_texts; kind:7; commit:; sort:A", - "label: /Supplement_texts; text: /Supplement_texts; kind:7; commit:; sort:A", - "label: /SupplementType_texts; text: /SupplementType_texts; kind:7; commit:; sort:A", + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/HighestTotal; text: /TravelService.EntityContainer/HighestTotal; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/Currencies; text: /TravelService.EntityContainer/Currencies; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/TravelStatus; text: /TravelService.EntityContainer/TravelStatus; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/TravelAgency; text: /TravelService.EntityContainer/TravelAgency; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Passenger; text: /TravelService.EntityContainer/Passenger; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Countries; text: /TravelService.EntityContainer/Countries; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingStatus; text: /TravelService.EntityContainer/BookingStatus; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Airline; text: /TravelService.EntityContainer/Airline; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Flight; text: /TravelService.EntityContainer/Flight; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Supplement; text: /TravelService.EntityContainer/Supplement; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/FlightConnection; text: /TravelService.EntityContainer/FlightConnection; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/SupplementType; text: /TravelService.EntityContainer/SupplementType; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Airport; text: /TravelService.EntityContainer/Airport; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Currencies_texts; text: /TravelService.EntityContainer/Currencies_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/TravelStatus_texts; text: /TravelService.EntityContainer/TravelStatus_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/Countries_texts; text: /TravelService.EntityContainer/Countries_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/BookingStatus_texts; text: /TravelService.EntityContainer/BookingStatus_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/Supplement_texts; text: /TravelService.EntityContainer/Supplement_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/SupplementType_texts; text: /TravelService.EntityContainer/SupplementType_texts; kind:2; commit:; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /HighestTotal; text: /HighestTotal; kind:7; commit:; sort:D", + "label: /Currencies; text: /Currencies; kind:7; commit:/; sort:D", + "label: /TravelStatus; text: /TravelStatus; kind:7; commit:/; sort:D", + "label: /TravelAgency; text: /TravelAgency; kind:7; commit:/; sort:D", + "label: /Passenger; text: /Passenger; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /Countries; text: /Countries; kind:7; commit:/; sort:D", + "label: /BookingStatus; text: /BookingStatus; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", + "label: /Airline; text: /Airline; kind:7; commit:/; sort:D", + "label: /Flight; text: /Flight; kind:7; commit:/; sort:D", + "label: /Supplement; text: /Supplement; kind:7; commit:/; sort:D", + "label: /FlightConnection; text: /FlightConnection; kind:7; commit:/; sort:D", + "label: /SupplementType; text: /SupplementType; kind:7; commit:/; sort:D", + "label: /Airport; text: /Airport; kind:7; commit:/; sort:D", + "label: /DraftAdministrativeData; text: /DraftAdministrativeData; kind:7; commit:; sort:D", + "label: /Currencies_texts; text: /Currencies_texts; kind:7; commit:; sort:D", + "label: /TravelStatus_texts; text: /TravelStatus_texts; kind:7; commit:; sort:D", + "label: /Countries_texts; text: /Countries_texts; kind:7; commit:; sort:D", + "label: /BookingStatus_texts; text: /BookingStatus_texts; kind:7; commit:; sort:D", + "label: /Supplement_texts; text: /Supplement_texts; kind:7; commit:; sort:D", + "label: /SupplementType_texts; text: /SupplementType_texts; kind:7; commit:; sort:D", ]); }); @@ -227,22 +227,22 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: Travel; text: Travel; kind:2; commit:/; sort:B", - "label: Currencies; text: Currencies; kind:2; commit:/; sort:B", - "label: TravelStatus; text: TravelStatus; kind:2; commit:/; sort:B", - "label: TravelAgency; text: TravelAgency; kind:2; commit:/; sort:B", - "label: Passenger; text: Passenger; kind:2; commit:/; sort:B", - "label: Booking; text: Booking; kind:2; commit:/; sort:B", - "label: BookedFlights; text: BookedFlights; kind:2; commit:/; sort:B", - "label: Countries; text: Countries; kind:2; commit:/; sort:B", - "label: BookingStatus; text: BookingStatus; kind:2; commit:/; sort:B", - "label: BookingSupplement; text: BookingSupplement; kind:2; commit:/; sort:B", - "label: Airline; text: Airline; kind:2; commit:/; sort:B", - "label: Flight; text: Flight; kind:2; commit:/; sort:B", - "label: Supplement; text: Supplement; kind:2; commit:/; sort:B", - "label: FlightConnection; text: FlightConnection; kind:2; commit:/; sort:B", - "label: SupplementType; text: SupplementType; kind:2; commit:/; sort:B", - "label: Airport; text: Airport; kind:2; commit:/; sort:B", + "label: Travel; text: Travel; kind:2; commit:/; sort:E", + "label: Currencies; text: Currencies; kind:2; commit:/; sort:E", + "label: TravelStatus; text: TravelStatus; kind:2; commit:/; sort:E", + "label: TravelAgency; text: TravelAgency; kind:2; commit:/; sort:E", + "label: Passenger; text: Passenger; kind:2; commit:/; sort:E", + "label: Booking; text: Booking; kind:2; commit:/; sort:E", + "label: BookedFlights; text: BookedFlights; kind:2; commit:/; sort:E", + "label: Countries; text: Countries; kind:2; commit:/; sort:E", + "label: BookingStatus; text: BookingStatus; kind:2; commit:/; sort:E", + "label: BookingSupplement; text: BookingSupplement; kind:2; commit:/; sort:E", + "label: Airline; text: Airline; kind:2; commit:/; sort:E", + "label: Flight; text: Flight; kind:2; commit:/; sort:E", + "label: Supplement; text: Supplement; kind:2; commit:/; sort:E", + "label: FlightConnection; text: FlightConnection; kind:2; commit:/; sort:E", + "label: SupplementType; text: SupplementType; kind:2; commit:/; sort:E", + "label: Airport; text: Airport; kind:2; commit:/; sort:E", ]); }); @@ -253,14 +253,14 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:N", - "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:N", - "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:N", - "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:N", - "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:N", - "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:N", - "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:N", - "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:N", + "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:B", + "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:B", + "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:B", + "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:B", + "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:B", + "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:B", + "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:B", + "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:B", ]); }); it("navigation segment completion (case 2)", async function () { @@ -270,14 +270,14 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:N", - "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:N", - "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:N", - "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:N", - "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:N", - "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:N", - "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:N", - "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:N", + "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:B", + "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:B", + "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:B", + "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:B", + "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:B", + "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:B", + "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:B", + "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:B", ]); }); @@ -288,13 +288,13 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:N", - "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:N", - "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:N", - "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:N", - "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:N", - "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:N", - "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:N", + "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:B", + "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:B", + "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:B", + "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:B", + "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:B", + "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:B", + "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:B", ]); }); @@ -305,12 +305,12 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:N", - "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:N", - "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:N", - "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:N", - "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:N", - "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:N", + "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:B", + "label: BookingStatus; text: BookingStatus; kind:18; commit:/; sort:B", + "label: to_Carrier; text: to_Carrier; kind:18; commit:/; sort:B", + "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:B", + "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:B", + "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:; sort:B", ]); }); @@ -341,15 +341,15 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:/; sort:Z", - "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:B", - "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:B", - "label: /Travel; text: /Travel; kind:7; commit:; sort:A", - "label: /Booking; text: /Booking; kind:7; commit:/; sort:A", - "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:A", - "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:A", + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", ]); }); @@ -377,10 +377,10 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: Travel; text: Travel; kind:2; commit:; sort:B", - "label: Booking; text: Booking; kind:2; commit:/; sort:B", - "label: BookedFlights; text: BookedFlights; kind:2; commit:/; sort:B", - "label: BookingSupplement; text: BookingSupplement; kind:2; commit:/; sort:B", + "label: Travel; text: Travel; kind:2; commit:; sort:E", + "label: Booking; text: Booking; kind:2; commit:/; sort:E", + "label: BookedFlights; text: BookedFlights; kind:2; commit:/; sort:E", + "label: BookingSupplement; text: BookingSupplement; kind:2; commit:/; sort:E", ]); }); @@ -391,8 +391,8 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:N", - "label: to_Travel; text: to_Travel; kind:18; commit:; sort:N", + "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:B", + "label: to_Travel; text: to_Travel; kind:18; commit:; sort:B", ]); }); @@ -403,8 +403,8 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:N", - "label: to_Travel; text: to_Travel; kind:18; commit:; sort:N", + "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:B", + "label: to_Travel; text: to_Travel; kind:18; commit:; sort:B", ]); }); @@ -415,7 +415,7 @@ describe("contextPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: to_Travel; text: to_Travel; kind:18; commit:; sort:N", + "label: to_Travel; text: to_Travel; kind:18; commit:; sort:B", ]); }); diff --git a/packages/fe/test/unit/services/completion/providers/meta-path.test.ts b/packages/fe/test/unit/services/completion/providers/meta-path.test.ts index 3d291a912..848b41519 100644 --- a/packages/fe/test/unit/services/completion/providers/meta-path.test.ts +++ b/packages/fe/test/unit/services/completion/providers/meta-path.test.ts @@ -134,13 +134,6 @@ describe("metaPath attribute value completion", () => { expect(result.length).toEqual(0); }); - it("path is absolute - not supported", async function () { - const result = await getCompletionResult( - `` - ); - expect(result.length).toEqual(0); - }); - it("existing navigation segments not allowed", async function () { const result = await getCompletionResult( `` @@ -198,6 +191,15 @@ describe("metaPath attribute value completion", () => { expect(result.length).toEqual(0); }); + it("contextPath is proved and CC is request after absolute path", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([]); + }); + it("service path is not provided in manifest", async function () { const result = await getCompletionResult( ``, @@ -211,34 +213,6 @@ describe("metaPath attribute value completion", () => { ); expect(result.length).toEqual(0); }); - - it("custom views are empty manifest", async function () { - const result = await getCompletionResult( - ``, - (c) => { - const newContext = { - ...c, - manifestDetails: { ...c.manifestDetails, customViews: {} }, - }; - return newContext; - } - ); - expect(result.length).toEqual(0); - }); - - it("custom view id not determined", async function () { - const result = await getCompletionResult( - ``, - (c) => { - const newContext: Context = { - ...c, - customViewId: "", - }; - return newContext; - } - ); - expect(result.length).toEqual(0); - }); }); describe("Annotation path", () => { @@ -254,6 +228,33 @@ describe("metaPath attribute value completion", () => { "label: @com.sap.vocabularies.UI.v1.Chart#sample1; text: @com.sap.vocabularies.UI.v1.Chart#sample1; kind:12; commit:undefined; sort:", "label: to_Booking; text: to_Booking; kind:18; commit:/; sort:B", "label: to_BookedFlights; text: to_BookedFlights; kind:18; commit:/; sort:B", + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", + ]); + }); + it("first segment completion - starting with absolute path", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: TravelService.EntityContainer; text: TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: TravelService.EntityContainer/Travel; text: TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Booking; text: TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/BookedFlights; text: TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/BookingSupplement; text: TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: Travel; text: Travel; kind:7; commit:/; sort:D", + "label: Booking; text: Booking; kind:7; commit:/; sort:D", + "label: BookedFlights; text: BookedFlights; kind:7; commit:/; sort:D", + "label: BookingSupplement; text: BookingSupplement; kind:7; commit:/; sort:D", ]); }); it("second segment completion", async function () { @@ -266,6 +267,17 @@ describe("metaPath attribute value completion", () => { "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:B", ]); }); + it("second segment completion - with absolute path", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: @com.sap.vocabularies.UI.v1.Chart; text: @com.sap.vocabularies.UI.v1.Chart; kind:12; commit:undefined; sort:", + "label: @com.sap.vocabularies.UI.v1.Chart#sample1; text: @com.sap.vocabularies.UI.v1.Chart#sample1; kind:12; commit:undefined; sort:", + ]); + }); it("third segment completion", async function () { const result = await getCompletionResult( `` @@ -277,6 +289,30 @@ describe("metaPath attribute value completion", () => { "label: @com.sap.vocabularies.UI.v1.Chart#sample1; text: @com.sap.vocabularies.UI.v1.Chart#sample1; kind:12; commit:undefined; sort:", ]); }); + it("third segment completion - with absolute path", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: @com.sap.vocabularies.UI.v1.Chart; text: @com.sap.vocabularies.UI.v1.Chart; kind:12; commit:undefined; sort:", + "label: @com.sap.vocabularies.UI.v1.Chart#sample1; text: @com.sap.vocabularies.UI.v1.Chart#sample1; kind:12; commit:undefined; sort:", + ]); + }); + it("after entity container ", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: Travel; text: Travel; kind:2; commit:/; sort:E", + "label: Booking; text: Booking; kind:2; commit:/; sort:E", + "label: BookedFlights; text: BookedFlights; kind:2; commit:/; sort:E", + "label: BookingSupplement; text: BookingSupplement; kind:2; commit:/; sort:E", + ]); + }); }); describe("metaPath completion with contextPath provided in manifest", () => { @@ -290,6 +326,34 @@ describe("metaPath attribute value completion", () => { ).toStrictEqual([ "label: @com.sap.vocabularies.UI.v1.Chart; text: @com.sap.vocabularies.UI.v1.Chart; kind:12; commit:undefined; sort:", "label: @com.sap.vocabularies.UI.v1.Chart#sample1; text: @com.sap.vocabularies.UI.v1.Chart#sample1; kind:12; commit:undefined; sort:", + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", + ]); + }); + it("term segment completion from entity type - starting with absolute path", async function () { + const result = await getCompletionResult( + ``, + prepareContextAdapter("/Travel") + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: TravelService.EntityContainer; text: TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: TravelService.EntityContainer/Travel; text: TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Booking; text: TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/BookedFlights; text: TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/BookingSupplement; text: TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: Travel; text: Travel; kind:7; commit:/; sort:D", + "label: Booking; text: Booking; kind:7; commit:/; sort:D", + "label: BookedFlights; text: BookedFlights; kind:7; commit:/; sort:D", + "label: BookingSupplement; text: BookingSupplement; kind:7; commit:/; sort:D", ]); }); it("segment completion from entity set (nav segments allowed)", async function () { @@ -302,6 +366,27 @@ describe("metaPath attribute value completion", () => { ).toStrictEqual([ "label: to_BookSupplement; text: to_BookSupplement; kind:18; commit:/; sort:B", "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:B", + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", + ]); + }); + it("two segment completion with absolute path", async function () { + const result = await getCompletionResult( + ``, + prepareContextAdapter("/TravelService.EntityContainer/Booking") + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: @com.sap.vocabularies.UI.v1.Chart; text: @com.sap.vocabularies.UI.v1.Chart; kind:12; commit:undefined; sort:", + "label: @com.sap.vocabularies.UI.v1.Chart#sample1; text: @com.sap.vocabularies.UI.v1.Chart#sample1; kind:12; commit:undefined; sort:", ]); }); }); @@ -348,30 +433,135 @@ describe("metaPath attribute value completion", () => { "label: to_Booking; text: to_Booking; kind:18; commit:/; sort:B", "label: to_BookedFlights; text: to_BookedFlights; kind:18; commit:/; sort:B", "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:/; sort:B", - "label: createdAt; text: createdAt; kind:10; commit:undefined; sort:A", - "label: createdBy; text: createdBy; kind:10; commit:undefined; sort:A", - "label: LastChangedAt; text: LastChangedAt; kind:10; commit:undefined; sort:A", - "label: LastChangedBy; text: LastChangedBy; kind:10; commit:undefined; sort:A", - "label: TravelUUID; text: TravelUUID; kind:10; commit:undefined; sort:A", - "label: TravelID; text: TravelID; kind:10; commit:undefined; sort:A", - "label: BeginDate; text: BeginDate; kind:10; commit:undefined; sort:A", - "label: EndDate; text: EndDate; kind:10; commit:undefined; sort:A", - "label: BookingFee; text: BookingFee; kind:10; commit:undefined; sort:A", - "label: TotalPrice; text: TotalPrice; kind:10; commit:undefined; sort:A", - "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:undefined; sort:A", - "label: Description; text: Description; kind:10; commit:undefined; sort:A", - "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:undefined; sort:A", - "label: GoGreen; text: GoGreen; kind:10; commit:undefined; sort:A", - "label: GreenFee; text: GreenFee; kind:10; commit:undefined; sort:A", - "label: TreesPlanted; text: TreesPlanted; kind:10; commit:undefined; sort:A", - "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:undefined; sort:A", - "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:undefined; sort:A", - "label: acceptEnabled; text: acceptEnabled; kind:10; commit:undefined; sort:A", - "label: rejectEnabled; text: rejectEnabled; kind:10; commit:undefined; sort:A", - "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:undefined; sort:A", - "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:undefined; sort:A", + "label: createdAt; text: createdAt; kind:10; commit:/; sort:A", + "label: createdBy; text: createdBy; kind:10; commit:/; sort:A", + "label: LastChangedAt; text: LastChangedAt; kind:10; commit:/; sort:A", + "label: LastChangedBy; text: LastChangedBy; kind:10; commit:/; sort:A", + "label: TravelUUID; text: TravelUUID; kind:10; commit:/; sort:A", + "label: TravelID; text: TravelID; kind:10; commit:/; sort:A", + "label: BeginDate; text: BeginDate; kind:10; commit:/; sort:A", + "label: EndDate; text: EndDate; kind:10; commit:/; sort:A", + "label: BookingFee; text: BookingFee; kind:10; commit:/; sort:A", + "label: TotalPrice; text: TotalPrice; kind:10; commit:/; sort:A", + "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:/; sort:A", + "label: Description; text: Description; kind:10; commit:/; sort:A", + "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:/; sort:A", + "label: GoGreen; text: GoGreen; kind:10; commit:/; sort:A", + "label: GreenFee; text: GreenFee; kind:10; commit:/; sort:A", + "label: TreesPlanted; text: TreesPlanted; kind:10; commit:/; sort:A", + "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:/; sort:A", + "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:/; sort:A", + "label: acceptEnabled; text: acceptEnabled; kind:10; commit:/; sort:A", + "label: rejectEnabled; text: rejectEnabled; kind:10; commit:/; sort:A", + "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:/; sort:A", + "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:/; sort:A", + "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:/; sort:A", + "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:/; sort:A", + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/HighestTotal; text: /TravelService.EntityContainer/HighestTotal; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/Currencies; text: /TravelService.EntityContainer/Currencies; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/TravelStatus; text: /TravelService.EntityContainer/TravelStatus; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/TravelAgency; text: /TravelService.EntityContainer/TravelAgency; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Passenger; text: /TravelService.EntityContainer/Passenger; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Countries; text: /TravelService.EntityContainer/Countries; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingStatus; text: /TravelService.EntityContainer/BookingStatus; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Airline; text: /TravelService.EntityContainer/Airline; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Flight; text: /TravelService.EntityContainer/Flight; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Supplement; text: /TravelService.EntityContainer/Supplement; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/FlightConnection; text: /TravelService.EntityContainer/FlightConnection; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/SupplementType; text: /TravelService.EntityContainer/SupplementType; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Airport; text: /TravelService.EntityContainer/Airport; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Currencies_texts; text: /TravelService.EntityContainer/Currencies_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/TravelStatus_texts; text: /TravelService.EntityContainer/TravelStatus_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/Countries_texts; text: /TravelService.EntityContainer/Countries_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/BookingStatus_texts; text: /TravelService.EntityContainer/BookingStatus_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/Supplement_texts; text: /TravelService.EntityContainer/Supplement_texts; kind:2; commit:; sort:E", + "label: /TravelService.EntityContainer/SupplementType_texts; text: /TravelService.EntityContainer/SupplementType_texts; kind:2; commit:; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /HighestTotal; text: /HighestTotal; kind:7; commit:; sort:D", + "label: /Currencies; text: /Currencies; kind:7; commit:/; sort:D", + "label: /TravelStatus; text: /TravelStatus; kind:7; commit:/; sort:D", + "label: /TravelAgency; text: /TravelAgency; kind:7; commit:/; sort:D", + "label: /Passenger; text: /Passenger; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /Countries; text: /Countries; kind:7; commit:/; sort:D", + "label: /BookingStatus; text: /BookingStatus; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", + "label: /Airline; text: /Airline; kind:7; commit:/; sort:D", + "label: /Flight; text: /Flight; kind:7; commit:/; sort:D", + "label: /Supplement; text: /Supplement; kind:7; commit:/; sort:D", + "label: /FlightConnection; text: /FlightConnection; kind:7; commit:/; sort:D", + "label: /SupplementType; text: /SupplementType; kind:7; commit:/; sort:D", + "label: /Airport; text: /Airport; kind:7; commit:/; sort:D", + "label: /DraftAdministrativeData; text: /DraftAdministrativeData; kind:7; commit:; sort:D", + "label: /Currencies_texts; text: /Currencies_texts; kind:7; commit:; sort:D", + "label: /TravelStatus_texts; text: /TravelStatus_texts; kind:7; commit:; sort:D", + "label: /Countries_texts; text: /Countries_texts; kind:7; commit:; sort:D", + "label: /BookingStatus_texts; text: /BookingStatus_texts; kind:7; commit:; sort:D", + "label: /Supplement_texts; text: /Supplement_texts; kind:7; commit:; sort:D", + "label: /SupplementType_texts; text: /SupplementType_texts; kind:7; commit:; sort:D", + ]); + }); + it("first segment completion - starting with absolute path", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: TravelService.EntityContainer; text: TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: TravelService.EntityContainer/Travel; text: TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/HighestTotal; text: TravelService.EntityContainer/HighestTotal; kind:2; commit:; sort:E", + "label: TravelService.EntityContainer/Currencies; text: TravelService.EntityContainer/Currencies; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/TravelStatus; text: TravelService.EntityContainer/TravelStatus; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/TravelAgency; text: TravelService.EntityContainer/TravelAgency; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Passenger; text: TravelService.EntityContainer/Passenger; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Booking; text: TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/BookedFlights; text: TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Countries; text: TravelService.EntityContainer/Countries; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/BookingStatus; text: TravelService.EntityContainer/BookingStatus; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/BookingSupplement; text: TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Airline; text: TravelService.EntityContainer/Airline; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Flight; text: TravelService.EntityContainer/Flight; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Supplement; text: TravelService.EntityContainer/Supplement; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/FlightConnection; text: TravelService.EntityContainer/FlightConnection; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/SupplementType; text: TravelService.EntityContainer/SupplementType; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Airport; text: TravelService.EntityContainer/Airport; kind:2; commit:/; sort:E", + "label: TravelService.EntityContainer/Currencies_texts; text: TravelService.EntityContainer/Currencies_texts; kind:2; commit:; sort:E", + "label: TravelService.EntityContainer/TravelStatus_texts; text: TravelService.EntityContainer/TravelStatus_texts; kind:2; commit:; sort:E", + "label: TravelService.EntityContainer/Countries_texts; text: TravelService.EntityContainer/Countries_texts; kind:2; commit:; sort:E", + "label: TravelService.EntityContainer/BookingStatus_texts; text: TravelService.EntityContainer/BookingStatus_texts; kind:2; commit:; sort:E", + "label: TravelService.EntityContainer/Supplement_texts; text: TravelService.EntityContainer/Supplement_texts; kind:2; commit:; sort:E", + "label: TravelService.EntityContainer/SupplementType_texts; text: TravelService.EntityContainer/SupplementType_texts; kind:2; commit:; sort:E", + "label: Travel; text: Travel; kind:7; commit:/; sort:D", + "label: HighestTotal; text: HighestTotal; kind:7; commit:; sort:D", + "label: Currencies; text: Currencies; kind:7; commit:/; sort:D", + "label: TravelStatus; text: TravelStatus; kind:7; commit:/; sort:D", + "label: TravelAgency; text: TravelAgency; kind:7; commit:/; sort:D", + "label: Passenger; text: Passenger; kind:7; commit:/; sort:D", + "label: Booking; text: Booking; kind:7; commit:/; sort:D", + "label: BookedFlights; text: BookedFlights; kind:7; commit:/; sort:D", + "label: Countries; text: Countries; kind:7; commit:/; sort:D", + "label: BookingStatus; text: BookingStatus; kind:7; commit:/; sort:D", + "label: BookingSupplement; text: BookingSupplement; kind:7; commit:/; sort:D", + "label: Airline; text: Airline; kind:7; commit:/; sort:D", + "label: Flight; text: Flight; kind:7; commit:/; sort:D", + "label: Supplement; text: Supplement; kind:7; commit:/; sort:D", + "label: FlightConnection; text: FlightConnection; kind:7; commit:/; sort:D", + "label: SupplementType; text: SupplementType; kind:7; commit:/; sort:D", + "label: Airport; text: Airport; kind:7; commit:/; sort:D", + "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:7; commit:; sort:D", + "label: Currencies_texts; text: Currencies_texts; kind:7; commit:; sort:D", + "label: TravelStatus_texts; text: TravelStatus_texts; kind:7; commit:; sort:D", + "label: Countries_texts; text: Countries_texts; kind:7; commit:; sort:D", + "label: BookingStatus_texts; text: BookingStatus_texts; kind:7; commit:; sort:D", + "label: Supplement_texts; text: Supplement_texts; kind:7; commit:; sort:D", + "label: SupplementType_texts; text: SupplementType_texts; kind:7; commit:; sort:D", ]); }); it("second segment completion", async function () { @@ -388,27 +578,67 @@ describe("metaPath attribute value completion", () => { "label: to_Travel; text: to_Travel; kind:18; commit:/; sort:B", "label: to_Flight; text: to_Flight; kind:18; commit:/; sort:B", "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:/; sort:B", - "label: createdAt; text: createdAt; kind:10; commit:undefined; sort:A", - "label: createdBy; text: createdBy; kind:10; commit:undefined; sort:A", - "label: LastChangedAt; text: LastChangedAt; kind:10; commit:undefined; sort:A", - "label: LastChangedBy; text: LastChangedBy; kind:10; commit:undefined; sort:A", - "label: BookingUUID; text: BookingUUID; kind:10; commit:undefined; sort:A", - "label: BookingID; text: BookingID; kind:10; commit:undefined; sort:A", - "label: BookingDate; text: BookingDate; kind:10; commit:undefined; sort:A", - "label: ConnectionID; text: ConnectionID; kind:10; commit:undefined; sort:A", - "label: FlightDate; text: FlightDate; kind:10; commit:undefined; sort:A", - "label: FlightPrice; text: FlightPrice; kind:10; commit:undefined; sort:A", - "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:undefined; sort:A", - "label: BookingStatus_code; text: BookingStatus_code; kind:10; commit:undefined; sort:A", - "label: to_Carrier_AirlineID; text: to_Carrier_AirlineID; kind:10; commit:undefined; sort:A", - "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:undefined; sort:A", - "label: to_Travel_TravelUUID; text: to_Travel_TravelUUID; kind:10; commit:undefined; sort:A", - "label: criticality; text: criticality; kind:10; commit:undefined; sort:A", - "label: BookedFlights; text: BookedFlights; kind:10; commit:undefined; sort:A", - "label: EligibleForPrime; text: EligibleForPrime; kind:10; commit:undefined; sort:A", - "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:undefined; sort:A", + "label: createdAt; text: createdAt; kind:10; commit:/; sort:A", + "label: createdBy; text: createdBy; kind:10; commit:/; sort:A", + "label: LastChangedAt; text: LastChangedAt; kind:10; commit:/; sort:A", + "label: LastChangedBy; text: LastChangedBy; kind:10; commit:/; sort:A", + "label: BookingUUID; text: BookingUUID; kind:10; commit:/; sort:A", + "label: BookingID; text: BookingID; kind:10; commit:/; sort:A", + "label: BookingDate; text: BookingDate; kind:10; commit:/; sort:A", + "label: ConnectionID; text: ConnectionID; kind:10; commit:/; sort:A", + "label: FlightDate; text: FlightDate; kind:10; commit:/; sort:A", + "label: FlightPrice; text: FlightPrice; kind:10; commit:/; sort:A", + "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:/; sort:A", + "label: BookingStatus_code; text: BookingStatus_code; kind:10; commit:/; sort:A", + "label: to_Carrier_AirlineID; text: to_Carrier_AirlineID; kind:10; commit:/; sort:A", + "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:/; sort:A", + "label: to_Travel_TravelUUID; text: to_Travel_TravelUUID; kind:10; commit:/; sort:A", + "label: criticality; text: criticality; kind:10; commit:/; sort:A", + "label: BookedFlights; text: BookedFlights; kind:10; commit:/; sort:A", + "label: EligibleForPrime; text: EligibleForPrime; kind:10; commit:/; sort:A", + "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:/; sort:A", + "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:/; sort:A", + "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:/; sort:A", + ]); + }); + it("second segment completion - with absolute path", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: CurrencyCode; text: CurrencyCode; kind:18; commit:/; sort:B", + "label: TravelStatus; text: TravelStatus; kind:18; commit:/; sort:B", + "label: to_Agency; text: to_Agency; kind:18; commit:/; sort:B", + "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:B", + "label: to_Booking; text: to_Booking; kind:18; commit:/; sort:B", + "label: to_BookedFlights; text: to_BookedFlights; kind:18; commit:/; sort:B", + "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:/; sort:B", + "label: createdAt; text: createdAt; kind:10; commit:/; sort:A", + "label: createdBy; text: createdBy; kind:10; commit:/; sort:A", + "label: LastChangedAt; text: LastChangedAt; kind:10; commit:/; sort:A", + "label: LastChangedBy; text: LastChangedBy; kind:10; commit:/; sort:A", + "label: TravelUUID; text: TravelUUID; kind:10; commit:/; sort:A", + "label: TravelID; text: TravelID; kind:10; commit:/; sort:A", + "label: BeginDate; text: BeginDate; kind:10; commit:/; sort:A", + "label: EndDate; text: EndDate; kind:10; commit:/; sort:A", + "label: BookingFee; text: BookingFee; kind:10; commit:/; sort:A", + "label: TotalPrice; text: TotalPrice; kind:10; commit:/; sort:A", + "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:/; sort:A", + "label: Description; text: Description; kind:10; commit:/; sort:A", + "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:/; sort:A", + "label: GoGreen; text: GoGreen; kind:10; commit:/; sort:A", + "label: GreenFee; text: GreenFee; kind:10; commit:/; sort:A", + "label: TreesPlanted; text: TreesPlanted; kind:10; commit:/; sort:A", + "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:/; sort:A", + "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:/; sort:A", + "label: acceptEnabled; text: acceptEnabled; kind:10; commit:/; sort:A", + "label: rejectEnabled; text: rejectEnabled; kind:10; commit:/; sort:A", + "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:/; sort:A", + "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:/; sort:A", + "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:/; sort:A", + "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:/; sort:A", ]); }); it("third segment completion", async function () { @@ -423,30 +653,49 @@ describe("metaPath attribute value completion", () => { "label: to_Agency; text: to_Agency; kind:18; commit:/; sort:B", "label: to_Customer; text: to_Customer; kind:18; commit:/; sort:B", "label: DraftAdministrativeData; text: DraftAdministrativeData; kind:18; commit:/; sort:B", - "label: createdAt; text: createdAt; kind:10; commit:undefined; sort:A", - "label: createdBy; text: createdBy; kind:10; commit:undefined; sort:A", - "label: LastChangedAt; text: LastChangedAt; kind:10; commit:undefined; sort:A", - "label: LastChangedBy; text: LastChangedBy; kind:10; commit:undefined; sort:A", - "label: TravelUUID; text: TravelUUID; kind:10; commit:undefined; sort:A", - "label: TravelID; text: TravelID; kind:10; commit:undefined; sort:A", - "label: BeginDate; text: BeginDate; kind:10; commit:undefined; sort:A", - "label: EndDate; text: EndDate; kind:10; commit:undefined; sort:A", - "label: BookingFee; text: BookingFee; kind:10; commit:undefined; sort:A", - "label: TotalPrice; text: TotalPrice; kind:10; commit:undefined; sort:A", - "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:undefined; sort:A", - "label: Description; text: Description; kind:10; commit:undefined; sort:A", - "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:undefined; sort:A", - "label: GoGreen; text: GoGreen; kind:10; commit:undefined; sort:A", - "label: GreenFee; text: GreenFee; kind:10; commit:undefined; sort:A", - "label: TreesPlanted; text: TreesPlanted; kind:10; commit:undefined; sort:A", - "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:undefined; sort:A", - "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:undefined; sort:A", - "label: acceptEnabled; text: acceptEnabled; kind:10; commit:undefined; sort:A", - "label: rejectEnabled; text: rejectEnabled; kind:10; commit:undefined; sort:A", - "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:undefined; sort:A", - "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:undefined; sort:A", + "label: createdAt; text: createdAt; kind:10; commit:/; sort:A", + "label: createdBy; text: createdBy; kind:10; commit:/; sort:A", + "label: LastChangedAt; text: LastChangedAt; kind:10; commit:/; sort:A", + "label: LastChangedBy; text: LastChangedBy; kind:10; commit:/; sort:A", + "label: TravelUUID; text: TravelUUID; kind:10; commit:/; sort:A", + "label: TravelID; text: TravelID; kind:10; commit:/; sort:A", + "label: BeginDate; text: BeginDate; kind:10; commit:/; sort:A", + "label: EndDate; text: EndDate; kind:10; commit:/; sort:A", + "label: BookingFee; text: BookingFee; kind:10; commit:/; sort:A", + "label: TotalPrice; text: TotalPrice; kind:10; commit:/; sort:A", + "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:/; sort:A", + "label: Description; text: Description; kind:10; commit:/; sort:A", + "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:/; sort:A", + "label: GoGreen; text: GoGreen; kind:10; commit:/; sort:A", + "label: GreenFee; text: GreenFee; kind:10; commit:/; sort:A", + "label: TreesPlanted; text: TreesPlanted; kind:10; commit:/; sort:A", + "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:/; sort:A", + "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:/; sort:A", + "label: acceptEnabled; text: acceptEnabled; kind:10; commit:/; sort:A", + "label: rejectEnabled; text: rejectEnabled; kind:10; commit:/; sort:A", + "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:/; sort:A", + "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:/; sort:A", + "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:/; sort:A", + "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:/; sort:A", + ]); + }); + it("third segment completion - with absolute path", async function () { + const result = await getCompletionResult( + `` + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: CountryCode; text: CountryCode; kind:18; commit:/; sort:B", + "label: AgencyID; text: AgencyID; kind:10; commit:/; sort:A", + "label: Name; text: Name; kind:10; commit:/; sort:A", + "label: Street; text: Street; kind:10; commit:/; sort:A", + "label: PostalCode; text: PostalCode; kind:10; commit:/; sort:A", + "label: City; text: City; kind:10; commit:/; sort:A", + "label: CountryCode_code; text: CountryCode_code; kind:10; commit:/; sort:A", + "label: PhoneNumber; text: PhoneNumber; kind:10; commit:/; sort:A", + "label: EMailAddress; text: EMailAddress; kind:10; commit:/; sort:A", + "label: WebAddress; text: WebAddress; kind:10; commit:/; sort:A", ]); }); }); @@ -459,30 +708,30 @@ describe("metaPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: createdAt; text: createdAt; kind:10; commit:undefined; sort:A", - "label: createdBy; text: createdBy; kind:10; commit:undefined; sort:A", - "label: LastChangedAt; text: LastChangedAt; kind:10; commit:undefined; sort:A", - "label: LastChangedBy; text: LastChangedBy; kind:10; commit:undefined; sort:A", - "label: TravelUUID; text: TravelUUID; kind:10; commit:undefined; sort:A", - "label: TravelID; text: TravelID; kind:10; commit:undefined; sort:A", - "label: BeginDate; text: BeginDate; kind:10; commit:undefined; sort:A", - "label: EndDate; text: EndDate; kind:10; commit:undefined; sort:A", - "label: BookingFee; text: BookingFee; kind:10; commit:undefined; sort:A", - "label: TotalPrice; text: TotalPrice; kind:10; commit:undefined; sort:A", - "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:undefined; sort:A", - "label: Description; text: Description; kind:10; commit:undefined; sort:A", - "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:undefined; sort:A", - "label: GoGreen; text: GoGreen; kind:10; commit:undefined; sort:A", - "label: GreenFee; text: GreenFee; kind:10; commit:undefined; sort:A", - "label: TreesPlanted; text: TreesPlanted; kind:10; commit:undefined; sort:A", - "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:undefined; sort:A", - "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:undefined; sort:A", - "label: acceptEnabled; text: acceptEnabled; kind:10; commit:undefined; sort:A", - "label: rejectEnabled; text: rejectEnabled; kind:10; commit:undefined; sort:A", - "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:undefined; sort:A", - "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:undefined; sort:A", + "label: createdAt; text: createdAt; kind:10; commit:/; sort:A", + "label: createdBy; text: createdBy; kind:10; commit:/; sort:A", + "label: LastChangedAt; text: LastChangedAt; kind:10; commit:/; sort:A", + "label: LastChangedBy; text: LastChangedBy; kind:10; commit:/; sort:A", + "label: TravelUUID; text: TravelUUID; kind:10; commit:/; sort:A", + "label: TravelID; text: TravelID; kind:10; commit:/; sort:A", + "label: BeginDate; text: BeginDate; kind:10; commit:/; sort:A", + "label: EndDate; text: EndDate; kind:10; commit:/; sort:A", + "label: BookingFee; text: BookingFee; kind:10; commit:/; sort:A", + "label: TotalPrice; text: TotalPrice; kind:10; commit:/; sort:A", + "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:/; sort:A", + "label: Description; text: Description; kind:10; commit:/; sort:A", + "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:/; sort:A", + "label: GoGreen; text: GoGreen; kind:10; commit:/; sort:A", + "label: GreenFee; text: GreenFee; kind:10; commit:/; sort:A", + "label: TreesPlanted; text: TreesPlanted; kind:10; commit:/; sort:A", + "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:/; sort:A", + "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:/; sort:A", + "label: acceptEnabled; text: acceptEnabled; kind:10; commit:/; sort:A", + "label: rejectEnabled; text: rejectEnabled; kind:10; commit:/; sort:A", + "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:/; sort:A", + "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:/; sort:A", + "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:/; sort:A", + "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:/; sort:A", ]); }); it("property segment completion from entity set", async function () { @@ -492,32 +741,86 @@ describe("metaPath attribute value completion", () => { expect( result.map((item) => completionItemToSnapshot(item)) ).toStrictEqual([ - "label: createdAt; text: createdAt; kind:10; commit:undefined; sort:A", - "label: createdBy; text: createdBy; kind:10; commit:undefined; sort:A", - "label: LastChangedAt; text: LastChangedAt; kind:10; commit:undefined; sort:A", - "label: LastChangedBy; text: LastChangedBy; kind:10; commit:undefined; sort:A", - "label: TravelUUID; text: TravelUUID; kind:10; commit:undefined; sort:A", - "label: TravelID; text: TravelID; kind:10; commit:undefined; sort:A", - "label: BeginDate; text: BeginDate; kind:10; commit:undefined; sort:A", - "label: EndDate; text: EndDate; kind:10; commit:undefined; sort:A", - "label: BookingFee; text: BookingFee; kind:10; commit:undefined; sort:A", - "label: TotalPrice; text: TotalPrice; kind:10; commit:undefined; sort:A", - "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:undefined; sort:A", - "label: Description; text: Description; kind:10; commit:undefined; sort:A", - "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:undefined; sort:A", - "label: GoGreen; text: GoGreen; kind:10; commit:undefined; sort:A", - "label: GreenFee; text: GreenFee; kind:10; commit:undefined; sort:A", - "label: TreesPlanted; text: TreesPlanted; kind:10; commit:undefined; sort:A", - "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:undefined; sort:A", - "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:undefined; sort:A", - "label: acceptEnabled; text: acceptEnabled; kind:10; commit:undefined; sort:A", - "label: rejectEnabled; text: rejectEnabled; kind:10; commit:undefined; sort:A", - "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:undefined; sort:A", - "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:undefined; sort:A", - "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:undefined; sort:A", + "label: createdAt; text: createdAt; kind:10; commit:/; sort:A", + "label: createdBy; text: createdBy; kind:10; commit:/; sort:A", + "label: LastChangedAt; text: LastChangedAt; kind:10; commit:/; sort:A", + "label: LastChangedBy; text: LastChangedBy; kind:10; commit:/; sort:A", + "label: TravelUUID; text: TravelUUID; kind:10; commit:/; sort:A", + "label: TravelID; text: TravelID; kind:10; commit:/; sort:A", + "label: BeginDate; text: BeginDate; kind:10; commit:/; sort:A", + "label: EndDate; text: EndDate; kind:10; commit:/; sort:A", + "label: BookingFee; text: BookingFee; kind:10; commit:/; sort:A", + "label: TotalPrice; text: TotalPrice; kind:10; commit:/; sort:A", + "label: CurrencyCode_code; text: CurrencyCode_code; kind:10; commit:/; sort:A", + "label: Description; text: Description; kind:10; commit:/; sort:A", + "label: TravelStatus_code; text: TravelStatus_code; kind:10; commit:/; sort:A", + "label: GoGreen; text: GoGreen; kind:10; commit:/; sort:A", + "label: GreenFee; text: GreenFee; kind:10; commit:/; sort:A", + "label: TreesPlanted; text: TreesPlanted; kind:10; commit:/; sort:A", + "label: to_Agency_AgencyID; text: to_Agency_AgencyID; kind:10; commit:/; sort:A", + "label: to_Customer_CustomerID; text: to_Customer_CustomerID; kind:10; commit:/; sort:A", + "label: acceptEnabled; text: acceptEnabled; kind:10; commit:/; sort:A", + "label: rejectEnabled; text: rejectEnabled; kind:10; commit:/; sort:A", + "label: deductDiscountEnabled; text: deductDiscountEnabled; kind:10; commit:/; sort:A", + "label: IsActiveEntity; text: IsActiveEntity; kind:10; commit:/; sort:A", + "label: HasActiveEntity; text: HasActiveEntity; kind:10; commit:/; sort:A", + "label: HasDraftEntity; text: HasDraftEntity; kind:10; commit:/; sort:A", ]); }); }); }); + + describe("custom views", () => { + it("custom views are empty manifest", async function () { + const result = await getCompletionResult( + ``, + (c) => { + const newContext = { + ...c, + manifestDetails: { ...c.manifestDetails, customViews: {} }, + }; + return newContext; + } + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", + ]); + }); + + it("custom view id not determined", async function () { + const result = await getCompletionResult( + ``, + (c) => { + const newContext: Context = { + ...c, + customViewId: "", + }; + return newContext; + } + ); + expect( + result.map((item) => completionItemToSnapshot(item)) + ).toStrictEqual([ + "label: /TravelService.EntityContainer; text: /TravelService.EntityContainer; kind:19; commit:; sort:Z", + "label: /TravelService.EntityContainer/Travel; text: /TravelService.EntityContainer/Travel; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/Booking; text: /TravelService.EntityContainer/Booking; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookedFlights; text: /TravelService.EntityContainer/BookedFlights; kind:2; commit:/; sort:E", + "label: /TravelService.EntityContainer/BookingSupplement; text: /TravelService.EntityContainer/BookingSupplement; kind:2; commit:/; sort:E", + "label: /Travel; text: /Travel; kind:7; commit:/; sort:D", + "label: /Booking; text: /Booking; kind:7; commit:/; sort:D", + "label: /BookedFlights; text: /BookedFlights; kind:7; commit:/; sort:D", + "label: /BookingSupplement; text: /BookingSupplement; kind:7; commit:/; sort:D", + ]); + }); + }); }); diff --git a/packages/fe/test/unit/services/diagnostics/validators/wrong-filterbar-id.test.ts b/packages/fe/test/unit/services/diagnostics/validators/wrong-filterbar-id.test.ts index 2753a9783..e27c55db5 100644 --- a/packages/fe/test/unit/services/diagnostics/validators/wrong-filterbar-id.test.ts +++ b/packages/fe/test/unit/services/diagnostics/validators/wrong-filterbar-id.test.ts @@ -101,7 +101,7 @@ describe("filterBar attribute value validation", () => { }); }); - it("shows warning when is is not empty and no filterBar macros elements in the document", async function () { + it("shows warning when it is not empty and no filterBar macros elements in the document", async function () { const result = await validateView( `` );