diff --git a/extensions/html-language-features/server/src/test/embedded.test.ts b/extensions/html-language-features/server/src/test/embedded.test.ts new file mode 100644 index 0000000000000..f28a12d940654 --- /dev/null +++ b/extensions/html-language-features/server/src/test/embedded.test.ts @@ -0,0 +1,144 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import 'mocha'; +import * as assert from 'assert'; +import * as embeddedSupport from '../modes/embeddedSupport'; +import { forEachEmbeddedCode, SourceMap, VirtualCode } from '@volar/language-core'; +import { htmlLanguagePlugin } from '../modes/languagePlugin'; +import { getLanguageService } from 'vscode-html-languageservice'; + +suite('HTML Embedded Support', () => { + + const htmlLanguageService = getLanguageService(); + + function assertLanguageId(value: string, expectedLanguageId: string | undefined): void { + const offset = value.indexOf('|'); + value = value.substr(0, offset) + value.substr(offset + 1); + + const virtualCode = htmlLanguagePlugin.createVirtualCode('', 'html', { + getText: () => value, + getLength: () => value.length, + getChangeRange: () => undefined, + }); + assert(!!virtualCode); + + let mappedCode: VirtualCode | undefined; + + for (const embeddedCode of [...forEachEmbeddedCode(virtualCode)].reverse()) { + const map = new SourceMap(embeddedCode.mappings); + const mapped = map.getGeneratedOffset(offset); + if (mapped) { + mappedCode = embeddedCode; + break; + } + } + + assert(!!mappedCode); + assert.strictEqual(mappedCode.languageId, expectedLanguageId); + } + + function assertEmbeddedLanguageContent(value: string, languageId: string, expectedContents: string[]): void { + const docRegions = embeddedSupport.getDocumentRegions(htmlLanguageService, value); + const contents = docRegions.getEmbeddedRegions().filter(r => r.languageId === languageId); + assert.strictEqual(contents.length, expectedContents.length); + for (let i = 0; i < contents.length; i++) { + assert.strictEqual(contents[i].content, expectedContents[i]); + } + } + + test('Styles', function (): any { + assertLanguageId('|', 'html'); + assertLanguageId('', 'html'); + assertLanguageId('foo { }', 'html'); + assertLanguageId('', 'css'); + assertLanguageId('', 'css'); + assertLanguageId('', 'css'); + assertLanguageId('', 'css', ['foo { }']); + assertEmbeddedLanguageContent('', 'css', []); + assertEmbeddedLanguageContent('Hello', 'css', ['foo { }', 'foo { }']); + assertEmbeddedLanguageContent('\n \n\n', 'css', ['\n foo { } \n ']); + + assertEmbeddedLanguageContent('
', 'css', ['__{color: red}']); + assertEmbeddedLanguageContent('
', 'css', ['__{color:red}']); + }); + + test('Scripts', function (): any { + assertLanguageId('|', 'html'); + assertLanguageId('', 'html'); + assertLanguageId('var i = 0;', 'html'); + assertLanguageId('', 'javascript'); + assertLanguageId('', 'javascript'); + assertLanguageId('', 'javascript'); + assertLanguageId('', 'javascript'); + assertLanguageId('', 'javascript'); + assertLanguageId('', 'javascript'); + assertLanguageId('', 'javascript'); + assertLanguageId('', 'html'); + assertLanguageId('', 'javascript'); + }); + + test('Scripts in attribute', function (): any { + assertLanguageId('
', 'html'); + assertLanguageId('
', 'html'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'html'); + assertLanguageId('
', 'html'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'html'); + + assertLanguageId('
', 'html'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'javascript'); + assertLanguageId('
', 'html'); + + assertLanguageId('