@vue/language-service 1.9.0-alpha.3 → 2.0.1

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.
Files changed (72) hide show
  1. package/data/template/en.json +2 -2
  2. package/data/template/fr.json +1 -1
  3. package/data/template/ja.json +2 -2
  4. package/data/template/ko.json +13 -13
  5. package/data/template/pt.json +18 -18
  6. package/data/template/zh-cn.json +2 -2
  7. package/index.d.ts +7 -0
  8. package/index.js +64 -0
  9. package/lib/ideFeatures/nameCasing.d.ts +13 -0
  10. package/{out → lib}/ideFeatures/nameCasing.js +82 -29
  11. package/lib/plugins/css.d.ts +2 -0
  12. package/lib/plugins/css.js +27 -0
  13. package/{out → lib}/plugins/data.d.ts +1 -2
  14. package/lib/plugins/vue-autoinsert-dotvalue.d.ts +10 -0
  15. package/{out → lib}/plugins/vue-autoinsert-dotvalue.js +70 -54
  16. package/lib/plugins/vue-autoinsert-parentheses.d.ts +2 -0
  17. package/lib/plugins/vue-autoinsert-parentheses.js +60 -0
  18. package/lib/plugins/vue-autoinsert-space.d.ts +2 -0
  19. package/lib/plugins/vue-autoinsert-space.js +34 -0
  20. package/lib/plugins/vue-codelens-references.d.ts +2 -0
  21. package/lib/plugins/vue-codelens-references.js +38 -0
  22. package/lib/plugins/vue-directive-comments.d.ts +2 -0
  23. package/lib/plugins/vue-directive-comments.js +61 -0
  24. package/lib/plugins/vue-document-drop.d.ts +2 -0
  25. package/lib/plugins/vue-document-drop.js +81 -0
  26. package/lib/plugins/vue-extract-file.d.ts +8 -0
  27. package/lib/plugins/vue-extract-file.js +258 -0
  28. package/lib/plugins/vue-sfc.d.ts +7 -0
  29. package/lib/plugins/vue-sfc.js +163 -0
  30. package/lib/plugins/vue-template.d.ts +3 -0
  31. package/lib/plugins/vue-template.js +594 -0
  32. package/lib/plugins/vue-toggle-v-bind-codeaction.d.ts +2 -0
  33. package/lib/plugins/vue-toggle-v-bind-codeaction.js +126 -0
  34. package/lib/plugins/vue-twoslash-queries.d.ts +2 -0
  35. package/lib/plugins/vue-twoslash-queries.js +50 -0
  36. package/lib/plugins/vue-visualize-hidden-callback-param.d.ts +2 -0
  37. package/lib/plugins/vue-visualize-hidden-callback-param.js +45 -0
  38. package/{out → lib}/types.d.ts +1 -2
  39. package/{out → lib}/types.js +1 -1
  40. package/package.json +20 -20
  41. package/scripts/update-html-data.js +426 -0
  42. package/out/helpers.d.ts +0 -17
  43. package/out/helpers.js +0 -235
  44. package/out/ideFeatures/dragImport.d.ts +0 -9
  45. package/out/ideFeatures/dragImport.js +0 -50
  46. package/out/ideFeatures/nameCasing.d.ts +0 -16
  47. package/out/index.d.ts +0 -8
  48. package/out/index.js +0 -26
  49. package/out/languageService.d.ts +0 -9
  50. package/out/languageService.js +0 -239
  51. package/out/plugins/vue-autoinsert-dotvalue.d.ts +0 -7
  52. package/out/plugins/vue-autoinsert-parentheses.d.ts +0 -3
  53. package/out/plugins/vue-autoinsert-parentheses.js +0 -61
  54. package/out/plugins/vue-autoinsert-space.d.ts +0 -3
  55. package/out/plugins/vue-autoinsert-space.js +0 -32
  56. package/out/plugins/vue-codelens-references.d.ts +0 -3
  57. package/out/plugins/vue-codelens-references.js +0 -54
  58. package/out/plugins/vue-directive-comments.d.ts +0 -3
  59. package/out/plugins/vue-directive-comments.js +0 -57
  60. package/out/plugins/vue-extract-file.d.ts +0 -9
  61. package/out/plugins/vue-extract-file.js +0 -293
  62. package/out/plugins/vue-template.d.ts +0 -12
  63. package/out/plugins/vue-template.js +0 -548
  64. package/out/plugins/vue-toggle-v-bind-codeaction.d.ts +0 -3
  65. package/out/plugins/vue-toggle-v-bind-codeaction.js +0 -126
  66. package/out/plugins/vue-twoslash-queries.d.ts +0 -3
  67. package/out/plugins/vue-twoslash-queries.js +0 -60
  68. package/out/plugins/vue-visualize-hidden-callback-param.d.ts +0 -3
  69. package/out/plugins/vue-visualize-hidden-callback-param.js +0 -43
  70. package/out/plugins/vue.d.ts +0 -8
  71. package/out/plugins/vue.js +0 -169
  72. /package/{out → lib}/plugins/data.js +0 -0
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAddComponentToOptionEdit = exports.getLastImportNode = exports.create = void 0;
4
+ const language_core_1 = require("@vue/language-core");
5
+ const client_1 = require("@vue/typescript-plugin/lib/client");
6
+ const unicodeReg = /\\u/g;
7
+ function create(ts) {
8
+ return {
9
+ name: 'vue-extract-file',
10
+ create(context) {
11
+ return {
12
+ async provideCodeActions(document, range, _context) {
13
+ const startOffset = document.offsetAt(range.start);
14
+ const endOffset = document.offsetAt(range.end);
15
+ if (startOffset === endOffset) {
16
+ return;
17
+ }
18
+ const [code, vueCode] = context.documents.getVirtualCodeByUri(document.uri);
19
+ if (!(vueCode?.generated?.code instanceof language_core_1.VueGeneratedCode) || code?.id !== 'template')
20
+ return;
21
+ const { sfc } = vueCode.generated.code;
22
+ const script = sfc.scriptSetup ?? sfc.script;
23
+ if (!sfc.template || !script)
24
+ return;
25
+ const templateCodeRange = selectTemplateCode(startOffset, endOffset, sfc.template);
26
+ if (!templateCodeRange)
27
+ return;
28
+ return [
29
+ {
30
+ title: 'Extract into new dumb component',
31
+ kind: 'refactor.move.newFile.dumb',
32
+ data: {
33
+ uri: document.uri,
34
+ range: [startOffset, endOffset],
35
+ newName: 'NewComponent',
36
+ },
37
+ },
38
+ ];
39
+ },
40
+ async resolveCodeAction(codeAction) {
41
+ const { uri, range, newName } = codeAction.data;
42
+ const [startOffset, endOffset] = range;
43
+ const [code, sourceFile] = context.documents.getVirtualCodeByUri(uri);
44
+ if (!(sourceFile?.generated?.code instanceof language_core_1.VueGeneratedCode) || code?.id !== 'template')
45
+ return codeAction;
46
+ const document = context.documents.get(uri, code.languageId, code.snapshot);
47
+ const sfcDocument = context.documents.get(sourceFile.id, sourceFile.languageId, sourceFile.snapshot);
48
+ const { sfc } = sourceFile.generated.code;
49
+ const script = sfc.scriptSetup ?? sfc.script;
50
+ if (!sfc.template || !script)
51
+ return codeAction;
52
+ const templateCodeRange = selectTemplateCode(startOffset, endOffset, sfc.template);
53
+ if (!templateCodeRange)
54
+ return codeAction;
55
+ const toExtract = await (0, client_1.collectExtractProps)(sourceFile.generated.code.fileName, templateCodeRange) ?? [];
56
+ if (!toExtract)
57
+ return codeAction;
58
+ const templateInitialIndent = await context.env.getConfiguration('vue.format.template.initialIndent') ?? true;
59
+ const scriptInitialIndent = await context.env.getConfiguration('vue.format.script.initialIndent') ?? false;
60
+ const newUri = sfcDocument.uri.substring(0, sfcDocument.uri.lastIndexOf('/') + 1) + `${newName}.vue`;
61
+ const lastImportNode = getLastImportNode(ts, script.ast);
62
+ let newFileTags = [];
63
+ newFileTags.push(constructTag('template', [], templateInitialIndent, sfc.template.content.substring(templateCodeRange[0], templateCodeRange[1])));
64
+ if (toExtract.length) {
65
+ newFileTags.push(constructTag('script', ['setup', 'lang="ts"'], scriptInitialIndent, generateNewScriptContents()));
66
+ }
67
+ if (sfc.template.startTagEnd > script.startTagEnd) {
68
+ newFileTags = newFileTags.reverse();
69
+ }
70
+ const templateEdits = [
71
+ {
72
+ range: {
73
+ start: document.positionAt(templateCodeRange[0]),
74
+ end: document.positionAt(templateCodeRange[1]),
75
+ },
76
+ newText: generateReplaceTemplate(),
77
+ },
78
+ ];
79
+ const sfcEdits = [
80
+ {
81
+ range: lastImportNode ? {
82
+ start: sfcDocument.positionAt(script.startTagEnd + lastImportNode.end),
83
+ end: sfcDocument.positionAt(script.startTagEnd + lastImportNode.end),
84
+ } : {
85
+ start: sfcDocument.positionAt(script.startTagEnd),
86
+ end: sfcDocument.positionAt(script.startTagEnd),
87
+ },
88
+ newText: `\nimport ${newName} from './${newName}.vue'`,
89
+ },
90
+ ];
91
+ if (sfc.script) {
92
+ const edit = createAddComponentToOptionEdit(ts, sfc.script.ast, newName);
93
+ if (edit) {
94
+ sfcEdits.push({
95
+ range: {
96
+ start: sfcDocument.positionAt(sfc.script.startTagEnd + edit.range.start),
97
+ end: sfcDocument.positionAt(sfc.script.startTagEnd + edit.range.end),
98
+ },
99
+ newText: edit.newText,
100
+ });
101
+ }
102
+ }
103
+ return {
104
+ ...codeAction,
105
+ edit: {
106
+ documentChanges: [
107
+ // editing template virtual document
108
+ {
109
+ textDocument: {
110
+ uri: document.uri,
111
+ version: null,
112
+ },
113
+ edits: templateEdits,
114
+ },
115
+ // editing vue sfc
116
+ {
117
+ textDocument: {
118
+ uri: sourceFile.id,
119
+ version: null,
120
+ },
121
+ edits: sfcEdits,
122
+ },
123
+ // creating new file with content
124
+ {
125
+ uri: newUri,
126
+ kind: 'create',
127
+ },
128
+ {
129
+ textDocument: {
130
+ uri: newUri,
131
+ version: null,
132
+ },
133
+ edits: [
134
+ {
135
+ range: {
136
+ start: { line: 0, character: 0 },
137
+ end: { line: 0, character: 0 },
138
+ },
139
+ newText: newFileTags.join('\n'),
140
+ },
141
+ ],
142
+ },
143
+ ],
144
+ },
145
+ };
146
+ function generateNewScriptContents() {
147
+ const lines = [];
148
+ const props = toExtract.filter(p => !p.model);
149
+ const models = toExtract.filter(p => p.model);
150
+ if (props.length) {
151
+ lines.push(`defineProps<{ \n\t${props.map(p => `${p.name}: ${p.type};`).join('\n\t')}\n}>()`);
152
+ }
153
+ for (const model of models) {
154
+ lines.push(`const ${model.name} = defineModel<${model.type}>('${model.name}', { required: true })`);
155
+ }
156
+ return lines.join('\n');
157
+ }
158
+ function generateReplaceTemplate() {
159
+ const props = toExtract.filter(p => !p.model);
160
+ const models = toExtract.filter(p => p.model);
161
+ return [
162
+ `<${newName}`,
163
+ ...props.map(p => `:${p.name}="${p.name}"`),
164
+ ...models.map(p => `v-model:${p.name}="${p.name}"`),
165
+ `/>`,
166
+ ].join(' ');
167
+ }
168
+ },
169
+ };
170
+ },
171
+ };
172
+ }
173
+ exports.create = create;
174
+ function selectTemplateCode(startOffset, endOffset, templateBlock) {
175
+ const insideNodes = [];
176
+ templateBlock.ast?.children.forEach(function visit(node) {
177
+ if (node.loc.start.offset >= startOffset
178
+ && node.loc.end.offset <= endOffset) {
179
+ insideNodes.push(node);
180
+ }
181
+ if ('children' in node) {
182
+ node.children.forEach(node => {
183
+ if (typeof node === 'object') {
184
+ visit(node);
185
+ }
186
+ });
187
+ }
188
+ else if ('branches' in node) {
189
+ node.branches.forEach(visit);
190
+ }
191
+ else if ('content' in node) {
192
+ if (typeof node.content === 'object') {
193
+ visit(node.content);
194
+ }
195
+ }
196
+ });
197
+ if (insideNodes.length) {
198
+ const first = insideNodes.sort((a, b) => a.loc.start.offset - b.loc.start.offset)[0];
199
+ const last = insideNodes.sort((a, b) => b.loc.end.offset - a.loc.end.offset)[0];
200
+ return [first.loc.start.offset, last.loc.end.offset];
201
+ }
202
+ }
203
+ function constructTag(name, attributes, initialIndent, content) {
204
+ if (initialIndent)
205
+ content = content.split('\n').map(line => `\t${line}`).join('\n');
206
+ const attributesString = attributes.length ? ` ${attributes.join(' ')}` : '';
207
+ return `<${name}${attributesString}>\n${content}\n</${name}>\n`;
208
+ }
209
+ function getLastImportNode(ts, sourceFile) {
210
+ let lastImportNode;
211
+ for (const statement of sourceFile.statements) {
212
+ if (ts.isImportDeclaration(statement)) {
213
+ lastImportNode = statement;
214
+ }
215
+ else {
216
+ break;
217
+ }
218
+ }
219
+ return lastImportNode;
220
+ }
221
+ exports.getLastImportNode = getLastImportNode;
222
+ function createAddComponentToOptionEdit(ts, ast, componentName) {
223
+ const exportDefault = language_core_1.scriptRanges.parseScriptRanges(ts, ast, false, true).exportDefault;
224
+ if (!exportDefault)
225
+ return;
226
+ // https://github.com/microsoft/TypeScript/issues/36174
227
+ const printer = ts.createPrinter();
228
+ if (exportDefault.componentsOption && exportDefault.componentsOptionNode) {
229
+ const newNode = {
230
+ ...exportDefault.componentsOptionNode,
231
+ properties: [
232
+ ...exportDefault.componentsOptionNode.properties,
233
+ ts.factory.createShorthandPropertyAssignment(componentName),
234
+ ],
235
+ };
236
+ const printText = printer.printNode(ts.EmitHint.Expression, newNode, ast);
237
+ return {
238
+ range: exportDefault.componentsOption,
239
+ newText: unescape(printText.replace(unicodeReg, '%u')),
240
+ };
241
+ }
242
+ else if (exportDefault.args && exportDefault.argsNode) {
243
+ const newNode = {
244
+ ...exportDefault.argsNode,
245
+ properties: [
246
+ ...exportDefault.argsNode.properties,
247
+ ts.factory.createShorthandPropertyAssignment(`components: { ${componentName} }`),
248
+ ],
249
+ };
250
+ const printText = printer.printNode(ts.EmitHint.Expression, newNode, ast);
251
+ return {
252
+ range: exportDefault.args,
253
+ newText: unescape(printText.replace(unicodeReg, '%u')),
254
+ };
255
+ }
256
+ }
257
+ exports.createAddComponentToOptionEdit = createAddComponentToOptionEdit;
258
+ //# sourceMappingURL=vue-extract-file.js.map
@@ -0,0 +1,7 @@
1
+ import type { ServicePlugin } from '@volar/language-service';
2
+ import * as vue from '@vue/language-core';
3
+ import type { TextDocument } from 'vscode-languageserver-textdocument';
4
+ export interface Provide {
5
+ 'vue/vueFile': (document: TextDocument) => vue.VueGeneratedCode | undefined;
6
+ }
7
+ export declare function create(): ServicePlugin;
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.create = void 0;
4
+ const vue = require("@vue/language-core");
5
+ const volar_service_html_1 = require("volar-service-html");
6
+ const html = require("vscode-html-languageservice");
7
+ const data_1 = require("./data");
8
+ let sfcDataProvider;
9
+ function create() {
10
+ return {
11
+ name: 'vue-sfc',
12
+ create(context) {
13
+ const htmlPlugin = (0, volar_service_html_1.create)({
14
+ documentSelector: ['vue'],
15
+ useCustomDataProviders: false,
16
+ }).create(context);
17
+ const htmlLanguageService = htmlPlugin.provide['html/languageService']();
18
+ sfcDataProvider ??= html.newHTMLDataProvider('vue', (0, data_1.loadLanguageBlocks)(context.env.locale ?? 'en'));
19
+ htmlLanguageService.setDataProviders(false, [sfcDataProvider]);
20
+ return {
21
+ ...htmlPlugin,
22
+ provide: {
23
+ 'vue/vueFile': document => {
24
+ return worker(document, (vueFile) => {
25
+ return vueFile;
26
+ });
27
+ },
28
+ },
29
+ async resolveEmbeddedCodeFormattingOptions(code, options) {
30
+ const sourceFile = context.language.files.getByVirtualCode(code);
31
+ if (sourceFile.generated?.code instanceof vue.VueGeneratedCode) {
32
+ if (code.id === 'scriptFormat' || code.id === 'scriptSetupFormat') {
33
+ if (await context.env.getConfiguration?.('vue.format.script.initialIndent') ?? false) {
34
+ options.initialIndentLevel++;
35
+ }
36
+ }
37
+ else if (code.id.startsWith('style_')) {
38
+ if (await context.env.getConfiguration?.('vue.format.style.initialIndent') ?? false) {
39
+ options.initialIndentLevel++;
40
+ }
41
+ }
42
+ else if (code.id === 'template') {
43
+ if (await context.env.getConfiguration?.('vue.format.template.initialIndent') ?? true) {
44
+ options.initialIndentLevel++;
45
+ }
46
+ }
47
+ }
48
+ return options;
49
+ },
50
+ provideDocumentLinks: undefined,
51
+ provideDocumentSymbols(document) {
52
+ return worker(document, (vueSourceFile) => {
53
+ const result = [];
54
+ const descriptor = vueSourceFile.sfc;
55
+ if (descriptor.template) {
56
+ result.push({
57
+ name: 'template',
58
+ kind: 2,
59
+ range: {
60
+ start: document.positionAt(descriptor.template.start),
61
+ end: document.positionAt(descriptor.template.end),
62
+ },
63
+ selectionRange: {
64
+ start: document.positionAt(descriptor.template.start),
65
+ end: document.positionAt(descriptor.template.startTagEnd),
66
+ },
67
+ });
68
+ }
69
+ if (descriptor.script) {
70
+ result.push({
71
+ name: 'script',
72
+ kind: 2,
73
+ range: {
74
+ start: document.positionAt(descriptor.script.start),
75
+ end: document.positionAt(descriptor.script.end),
76
+ },
77
+ selectionRange: {
78
+ start: document.positionAt(descriptor.script.start),
79
+ end: document.positionAt(descriptor.script.startTagEnd),
80
+ },
81
+ });
82
+ }
83
+ if (descriptor.scriptSetup) {
84
+ result.push({
85
+ name: 'script setup',
86
+ kind: 2,
87
+ range: {
88
+ start: document.positionAt(descriptor.scriptSetup.start),
89
+ end: document.positionAt(descriptor.scriptSetup.end),
90
+ },
91
+ selectionRange: {
92
+ start: document.positionAt(descriptor.scriptSetup.start),
93
+ end: document.positionAt(descriptor.scriptSetup.startTagEnd),
94
+ },
95
+ });
96
+ }
97
+ for (const style of descriptor.styles) {
98
+ let name = 'style';
99
+ if (style.scoped)
100
+ name += ' scoped';
101
+ if (style.module)
102
+ name += ' module';
103
+ result.push({
104
+ name,
105
+ kind: 2,
106
+ range: {
107
+ start: document.positionAt(style.start),
108
+ end: document.positionAt(style.end),
109
+ },
110
+ selectionRange: {
111
+ start: document.positionAt(style.start),
112
+ end: document.positionAt(style.startTagEnd),
113
+ },
114
+ });
115
+ }
116
+ for (const customBlock of descriptor.customBlocks) {
117
+ result.push({
118
+ name: `${customBlock.type}`,
119
+ kind: 2,
120
+ range: {
121
+ start: document.positionAt(customBlock.start),
122
+ end: document.positionAt(customBlock.end),
123
+ },
124
+ selectionRange: {
125
+ start: document.positionAt(customBlock.start),
126
+ end: document.positionAt(customBlock.startTagEnd),
127
+ },
128
+ });
129
+ }
130
+ return result;
131
+ });
132
+ },
133
+ provideDocumentFormattingEdits(document, range, options) {
134
+ return worker(document, async (vueCode) => {
135
+ const formatSettings = await context.env.getConfiguration?.('html.format') ?? {};
136
+ const blockTypes = ['template', 'script', 'style'];
137
+ for (const customBlock of vueCode.sfc.customBlocks) {
138
+ blockTypes.push(customBlock.type);
139
+ }
140
+ return htmlLanguageService.format(document, range, {
141
+ ...options,
142
+ ...formatSettings,
143
+ unformatted: '',
144
+ contentUnformatted: blockTypes.join(','),
145
+ extraLiners: blockTypes.join(','),
146
+ endWithNewline: options.insertFinalNewline ? true
147
+ : options.trimFinalNewlines ? false
148
+ : document.getText().endsWith('\n'),
149
+ });
150
+ });
151
+ },
152
+ };
153
+ function worker(document, callback) {
154
+ const [vueFile] = context.documents.getVirtualCodeByUri(document.uri);
155
+ if (vueFile instanceof vue.VueGeneratedCode) {
156
+ return callback(vueFile);
157
+ }
158
+ }
159
+ },
160
+ };
161
+ }
162
+ exports.create = create;
163
+ //# sourceMappingURL=vue-sfc.js.map
@@ -0,0 +1,3 @@
1
+ import type { ServiceEnvironment } from '@volar/language-service';
2
+ import { ServicePlugin, VueCompilerOptions } from '../types';
3
+ export declare function create(mode: 'html' | 'pug', ts: typeof import('typescript'), getVueOptions: (env: ServiceEnvironment) => VueCompilerOptions): ServicePlugin;