Skip to content

Commit d89071c

Browse files
committed
Basic support <script setup>
1 parent ce241f6 commit d89071c

File tree

16 files changed

+456
-128
lines changed

16 files changed

+456
-128
lines changed

server/src/embeddedSupport/embeddedSupport.ts

+31-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Position, Range } from 'vscode-languageserver-types';
22
import { TextDocument } from 'vscode-languageserver-textdocument';
3-
import { parseVueDocumentRegions, EmbeddedRegion } from './vueDocumentRegionParser';
3+
import { parseVueDocumentRegions, EmbeddedRegion, RegionAttrs } from './vueDocumentRegionParser';
44

55
export type LanguageId =
66
| 'vue'
@@ -19,7 +19,7 @@ export type LanguageId =
1919

2020
export interface LanguageRange extends Range {
2121
languageId: LanguageId;
22-
attributeValue?: boolean;
22+
attrs: RegionAttrs;
2323
}
2424

2525
export interface VueDocumentRegions {
@@ -49,6 +49,7 @@ export interface VueDocumentRegions {
4949
* Get language for determining
5050
*/
5151
getLanguageAtPosition(position: Position): LanguageId;
52+
getLanguageRangeAtPosition(position: Position): LanguageRange | null;
5253

5354
getImportedScripts(): string[];
5455
}
@@ -72,6 +73,7 @@ export function getVueDocumentRegions(document: TextDocument): VueDocumentRegion
7273

7374
getAllLanguageRanges: () => getAllLanguageRanges(document, regions),
7475
getLanguageAtPosition: (position: Position) => getLanguageAtPosition(document, regions, position),
76+
getLanguageRangeAtPosition: (position: Position) => getLanguageRangeAtPosition(document, regions, position),
7577
getImportedScripts: () => importedScripts
7678
};
7779
}
@@ -81,7 +83,8 @@ function getAllLanguageRanges(document: TextDocument, regions: EmbeddedRegion[])
8183
return {
8284
languageId: r.languageId,
8385
start: document.positionAt(r.start),
84-
end: document.positionAt(r.end)
86+
end: document.positionAt(r.end),
87+
attrs: r.attrs
8588
};
8689
});
8790
}
@@ -100,6 +103,29 @@ function getLanguageAtPosition(document: TextDocument, regions: EmbeddedRegion[]
100103
return 'vue';
101104
}
102105

106+
function getLanguageRangeAtPosition(
107+
document: TextDocument,
108+
regions: EmbeddedRegion[],
109+
position: Position
110+
): LanguageRange | null {
111+
const offset = document.offsetAt(position);
112+
for (const region of regions) {
113+
if (region.start <= offset) {
114+
if (offset <= region.end) {
115+
return {
116+
start: document.positionAt(region.start),
117+
end: document.positionAt(region.end),
118+
languageId: region.languageId,
119+
attrs: region.attrs
120+
};
121+
}
122+
} else {
123+
break;
124+
}
125+
}
126+
return null;
127+
}
128+
103129
export function getSingleLanguageDocument(
104130
document: TextDocument,
105131
regions: EmbeddedRegion[],
@@ -159,7 +185,8 @@ export function getLanguageRangesOfType(
159185
result.push({
160186
start: document.positionAt(r.start),
161187
end: document.positionAt(r.end),
162-
languageId: r.languageId
188+
languageId: r.languageId,
189+
attrs: r.attrs
163190
});
164191
}
165192
}

server/src/embeddedSupport/test/embeddedSupport.test.ts

+29
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,32 @@ suite('Embedded <template> ', () => {
205205
);
206206
});
207207
});
208+
209+
suite('Embedded region attrs', () => {
210+
const src = `
211+
<template other other-string="other">
212+
213+
</template>
214+
<script setup lang="ts">
215+
export default {
216+
}
217+
</script>
218+
<style lang="scss" scoped>
219+
</style>
220+
<style lang="less" module>
221+
</style>
222+
`;
223+
224+
test('Basic', () => {
225+
const { regions } = parseVueDocumentRegions(TextDocument.create('test://test.vue', 'vue', 0, src));
226+
227+
assert.equal(regions[0].attrs['other'], true);
228+
assert.equal(regions[0].attrs['other-string'], 'other');
229+
assert.equal(regions[1].attrs.setup, true);
230+
assert.equal(regions[1].attrs.lang, 'ts');
231+
assert.equal(regions[2].attrs['lang'], 'scss');
232+
assert.equal(regions[2].attrs['scoped'], true);
233+
assert.equal(regions[3].attrs['lang'], 'less');
234+
assert.equal(regions[3].attrs['module'], true);
235+
});
236+
});

server/src/embeddedSupport/vueDocumentRegionParser.ts

+39-16
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import { removeQuotes } from '../utils/strings';
44
import { LanguageId } from './embeddedSupport';
55

66
export type RegionType = 'template' | 'script' | 'style' | 'custom';
7+
export type RegionAttrKey = 'setup' | 'module' | 'scoped' | 'lang';
8+
9+
export type RegionAttrs = Partial<Record<RegionAttrKey, boolean | string>> & Partial<Record<string, boolean | string>>;
710

811
export interface EmbeddedRegion {
912
languageId: LanguageId;
1013
start: number;
1114
end: number;
1215
type: RegionType;
16+
attrs: RegionAttrs;
1317
}
1418

1519
const defaultScriptLang = 'javascript';
@@ -22,6 +26,7 @@ export function parseVueDocumentRegions(document: TextDocument) {
2226
let lastTagName = '';
2327
let lastAttributeName = '';
2428
let languageIdFromType: LanguageId | '' = '';
29+
let attrs: Partial<Record<string, boolean | string>> = {};
2530
const importedScripts: string[] = [];
2631
let stakes = 0;
2732

@@ -35,7 +40,8 @@ export function parseVueDocumentRegions(document: TextDocument) {
3540
: defaultCSSLang,
3641
start: scanner.getTokenOffset(),
3742
end: scanner.getTokenEnd(),
38-
type: 'style'
43+
type: 'style',
44+
attrs
3945
});
4046
languageIdFromType = '';
4147
break;
@@ -44,7 +50,8 @@ export function parseVueDocumentRegions(document: TextDocument) {
4450
languageId: languageIdFromType ? languageIdFromType : defaultScriptLang,
4551
start: scanner.getTokenOffset(),
4652
end: scanner.getTokenEnd(),
47-
type: 'script'
53+
type: 'script',
54+
attrs
4855
});
4956
languageIdFromType = '';
5057
break;
@@ -67,23 +74,24 @@ export function parseVueDocumentRegions(document: TextDocument) {
6774
break;
6875
case HtmlTokenType.AttributeName:
6976
lastAttributeName = scanner.getTokenText();
77+
attrs[lastAttributeName] = true;
7078
break;
7179
case HtmlTokenType.AttributeValue:
80+
const attrValue = removeQuotes(scanner.getTokenText());
7281
if (lastAttributeName === 'lang') {
73-
languageIdFromType = getLanguageIdFromLangAttr(scanner.getTokenText());
82+
languageIdFromType = getLanguageIdFromLangAttr(attrValue);
7483
} else {
7584
if (lastAttributeName === 'src' && lastTagName.toLowerCase() === 'script') {
76-
let value = scanner.getTokenText();
77-
if (value[0] === "'" || value[0] === '"') {
78-
value = value.slice(1, value.length - 1);
79-
}
85+
const value = attrValue;
8086
importedScripts.push(value);
8187
}
8288
}
89+
attrs[lastAttributeName] = attrValue;
8390
lastAttributeName = '';
8491
break;
8592
case HtmlTokenType.StartTagSelfClose:
8693
case HtmlTokenType.EndTagClose:
94+
attrs = {};
8795
stakes--;
8896
lastAttributeName = '';
8997
languageIdFromType = '';
@@ -104,6 +112,7 @@ function scanTemplateRegion(scanner: Scanner, text: string): EmbeddedRegion | nu
104112
let token = -1;
105113
let start = 0;
106114
let end: number;
115+
const attrs: Partial<Record<string, boolean | string>> = {};
107116

108117
// Scan until finding matching template EndTag
109118
// Also record immediate next StartTagClose to find start
@@ -138,9 +147,14 @@ function scanTemplateRegion(scanner: Scanner, text: string): EmbeddedRegion | nu
138147
if (start === 0) {
139148
if (token === HtmlTokenType.AttributeName) {
140149
lastAttributeName = scanner.getTokenText();
150+
attrs[lastAttributeName] = true;
141151
} else if (token === HtmlTokenType.AttributeValue) {
152+
const attrValue = removeQuotes(scanner.getTokenText());
142153
if (lastAttributeName === 'lang') {
143-
languageId = getLanguageIdFromLangAttr(scanner.getTokenText());
154+
languageId = getLanguageIdFromLangAttr(attrValue);
155+
}
156+
if (lastAttributeName) {
157+
attrs[lastAttributeName] = attrValue;
144158
}
145159
lastAttributeName = null;
146160
} else if (token === HtmlTokenType.StartTagClose) {
@@ -168,7 +182,8 @@ function scanTemplateRegion(scanner: Scanner, text: string): EmbeddedRegion | nu
168182
languageId,
169183
start,
170184
end: offset,
171-
type: 'template'
185+
type: 'template',
186+
attrs
172187
};
173188
}
174189
}
@@ -185,7 +200,8 @@ function scanTemplateRegion(scanner: Scanner, text: string): EmbeddedRegion | nu
185200
languageId,
186201
start,
187202
end,
188-
type: 'template'
203+
type: 'template',
204+
attrs
189205
};
190206
}
191207

@@ -195,11 +211,12 @@ function scanCustomRegion(tagName: string, scanner: Scanner, text: string): Embe
195211
let token = -1;
196212
let start = 0;
197213
let end: number;
214+
const attrs: Partial<Record<string, boolean | string>> = {};
198215

199216
// Scan until finding matching template EndTag
200217
// Also record immediate next StartTagClose to find start
201218
let unClosedTag = 1;
202-
let lastAttributeName = null;
219+
let lastAttributeName: string | null = null;
203220
while (unClosedTag !== 0) {
204221
token = scanner.scan();
205222

@@ -210,9 +227,14 @@ function scanCustomRegion(tagName: string, scanner: Scanner, text: string): Embe
210227
if (start === 0) {
211228
if (token === HtmlTokenType.AttributeName) {
212229
lastAttributeName = scanner.getTokenText();
230+
attrs[lastAttributeName] = true;
213231
} else if (token === HtmlTokenType.AttributeValue) {
232+
const attrValue = removeQuotes(scanner.getTokenText());
214233
if (lastAttributeName === 'lang') {
215-
languageId = getLanguageIdFromLangAttr(scanner.getTokenText());
234+
languageId = getLanguageIdFromLangAttr(attrValue);
235+
}
236+
if (lastAttributeName) {
237+
attrs[lastAttributeName] = attrValue;
216238
}
217239
lastAttributeName = null;
218240
} else if (token === HtmlTokenType.StartTagClose) {
@@ -240,7 +262,8 @@ function scanCustomRegion(tagName: string, scanner: Scanner, text: string): Embe
240262
languageId,
241263
start,
242264
end: offset,
243-
type: 'custom'
265+
type: 'custom',
266+
attrs
244267
};
245268
}
246269
}
@@ -257,12 +280,12 @@ function scanCustomRegion(tagName: string, scanner: Scanner, text: string): Embe
257280
languageId,
258281
start,
259282
end,
260-
type: 'custom'
283+
type: 'custom',
284+
attrs
261285
};
262286
}
263287

264-
function getLanguageIdFromLangAttr(lang: string): LanguageId {
265-
let languageIdFromType = removeQuotes(lang);
288+
function getLanguageIdFromLangAttr(languageIdFromType: string): LanguageId {
266289
if (languageIdFromType === 'jade') {
267290
languageIdFromType = 'pug';
268291
}

server/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export {
141141
printSourceMap,
142142
stringifySourceMapNodes
143143
} from './services/typescriptService/sourceMap';
144-
export { createTemplateDiagnosticFilter } from './services/typescriptService/templateDiagnosticFilter';
144+
export { createTemplateDiagnosticFilter as createTemplateDiagnosticFilter } from './services/typescriptService/diagnosticFilter';
145145
export {
146146
getTemplateTransformFunctions,
147147
renderHelperName,

0 commit comments

Comments
 (0)