@vue/language-service 1.7.3 → 1.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,508 +10,504 @@ const types_1 = require("../types");
10
10
  const data_1 = require("./data");
11
11
  let builtInData;
12
12
  let modelData;
13
- function useVueTemplateLanguagePlugin(options) {
14
- const plugin = (_context, modules) => {
15
- const templatePlugin = options.templateLanguagePlugin(_context);
16
- const triggerCharacters = [
17
- ...templatePlugin.triggerCharacters ?? [],
18
- '@', // vue event shorthand
19
- ];
20
- if (!_context?.typescript || !modules?.typescript)
21
- return { triggerCharacters };
22
- builtInData ??= (0, data_1.loadTemplateData)(_context.env.locale ?? 'en');
23
- modelData ??= (0, data_1.loadModelModifiersData)(_context.env.locale ?? 'en');
24
- // https://vuejs.org/api/built-in-directives.html#v-on
25
- // https://vuejs.org/api/built-in-directives.html#v-bind
26
- const eventModifiers = {};
27
- const propModifiers = {};
28
- const vOn = builtInData.globalAttributes?.find(x => x.name === 'v-on');
29
- const vBind = builtInData.globalAttributes?.find(x => x.name === 'v-bind');
30
- if (vOn) {
31
- const markdown = (typeof vOn.description === 'string' ? vOn.description : vOn.description?.value) ?? '';
32
- const modifiers = markdown
33
- .split('\n- ')[4]
34
- .split('\n').slice(2, -1);
35
- for (let text of modifiers) {
36
- text = text.substring(' - `.'.length);
37
- const [name, disc] = text.split('` - ');
38
- eventModifiers[name] = disc;
39
- }
13
+ exports.default = (options) => (_context, modules) => {
14
+ const htmlOrPugService = options.baseService(_context, modules);
15
+ const triggerCharacters = [
16
+ ...htmlOrPugService.triggerCharacters ?? [],
17
+ '@', // vue event shorthand
18
+ ];
19
+ if (!_context?.typescript || !modules?.typescript)
20
+ return { triggerCharacters };
21
+ builtInData ??= (0, data_1.loadTemplateData)(_context.env.locale ?? 'en');
22
+ modelData ??= (0, data_1.loadModelModifiersData)(_context.env.locale ?? 'en');
23
+ // https://vuejs.org/api/built-in-directives.html#v-on
24
+ // https://vuejs.org/api/built-in-directives.html#v-bind
25
+ const eventModifiers = {};
26
+ const propModifiers = {};
27
+ const vOn = builtInData.globalAttributes?.find(x => x.name === 'v-on');
28
+ const vBind = builtInData.globalAttributes?.find(x => x.name === 'v-bind');
29
+ if (vOn) {
30
+ const markdown = (typeof vOn.description === 'string' ? vOn.description : vOn.description?.value) ?? '';
31
+ const modifiers = markdown
32
+ .split('\n- ')[4]
33
+ .split('\n').slice(2, -1);
34
+ for (let text of modifiers) {
35
+ text = text.substring(' - `.'.length);
36
+ const [name, disc] = text.split('` - ');
37
+ eventModifiers[name] = disc;
40
38
  }
41
- if (vBind) {
42
- const markdown = (typeof vBind.description === 'string' ? vBind.description : vBind.description?.value) ?? '';
43
- const modifiers = markdown
44
- .split('\n- ')[4]
45
- .split('\n').slice(2, -1);
46
- for (let text of modifiers) {
47
- text = text.substring(' - `.'.length);
48
- const [name, disc] = text.split('` - ');
49
- propModifiers[name] = disc;
50
- }
39
+ }
40
+ if (vBind) {
41
+ const markdown = (typeof vBind.description === 'string' ? vBind.description : vBind.description?.value) ?? '';
42
+ const modifiers = markdown
43
+ .split('\n- ')[4]
44
+ .split('\n').slice(2, -1);
45
+ for (let text of modifiers) {
46
+ text = text.substring(' - `.'.length);
47
+ const [name, disc] = text.split('` - ');
48
+ propModifiers[name] = disc;
51
49
  }
52
- const ts = modules.typescript;
53
- const _ts = _context.typescript;
54
- return {
55
- ...templatePlugin,
56
- triggerCharacters,
57
- async provideCompletionItems(document, position, context, token) {
58
- if (!options.isSupportedDocument(document))
59
- return;
60
- for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
61
- const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
62
- if (virtualFile && virtualFile instanceof vue.VueFile) {
63
- await provideHtmlData(map, virtualFile);
64
- }
50
+ }
51
+ const ts = modules.typescript;
52
+ const _ts = _context.typescript;
53
+ return {
54
+ ...htmlOrPugService,
55
+ triggerCharacters,
56
+ async provideCompletionItems(document, position, context, token) {
57
+ if (!options.isSupportedDocument(document))
58
+ return;
59
+ for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
60
+ const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
61
+ if (virtualFile && virtualFile instanceof vue.VueFile) {
62
+ await provideHtmlData(map, virtualFile);
65
63
  }
66
- const htmlComplete = await templatePlugin.provideCompletionItems?.(document, position, context, token);
67
- if (!htmlComplete)
68
- return;
69
- for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
70
- const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
71
- if (virtualFile && virtualFile instanceof vue.VueFile) {
72
- afterHtmlCompletion(htmlComplete, map, virtualFile);
73
- }
64
+ }
65
+ const htmlComplete = await htmlOrPugService.provideCompletionItems?.(document, position, context, token);
66
+ if (!htmlComplete)
67
+ return;
68
+ for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
69
+ const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
70
+ if (virtualFile && virtualFile instanceof vue.VueFile) {
71
+ afterHtmlCompletion(htmlComplete, map, virtualFile);
74
72
  }
75
- return htmlComplete;
76
- },
77
- async provideInlayHints(document) {
78
- if (!options.isSupportedDocument(document))
79
- return;
80
- const enabled = await _context.env.getConfiguration?.('vue.inlayHints.missingProps') ?? false;
81
- if (!enabled)
82
- return;
83
- const result = [];
84
- for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
85
- const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
86
- const scanner = options.getScanner(document, templatePlugin);
87
- if (virtualFile && virtualFile instanceof vue.VueFile && scanner) {
88
- // visualize missing required props
89
- const casing = await (0, nameCasing_1.getNameCasing)(ts, _context, map.sourceFileDocument.uri);
90
- const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, virtualFile.fileName);
91
- const components = (0, helpers_1.checkComponentNames)(ts, _ts.languageService, virtualFile, nativeTags);
92
- const componentProps = {};
93
- let token;
94
- let current;
95
- while ((token = scanner.scan()) !== html.TokenType.EOS) {
96
- if (token === html.TokenType.StartTag) {
97
- const tagName = scanner.getTokenText();
98
- const component = tagName.indexOf('.') >= 0
99
- ? components.find(component => component === tagName.split('.')[0])
100
- : components.find(component => component === tagName || (0, shared_1.hyphenate)(component) === tagName);
101
- const checkTag = tagName.indexOf('.') >= 0 ? tagName : component;
102
- if (checkTag) {
103
- componentProps[checkTag] ??= (0, helpers_1.checkPropsOfTag)(ts, _ts.languageService, virtualFile, checkTag, nativeTags, true);
104
- current = {
105
- unburnedRequiredProps: [...componentProps[checkTag]],
106
- labelOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
107
- insertOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
108
- };
109
- }
73
+ }
74
+ return htmlComplete;
75
+ },
76
+ async provideInlayHints(document) {
77
+ if (!options.isSupportedDocument(document))
78
+ return;
79
+ const enabled = await _context.env.getConfiguration?.('vue.inlayHints.missingProps') ?? false;
80
+ if (!enabled)
81
+ return;
82
+ const result = [];
83
+ for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
84
+ const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
85
+ const scanner = options.getScanner(htmlOrPugService, document);
86
+ if (virtualFile && virtualFile instanceof vue.VueFile && scanner) {
87
+ // visualize missing required props
88
+ const casing = await (0, nameCasing_1.getNameCasing)(ts, _context, map.sourceFileDocument.uri);
89
+ const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, _ts.languageServiceHost);
90
+ const components = (0, helpers_1.checkComponentNames)(ts, _ts.languageService, virtualFile, nativeTags);
91
+ const componentProps = {};
92
+ let token;
93
+ let current;
94
+ while ((token = scanner.scan()) !== html.TokenType.EOS) {
95
+ if (token === html.TokenType.StartTag) {
96
+ const tagName = scanner.getTokenText();
97
+ const component = tagName.indexOf('.') >= 0
98
+ ? components.find(component => component === tagName.split('.')[0])
99
+ : components.find(component => component === tagName || (0, shared_1.hyphenate)(component) === tagName);
100
+ const checkTag = tagName.indexOf('.') >= 0 ? tagName : component;
101
+ if (checkTag) {
102
+ componentProps[checkTag] ??= (0, helpers_1.checkPropsOfTag)(ts, _ts.languageService, virtualFile, checkTag, nativeTags, true);
103
+ current = {
104
+ unburnedRequiredProps: [...componentProps[checkTag]],
105
+ labelOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
106
+ insertOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
107
+ };
110
108
  }
111
- else if (token === html.TokenType.AttributeName) {
112
- if (current) {
113
- let attrText = scanner.getTokenText();
114
- if (attrText === 'v-bind') {
115
- current.unburnedRequiredProps = [];
109
+ }
110
+ else if (token === html.TokenType.AttributeName) {
111
+ if (current) {
112
+ let attrText = scanner.getTokenText();
113
+ if (attrText === 'v-bind') {
114
+ current.unburnedRequiredProps = [];
115
+ }
116
+ else {
117
+ // remove modifiers
118
+ if (attrText.indexOf('.') >= 0) {
119
+ attrText = attrText.split('.')[0];
116
120
  }
117
- else {
118
- // remove modifiers
119
- if (attrText.indexOf('.') >= 0) {
120
- attrText = attrText.split('.')[0];
121
- }
122
- // normalize
123
- if (attrText.startsWith('v-bind:')) {
124
- attrText = attrText.substring('v-bind:'.length);
125
- }
126
- else if (attrText.startsWith(':')) {
127
- attrText = attrText.substring(':'.length);
128
- }
129
- else if (attrText.startsWith('v-model:')) {
130
- attrText = attrText.substring('v-model:'.length);
131
- }
132
- else if (attrText === 'v-model') {
133
- attrText = options.vueCompilerOptions.target >= 3 ? 'modelValue' : 'value'; // TODO: support for experimentalModelPropName?
134
- }
135
- else if (attrText.startsWith('@')) {
136
- attrText = 'on-' + (0, shared_1.hyphenate)(attrText.substring('@'.length));
137
- }
138
- current.unburnedRequiredProps = current.unburnedRequiredProps.filter(propName => {
139
- return attrText !== propName
140
- && attrText !== (0, shared_1.hyphenate)(propName);
141
- });
121
+ // normalize
122
+ if (attrText.startsWith('v-bind:')) {
123
+ attrText = attrText.substring('v-bind:'.length);
142
124
  }
143
- }
144
- }
145
- else if (token === html.TokenType.StartTagSelfClose || token === html.TokenType.StartTagClose) {
146
- if (current) {
147
- for (const requiredProp of current.unburnedRequiredProps) {
148
- result.push({
149
- label: `${requiredProp}!`,
150
- paddingLeft: true,
151
- position: document.positionAt(current.labelOffset),
152
- kind: vscode.InlayHintKind.Parameter,
153
- textEdits: [{
154
- range: {
155
- start: document.positionAt(current.insertOffset),
156
- end: document.positionAt(current.insertOffset),
157
- },
158
- newText: ` :${casing.attr === types_1.AttrNameCasing.Kebab ? (0, shared_1.hyphenate)(requiredProp) : requiredProp}=`,
159
- }],
160
- });
125
+ else if (attrText.startsWith(':')) {
126
+ attrText = attrText.substring(':'.length);
127
+ }
128
+ else if (attrText.startsWith('v-model:')) {
129
+ attrText = attrText.substring('v-model:'.length);
130
+ }
131
+ else if (attrText === 'v-model') {
132
+ attrText = options.vueCompilerOptions.target >= 3 ? 'modelValue' : 'value'; // TODO: support for experimentalModelPropName?
133
+ }
134
+ else if (attrText.startsWith('@')) {
135
+ attrText = 'on-' + (0, shared_1.hyphenate)(attrText.substring('@'.length));
161
136
  }
162
- current = undefined;
137
+ current.unburnedRequiredProps = current.unburnedRequiredProps.filter(propName => {
138
+ return attrText !== propName
139
+ && attrText !== (0, shared_1.hyphenate)(propName);
140
+ });
163
141
  }
164
142
  }
165
- if (token === html.TokenType.AttributeName || token === html.TokenType.AttributeValue) {
166
- if (current) {
167
- current.insertOffset = scanner.getTokenOffset() + scanner.getTokenLength();
143
+ }
144
+ else if (token === html.TokenType.StartTagSelfClose || token === html.TokenType.StartTagClose) {
145
+ if (current) {
146
+ for (const requiredProp of current.unburnedRequiredProps) {
147
+ result.push({
148
+ label: `${requiredProp}!`,
149
+ paddingLeft: true,
150
+ position: document.positionAt(current.labelOffset),
151
+ kind: vscode.InlayHintKind.Parameter,
152
+ textEdits: [{
153
+ range: {
154
+ start: document.positionAt(current.insertOffset),
155
+ end: document.positionAt(current.insertOffset),
156
+ },
157
+ newText: ` :${casing.attr === types_1.AttrNameCasing.Kebab ? (0, shared_1.hyphenate)(requiredProp) : requiredProp}=`,
158
+ }],
159
+ });
168
160
  }
161
+ current = undefined;
162
+ }
163
+ }
164
+ if (token === html.TokenType.AttributeName || token === html.TokenType.AttributeValue) {
165
+ if (current) {
166
+ current.insertOffset = scanner.getTokenOffset() + scanner.getTokenLength();
169
167
  }
170
168
  }
171
169
  }
172
170
  }
173
- return result;
174
- },
175
- provideHover(document, position, token) {
176
- if (!options.isSupportedDocument(document))
177
- return;
178
- if (_context.documents.isVirtualFileUri(document.uri))
179
- templatePlugin.updateCustomData([]);
180
- return templatePlugin.provideHover?.(document, position, token);
181
- },
182
- async provideDiagnostics(document, token) {
183
- if (!options.isSupportedDocument(document))
184
- return;
185
- const originalResult = await templatePlugin.provideDiagnostics?.(document, token);
186
- for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
187
- const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
188
- if (!virtualFile || !(virtualFile instanceof vue.VueFile))
189
- continue;
190
- const templateErrors = [];
191
- const sfcVueTemplateCompiled = virtualFile.compiledSFCTemplate;
192
- if (sfcVueTemplateCompiled) {
193
- for (const error of sfcVueTemplateCompiled.errors) {
194
- onCompilerError(error, vscode.DiagnosticSeverity.Error);
195
- }
196
- for (const warning of sfcVueTemplateCompiled.warnings) {
197
- onCompilerError(warning, vscode.DiagnosticSeverity.Warning);
198
- }
199
- function onCompilerError(error, severity) {
200
- const templateHtmlRange = {
201
- start: error.loc?.start.offset ?? 0,
202
- end: error.loc?.end.offset ?? 0,
203
- };
204
- let errorMessage = error.message;
205
- templateErrors.push({
206
- range: {
207
- start: document.positionAt(templateHtmlRange.start),
208
- end: document.positionAt(templateHtmlRange.end),
209
- },
210
- severity,
211
- code: error.code,
212
- source: 'vue',
213
- message: errorMessage,
214
- });
215
- }
171
+ }
172
+ return result;
173
+ },
174
+ provideHover(document, position, token) {
175
+ if (!options.isSupportedDocument(document))
176
+ return;
177
+ if (_context.documents.isVirtualFileUri(document.uri))
178
+ options.updateCustomData(htmlOrPugService, []);
179
+ return htmlOrPugService.provideHover?.(document, position, token);
180
+ },
181
+ async provideDiagnostics(document, token) {
182
+ if (!options.isSupportedDocument(document))
183
+ return;
184
+ const originalResult = await htmlOrPugService.provideDiagnostics?.(document, token);
185
+ for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
186
+ const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
187
+ if (!virtualFile || !(virtualFile instanceof vue.VueFile))
188
+ continue;
189
+ const templateErrors = [];
190
+ const sfcVueTemplateCompiled = virtualFile.compiledSFCTemplate;
191
+ if (sfcVueTemplateCompiled) {
192
+ for (const error of sfcVueTemplateCompiled.errors) {
193
+ onCompilerError(error, vscode.DiagnosticSeverity.Error);
194
+ }
195
+ for (const warning of sfcVueTemplateCompiled.warnings) {
196
+ onCompilerError(warning, vscode.DiagnosticSeverity.Warning);
197
+ }
198
+ function onCompilerError(error, severity) {
199
+ const templateHtmlRange = {
200
+ start: error.loc?.start.offset ?? 0,
201
+ end: error.loc?.end.offset ?? 0,
202
+ };
203
+ let errorMessage = error.message;
204
+ templateErrors.push({
205
+ range: {
206
+ start: document.positionAt(templateHtmlRange.start),
207
+ end: document.positionAt(templateHtmlRange.end),
208
+ },
209
+ severity,
210
+ code: error.code,
211
+ source: 'vue',
212
+ message: errorMessage,
213
+ });
216
214
  }
217
- return [
218
- ...originalResult ?? [],
219
- ...templateErrors,
220
- ];
221
215
  }
222
- },
223
- async provideDocumentSemanticTokens(document, range, legend, token) {
224
- if (!options.isSupportedDocument(document))
225
- return;
226
- const result = await templatePlugin.provideDocumentSemanticTokens?.(document, range, legend, token) ?? [];
227
- const scanner = options.getScanner(document, templatePlugin);
228
- if (!scanner)
229
- return;
230
- for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
231
- const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
232
- if (!virtualFile || !(virtualFile instanceof vue.VueFile))
233
- continue;
234
- const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, virtualFile.fileName);
235
- const templateScriptData = (0, helpers_1.checkComponentNames)(ts, _ts.languageService, virtualFile, nativeTags);
236
- const components = new Set([
237
- ...templateScriptData,
238
- ...templateScriptData.map(shared_1.hyphenate),
239
- ]);
240
- const offsetRange = {
241
- start: document.offsetAt(range.start),
242
- end: document.offsetAt(range.end),
243
- };
244
- let token = scanner.scan();
245
- while (token !== html.TokenType.EOS) {
246
- const tokenOffset = scanner.getTokenOffset();
247
- // TODO: fix source map perf and break in while condition
248
- if (tokenOffset > offsetRange.end)
249
- break;
250
- if (tokenOffset >= offsetRange.start && (token === html.TokenType.StartTag || token === html.TokenType.EndTag)) {
251
- const tokenText = scanner.getTokenText();
252
- if (components.has(tokenText) || tokenText.indexOf('.') >= 0) {
253
- const tokenLength = scanner.getTokenLength();
254
- const tokenPosition = document.positionAt(tokenOffset);
255
- if (components.has(tokenText)) {
256
- let tokenType = legend.tokenTypes.indexOf('component');
257
- if (tokenType === -1) {
258
- tokenType = legend.tokenTypes.indexOf('class');
259
- }
260
- result.push([tokenPosition.line, tokenPosition.character, tokenLength, tokenType, 0]);
216
+ return [
217
+ ...originalResult ?? [],
218
+ ...templateErrors,
219
+ ];
220
+ }
221
+ },
222
+ async provideDocumentSemanticTokens(document, range, legend, token) {
223
+ if (!options.isSupportedDocument(document))
224
+ return;
225
+ const result = await htmlOrPugService.provideDocumentSemanticTokens?.(document, range, legend, token) ?? [];
226
+ const scanner = options.getScanner(htmlOrPugService, document);
227
+ if (!scanner)
228
+ return;
229
+ for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
230
+ const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
231
+ if (!virtualFile || !(virtualFile instanceof vue.VueFile))
232
+ continue;
233
+ const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, _ts.languageServiceHost);
234
+ const templateScriptData = (0, helpers_1.checkComponentNames)(ts, _ts.languageService, virtualFile, nativeTags);
235
+ const components = new Set([
236
+ ...templateScriptData,
237
+ ...templateScriptData.map(shared_1.hyphenate),
238
+ ]);
239
+ const offsetRange = {
240
+ start: document.offsetAt(range.start),
241
+ end: document.offsetAt(range.end),
242
+ };
243
+ let token = scanner.scan();
244
+ while (token !== html.TokenType.EOS) {
245
+ const tokenOffset = scanner.getTokenOffset();
246
+ // TODO: fix source map perf and break in while condition
247
+ if (tokenOffset > offsetRange.end)
248
+ break;
249
+ if (tokenOffset >= offsetRange.start && (token === html.TokenType.StartTag || token === html.TokenType.EndTag)) {
250
+ const tokenText = scanner.getTokenText();
251
+ if (components.has(tokenText) || tokenText.indexOf('.') >= 0) {
252
+ const tokenLength = scanner.getTokenLength();
253
+ const tokenPosition = document.positionAt(tokenOffset);
254
+ if (components.has(tokenText)) {
255
+ let tokenType = legend.tokenTypes.indexOf('component');
256
+ if (tokenType === -1) {
257
+ tokenType = legend.tokenTypes.indexOf('class');
261
258
  }
259
+ result.push([tokenPosition.line, tokenPosition.character, tokenLength, tokenType, 0]);
262
260
  }
263
261
  }
264
- token = scanner.scan();
265
262
  }
263
+ token = scanner.scan();
266
264
  }
267
- return result;
268
- },
269
- };
270
- async function provideHtmlData(map, vueSourceFile) {
271
- const casing = await (0, nameCasing_1.getNameCasing)(ts, _context, map.sourceFileDocument.uri);
272
- if (builtInData.tags) {
273
- for (const tag of builtInData.tags) {
274
- if (tag.name === 'slot')
275
- continue;
276
- if (tag.name === 'component')
277
- continue;
278
- if (tag.name === 'template')
279
- continue;
280
- if (casing.tag === types_1.TagNameCasing.Kebab) {
281
- tag.name = (0, shared_1.hyphenate)(tag.name);
282
- }
283
- else {
284
- tag.name = (0, shared_1.camelize)((0, shared_1.capitalize)(tag.name));
285
- }
265
+ }
266
+ return result;
267
+ },
268
+ };
269
+ async function provideHtmlData(map, vueSourceFile) {
270
+ const casing = await (0, nameCasing_1.getNameCasing)(ts, _context, map.sourceFileDocument.uri);
271
+ if (builtInData.tags) {
272
+ for (const tag of builtInData.tags) {
273
+ if (tag.name === 'slot')
274
+ continue;
275
+ if (tag.name === 'component')
276
+ continue;
277
+ if (tag.name === 'template')
278
+ continue;
279
+ if (casing.tag === types_1.TagNameCasing.Kebab) {
280
+ tag.name = (0, shared_1.hyphenate)(tag.name);
281
+ }
282
+ else {
283
+ tag.name = (0, shared_1.camelize)((0, shared_1.capitalize)(tag.name));
286
284
  }
287
285
  }
288
- const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, vueSourceFile.fileName);
289
- templatePlugin.updateCustomData([
290
- html.newHTMLDataProvider('vue-template-built-in', builtInData),
291
- {
292
- getId: () => 'vue-template',
293
- isApplicable: () => true,
294
- provideTags: () => {
295
- const components = (0, helpers_1.checkComponentNames)(ts, _ts.languageService, vueSourceFile, nativeTags)
296
- .filter(name => name !== 'Transition'
297
- && name !== 'TransitionGroup'
298
- && name !== 'KeepAlive'
299
- && name !== 'Suspense'
300
- && name !== 'Teleport');
301
- const scriptSetupRanges = vueSourceFile.sfc.scriptSetupAst ? vue.parseScriptSetupRanges(ts, vueSourceFile.sfc.scriptSetupAst, options.vueCompilerOptions) : undefined;
302
- const names = new Set();
303
- const tags = [];
304
- for (const tag of components) {
305
- if (casing.tag === types_1.TagNameCasing.Kebab) {
306
- names.add((0, shared_1.hyphenate)(tag));
307
- }
308
- else if (casing.tag === types_1.TagNameCasing.Pascal) {
309
- names.add(tag);
310
- }
286
+ }
287
+ const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, _ts.languageServiceHost);
288
+ options.updateCustomData(htmlOrPugService, [
289
+ html.newHTMLDataProvider('vue-template-built-in', builtInData),
290
+ {
291
+ getId: () => 'vue-template',
292
+ isApplicable: () => true,
293
+ provideTags: () => {
294
+ const components = (0, helpers_1.checkComponentNames)(ts, _ts.languageService, vueSourceFile, nativeTags)
295
+ .filter(name => name !== 'Transition'
296
+ && name !== 'TransitionGroup'
297
+ && name !== 'KeepAlive'
298
+ && name !== 'Suspense'
299
+ && name !== 'Teleport');
300
+ const scriptSetupRanges = vueSourceFile.sfc.scriptSetupAst ? vue.parseScriptSetupRanges(ts, vueSourceFile.sfc.scriptSetupAst, options.vueCompilerOptions) : undefined;
301
+ const names = new Set();
302
+ const tags = [];
303
+ for (const tag of components) {
304
+ if (casing.tag === types_1.TagNameCasing.Kebab) {
305
+ names.add((0, shared_1.hyphenate)(tag));
311
306
  }
312
- for (const binding of scriptSetupRanges?.bindings ?? []) {
313
- const name = vueSourceFile.sfc.scriptSetup.content.substring(binding.start, binding.end);
314
- if (casing.tag === types_1.TagNameCasing.Kebab) {
315
- names.add((0, shared_1.hyphenate)(name));
316
- }
317
- else if (casing.tag === types_1.TagNameCasing.Pascal) {
318
- names.add(name);
319
- }
307
+ else if (casing.tag === types_1.TagNameCasing.Pascal) {
308
+ names.add(tag);
320
309
  }
321
- for (const name of names) {
322
- tags.push({
323
- name: name,
324
- attributes: [],
325
- });
310
+ }
311
+ for (const binding of scriptSetupRanges?.bindings ?? []) {
312
+ const name = vueSourceFile.sfc.scriptSetup.content.substring(binding.start, binding.end);
313
+ if (casing.tag === types_1.TagNameCasing.Kebab) {
314
+ names.add((0, shared_1.hyphenate)(name));
326
315
  }
327
- return tags;
328
- },
329
- provideAttributes: (tag) => {
330
- const attrs = (0, helpers_1.getElementAttrs)(ts, _ts.languageService, vueSourceFile.fileName, tag);
331
- const props = new Set((0, helpers_1.checkPropsOfTag)(ts, _ts.languageService, vueSourceFile, tag, nativeTags));
332
- const events = (0, helpers_1.checkEventsOfTag)(ts, _ts.languageService, vueSourceFile, tag, nativeTags);
333
- const attributes = [];
334
- for (const prop of [...props, ...attrs]) {
335
- const isGlobal = !props.has(prop);
336
- const name = casing.attr === types_1.AttrNameCasing.Camel ? prop : (0, shared_1.hyphenate)(prop);
337
- if ((0, shared_1.hyphenate)(name).startsWith('on-')) {
338
- const propNameBase = name.startsWith('on-')
339
- ? name.slice('on-'.length)
340
- : (name['on'.length].toLowerCase() + name.slice('onX'.length));
341
- const propKey = createInternalItemId('componentEvent', [isGlobal ? '*' : tag, propNameBase]);
342
- attributes.push({
343
- name: 'v-on:' + propNameBase,
344
- description: propKey,
345
- }, {
346
- name: '@' + propNameBase,
347
- description: propKey,
348
- });
349
- }
350
- {
351
- const propName = name;
352
- const propKey = createInternalItemId('componentProp', [isGlobal ? '*' : tag, propName]);
353
- attributes.push({
354
- name: propName,
355
- description: propKey,
356
- }, {
357
- name: ':' + propName,
358
- description: propKey,
359
- }, {
360
- name: 'v-bind:' + propName,
361
- description: propKey,
362
- });
363
- }
316
+ else if (casing.tag === types_1.TagNameCasing.Pascal) {
317
+ names.add(name);
364
318
  }
365
- for (const event of events) {
366
- const name = casing.attr === types_1.AttrNameCasing.Camel ? event : (0, shared_1.hyphenate)(event);
367
- const propKey = createInternalItemId('componentEvent', [tag, name]);
319
+ }
320
+ for (const name of names) {
321
+ tags.push({
322
+ name: name,
323
+ attributes: [],
324
+ });
325
+ }
326
+ return tags;
327
+ },
328
+ provideAttributes: (tag) => {
329
+ const attrs = (0, helpers_1.getElementAttrs)(ts, _ts.languageService, _ts.languageServiceHost, tag);
330
+ const props = new Set((0, helpers_1.checkPropsOfTag)(ts, _ts.languageService, vueSourceFile, tag, nativeTags));
331
+ const events = (0, helpers_1.checkEventsOfTag)(ts, _ts.languageService, vueSourceFile, tag, nativeTags);
332
+ const attributes = [];
333
+ for (const prop of [...props, ...attrs]) {
334
+ const isGlobal = !props.has(prop);
335
+ const name = casing.attr === types_1.AttrNameCasing.Camel ? prop : (0, shared_1.hyphenate)(prop);
336
+ if ((0, shared_1.hyphenate)(name).startsWith('on-')) {
337
+ const propNameBase = name.startsWith('on-')
338
+ ? name.slice('on-'.length)
339
+ : (name['on'.length].toLowerCase() + name.slice('onX'.length));
340
+ const propKey = createInternalItemId('componentEvent', [isGlobal ? '*' : tag, propNameBase]);
368
341
  attributes.push({
369
- name: 'v-on:' + name,
342
+ name: 'v-on:' + propNameBase,
343
+ description: propKey,
344
+ }, {
345
+ name: '@' + propNameBase,
370
346
  description: propKey,
371
347
  });
348
+ }
349
+ {
350
+ const propName = name;
351
+ const propKey = createInternalItemId('componentProp', [isGlobal ? '*' : tag, propName]);
372
352
  attributes.push({
373
- name: '@' + name,
353
+ name: propName,
354
+ description: propKey,
355
+ }, {
356
+ name: ':' + propName,
357
+ description: propKey,
358
+ }, {
359
+ name: 'v-bind:' + propName,
374
360
  description: propKey,
375
361
  });
376
362
  }
377
- const models = [];
378
- for (const prop of [...props, ...attrs]) {
379
- if (prop.startsWith('onUpdate:')) {
380
- const isGlobal = !props.has(prop);
381
- models.push([isGlobal, prop.substring('onUpdate:'.length)]);
382
- }
363
+ }
364
+ for (const event of events) {
365
+ const name = casing.attr === types_1.AttrNameCasing.Camel ? event : (0, shared_1.hyphenate)(event);
366
+ const propKey = createInternalItemId('componentEvent', [tag, name]);
367
+ attributes.push({
368
+ name: 'v-on:' + name,
369
+ description: propKey,
370
+ });
371
+ attributes.push({
372
+ name: '@' + name,
373
+ description: propKey,
374
+ });
375
+ }
376
+ const models = [];
377
+ for (const prop of [...props, ...attrs]) {
378
+ if (prop.startsWith('onUpdate:')) {
379
+ const isGlobal = !props.has(prop);
380
+ models.push([isGlobal, prop.substring('onUpdate:'.length)]);
383
381
  }
384
- for (const event of events) {
385
- if (event.startsWith('update:')) {
386
- models.push([false, event.substring('update:'.length)]);
387
- }
382
+ }
383
+ for (const event of events) {
384
+ if (event.startsWith('update:')) {
385
+ models.push([false, event.substring('update:'.length)]);
388
386
  }
389
- for (const [isGlobal, model] of models) {
390
- const name = casing.attr === types_1.AttrNameCasing.Camel ? model : (0, shared_1.hyphenate)(model);
391
- const propKey = createInternalItemId('componentProp', [isGlobal ? '*' : tag, name]);
387
+ }
388
+ for (const [isGlobal, model] of models) {
389
+ const name = casing.attr === types_1.AttrNameCasing.Camel ? model : (0, shared_1.hyphenate)(model);
390
+ const propKey = createInternalItemId('componentProp', [isGlobal ? '*' : tag, name]);
391
+ attributes.push({
392
+ name: 'v-model:' + name,
393
+ description: propKey,
394
+ });
395
+ if (model === 'modelValue') {
392
396
  attributes.push({
393
- name: 'v-model:' + name,
397
+ name: 'v-model',
394
398
  description: propKey,
395
399
  });
396
- if (model === 'modelValue') {
397
- attributes.push({
398
- name: 'v-model',
399
- description: propKey,
400
- });
401
- }
402
400
  }
403
- return attributes;
404
- },
405
- provideValues: () => [],
406
- },
407
- ]);
408
- }
409
- function afterHtmlCompletion(completionList, map, vueSourceFile) {
410
- const replacement = getReplacement(completionList, map.sourceFileDocument);
411
- const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, vueSourceFile.fileName);
412
- const componentNames = new Set((0, helpers_1.checkComponentNames)(ts, _ts.languageService, vueSourceFile, nativeTags).map(shared_1.hyphenate));
413
- if (replacement) {
414
- const isEvent = replacement.text.startsWith('v-on:') || replacement.text.startsWith('@');
415
- const isProp = replacement.text.startsWith('v-bind:') || replacement.text.startsWith(':');
416
- const isModel = replacement.text.startsWith('v-model:') || replacement.text.split('.')[0] === 'v-model';
417
- const hasModifier = replacement.text.includes('.');
418
- const validModifiers = isEvent ? eventModifiers
419
- : isProp ? propModifiers
420
- : undefined;
421
- const modifiers = replacement.text.split('.').slice(1);
422
- const textWithoutModifier = replacement.text.split('.')[0];
423
- if (validModifiers && hasModifier) {
424
- for (const modifier in validModifiers) {
425
- if (modifiers.includes(modifier))
426
- continue;
427
- const modifierDes = validModifiers[modifier];
428
- const insertText = textWithoutModifier + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier;
429
- const newItem = {
430
- label: modifier,
431
- filterText: insertText,
432
- documentation: {
433
- kind: 'markdown',
434
- value: modifierDes,
435
- },
436
- textEdit: {
437
- range: replacement.textEdit.range,
438
- newText: insertText,
439
- },
440
- kind: vscode.CompletionItemKind.EnumMember,
441
- };
442
- completionList.items.push(newItem);
443
- }
444
- }
445
- else if (hasModifier && isModel) {
446
- for (const modifier of modelData.globalAttributes ?? []) {
447
- if (modifiers.includes(modifier.name))
448
- continue;
449
- const insertText = textWithoutModifier + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier.name;
450
- const newItem = {
451
- label: modifier.name,
452
- filterText: insertText,
453
- documentation: {
454
- kind: 'markdown',
455
- value: (typeof modifier.description === 'object' ? modifier.description.value : modifier.description)
456
- + '\n\n' + modifier.references?.map(ref => `[${ref.name}](${ref.url})`).join(' | '),
457
- },
458
- textEdit: {
459
- range: replacement.textEdit.range,
460
- newText: insertText,
461
- },
462
- kind: vscode.CompletionItemKind.EnumMember,
463
- };
464
- completionList.items.push(newItem);
465
401
  }
402
+ return attributes;
403
+ },
404
+ provideValues: () => [],
405
+ },
406
+ ]);
407
+ }
408
+ function afterHtmlCompletion(completionList, map, vueSourceFile) {
409
+ const replacement = getReplacement(completionList, map.sourceFileDocument);
410
+ const nativeTags = (0, helpers_1.checkNativeTags)(ts, _ts.languageService, _ts.languageServiceHost);
411
+ const componentNames = new Set((0, helpers_1.checkComponentNames)(ts, _ts.languageService, vueSourceFile, nativeTags).map(shared_1.hyphenate));
412
+ if (replacement) {
413
+ const isEvent = replacement.text.startsWith('v-on:') || replacement.text.startsWith('@');
414
+ const isProp = replacement.text.startsWith('v-bind:') || replacement.text.startsWith(':');
415
+ const isModel = replacement.text.startsWith('v-model:') || replacement.text.split('.')[0] === 'v-model';
416
+ const hasModifier = replacement.text.includes('.');
417
+ const validModifiers = isEvent ? eventModifiers
418
+ : isProp ? propModifiers
419
+ : undefined;
420
+ const modifiers = replacement.text.split('.').slice(1);
421
+ const textWithoutModifier = replacement.text.split('.')[0];
422
+ if (validModifiers && hasModifier) {
423
+ for (const modifier in validModifiers) {
424
+ if (modifiers.includes(modifier))
425
+ continue;
426
+ const modifierDes = validModifiers[modifier];
427
+ const insertText = textWithoutModifier + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier;
428
+ const newItem = {
429
+ label: modifier,
430
+ filterText: insertText,
431
+ documentation: {
432
+ kind: 'markdown',
433
+ value: modifierDes,
434
+ },
435
+ textEdit: {
436
+ range: replacement.textEdit.range,
437
+ newText: insertText,
438
+ },
439
+ kind: vscode.CompletionItemKind.EnumMember,
440
+ };
441
+ completionList.items.push(newItem);
466
442
  }
467
443
  }
468
- for (const item of completionList.items) {
469
- const itemIdKey = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value;
470
- const itemId = itemIdKey ? readInternalItemId(itemIdKey) : undefined;
471
- if (itemId) {
472
- item.documentation = undefined;
444
+ else if (hasModifier && isModel) {
445
+ for (const modifier of modelData.globalAttributes ?? []) {
446
+ if (modifiers.includes(modifier.name))
447
+ continue;
448
+ const insertText = textWithoutModifier + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier.name;
449
+ const newItem = {
450
+ label: modifier.name,
451
+ filterText: insertText,
452
+ documentation: {
453
+ kind: 'markdown',
454
+ value: (typeof modifier.description === 'object' ? modifier.description.value : modifier.description)
455
+ + '\n\n' + modifier.references?.map(ref => `[${ref.name}](${ref.url})`).join(' | '),
456
+ },
457
+ textEdit: {
458
+ range: replacement.textEdit.range,
459
+ newText: insertText,
460
+ },
461
+ kind: vscode.CompletionItemKind.EnumMember,
462
+ };
463
+ completionList.items.push(newItem);
473
464
  }
474
- if (itemIdKey && itemId) {
475
- if (itemId.type === 'componentProp' || itemId.type === 'componentEvent') {
476
- const [componentName] = itemId.args;
465
+ }
466
+ }
467
+ for (const item of completionList.items) {
468
+ const itemIdKey = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value;
469
+ const itemId = itemIdKey ? readInternalItemId(itemIdKey) : undefined;
470
+ if (itemId) {
471
+ item.documentation = undefined;
472
+ }
473
+ if (itemIdKey && itemId) {
474
+ if (itemId.type === 'componentProp' || itemId.type === 'componentEvent') {
475
+ const [componentName] = itemId.args;
476
+ if (componentName !== '*') {
477
+ item.sortText = '\u0000' + (item.sortText ?? item.label);
478
+ }
479
+ if (itemId.type === 'componentProp') {
477
480
  if (componentName !== '*') {
478
- item.sortText = '\u0000' + (item.sortText ?? item.label);
479
- }
480
- if (itemId.type === 'componentProp') {
481
- if (componentName !== '*') {
482
- item.kind = vscode.CompletionItemKind.Field;
483
- }
481
+ item.kind = vscode.CompletionItemKind.Field;
484
482
  }
485
- else {
486
- item.kind = componentName !== '*' ? vscode.CompletionItemKind.Function : vscode.CompletionItemKind.Event;
487
- }
488
- }
489
- else if (item.label === 'v-if'
490
- || item.label === 'v-else-if'
491
- || item.label === 'v-else'
492
- || item.label === 'v-for') {
493
- item.kind = vscode.CompletionItemKind.Method;
494
- item.sortText = '\u0003' + (item.sortText ?? item.label);
495
- }
496
- else if (item.label.startsWith('v-')) {
497
- item.kind = vscode.CompletionItemKind.Function;
498
- item.sortText = '\u0002' + (item.sortText ?? item.label);
499
483
  }
500
484
  else {
501
- item.sortText = '\u0001' + (item.sortText ?? item.label);
485
+ item.kind = componentName !== '*' ? vscode.CompletionItemKind.Function : vscode.CompletionItemKind.Event;
502
486
  }
503
487
  }
504
- else if (item.kind === vscode.CompletionItemKind.Property && componentNames.has((0, shared_1.hyphenate)(item.label))) {
505
- item.kind = vscode.CompletionItemKind.Variable;
506
- item.sortText = '\u0000' + (item.sortText ?? item.label);
488
+ else if (item.label === 'v-if'
489
+ || item.label === 'v-else-if'
490
+ || item.label === 'v-else'
491
+ || item.label === 'v-for') {
492
+ item.kind = vscode.CompletionItemKind.Method;
493
+ item.sortText = '\u0003' + (item.sortText ?? item.label);
507
494
  }
495
+ else if (item.label.startsWith('v-')) {
496
+ item.kind = vscode.CompletionItemKind.Function;
497
+ item.sortText = '\u0002' + (item.sortText ?? item.label);
498
+ }
499
+ else {
500
+ item.sortText = '\u0001' + (item.sortText ?? item.label);
501
+ }
502
+ }
503
+ else if (item.kind === vscode.CompletionItemKind.Property && componentNames.has((0, shared_1.hyphenate)(item.label))) {
504
+ item.kind = vscode.CompletionItemKind.Variable;
505
+ item.sortText = '\u0000' + (item.sortText ?? item.label);
508
506
  }
509
- templatePlugin.updateCustomData([]);
510
507
  }
511
- };
512
- return plugin;
513
- }
514
- exports.default = useVueTemplateLanguagePlugin;
508
+ options.updateCustomData(htmlOrPugService, []);
509
+ }
510
+ };
515
511
  function createInternalItemId(type, args) {
516
512
  return '__VLS_::' + type + '::' + args.join(',');
517
513
  }