diff --git a/server/src/modes/template/services/htmlCompletion.ts b/server/src/modes/template/services/htmlCompletion.ts index 6f64d8a548..50ab028d27 100644 --- a/server/src/modes/template/services/htmlCompletion.ts +++ b/server/src/modes/template/services/htmlCompletion.ts @@ -6,7 +6,7 @@ import { Range, TextEdit, InsertTextFormat, - CompletionItem + CompletionItem, } from 'vscode-languageserver-types'; import { HTMLDocument } from '../parser/htmlParser'; import { TokenType, createScanner, ScannerState } from '../parser/htmlScanner'; @@ -26,7 +26,7 @@ export function doComplete( const result: CompletionList = { isIncomplete: false, - items: [] + items: [], }; const offset = document.offsetAt(position); @@ -49,7 +49,7 @@ export function doComplete( function collectOpenTagSuggestions(afterOpenBracket: number, tagNameEnd?: number): CompletionList { const range = getReplaceRange(afterOpenBracket, tagNameEnd); - tagProviders.forEach(provider => { + tagProviders.forEach((provider) => { const priority = provider.priority; provider.collectTags((tag, label) => { result.items.push({ @@ -58,7 +58,7 @@ export function doComplete( documentation: label, textEdit: TextEdit.replace(range, tag), sortText: priority + tag, - insertTextFormat: InsertTextFormat.PlainText + insertTextFormat: InsertTextFormat.PlainText, }); }); }); @@ -96,7 +96,7 @@ export function doComplete( kind: CompletionItemKind.Property, filterText: '/' + tag + closeTag, textEdit: TextEdit.replace(range, '/' + tag + closeTag), - insertTextFormat: InsertTextFormat.PlainText + insertTextFormat: InsertTextFormat.PlainText, }; const startIndent = getLineIndent(curr.start); const endIndent = getLineIndent(afterOpenBracket - 1); @@ -114,7 +114,7 @@ export function doComplete( return result; } - tagProviders.forEach(provider => { + tagProviders.forEach((provider) => { provider.collectTags((tag, label) => { result.items.push({ label: '/' + tag, @@ -122,7 +122,7 @@ export function doComplete( documentation: label, filterText: '/' + tag + closeTag, textEdit: TextEdit.replace(range, '/' + tag + closeTag), - insertTextFormat: InsertTextFormat.PlainText + insertTextFormat: InsertTextFormat.PlainText, }); }); }); @@ -143,10 +143,9 @@ export function doComplete( const value = isFollowedBy(text, nameEnd, ScannerState.AfterAttributeName, TokenType.DelimiterAssign) ? '' : '="$1"'; - const tag = currentTag.toLowerCase(); - tagProviders.forEach(provider => { + tagProviders.forEach((provider) => { const priority = provider.priority; - provider.collectAttributes(tag, (attribute, type, documentation) => { + provider.collectAttributes(currentTag, (attribute, type, documentation) => { if ((type === 'event' && filterPrefix !== '@') || (type !== 'event' && filterPrefix === '@')) { return; } @@ -160,21 +159,21 @@ export function doComplete( textEdit: TextEdit.replace(range, codeSnippet), insertTextFormat: InsertTextFormat.Snippet, sortText: priority + attribute, - documentation + documentation, }); }); }); const attributeName = scanner.getTokenText(); if (/\.$/.test(attributeName)) { function addModifier(modifiers: { items: Modifier[]; priority: number }) { - modifiers.items.forEach(modifier => { + modifiers.items.forEach((modifier) => { result.items.push({ label: modifier.label, kind: CompletionItemKind.Method, textEdit: TextEdit.insert(document.positionAt(nameEnd), modifier.label), insertTextFormat: InsertTextFormat.Snippet, sortText: modifiers.priority + modifier.label, - documentation: modifier.documentation + documentation: modifier.documentation, }); }); } @@ -229,17 +228,16 @@ export function doComplete( range = getReplaceRange(valueStart, valueEnd); addQuotes = true; } - const tag = currentTag.toLowerCase(); const attribute = currentAttributeName.toLowerCase(); - tagProviders.forEach(provider => { - provider.collectValues(tag, attribute, value => { + tagProviders.forEach((provider) => { + provider.collectValues(currentTag, attribute, (value) => { const insertText = addQuotes ? '"' + value + '"' : value; result.items.push({ label: value, filterText: insertText, kind: CompletionItemKind.Unit, textEdit: TextEdit.replace(range, insertText), - insertTextFormat: InsertTextFormat.PlainText + insertTextFormat: InsertTextFormat.PlainText, }); }); }); diff --git a/server/src/modes/template/services/htmlHover.ts b/server/src/modes/template/services/htmlHover.ts index a955a8752e..9965397662 100644 --- a/server/src/modes/template/services/htmlHover.ts +++ b/server/src/modes/template/services/htmlHover.ts @@ -41,7 +41,6 @@ export function doHover( } function getAttributeHover(tag: string, attribute: string, range: Range): Hover { - tag = tag.toLowerCase(); let hover: Hover = NULL_HOVER; for (const provider of tagProviders) { provider.collectAttributes(tag, (attr, type, documentation) => { @@ -89,7 +88,7 @@ export function doHover( } const tagRange = { start: document.positionAt(scanner.getTokenOffset()), - end: document.positionAt(scanner.getTokenEnd()) + end: document.positionAt(scanner.getTokenEnd()), }; switch (token) { case TokenType.StartTag: diff --git a/server/src/modes/template/tagProviders/common.ts b/server/src/modes/template/tagProviders/common.ts index 1bf45d1d40..1b0a1051a2 100644 --- a/server/src/modes/template/tagProviders/common.ts +++ b/server/src/modes/template/tagProviders/common.ts @@ -1,4 +1,5 @@ import { MarkupContent } from 'vscode-languageserver-types'; +import { kebabCase } from 'lodash'; interface TagCollector { (tag: string, documentation: string | MarkupContent): void; @@ -50,6 +51,10 @@ export interface IValueSets { [tag: string]: string[]; } +export function getSameTagInSet(tagSet: Record, tag: string): T | undefined { + return tagSet[tag] ?? tagSet[tag.toLowerCase()] ?? tagSet[kebabCase(tag)]; +} + export function collectTagsDefault(collector: TagCollector, tagSet: ITagSet): void { for (const tag in tagSet) { collector(tag, tagSet[tag].label); @@ -63,14 +68,7 @@ export function collectAttributesDefault( globalAttributes: StandaloneAttribute[] ): void { if (tag) { - let tags = tagSet[tag]; - if (!tags) { - for (const t in tagSet) { - if (t.toLowerCase() === tag) { - tags = tagSet[t]; - } - } - } + const tags = getSameTagInSet(tagSet, tag); if (tags) { const attributes = tags.attributes; @@ -110,7 +108,7 @@ export function collectValuesDefault( } } if (tag) { - const tags = tagSet[tag]; + const tags = getSameTagInSet(tagSet, tag); if (tags) { const attributes = tags.attributes; if (attributes) { diff --git a/server/src/modes/template/tagProviders/externalTagProviders.ts b/server/src/modes/template/tagProviders/externalTagProviders.ts index 8dde32c2ce..a04442ff5d 100644 --- a/server/src/modes/template/tagProviders/externalTagProviders.ts +++ b/server/src/modes/template/tagProviders/externalTagProviders.ts @@ -1,8 +1,9 @@ import * as ts from 'typescript'; import * as fs from 'fs'; import * as path from 'path'; +import { kebabCase } from 'lodash'; -import { IHTMLTagProvider, Priority } from './common'; +import { IHTMLTagProvider, Priority, getSameTagInSet } from './common'; import * as elementTags from 'element-helper-json/element-tags.json'; import * as elementAttributes from 'element-helper-json/element-attributes.json'; @@ -77,7 +78,12 @@ export function getDependencyTagProvider(workspacePath: string, depPkgJson: any) export function getExternalTagProvider(id: string, tags: any, attributes: any): IHTMLTagProvider { function findAttributeDetail(tag: string, attr: string) { - return attributes[attr] || attributes[tag + '/' + attr]; + return ( + attributes[attr] || + attributes[`${tag}/${attr}`] || + attributes[`${tag.toLowerCase}/${attr}`] || + attributes[`${kebabCase(tag)}/${attr}`] + ); } return { @@ -89,10 +95,7 @@ export function getExternalTagProvider(id: string, tags: any, attributes: any): } }, collectAttributes(tag, collector) { - if (!tags[tag]) { - return; - } - const attrs = tags[tag].attributes; + const attrs = getSameTagInSet(tags, tag)?.attributes; if (!attrs) { return; } @@ -102,10 +105,7 @@ export function getExternalTagProvider(id: string, tags: any, attributes: any): } }, collectValues(tag, attr, collector) { - if (!tags[tag]) { - return; - } - const attrs = tags[tag].attributes; + const attrs = getSameTagInSet(tags, tag)?.attributes; if (!attrs || attrs.indexOf(attr) < 0) { return; } @@ -116,6 +116,6 @@ export function getExternalTagProvider(id: string, tags: any, attributes: any): for (const option of detail.options) { collector(option); } - } + }, }; } diff --git a/test/interpolation/completion/basic.test.ts b/test/interpolation/completion/basic.test.ts index 6f6474c404..a119f8c9e3 100644 --- a/test/interpolation/completion/basic.test.ts +++ b/test/interpolation/completion/basic.test.ts @@ -22,12 +22,12 @@ describe('Should autocomplete interpolation for