@vue/language-service 1.8.6 → 1.8.8

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.
package/out/helpers.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import * as vue from '@vue/language-core';
2
2
  import * as embedded from '@volar/language-core';
3
3
  import type * as ts from 'typescript/lib/tsserverlibrary';
4
- export declare function checkPropsOfTag(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, sourceFile: embedded.VirtualFile, tag: string, vueCompilerOptions: vue.VueCompilerOptions, requiredOnly?: boolean): string[];
5
- export declare function checkEventsOfTag(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, sourceFile: embedded.VirtualFile, tag: string, vueCompilerOptions: vue.VueCompilerOptions): string[];
6
- export declare function checkComponentNames(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, sourceFile: embedded.VirtualFile, vueCompilerOptions: vue.VueCompilerOptions): string[];
4
+ export declare function getPropsByTag(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, sourceFile: embedded.VirtualFile, tag: string, vueCompilerOptions: vue.VueCompilerOptions, requiredOnly?: boolean): string[];
5
+ export declare function getEventsOfTag(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, sourceFile: embedded.VirtualFile, tag: string, vueCompilerOptions: vue.VueCompilerOptions): string[];
6
+ export declare function getTemplateCtx(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, sourceFile: embedded.VirtualFile): string[] | undefined;
7
+ export declare function getComponentNames(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, sourceFile: embedded.VirtualFile, vueCompilerOptions: vue.VueCompilerOptions): string[];
7
8
  export declare function getElementAttrs(ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, tsLsHost: ts.LanguageServiceHost, tagName: string): string[];
8
9
  type Tags = Map<string, {
9
10
  offsets: number[];
package/out/helpers.js CHANGED
@@ -1,29 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTemplateTagsAndAttrs = exports.getElementAttrs = exports.checkComponentNames = exports.checkEventsOfTag = exports.checkPropsOfTag = void 0;
3
+ exports.getTemplateTagsAndAttrs = exports.getElementAttrs = exports.getComponentNames = exports.getTemplateCtx = exports.getEventsOfTag = exports.getPropsByTag = void 0;
4
4
  const vue = require("@vue/language-core");
5
5
  const embedded = require("@volar/language-core");
6
6
  const reactivity_1 = require("@vue/reactivity");
7
7
  const language_core_1 = require("@vue/language-core");
8
8
  const shared_1 = require("@vue/shared");
9
- function checkPropsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions, requiredOnly = false) {
9
+ function getPropsByTag(ts, tsLs, sourceFile, tag, vueCompilerOptions, requiredOnly = false) {
10
10
  const checker = tsLs.getProgram().getTypeChecker();
11
- const components = getComponentsType(ts, tsLs, sourceFile);
11
+ const components = getVariableType(ts, tsLs, sourceFile, '__VLS_components');
12
12
  if (!components)
13
13
  return [];
14
14
  const name = tag.split('.');
15
- let componentSymbol = components.componentsType.getProperty(name[0]);
15
+ let componentSymbol = components.type.getProperty(name[0]);
16
16
  if (!componentSymbol && !vueCompilerOptions.nativeTags.includes(name[0])) {
17
- componentSymbol = components.componentsType.getProperty((0, shared_1.camelize)(name[0]))
18
- ?? components.componentsType.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
17
+ componentSymbol = components.type.getProperty((0, shared_1.camelize)(name[0]))
18
+ ?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
19
19
  }
20
20
  if (!componentSymbol)
21
21
  return [];
22
- let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.componentsNode);
22
+ let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
23
23
  for (let i = 1; i < name.length; i++) {
24
24
  componentSymbol = componentType.getProperty(name[i]);
25
25
  if (componentSymbol) {
26
- componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.componentsNode);
26
+ componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
27
27
  }
28
28
  else {
29
29
  return [];
@@ -33,7 +33,7 @@ function checkPropsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions, required
33
33
  for (const sig of componentType.getCallSignatures()) {
34
34
  const propParam = sig.parameters[0];
35
35
  if (propParam) {
36
- const propsType = checker.getTypeOfSymbolAtLocation(propParam, components.componentsNode);
36
+ const propsType = checker.getTypeOfSymbolAtLocation(propParam, components.node);
37
37
  const props = propsType.getProperties();
38
38
  for (const prop of props) {
39
39
  if (!requiredOnly || !(prop.flags & ts.SymbolFlags.Optional)) {
@@ -46,7 +46,7 @@ function checkPropsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions, required
46
46
  const instanceType = sig.getReturnType();
47
47
  const propsSymbol = instanceType.getProperty('$props');
48
48
  if (propsSymbol) {
49
- const propsType = checker.getTypeOfSymbolAtLocation(propsSymbol, components.componentsNode);
49
+ const propsType = checker.getTypeOfSymbolAtLocation(propsSymbol, components.node);
50
50
  const props = propsType.getProperties();
51
51
  for (const prop of props) {
52
52
  if (prop.flags & ts.SymbolFlags.Method) { // #2443
@@ -60,25 +60,25 @@ function checkPropsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions, required
60
60
  }
61
61
  return [...result];
62
62
  }
63
- exports.checkPropsOfTag = checkPropsOfTag;
64
- function checkEventsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions) {
63
+ exports.getPropsByTag = getPropsByTag;
64
+ function getEventsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions) {
65
65
  const checker = tsLs.getProgram().getTypeChecker();
66
- const components = getComponentsType(ts, tsLs, sourceFile);
66
+ const components = getVariableType(ts, tsLs, sourceFile, '__VLS_components');
67
67
  if (!components)
68
68
  return [];
69
69
  const name = tag.split('.');
70
- let componentSymbol = components.componentsType.getProperty(name[0]);
70
+ let componentSymbol = components.type.getProperty(name[0]);
71
71
  if (!componentSymbol && !vueCompilerOptions.nativeTags.includes(name[0])) {
72
- componentSymbol = components.componentsType.getProperty((0, shared_1.camelize)(name[0]))
73
- ?? components.componentsType.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
72
+ componentSymbol = components.type.getProperty((0, shared_1.camelize)(name[0]))
73
+ ?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
74
74
  }
75
75
  if (!componentSymbol)
76
76
  return [];
77
- let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.componentsNode);
77
+ let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
78
78
  for (let i = 1; i < name.length; i++) {
79
79
  componentSymbol = componentType.getProperty(name[i]);
80
80
  if (componentSymbol) {
81
- componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.componentsNode);
81
+ componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
82
82
  }
83
83
  else {
84
84
  return [];
@@ -95,11 +95,11 @@ function checkEventsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions) {
95
95
  const instanceType = sig.getReturnType();
96
96
  const emitSymbol = instanceType.getProperty('$emit');
97
97
  if (emitSymbol) {
98
- const emitType = checker.getTypeOfSymbolAtLocation(emitSymbol, components.componentsNode);
98
+ const emitType = checker.getTypeOfSymbolAtLocation(emitSymbol, components.node);
99
99
  for (const call of emitType.getCallSignatures()) {
100
100
  const eventNameParamSymbol = call.parameters[0];
101
101
  if (eventNameParamSymbol) {
102
- const eventNameParamType = checker.getTypeOfSymbolAtLocation(eventNameParamSymbol, components.componentsNode);
102
+ const eventNameParamType = checker.getTypeOfSymbolAtLocation(eventNameParamSymbol, components.node);
103
103
  if (eventNameParamType.isStringLiteral()) {
104
104
  result.add(eventNameParamType.value);
105
105
  }
@@ -109,17 +109,24 @@ function checkEventsOfTag(ts, tsLs, sourceFile, tag, vueCompilerOptions) {
109
109
  }
110
110
  return [...result];
111
111
  }
112
- exports.checkEventsOfTag = checkEventsOfTag;
113
- function checkComponentNames(ts, tsLs, sourceFile, vueCompilerOptions) {
114
- return getComponentsType(ts, tsLs, sourceFile)
115
- ?.componentsType
112
+ exports.getEventsOfTag = getEventsOfTag;
113
+ function getTemplateCtx(ts, tsLs, sourceFile) {
114
+ return getVariableType(ts, tsLs, sourceFile, '__VLS_ctx')
115
+ ?.type
116
+ ?.getProperties()
117
+ .map(c => c.name);
118
+ }
119
+ exports.getTemplateCtx = getTemplateCtx;
120
+ function getComponentNames(ts, tsLs, sourceFile, vueCompilerOptions) {
121
+ return getVariableType(ts, tsLs, sourceFile, '__VLS_components')
122
+ ?.type
116
123
  ?.getProperties()
117
124
  .map(c => c.name)
118
125
  .filter(entry => entry.indexOf('$') === -1 && !entry.startsWith('_'))
119
126
  .filter(entry => !vueCompilerOptions.nativeTags.includes(entry))
120
127
  ?? [];
121
128
  }
122
- exports.checkComponentNames = checkComponentNames;
129
+ exports.getComponentNames = getComponentNames;
123
130
  function getElementAttrs(ts, tsLs, tsLsHost, tagName) {
124
131
  const sharedTypesFileName = tsLsHost.getCurrentDirectory() + '/' + language_core_1.sharedTypes.baseName;
125
132
  let tsSourceFile;
@@ -138,7 +145,7 @@ function getElementAttrs(ts, tsLs, tsLsHost, tagName) {
138
145
  return [];
139
146
  }
140
147
  exports.getElementAttrs = getElementAttrs;
141
- function getComponentsType(ts, tsLs, sourceFile) {
148
+ function getVariableType(ts, tsLs, sourceFile, name) {
142
149
  if (!(sourceFile instanceof vue.VueFile)) {
143
150
  return;
144
151
  }
@@ -150,29 +157,29 @@ function getComponentsType(ts, tsLs, sourceFile) {
150
157
  }
151
158
  });
152
159
  if (file && (tsSourceFile = tsLs.getProgram()?.getSourceFile(file.fileName))) {
153
- const componentsNode = getComponentsNode(ts, tsSourceFile);
160
+ const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
154
161
  const checker = tsLs.getProgram()?.getTypeChecker();
155
- if (checker && componentsNode) {
162
+ if (checker && node) {
156
163
  return {
157
- componentsNode,
158
- componentsType: checker.getTypeAtLocation(componentsNode),
164
+ node: node,
165
+ type: checker.getTypeAtLocation(node),
159
166
  };
160
167
  }
161
168
  }
162
- function getComponentsNode(ts, sourceFile) {
163
- let componentsNode;
164
- walk(sourceFile);
165
- return componentsNode;
166
- function walk(node) {
167
- if (componentsNode) {
168
- return;
169
- }
170
- else if (ts.isVariableDeclaration(node) && node.name.getText() === '__VLS_components') {
171
- componentsNode = node;
172
- }
173
- else {
174
- node.forEachChild(walk);
175
- }
169
+ }
170
+ function searchVariableDeclarationNode(ts, sourceFile, name) {
171
+ let componentsNode;
172
+ walk(sourceFile);
173
+ return componentsNode;
174
+ function walk(node) {
175
+ if (componentsNode) {
176
+ return;
177
+ }
178
+ else if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
179
+ componentsNode = node;
180
+ }
181
+ else {
182
+ node.forEachChild(walk);
176
183
  }
177
184
  }
178
185
  }
@@ -16,7 +16,7 @@ async function convertTagName(ts, context, uri, casing, vueCompilerOptions) {
16
16
  const template = desc.template;
17
17
  const document = context.documents.getDocumentByFileName(rootFile.snapshot, rootFile.fileName);
18
18
  const edits = [];
19
- const components = (0, helpers_1.checkComponentNames)(ts, languageService, rootFile, vueCompilerOptions);
19
+ const components = (0, helpers_1.getComponentNames)(ts, languageService, rootFile, vueCompilerOptions);
20
20
  const tags = (0, helpers_1.getTemplateTagsAndAttrs)(rootFile);
21
21
  for (const [tagName, { offsets }] of tags) {
22
22
  const componentName = components.find(component => component === tagName || (0, shared_1.hyphenate)(component) === tagName);
@@ -48,12 +48,12 @@ async function convertAttrName(ts, context, uri, casing, vueCompilerOptions) {
48
48
  const template = desc.template;
49
49
  const document = context.documents.getDocumentByFileName(rootFile.snapshot, rootFile.fileName);
50
50
  const edits = [];
51
- const components = (0, helpers_1.checkComponentNames)(ts, languageService, rootFile, vueCompilerOptions);
51
+ const components = (0, helpers_1.getComponentNames)(ts, languageService, rootFile, vueCompilerOptions);
52
52
  const tags = (0, helpers_1.getTemplateTagsAndAttrs)(rootFile);
53
53
  for (const [tagName, { attrs }] of tags) {
54
54
  const componentName = components.find(component => component === tagName || (0, shared_1.hyphenate)(component) === tagName);
55
55
  if (componentName) {
56
- const props = (0, helpers_1.checkPropsOfTag)(ts, languageService, rootFile, componentName, vueCompilerOptions);
56
+ const props = (0, helpers_1.getPropsByTag)(ts, languageService, rootFile, componentName, vueCompilerOptions);
57
57
  for (const [attrName, { offsets }] of attrs) {
58
58
  const propName = props.find(prop => prop === attrName || (0, shared_1.hyphenate)(prop) === attrName);
59
59
  if (propName) {
@@ -124,7 +124,7 @@ function detect(ts, context, uri, vueCompilerOptions) {
124
124
  return result;
125
125
  }
126
126
  function getTagNameCase(file) {
127
- const components = (0, helpers_1.checkComponentNames)(ts, languageService, file, vueCompilerOptions);
127
+ const components = (0, helpers_1.getComponentNames)(ts, languageService, file, vueCompilerOptions);
128
128
  const tagNames = (0, helpers_1.getTemplateTagsAndAttrs)(file);
129
129
  const result = [];
130
130
  let anyComponentUsed = false;
@@ -32,23 +32,16 @@ function resolveConfig(config, compilerOptions = {}, vueCompilerOptions = {}, ts
32
32
  return config;
33
33
  }
34
34
  exports.resolveConfig = resolveConfig;
35
- const unicodeReg = /\\u/g;
36
35
  function resolvePlugins(services, vueCompilerOptions) {
37
36
  const originalTsPlugin = services?.typescript ?? (0, volar_service_typescript_1.default)();
38
37
  services ??= {};
39
- services.typescript = (_context, modules) => {
40
- const base = typeof originalTsPlugin === 'function' ? originalTsPlugin(_context, modules) : originalTsPlugin;
41
- if (!_context || !modules?.typescript)
38
+ services.typescript = (ctx, modules) => {
39
+ const base = typeof originalTsPlugin === 'function' ? originalTsPlugin(ctx, modules) : originalTsPlugin;
40
+ if (!ctx || !modules?.typescript)
42
41
  return base;
43
42
  const ts = modules.typescript;
44
- const transformedItem = new WeakSet();
45
43
  return {
46
44
  ...base,
47
- transformCompletionItem(item) {
48
- if (transformedItem.has(item)) {
49
- return item;
50
- }
51
- },
52
45
  async provideCompletionItems(document, position, context, item) {
53
46
  const result = await base.provideCompletionItems?.(document, position, context, item);
54
47
  if (result) {
@@ -57,18 +50,18 @@ function resolvePlugins(services, vueCompilerOptions) {
57
50
  && (!item.labelDetails?.description || item.labelDetails.description.indexOf('__VLS_') === -1));
58
51
  // handle component auto-import patch
59
52
  let casing;
60
- for (const [_, map] of _context.documents.getMapsByVirtualFileUri(document.uri)) {
61
- const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
53
+ for (const [_, map] of ctx.documents.getMapsByVirtualFileUri(document.uri)) {
54
+ const virtualFile = ctx.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
62
55
  if (virtualFile instanceof vue.VueFile) {
63
56
  const isAutoImport = !!map.toSourcePosition(position, data => typeof data.completion === 'object' && !!data.completion.autoImportOnly);
64
57
  if (isAutoImport) {
65
- const source = _context.documents.getVirtualFileByUri(document.uri)[1];
58
+ const source = ctx.documents.getVirtualFileByUri(document.uri)[1];
66
59
  for (const item of result.items) {
67
60
  item.data.__isComponentAutoImport = true;
68
61
  }
69
62
  // fix #2458
70
63
  if (source) {
71
- casing ??= await (0, nameCasing_1.getNameCasing)(ts, _context, _context.env.fileNameToUri(source.fileName), vueCompilerOptions);
64
+ casing ??= await (0, nameCasing_1.getNameCasing)(ts, ctx, ctx.env.fileNameToUri(source.fileName), vueCompilerOptions);
72
65
  if (casing.tag === types_1.TagNameCasing.Kebab) {
73
66
  for (const item of result.items) {
74
67
  item.filterText = (0, shared_1.hyphenate)(item.filterText ?? item.label);
@@ -93,7 +86,7 @@ function resolvePlugins(services, vueCompilerOptions) {
93
86
  if (itemData?.uri
94
87
  && item.textEdit?.newText.endsWith(suffix)
95
88
  && item.additionalTextEdits?.length === 1 && item.additionalTextEdits[0].newText.indexOf('import ' + item.textEdit.newText + ' from ') >= 0
96
- && (await _context.env.getConfiguration?.('vue.complete.normalizeComponentImportName') ?? true)) {
89
+ && (await ctx.env.getConfiguration?.('vue.complete.normalizeComponentImportName') ?? true)) {
97
90
  newName = item.textEdit.newText.slice(0, -suffix.length);
98
91
  newName = newName[0].toUpperCase() + newName.substring(1);
99
92
  if (newName === 'Index') {
@@ -108,9 +101,9 @@ function resolvePlugins(services, vueCompilerOptions) {
108
101
  }
109
102
  item.additionalTextEdits[0].newText = item.additionalTextEdits[0].newText.replace('import ' + item.textEdit.newText + ' from ', 'import ' + newName + ' from ');
110
103
  item.textEdit.newText = newName;
111
- const source = _context.documents.getVirtualFileByUri(itemData.uri)[1];
104
+ const source = ctx.documents.getVirtualFileByUri(itemData.uri)[1];
112
105
  if (source) {
113
- const casing = await (0, nameCasing_1.getNameCasing)(ts, _context, _context.env.fileNameToUri(source.fileName), vueCompilerOptions);
106
+ const casing = await (0, nameCasing_1.getNameCasing)(ts, ctx, ctx.env.fileNameToUri(source.fileName), vueCompilerOptions);
114
107
  if (casing.tag === types_1.TagNameCasing.Kebab) {
115
108
  item.textEdit.newText = (0, shared_1.hyphenate)(item.textEdit.newText);
116
109
  }
@@ -122,65 +115,26 @@ function resolvePlugins(services, vueCompilerOptions) {
122
115
  }
123
116
  }
124
117
  const data = item.data;
125
- if (item.data?.__isComponentAutoImport && data && item.additionalTextEdits?.length && item.textEdit) {
126
- let transformed = false;
127
- for (const [_, map] of _context.documents.getMapsByVirtualFileUri(data.uri)) {
128
- const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
129
- if (virtualFile instanceof vue.VueFile) {
130
- const sfc = virtualFile.sfc;
131
- const componentName = newName ?? item.textEdit.newText;
132
- const textDoc = _context.documents.getDocumentByFileName(virtualFile.snapshot, virtualFile.fileName);
133
- if (sfc.scriptAst && sfc.script) {
134
- const _scriptRanges = vue.scriptRanges.parseScriptRanges(ts, sfc.scriptAst, !!sfc.scriptSetup, true);
135
- const exportDefault = _scriptRanges.exportDefault;
136
- if (exportDefault) {
137
- // https://github.com/microsoft/TypeScript/issues/36174
138
- const printer = ts.createPrinter();
139
- if (exportDefault.componentsOption && exportDefault.componentsOptionNode) {
140
- const newNode = {
141
- ...exportDefault.componentsOptionNode,
142
- properties: [
143
- ...exportDefault.componentsOptionNode.properties,
144
- ts.factory.createShorthandPropertyAssignment(componentName),
145
- ],
146
- };
147
- const printText = printer.printNode(ts.EmitHint.Expression, newNode, sfc.scriptAst);
148
- const editRange = {
149
- start: textDoc.positionAt(sfc.script.startTagEnd + exportDefault.componentsOption.start),
150
- end: textDoc.positionAt(sfc.script.startTagEnd + exportDefault.componentsOption.end),
151
- };
152
- transformed = true;
153
- item.additionalTextEdits.push({
154
- range: editRange,
155
- newText: unescape(printText.replace(unicodeReg, '%u')),
156
- });
157
- }
158
- else if (exportDefault.args && exportDefault.argsNode) {
159
- const newNode = {
160
- ...exportDefault.argsNode,
161
- properties: [
162
- ...exportDefault.argsNode.properties,
163
- ts.factory.createShorthandPropertyAssignment(`components: { ${componentName} }`),
164
- ],
165
- };
166
- const printText = printer.printNode(ts.EmitHint.Expression, newNode, sfc.scriptAst);
167
- const editRange = {
168
- start: textDoc.positionAt(sfc.script.startTagEnd + exportDefault.args.start),
169
- end: textDoc.positionAt(sfc.script.startTagEnd + exportDefault.args.end),
170
- };
171
- transformed = true;
172
- item.additionalTextEdits.push({
173
- range: editRange,
174
- newText: unescape(printText.replace(unicodeReg, '%u')),
175
- });
176
- }
177
- }
178
- }
118
+ if (item.data?.__isComponentAutoImport && data && item.additionalTextEdits?.length && item.textEdit && itemData?.uri) {
119
+ const fileName = ctx.env.uriToFileName(itemData.uri);
120
+ const langaugeService = ctx.inject('typescript/languageService');
121
+ const [virtualFile] = ctx.virtualFiles.getVirtualFile(fileName);
122
+ const ast = langaugeService.getProgram()?.getSourceFile(fileName);
123
+ const exportDefault = ast ? vue.scriptRanges.parseScriptRanges(ts, ast, false, true).exportDefault : undefined;
124
+ if (virtualFile && ast && exportDefault) {
125
+ const componentName = newName ?? item.textEdit.newText;
126
+ const optionEdit = (0, vue_extract_file_1.createAddComponentToOptionEdit)(ts, ast, componentName);
127
+ if (optionEdit) {
128
+ const textDoc = ctx.documents.getDocumentByFileName(virtualFile.snapshot, virtualFile.fileName);
129
+ item.additionalTextEdits.push({
130
+ range: {
131
+ start: textDoc.positionAt(optionEdit.range.start),
132
+ end: textDoc.positionAt(optionEdit.range.end),
133
+ },
134
+ newText: optionEdit.newText,
135
+ });
179
136
  }
180
137
  }
181
- if (transformed) {
182
- transformedItem.add(item);
183
- }
184
138
  }
185
139
  return item;
186
140
  },
@@ -1,2 +1,7 @@
1
1
  import { Service } from '@volar/language-service';
2
+ import type * as ts from 'typescript/lib/tsserverlibrary';
2
3
  export default function (): Service;
4
+ export declare function createAddComponentToOptionEdit(ts: typeof import('typescript/lib/tsserverlibrary'), ast: ts.SourceFile, componentName: string): {
5
+ range: import("@vue/language-core").TextRange;
6
+ newText: string;
7
+ } | undefined;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAddComponentToOptionEdit = void 0;
3
4
  const language_core_1 = require("@vue/language-core");
5
+ const unicodeReg = /\\u/g;
4
6
  function default_1() {
5
7
  return (ctx, modules) => {
6
8
  if (!modules?.typescript)
@@ -65,6 +67,37 @@ function default_1() {
65
67
  if (sfc.template.startTagEnd > script.startTagEnd) {
66
68
  newFileTags = newFileTags.reverse();
67
69
  }
70
+ const currentFileEdits = [
71
+ {
72
+ range: {
73
+ start: document.positionAt(sfc.template.startTagEnd + templateCodeRange[0]),
74
+ end: document.positionAt(sfc.template.startTagEnd + templateCodeRange[1]),
75
+ },
76
+ newText: generateReplaceTemplate(),
77
+ },
78
+ {
79
+ range: lastImportNode ? {
80
+ start: document.positionAt(script.startTagEnd + lastImportNode.end),
81
+ end: document.positionAt(script.startTagEnd + lastImportNode.end),
82
+ } : {
83
+ start: document.positionAt(script.startTagEnd),
84
+ end: document.positionAt(script.startTagEnd),
85
+ },
86
+ newText: `\nimport ${newName} from './${newName}.vue'`,
87
+ },
88
+ ];
89
+ if (sfc.script && sfc.scriptAst) {
90
+ const edit = createAddComponentToOptionEdit(ts, sfc.scriptAst, newName);
91
+ if (edit) {
92
+ currentFileEdits.push({
93
+ range: {
94
+ start: document.positionAt(sfc.script.startTagEnd + edit.range.start),
95
+ end: document.positionAt(sfc.script.startTagEnd + edit.range.end),
96
+ },
97
+ newText: edit.newText,
98
+ });
99
+ }
100
+ }
68
101
  return {
69
102
  ...codeAction,
70
103
  edit: {
@@ -75,25 +108,7 @@ function default_1() {
75
108
  uri: document.uri,
76
109
  version: null,
77
110
  },
78
- edits: [
79
- {
80
- range: {
81
- start: document.positionAt(sfc.template.startTagEnd + templateCodeRange[0]),
82
- end: document.positionAt(sfc.template.startTagEnd + templateCodeRange[1]),
83
- },
84
- newText: generateReplaceTemplate(),
85
- },
86
- {
87
- range: lastImportNode ? {
88
- start: document.positionAt(script.startTagEnd + lastImportNode.end),
89
- end: document.positionAt(script.startTagEnd + lastImportNode.end),
90
- } : {
91
- start: document.positionAt(script.startTagEnd),
92
- end: document.positionAt(script.startTagEnd),
93
- },
94
- newText: `\nimport ${newName} from './${newName}.vue'`,
95
- },
96
- ],
111
+ edits: currentFileEdits,
97
112
  },
98
113
  // creating new file with content
99
114
  {
@@ -198,11 +213,26 @@ function selectTemplateCode(startOffset, endOffset, templateBlock, templateAst)
198
213
  if (startOffset < templateBlock.startTagEnd || endOffset > templateBlock.endTagStart)
199
214
  return;
200
215
  const insideNodes = [];
201
- (0, language_core_1.walkElementNodes)(templateAst, (node) => {
216
+ templateAst.children.forEach(function visit(node) {
202
217
  if (node.loc.start.offset + templateBlock.startTagEnd >= startOffset
203
218
  && node.loc.end.offset + templateBlock.startTagEnd <= endOffset) {
204
219
  insideNodes.push(node);
205
220
  }
221
+ if ('children' in node) {
222
+ node.children.forEach(node => {
223
+ if (typeof node === 'object') {
224
+ visit(node);
225
+ }
226
+ });
227
+ }
228
+ else if ('branches' in node) {
229
+ node.branches.forEach(visit);
230
+ }
231
+ else if ('content' in node) {
232
+ if (typeof node.content === 'object') {
233
+ visit(node.content);
234
+ }
235
+ }
206
236
  });
207
237
  if (insideNodes.length) {
208
238
  const first = insideNodes.sort((a, b) => a.loc.start.offset - b.loc.start.offset)[0];
@@ -225,4 +255,40 @@ function isInitialIndentNeeded(ts, languageKind, initialIndentSetting) {
225
255
  };
226
256
  return initialIndentSetting[languageKindIdMap[languageKind]] ?? false;
227
257
  }
258
+ function createAddComponentToOptionEdit(ts, ast, componentName) {
259
+ const exportDefault = language_core_1.scriptRanges.parseScriptRanges(ts, ast, false, true).exportDefault;
260
+ if (!exportDefault)
261
+ return;
262
+ // https://github.com/microsoft/TypeScript/issues/36174
263
+ const printer = ts.createPrinter();
264
+ if (exportDefault.componentsOption && exportDefault.componentsOptionNode) {
265
+ const newNode = {
266
+ ...exportDefault.componentsOptionNode,
267
+ properties: [
268
+ ...exportDefault.componentsOptionNode.properties,
269
+ ts.factory.createShorthandPropertyAssignment(componentName),
270
+ ],
271
+ };
272
+ const printText = printer.printNode(ts.EmitHint.Expression, newNode, ast);
273
+ return {
274
+ range: exportDefault.componentsOption,
275
+ newText: unescape(printText.replace(unicodeReg, '%u')),
276
+ };
277
+ }
278
+ else if (exportDefault.args && exportDefault.argsNode) {
279
+ const newNode = {
280
+ ...exportDefault.argsNode,
281
+ properties: [
282
+ ...exportDefault.argsNode.properties,
283
+ ts.factory.createShorthandPropertyAssignment(`components: { ${componentName} }`),
284
+ ],
285
+ };
286
+ const printText = printer.printNode(ts.EmitHint.Expression, newNode, ast);
287
+ return {
288
+ range: exportDefault.args,
289
+ newText: unescape(printText.replace(unicodeReg, '%u')),
290
+ };
291
+ }
292
+ }
293
+ exports.createAddComponentToOptionEdit = createAddComponentToOptionEdit;
228
294
  //# sourceMappingURL=vue-extract-file.js.map
@@ -85,7 +85,7 @@ exports.default = (options) => (_context, modules) => {
85
85
  if (virtualFile && virtualFile instanceof vue.VueFile && scanner) {
86
86
  // visualize missing required props
87
87
  const casing = await (0, nameCasing_1.getNameCasing)(ts, _context, map.sourceFileDocument.uri, options.vueCompilerOptions);
88
- const components = (0, helpers_1.checkComponentNames)(ts, languageService, virtualFile, options.vueCompilerOptions);
88
+ const components = (0, helpers_1.getComponentNames)(ts, languageService, virtualFile, options.vueCompilerOptions);
89
89
  const componentProps = {};
90
90
  let token;
91
91
  let current;
@@ -97,7 +97,7 @@ exports.default = (options) => (_context, modules) => {
97
97
  : components.find(component => component === tagName || (0, shared_1.hyphenate)(component) === tagName);
98
98
  const checkTag = tagName.indexOf('.') >= 0 ? tagName : component;
99
99
  if (checkTag) {
100
- componentProps[checkTag] ??= (0, helpers_1.checkPropsOfTag)(ts, languageService, virtualFile, checkTag, options.vueCompilerOptions, true);
100
+ componentProps[checkTag] ??= (0, helpers_1.getPropsByTag)(ts, languageService, virtualFile, checkTag, options.vueCompilerOptions, true);
101
101
  current = {
102
102
  unburnedRequiredProps: [...componentProps[checkTag]],
103
103
  labelOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
@@ -229,7 +229,7 @@ exports.default = (options) => (_context, modules) => {
229
229
  const virtualFile = _context.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
230
230
  if (!virtualFile || !(virtualFile instanceof vue.VueFile))
231
231
  continue;
232
- const templateScriptData = (0, helpers_1.checkComponentNames)(ts, languageService, virtualFile, options.vueCompilerOptions);
232
+ const templateScriptData = (0, helpers_1.getComponentNames)(ts, languageService, virtualFile, options.vueCompilerOptions);
233
233
  const components = new Set([
234
234
  ...templateScriptData,
235
235
  ...templateScriptData.map(shared_1.hyphenate),
@@ -290,7 +290,7 @@ exports.default = (options) => (_context, modules) => {
290
290
  getId: () => 'vue-template',
291
291
  isApplicable: () => true,
292
292
  provideTags: () => {
293
- const components = (0, helpers_1.checkComponentNames)(ts, languageService, vueSourceFile, options.vueCompilerOptions)
293
+ const components = (0, helpers_1.getComponentNames)(ts, languageService, vueSourceFile, options.vueCompilerOptions)
294
294
  .filter(name => name !== 'Transition'
295
295
  && name !== 'TransitionGroup'
296
296
  && name !== 'KeepAlive'
@@ -326,9 +326,24 @@ exports.default = (options) => (_context, modules) => {
326
326
  },
327
327
  provideAttributes: (tag) => {
328
328
  const attrs = (0, helpers_1.getElementAttrs)(ts, languageService, languageServiceHost, tag);
329
- const props = new Set((0, helpers_1.checkPropsOfTag)(ts, languageService, vueSourceFile, tag, options.vueCompilerOptions));
330
- const events = (0, helpers_1.checkEventsOfTag)(ts, languageService, vueSourceFile, tag, options.vueCompilerOptions);
329
+ const props = new Set((0, helpers_1.getPropsByTag)(ts, languageService, vueSourceFile, tag, options.vueCompilerOptions));
330
+ const events = (0, helpers_1.getEventsOfTag)(ts, languageService, vueSourceFile, tag, options.vueCompilerOptions);
331
331
  const attributes = [];
332
+ const tsCodegen = vue.tsCodegen.get(vueSourceFile.sfc);
333
+ if (tsCodegen) {
334
+ let ctxVars = [
335
+ ...tsCodegen.scriptRanges.value?.bindings.map(binding => vueSourceFile.sfc.script.content.substring(binding.start, binding.end)) ?? [],
336
+ ...tsCodegen.scriptSetupRanges.value?.bindings.map(binding => vueSourceFile.sfc.scriptSetup.content.substring(binding.start, binding.end)) ?? [],
337
+ ...(0, helpers_1.getTemplateCtx)(ts, languageService, vueSourceFile) ?? [],
338
+ ];
339
+ ctxVars = [...new Set(ctxVars)];
340
+ const dirs = ctxVars.map(shared_1.hyphenate).filter(v => v.startsWith('v-'));
341
+ for (const dir of dirs) {
342
+ attributes.push({
343
+ name: dir,
344
+ });
345
+ }
346
+ }
332
347
  for (const prop of [...props, ...attrs]) {
333
348
  const isGlobal = !props.has(prop);
334
349
  const name = casing.attr === types_1.AttrNameCasing.Camel ? prop : (0, shared_1.hyphenate)(prop);
@@ -407,7 +422,7 @@ exports.default = (options) => (_context, modules) => {
407
422
  function afterHtmlCompletion(completionList, map, vueSourceFile) {
408
423
  const languageService = _context.inject('typescript/languageService');
409
424
  const replacement = getReplacement(completionList, map.sourceFileDocument);
410
- const componentNames = new Set((0, helpers_1.checkComponentNames)(ts, languageService, vueSourceFile, options.vueCompilerOptions).map(shared_1.hyphenate));
425
+ const componentNames = new Set((0, helpers_1.getComponentNames)(ts, languageService, vueSourceFile, options.vueCompilerOptions).map(shared_1.hyphenate));
411
426
  if (replacement) {
412
427
  const isEvent = replacement.text.startsWith('v-on:') || replacement.text.startsWith('@');
413
428
  const isProp = replacement.text.startsWith('v-bind:') || replacement.text.startsWith(':');
@@ -469,39 +484,37 @@ exports.default = (options) => (_context, modules) => {
469
484
  if (itemId) {
470
485
  item.documentation = undefined;
471
486
  }
472
- if (itemIdKey && itemId) {
473
- if (itemId.type === 'componentProp' || itemId.type === 'componentEvent') {
474
- const [componentName] = itemId.args;
487
+ if (item.kind === 10 && componentNames.has((0, shared_1.hyphenate)(item.label))) {
488
+ item.kind = 6;
489
+ item.sortText = '\u0000' + (item.sortText ?? item.label);
490
+ }
491
+ else if (itemId && (itemId.type === 'componentProp' || itemId.type === 'componentEvent')) {
492
+ const [componentName] = itemId.args;
493
+ if (componentName !== '*') {
494
+ item.sortText = '\u0000' + (item.sortText ?? item.label);
495
+ }
496
+ if (itemId.type === 'componentProp') {
475
497
  if (componentName !== '*') {
476
- item.sortText = '\u0000' + (item.sortText ?? item.label);
498
+ item.kind = 5;
477
499
  }
478
- if (itemId.type === 'componentProp') {
479
- if (componentName !== '*') {
480
- item.kind = 5;
481
- }
482
- }
483
- else {
484
- item.kind = componentName !== '*' ? 3 : 23;
485
- }
486
- }
487
- else if (item.label === 'v-if'
488
- || item.label === 'v-else-if'
489
- || item.label === 'v-else'
490
- || item.label === 'v-for') {
491
- item.kind = 2;
492
- item.sortText = '\u0003' + (item.sortText ?? item.label);
493
- }
494
- else if (item.label.startsWith('v-')) {
495
- item.kind = 3;
496
- item.sortText = '\u0002' + (item.sortText ?? item.label);
497
500
  }
498
501
  else {
499
- item.sortText = '\u0001' + (item.sortText ?? item.label);
502
+ item.kind = componentName !== '*' ? 3 : 23;
500
503
  }
501
504
  }
502
- else if (item.kind === 10 && componentNames.has((0, shared_1.hyphenate)(item.label))) {
503
- item.kind = 6;
504
- item.sortText = '\u0000' + (item.sortText ?? item.label);
505
+ else if (item.label === 'v-if'
506
+ || item.label === 'v-else-if'
507
+ || item.label === 'v-else'
508
+ || item.label === 'v-for') {
509
+ item.kind = 14;
510
+ item.sortText = '\u0003' + (item.sortText ?? item.label);
511
+ }
512
+ else if (item.label.startsWith('v-')) {
513
+ item.kind = 3;
514
+ item.sortText = '\u0002' + (item.sortText ?? item.label);
515
+ }
516
+ else {
517
+ item.sortText = '\u0001' + (item.sortText ?? item.label);
505
518
  }
506
519
  }
507
520
  options.updateCustomData(htmlOrPugService, []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue/language-service",
3
- "version": "1.8.6",
3
+ "version": "1.8.8",
4
4
  "main": "out/index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -17,28 +17,28 @@
17
17
  "update-html-data": "node ./scripts/update-html-data.js"
18
18
  },
19
19
  "dependencies": {
20
- "@volar/language-core": "~1.9.0",
21
- "@volar/language-service": "~1.9.0",
22
- "@volar/typescript": "~1.9.0",
20
+ "@volar/language-core": "~1.10.0",
21
+ "@volar/language-service": "~1.10.0",
22
+ "@volar/typescript": "~1.10.0",
23
23
  "@vue/compiler-dom": "^3.3.0",
24
- "@vue/language-core": "1.8.6",
24
+ "@vue/language-core": "1.8.8",
25
25
  "@vue/reactivity": "^3.3.0",
26
26
  "@vue/shared": "^3.3.0",
27
- "volar-service-css": "0.0.10",
28
- "volar-service-emmet": "0.0.10",
29
- "volar-service-html": "0.0.10",
30
- "volar-service-json": "0.0.10",
31
- "volar-service-pug": "0.0.10",
32
- "volar-service-pug-beautify": "0.0.10",
33
- "volar-service-typescript": "0.0.10",
34
- "volar-service-typescript-twoslash-queries": "0.0.10",
27
+ "volar-service-css": "0.0.11",
28
+ "volar-service-emmet": "0.0.11",
29
+ "volar-service-html": "0.0.11",
30
+ "volar-service-json": "0.0.11",
31
+ "volar-service-pug": "0.0.11",
32
+ "volar-service-pug-beautify": "0.0.11",
33
+ "volar-service-typescript": "0.0.11",
34
+ "volar-service-typescript-twoslash-queries": "0.0.11",
35
35
  "vscode-html-languageservice": "^5.0.4",
36
36
  "vscode-languageserver-textdocument": "^1.0.8"
37
37
  },
38
38
  "devDependencies": {
39
- "@volar/kit": "~1.9.0",
39
+ "@volar/kit": "~1.10.0",
40
40
  "vscode-languageserver-protocol": "^3.17.3",
41
41
  "vscode-uri": "^3.0.7"
42
42
  },
43
- "gitHead": "9da8afee02bc7251ae97716480ba31f8aff2794a"
43
+ "gitHead": "62a08c35722319bcca90ea3ebd3236fbd986a6a6"
44
44
  }