@vue/typescript-plugin 2.2.6 → 3.0.0-alpha.0

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/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import type * as ts from 'typescript';
2
- declare const plugin: ts.server.PluginModuleFactory;
3
- export = plugin;
2
+ declare const _default: ts.server.PluginModuleFactory;
3
+ export = _default;
package/index.js CHANGED
@@ -2,21 +2,27 @@
2
2
  const createLanguageServicePlugin_1 = require("@volar/typescript/lib/quickstart/createLanguageServicePlugin");
3
3
  const vue = require("@vue/language-core");
4
4
  const common_1 = require("./lib/common");
5
- const server_1 = require("./lib/server");
5
+ const collectExtractProps_1 = require("./lib/requests/collectExtractProps");
6
+ const getComponentDirectives_1 = require("./lib/requests/getComponentDirectives");
7
+ const getComponentEvents_1 = require("./lib/requests/getComponentEvents");
8
+ const getComponentNames_1 = require("./lib/requests/getComponentNames");
9
+ const getComponentProps_1 = require("./lib/requests/getComponentProps");
10
+ const getElementAttrs_1 = require("./lib/requests/getElementAttrs");
11
+ const getElementNames_1 = require("./lib/requests/getElementNames");
12
+ const getImportPathForFile_1 = require("./lib/requests/getImportPathForFile");
13
+ const getPropertiesAtLocation_1 = require("./lib/requests/getPropertiesAtLocation");
14
+ const getQuickInfoAtPosition_1 = require("./lib/requests/getQuickInfoAtPosition");
6
15
  const windowsPathReg = /\\/g;
7
- const vueCompilerOptions = new WeakMap();
8
- const plugin = (0, createLanguageServicePlugin_1.createLanguageServicePlugin)((ts, info) => {
16
+ const project2Service = new WeakMap();
17
+ module.exports = (0, createLanguageServicePlugin_1.createLanguageServicePlugin)((ts, info) => {
9
18
  const vueOptions = getVueCompilerOptions();
10
19
  const languagePlugin = vue.createVueLanguagePlugin(ts, info.languageServiceHost.getCompilationSettings(), vueOptions, id => id);
11
- vueCompilerOptions.set(info.project, vueOptions);
20
+ addVueCommands();
12
21
  return {
13
22
  languagePlugins: [languagePlugin],
14
23
  setup: language => {
24
+ project2Service.set(info.project, [language, info.languageServiceHost, info.languageService]);
15
25
  info.languageService = (0, common_1.proxyLanguageServiceForVue)(ts, language, info.languageService, vueOptions, fileName => fileName);
16
- if (info.project.projectKind === ts.server.ProjectKind.Configured
17
- || info.project.projectKind === ts.server.ProjectKind.Inferred) {
18
- (0, server_1.startNamedPipeServer)(ts, info, language, info.project.projectKind);
19
- }
20
26
  // #3963
21
27
  const timer = setInterval(() => {
22
28
  if (info.project['program']) {
@@ -35,6 +41,93 @@ const plugin = (0, createLanguageServicePlugin_1.createLanguageServicePlugin)((t
35
41
  return vue.createParsedCommandLineByJson(ts, ts.sys, info.languageServiceHost.getCurrentDirectory(), {}).vueOptions;
36
42
  }
37
43
  }
44
+ // https://github.com/JetBrains/intellij-plugins/blob/6435723ad88fa296b41144162ebe3b8513f4949b/Angular/src-js/angular-service/src/index.ts#L69
45
+ function addVueCommands() {
46
+ const projectService = info.project.projectService;
47
+ projectService.logger.info("Vue: called handler processing " + info.project.projectKind);
48
+ const session = info.session;
49
+ if (session == undefined) {
50
+ projectService.logger.info("Vue: there is no session in info.");
51
+ return;
52
+ }
53
+ if (session.addProtocolHandler == undefined) {
54
+ // addProtocolHandler was introduced in TS 4.4 or 4.5 in 2021, see https://github.com/microsoft/TypeScript/issues/43893
55
+ projectService.logger.info("Vue: there is no addProtocolHandler method.");
56
+ return;
57
+ }
58
+ if (session.vueCommandsAdded) {
59
+ return;
60
+ }
61
+ session.vueCommandsAdded = true;
62
+ session.addProtocolHandler('vue:collectExtractProps', ({ arguments: args }) => {
63
+ return {
64
+ response: collectExtractProps_1.collectExtractProps.apply(getRequestContext(args[0]), args),
65
+ };
66
+ });
67
+ session.addProtocolHandler('vue:getImportPathForFile', ({ arguments: args }) => {
68
+ return {
69
+ response: getImportPathForFile_1.getImportPathForFile.apply(getRequestContext(args[0]), args),
70
+ };
71
+ });
72
+ session.addProtocolHandler('vue:getPropertiesAtLocation', ({ arguments: args }) => {
73
+ return {
74
+ response: getPropertiesAtLocation_1.getPropertiesAtLocation.apply(getRequestContext(args[0]), args),
75
+ };
76
+ });
77
+ session.addProtocolHandler('vue:getQuickInfoAtPosition', ({ arguments: args }) => {
78
+ return {
79
+ response: getQuickInfoAtPosition_1.getQuickInfoAtPosition.apply(getRequestContext(args[0]), args),
80
+ };
81
+ });
82
+ session.addProtocolHandler('vue:getComponentNames', ({ arguments: args }) => {
83
+ return {
84
+ response: getComponentNames_1.getComponentNames.apply(getRequestContext(args[0]), args) ?? [],
85
+ };
86
+ });
87
+ session.addProtocolHandler('vue:getComponentProps', ({ arguments: args }) => {
88
+ return {
89
+ response: getComponentProps_1.getComponentProps.apply(getRequestContext(args[0]), args),
90
+ };
91
+ });
92
+ session.addProtocolHandler('vue:getComponentEvents', ({ arguments: args }) => {
93
+ return {
94
+ response: getComponentEvents_1.getComponentEvents.apply(getRequestContext(args[0]), args),
95
+ };
96
+ });
97
+ session.addProtocolHandler('vue:getComponentDirectives', ({ arguments: args }) => {
98
+ return {
99
+ response: getComponentDirectives_1.getComponentDirectives.apply(getRequestContext(args[0]), args),
100
+ };
101
+ });
102
+ session.addProtocolHandler('vue:getElementAttrs', ({ arguments: args }) => {
103
+ return {
104
+ response: getElementAttrs_1.getElementAttrs.apply(getRequestContext(args[0]), args),
105
+ };
106
+ });
107
+ session.addProtocolHandler('vue:getElementNames', ({ arguments: args }) => {
108
+ return {
109
+ response: getElementNames_1.getElementNames.apply(getRequestContext(args[0]), args),
110
+ };
111
+ });
112
+ projectService.logger.info('Vue specific commands are successfully added.');
113
+ }
114
+ function getRequestContext(fileName) {
115
+ const fileAndProject = info.session.getFileAndProject({
116
+ file: fileName,
117
+ projectFileName: undefined,
118
+ });
119
+ const service = project2Service.get(fileAndProject.project);
120
+ if (!service) {
121
+ throw 'No RequestContext';
122
+ }
123
+ return {
124
+ typescript: ts,
125
+ languageService: service[2],
126
+ languageServiceHost: service[1],
127
+ language: service[0],
128
+ isTsPlugin: true,
129
+ getFileId: (fileName) => fileName,
130
+ };
131
+ }
38
132
  });
39
- module.exports = plugin;
40
133
  //# sourceMappingURL=index.js.map
package/lib/common.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { Language, VueCompilerOptions, VueVirtualCode } from '@vue/language-core';
1
+ import { Language, VueCompilerOptions } from '@vue/language-core';
2
2
  import type * as ts from 'typescript';
3
- import type { RequestContext } from './requests/types';
4
3
  export declare function proxyLanguageServiceForVue<T>(ts: typeof import('typescript'), language: Language<T>, languageService: ts.LanguageService, vueOptions: VueCompilerOptions, asScriptId: (fileName: string) => T): ts.LanguageService;
5
- export declare function getComponentSpans(this: Pick<RequestContext, 'typescript' | 'languageService'>, vueCode: VueVirtualCode, template: NonNullable<VueVirtualCode['_sfc']['template']>, spanTemplateRange: ts.TextSpan): ts.TextSpan[];
package/lib/common.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.proxyLanguageServiceForVue = proxyLanguageServiceForVue;
4
- exports.getComponentSpans = getComponentSpans;
5
4
  const language_core_1 = require("@vue/language-core");
6
5
  const shared_1 = require("@vue/shared");
7
6
  const getComponentNames_1 = require("./requests/getComponentNames");
7
+ const getElementNames_1 = require("./requests/getElementNames");
8
8
  const windowsPathReg = /\\/g;
9
9
  function proxyLanguageServiceForVue(ts, language, languageService, vueOptions, asScriptId) {
10
10
  const proxyCache = new Map();
@@ -13,6 +13,7 @@ function proxyLanguageServiceForVue(ts, language, languageService, vueOptions, a
13
13
  case 'getCompletionsAtPosition': return getCompletionsAtPosition(vueOptions, target[p]);
14
14
  case 'getCompletionEntryDetails': return getCompletionEntryDetails(language, asScriptId, target[p]);
15
15
  case 'getCodeFixesAtPosition': return getCodeFixesAtPosition(target[p]);
16
+ case 'getDefinitionAndBoundSpan': return getDefinitionAndBoundSpan(ts, language, languageService, vueOptions, asScriptId, target[p]);
16
17
  case 'getQuickInfoAtPosition': return getQuickInfoAtPosition(ts, target, target[p]);
17
18
  // TS plugin only
18
19
  case 'getEncodedSemanticClassifications': return getEncodedSemanticClassifications(ts, language, target, asScriptId, target[p]);
@@ -128,6 +129,77 @@ function getCodeFixesAtPosition(getCodeFixesAtPosition) {
128
129
  return result;
129
130
  };
130
131
  }
132
+ function getDefinitionAndBoundSpan(ts, language, languageService, vueOptions, asScriptId, getDefinitionAndBoundSpan) {
133
+ return (fileName, position) => {
134
+ const result = getDefinitionAndBoundSpan(fileName, position);
135
+ if (!result?.definitions?.length) {
136
+ return result;
137
+ }
138
+ const program = languageService.getProgram();
139
+ const sourceScript = language.scripts.get(asScriptId(fileName));
140
+ if (!sourceScript?.generated) {
141
+ return result;
142
+ }
143
+ const root = sourceScript.generated.root;
144
+ if (!(root instanceof language_core_1.VueVirtualCode)) {
145
+ return result;
146
+ }
147
+ if (!root.sfc.template
148
+ || position < root.sfc.template.startTagEnd
149
+ || position > root.sfc.template.endTagStart) {
150
+ return result;
151
+ }
152
+ const definitions = new Set(result.definitions);
153
+ const skippedDefinitions = [];
154
+ for (const definition of result.definitions) {
155
+ if (vueOptions.extensions.some(ext => definition.fileName.endsWith(ext))) {
156
+ continue;
157
+ }
158
+ const sourceFile = program.getSourceFile(definition.fileName);
159
+ if (!sourceFile) {
160
+ continue;
161
+ }
162
+ visit(sourceFile, definition, sourceFile);
163
+ }
164
+ for (const definition of skippedDefinitions) {
165
+ definitions.delete(definition);
166
+ }
167
+ return {
168
+ definitions: [...definitions],
169
+ textSpan: result.textSpan,
170
+ };
171
+ function visit(node, definition, sourceFile) {
172
+ if (ts.isPropertySignature(node) && node.type) {
173
+ proxy(node.name, node.type, definition, sourceFile);
174
+ }
175
+ else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.type && !node.initializer) {
176
+ proxy(node.name, node.type, definition, sourceFile);
177
+ }
178
+ else {
179
+ ts.forEachChild(node, child => visit(child, definition, sourceFile));
180
+ }
181
+ }
182
+ function proxy(name, type, definition, sourceFile) {
183
+ const { textSpan, fileName } = definition;
184
+ const start = name.getStart(sourceFile);
185
+ const end = name.getEnd();
186
+ if (start !== textSpan.start || end - start !== textSpan.length) {
187
+ return;
188
+ }
189
+ if (!ts.isIndexedAccessTypeNode(type)) {
190
+ return;
191
+ }
192
+ const pos = type.indexType.getStart(sourceFile);
193
+ const res = getDefinitionAndBoundSpan(fileName, pos);
194
+ if (res?.definitions?.length) {
195
+ for (const definition of res.definitions) {
196
+ definitions.add(definition);
197
+ }
198
+ skippedDefinitions.push(definition);
199
+ }
200
+ }
201
+ };
202
+ }
131
203
  function getQuickInfoAtPosition(ts, languageService, getQuickInfoAtPosition) {
132
204
  return (...args) => {
133
205
  const result = getQuickInfoAtPosition(...args);
@@ -191,6 +263,7 @@ function getComponentSpans(vueCode, template, spanTemplateRange) {
191
263
  const { typescript: ts, languageService } = this;
192
264
  const result = [];
193
265
  const validComponentNames = (0, getComponentNames_1._getComponentNames)(ts, languageService, vueCode);
266
+ const elements = new Set((0, getElementNames_1._getElementNames)(ts, languageService, vueCode));
194
267
  const components = new Set([
195
268
  ...validComponentNames,
196
269
  ...validComponentNames.map(language_core_1.hyphenateTag),
@@ -200,7 +273,7 @@ function getComponentSpans(vueCode, template, spanTemplateRange) {
200
273
  if (node.loc.end.offset <= spanTemplateRange.start || node.loc.start.offset >= (spanTemplateRange.start + spanTemplateRange.length)) {
201
274
  continue;
202
275
  }
203
- if (components.has(node.tag)) {
276
+ if (components.has(node.tag) && !elements.has(node.tag)) {
204
277
  let start = node.loc.start.offset;
205
278
  if (template.lang === 'html') {
206
279
  start += '<'.length;
@@ -1,29 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getElementAttrs = getElementAttrs;
4
- const vue = require("@vue/language-core");
4
+ const language_core_1 = require("@vue/language-core");
5
+ const utils_1 = require("./utils");
5
6
  function getElementAttrs(fileName, tagName) {
6
7
  const { typescript: ts, language, languageService, getFileId } = this;
7
8
  const volarFile = language.scripts.get(getFileId(fileName));
8
- if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
9
+ if (!(volarFile?.generated?.root instanceof language_core_1.VueVirtualCode)) {
9
10
  return;
10
11
  }
12
+ const vueCode = volarFile.generated.root;
11
13
  const program = languageService.getProgram();
12
- let tsSourceFile;
13
- if (tsSourceFile = program.getSourceFile(fileName)) {
14
- const checker = program.getTypeChecker();
15
- const typeNode = tsSourceFile.statements
16
- .filter(ts.isTypeAliasDeclaration)
17
- .find(node => node.name.getText() === '__VLS_IntrinsicElementsCompletion');
18
- if (checker && typeNode) {
19
- const type = checker.getTypeFromTypeNode(typeNode.type);
20
- const el = type.getProperty(tagName);
21
- if (el) {
22
- const attrs = checker.getTypeOfSymbolAtLocation(el, typeNode).getProperties();
23
- return attrs.map(c => c.name);
24
- }
25
- }
14
+ const checker = program.getTypeChecker();
15
+ const elements = (0, utils_1.getVariableType)(ts, languageService, vueCode, '__VLS_elements');
16
+ if (!elements) {
17
+ return [];
26
18
  }
27
- return [];
19
+ const elementType = elements.type.getProperty(tagName);
20
+ if (!elementType) {
21
+ return [];
22
+ }
23
+ const attrs = checker.getTypeOfSymbol(elementType).getProperties();
24
+ return attrs.map(c => c.name);
28
25
  }
29
26
  //# sourceMappingURL=getElementAttrs.js.map
@@ -0,0 +1,5 @@
1
+ import { VueVirtualCode } from '@vue/language-core';
2
+ import type * as ts from 'typescript';
3
+ import type { RequestContext } from './types';
4
+ export declare function getElementNames(this: RequestContext, fileName: string): string[] | undefined;
5
+ export declare function _getElementNames(ts: typeof import('typescript'), tsLs: ts.LanguageService, vueCode: VueVirtualCode): string[];
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getElementNames = getElementNames;
4
+ exports._getElementNames = _getElementNames;
5
+ const language_core_1 = require("@vue/language-core");
6
+ const utils_1 = require("./utils");
7
+ function getElementNames(fileName) {
8
+ const { typescript: ts, language, languageService, getFileId } = this;
9
+ const volarFile = language.scripts.get(getFileId(fileName));
10
+ if (!(volarFile?.generated?.root instanceof language_core_1.VueVirtualCode)) {
11
+ return;
12
+ }
13
+ const vueCode = volarFile.generated.root;
14
+ return _getElementNames(ts, languageService, vueCode);
15
+ }
16
+ function _getElementNames(ts, tsLs, vueCode) {
17
+ return (0, utils_1.getVariableType)(ts, tsLs, vueCode, '__VLS_elements')
18
+ ?.type
19
+ ?.getProperties()
20
+ .map(c => c.name)
21
+ ?? [];
22
+ }
23
+ //# sourceMappingURL=getElementNames.js.map
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ /// <reference types="@volar/typescript" />
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.getPropertiesAtLocation = getPropertiesAtLocation;
4
5
  const language_core_1 = require("@vue/language-core");
@@ -0,0 +1,14 @@
1
+ type ToRequest<T extends (...args: any) => any> = (...args: Parameters<T>) => Promise<ReturnType<T> | null | undefined>;
2
+ export type Requests = {
3
+ collectExtractProps: ToRequest<typeof import('./collectExtractProps.js')['collectExtractProps']>;
4
+ getImportPathForFile: ToRequest<typeof import('./getImportPathForFile.js')['getImportPathForFile']>;
5
+ getPropertiesAtLocation: ToRequest<typeof import('./getPropertiesAtLocation.js')['getPropertiesAtLocation']>;
6
+ getQuickInfoAtPosition: ToRequest<typeof import('./getQuickInfoAtPosition.js')['getQuickInfoAtPosition']>;
7
+ getComponentNames: ToRequest<typeof import('./getComponentNames.js')['getComponentNames']>;
8
+ getComponentProps: ToRequest<typeof import('./getComponentProps.js')['getComponentProps']>;
9
+ getComponentEvents: ToRequest<typeof import('./getComponentEvents.js')['getComponentEvents']>;
10
+ getComponentDirectives: ToRequest<typeof import('./getComponentDirectives.js')['getComponentDirectives']>;
11
+ getElementAttrs: ToRequest<typeof import('./getElementAttrs.js')['getElementAttrs']>;
12
+ getElementNames: ToRequest<typeof import('./getElementNames.js')['getElementNames']>;
13
+ };
14
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=index.js.map
@@ -36,11 +36,11 @@ function getSelfComponentName(fileName) {
36
36
  }
37
37
  function getVariableType(ts, languageService, vueCode, name) {
38
38
  const program = languageService.getProgram();
39
- let tsSourceFile;
40
- if (tsSourceFile = program.getSourceFile(vueCode.fileName)) {
41
- const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
39
+ const tsSourceFile = program.getSourceFile(vueCode.fileName);
40
+ if (tsSourceFile) {
42
41
  const checker = program.getTypeChecker();
43
- if (checker && node) {
42
+ const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
43
+ if (node) {
44
44
  return {
45
45
  node: node,
46
46
  type: checker.getTypeAtLocation(node),
@@ -49,15 +49,15 @@ function getVariableType(ts, languageService, vueCode, name) {
49
49
  }
50
50
  }
51
51
  function searchVariableDeclarationNode(ts, sourceFile, name) {
52
- let componentsNode;
52
+ let result;
53
53
  walk(sourceFile);
54
- return componentsNode;
54
+ return result;
55
55
  function walk(node) {
56
- if (componentsNode) {
56
+ if (result) {
57
57
  return;
58
58
  }
59
59
  else if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
60
- componentsNode = node;
60
+ result = node;
61
61
  }
62
62
  else {
63
63
  node.forEachChild(walk);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue/typescript-plugin",
3
- "version": "2.2.6",
3
+ "version": "3.0.0-alpha.0",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -14,11 +14,11 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@volar/typescript": "~2.4.11",
17
- "@vue/language-core": "2.2.6",
17
+ "@vue/language-core": "3.0.0-alpha.0",
18
18
  "@vue/shared": "^3.5.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^22.10.4"
22
22
  },
23
- "gitHead": "f2088e256dc0220db9549d28d9f865a5711dcfbe"
23
+ "gitHead": "4b49cbe09097e482def4603b90f6c3b93bb2e913"
24
24
  }
package/lib/client.d.ts DELETED
@@ -1,13 +0,0 @@
1
- export declare const collectExtractProps: (fileName: string, templateCodeRange: [number, number]) => Promise<{
2
- name: string;
3
- type: string;
4
- model: boolean;
5
- }[] | null | undefined>;
6
- export declare const getImportPathForFile: (fileName: string, incomingFileName: string, preferences: import("typescript").UserPreferences) => Promise<string | null | undefined>;
7
- export declare const getPropertiesAtLocation: (fileName: string, position: number) => Promise<string[] | null | undefined>;
8
- export declare const getQuickInfoAtPosition: (fileName: string, position: number) => Promise<string | null | undefined>;
9
- export declare function getComponentProps(fileName: string, componentName: string): Promise<import("./requests/getComponentProps").ComponentPropInfo[] | null | undefined>;
10
- export declare const getComponentEvents: (fileName: string, tag: string) => Promise<string[] | null | undefined>;
11
- export declare const getComponentDirectives: (fileName: string) => Promise<string[] | null | undefined>;
12
- export declare function getComponentNames(fileName: string): Promise<string[] | undefined>;
13
- export declare const getElementAttrs: (fileName: string, tagName: string) => Promise<string[] | null | undefined>;
package/lib/client.js DELETED
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getElementAttrs = exports.getComponentDirectives = exports.getComponentEvents = exports.getQuickInfoAtPosition = exports.getPropertiesAtLocation = exports.getImportPathForFile = exports.collectExtractProps = void 0;
4
- exports.getComponentProps = getComponentProps;
5
- exports.getComponentNames = getComponentNames;
6
- const utils_1 = require("./utils");
7
- exports.collectExtractProps = createRequest('collectExtractProps');
8
- exports.getImportPathForFile = createRequest('getImportPathForFile');
9
- exports.getPropertiesAtLocation = createRequest('getPropertiesAtLocation');
10
- exports.getQuickInfoAtPosition = createRequest('getQuickInfoAtPosition');
11
- // Component Infos
12
- async function getComponentProps(fileName, componentName) {
13
- const server = await (0, utils_1.getBestServer)(fileName);
14
- if (!server) {
15
- return;
16
- }
17
- return await server.getComponentProps(fileName, componentName);
18
- }
19
- exports.getComponentEvents = createRequest('getComponentEvents');
20
- exports.getComponentDirectives = createRequest('getComponentDirectives');
21
- async function getComponentNames(fileName) {
22
- const server = await (0, utils_1.getBestServer)(fileName);
23
- if (!server) {
24
- return;
25
- }
26
- const componentAndProps = server.componentNamesAndProps.get(fileName);
27
- if (!componentAndProps) {
28
- return;
29
- }
30
- return Object.keys(componentAndProps);
31
- }
32
- exports.getElementAttrs = createRequest('getElementAttrs');
33
- function createRequest(requestType) {
34
- return async function (...[fileName, ...rest]) {
35
- const server = await (0, utils_1.getBestServer)(fileName);
36
- if (!server) {
37
- return;
38
- }
39
- return server.sendRequest(requestType, fileName, ...rest);
40
- };
41
- }
42
- //# sourceMappingURL=client.js.map
@@ -1,13 +0,0 @@
1
- import * as vue from '@vue/language-core';
2
- import type * as ts from 'typescript';
3
- import type { RequestContext } from './types';
4
- export declare function getComponentProps(this: RequestContext, fileName: string, tag: string): {
5
- name: string;
6
- required?: true;
7
- commentMarkdown?: string;
8
- }[] | undefined;
9
- export declare function getComponentEvents(this: RequestContext, fileName: string, tag: string): string[] | undefined;
10
- export declare function getTemplateContextProps(this: RequestContext, fileName: string): string[] | undefined;
11
- export declare function getComponentNames(this: RequestContext, fileName: string): string[] | undefined;
12
- export declare function _getComponentNames(ts: typeof import('typescript'), tsLs: ts.LanguageService, vueCode: vue.VueVirtualCode): string[];
13
- export declare function getElementAttrs(this: RequestContext, fileName: string, tagName: string): string[] | undefined;
@@ -1,249 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getComponentProps = getComponentProps;
4
- exports.getComponentEvents = getComponentEvents;
5
- exports.getTemplateContextProps = getTemplateContextProps;
6
- exports.getComponentNames = getComponentNames;
7
- exports._getComponentNames = _getComponentNames;
8
- exports.getElementAttrs = getElementAttrs;
9
- const vue = require("@vue/language-core");
10
- const shared_1 = require("@vue/shared");
11
- function getComponentProps(fileName, tag) {
12
- const { typescript: ts, language, languageService, getFileId } = this;
13
- const volarFile = language.scripts.get(getFileId(fileName));
14
- if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
15
- return;
16
- }
17
- const vueCode = volarFile.generated.root;
18
- const program = languageService.getProgram();
19
- const checker = program.getTypeChecker();
20
- const components = getVariableType(ts, languageService, vueCode, '__VLS_components');
21
- if (!components) {
22
- return [];
23
- }
24
- const name = tag.split('.');
25
- let componentSymbol = components.type.getProperty(name[0])
26
- ?? components.type.getProperty((0, shared_1.camelize)(name[0]))
27
- ?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
28
- if (!componentSymbol) {
29
- return [];
30
- }
31
- let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
32
- for (let i = 1; i < name.length; i++) {
33
- componentSymbol = componentType.getProperty(name[i]);
34
- if (componentSymbol) {
35
- componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
36
- }
37
- else {
38
- return [];
39
- }
40
- }
41
- const result = new Map();
42
- for (const sig of componentType.getCallSignatures()) {
43
- const propParam = sig.parameters[0];
44
- if (propParam) {
45
- const propsType = checker.getTypeOfSymbolAtLocation(propParam, components.node);
46
- const props = propsType.getProperties();
47
- for (const prop of props) {
48
- const name = prop.name;
49
- const required = !(prop.flags & ts.SymbolFlags.Optional) || undefined;
50
- const commentMarkdown = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags()) || undefined;
51
- result.set(name, { name, required, commentMarkdown });
52
- }
53
- }
54
- }
55
- for (const sig of componentType.getConstructSignatures()) {
56
- const instanceType = sig.getReturnType();
57
- const propsSymbol = instanceType.getProperty('$props');
58
- if (propsSymbol) {
59
- const propsType = checker.getTypeOfSymbolAtLocation(propsSymbol, components.node);
60
- const props = propsType.getProperties();
61
- for (const prop of props) {
62
- if (prop.flags & ts.SymbolFlags.Method) { // #2443
63
- continue;
64
- }
65
- const name = prop.name;
66
- const required = !(prop.flags & ts.SymbolFlags.Optional) || undefined;
67
- const commentMarkdown = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags()) || undefined;
68
- result.set(name, { name, required, commentMarkdown });
69
- }
70
- }
71
- }
72
- return [...result.values()];
73
- }
74
- function getComponentEvents(fileName, tag) {
75
- const { typescript: ts, language, languageService, getFileId } = this;
76
- const volarFile = language.scripts.get(getFileId(fileName));
77
- if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
78
- return;
79
- }
80
- const vueCode = volarFile.generated.root;
81
- const program = languageService.getProgram();
82
- const checker = program.getTypeChecker();
83
- const components = getVariableType(ts, languageService, vueCode, '__VLS_components');
84
- if (!components) {
85
- return [];
86
- }
87
- const name = tag.split('.');
88
- let componentSymbol = components.type.getProperty(name[0]);
89
- if (!componentSymbol) {
90
- componentSymbol = components.type.getProperty((0, shared_1.camelize)(name[0]))
91
- ?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
92
- }
93
- if (!componentSymbol) {
94
- return [];
95
- }
96
- let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
97
- for (let i = 1; i < name.length; i++) {
98
- componentSymbol = componentType.getProperty(name[i]);
99
- if (componentSymbol) {
100
- componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
101
- }
102
- else {
103
- return [];
104
- }
105
- }
106
- const result = new Set();
107
- // for (const sig of componentType.getCallSignatures()) {
108
- // const emitParam = sig.parameters[1];
109
- // if (emitParam) {
110
- // // TODO
111
- // }
112
- // }
113
- for (const sig of componentType.getConstructSignatures()) {
114
- const instanceType = sig.getReturnType();
115
- const emitSymbol = instanceType.getProperty('$emit');
116
- if (emitSymbol) {
117
- const emitType = checker.getTypeOfSymbolAtLocation(emitSymbol, components.node);
118
- for (const call of emitType.getCallSignatures()) {
119
- const eventNameParamSymbol = call.parameters[0];
120
- if (eventNameParamSymbol) {
121
- const eventNameParamType = checker.getTypeOfSymbolAtLocation(eventNameParamSymbol, components.node);
122
- if (eventNameParamType.isStringLiteral()) {
123
- result.add(eventNameParamType.value);
124
- }
125
- }
126
- }
127
- }
128
- }
129
- return [...result];
130
- }
131
- function getTemplateContextProps(fileName) {
132
- const { typescript: ts, language, languageService, getFileId } = this;
133
- const volarFile = language.scripts.get(getFileId(fileName));
134
- if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
135
- return;
136
- }
137
- const vueCode = volarFile.generated.root;
138
- return getVariableType(ts, languageService, vueCode, '__VLS_ctx')
139
- ?.type
140
- ?.getProperties()
141
- .map(c => c.name);
142
- }
143
- function getComponentNames(fileName) {
144
- const { typescript: ts, language, languageService, getFileId } = this;
145
- const volarFile = language.scripts.get(getFileId(fileName));
146
- if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
147
- return;
148
- }
149
- const vueCode = volarFile.generated.root;
150
- return getVariableType(ts, languageService, vueCode, '__VLS_components')
151
- ?.type
152
- ?.getProperties()
153
- .map(c => c.name)
154
- .filter(entry => !entry.includes('$') && !entry.startsWith('_'))
155
- ?? [];
156
- }
157
- function _getComponentNames(ts, tsLs, vueCode) {
158
- return getVariableType(ts, tsLs, vueCode, '__VLS_components')
159
- ?.type
160
- ?.getProperties()
161
- .map(c => c.name)
162
- .filter(entry => !entry.includes('$') && !entry.startsWith('_'))
163
- ?? [];
164
- }
165
- function getElementAttrs(fileName, tagName) {
166
- const { typescript: ts, language, languageService, getFileId } = this;
167
- const volarFile = language.scripts.get(getFileId(fileName));
168
- if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
169
- return;
170
- }
171
- const program = languageService.getProgram();
172
- let tsSourceFile;
173
- if (tsSourceFile = program.getSourceFile(fileName)) {
174
- const typeNode = tsSourceFile.statements.find((node) => ts.isTypeAliasDeclaration(node) && node.name.getText() === '__VLS_IntrinsicElementsCompletion');
175
- const checker = program.getTypeChecker();
176
- if (checker && typeNode) {
177
- const type = checker.getTypeFromTypeNode(typeNode.type);
178
- const el = type.getProperty(tagName);
179
- if (el) {
180
- const attrs = checker.getTypeOfSymbolAtLocation(el, typeNode).getProperties();
181
- return attrs.map(c => c.name);
182
- }
183
- }
184
- }
185
- return [];
186
- }
187
- function getVariableType(ts, languageService, vueCode, name) {
188
- const program = languageService.getProgram();
189
- let tsSourceFile;
190
- if (tsSourceFile = program.getSourceFile(vueCode.fileName)) {
191
- const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
192
- const checker = program.getTypeChecker();
193
- if (checker && node) {
194
- return {
195
- node: node,
196
- type: checker.getTypeAtLocation(node),
197
- };
198
- }
199
- }
200
- }
201
- function searchVariableDeclarationNode(ts, sourceFile, name) {
202
- let componentsNode;
203
- walk(sourceFile);
204
- return componentsNode;
205
- function walk(node) {
206
- if (componentsNode) {
207
- return;
208
- }
209
- else if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
210
- componentsNode = node;
211
- }
212
- else {
213
- node.forEachChild(walk);
214
- }
215
- }
216
- }
217
- function generateCommentMarkdown(parts, jsDocTags) {
218
- const parsedComment = _symbolDisplayPartsToMarkdown(parts);
219
- const parsedJsDoc = _jsDocTagInfoToMarkdown(jsDocTags);
220
- let result = [parsedComment, parsedJsDoc].filter(str => !!str).join('\n\n');
221
- return result;
222
- }
223
- function _symbolDisplayPartsToMarkdown(parts) {
224
- return parts.map(part => {
225
- switch (part.kind) {
226
- case 'keyword':
227
- return `\`${part.text}\``;
228
- case 'functionName':
229
- return `**${part.text}**`;
230
- default:
231
- return part.text;
232
- }
233
- }).join('');
234
- }
235
- function _jsDocTagInfoToMarkdown(jsDocTags) {
236
- return jsDocTags.map(tag => {
237
- const tagName = `*@${tag.name}*`;
238
- const tagText = tag.text?.map(t => {
239
- if (t.kind === 'parameterName') {
240
- return `\`${t.text}\``;
241
- }
242
- else {
243
- return t.text;
244
- }
245
- }).join('') || '';
246
- return `${tagName} ${tagText}`;
247
- }).join('\n\n');
248
- }
249
- //# sourceMappingURL=componentInfos.js.map
package/lib/server.d.ts DELETED
@@ -1,25 +0,0 @@
1
- import { Language } from '@vue/language-core';
2
- import type * as ts from 'typescript';
3
- export type RequestType = 'containsFile' | 'projectInfo' | 'collectExtractProps' | 'getImportPathForFile' | 'getPropertiesAtLocation' | 'getQuickInfoAtPosition' | 'subscribeComponentProps' | 'getComponentEvents' | 'getComponentDirectives' | 'getElementAttrs';
4
- export type NotificationType = 'componentNamesUpdated' | 'componentPropsUpdated';
5
- export type RequestData = [
6
- seq: number,
7
- type: RequestType,
8
- fileName: string,
9
- ...args: any[]
10
- ];
11
- export type ResponseData = [
12
- seq: number,
13
- data: any
14
- ];
15
- export type NotificationData = [
16
- type: NotificationType,
17
- fileName: string,
18
- data: any
19
- ];
20
- export interface ProjectInfo {
21
- name: string;
22
- kind: ts.server.ProjectKind;
23
- currentDirectory: string;
24
- }
25
- export declare function startNamedPipeServer(ts: typeof import('typescript'), info: ts.server.PluginCreateInfo, language: Language<string>, projectKind: ts.server.ProjectKind.Inferred | ts.server.ProjectKind.Configured): Promise<void>;
package/lib/server.js DELETED
@@ -1,260 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.startNamedPipeServer = startNamedPipeServer;
4
- const language_core_1 = require("@vue/language-core");
5
- const fs = require("node:fs");
6
- const net = require("node:net");
7
- const collectExtractProps_1 = require("./requests/collectExtractProps");
8
- const getComponentDirectives_1 = require("./requests/getComponentDirectives");
9
- const getComponentEvents_1 = require("./requests/getComponentEvents");
10
- const getComponentNames_1 = require("./requests/getComponentNames");
11
- const getComponentProps_1 = require("./requests/getComponentProps");
12
- const getElementAttrs_1 = require("./requests/getElementAttrs");
13
- const getImportPathForFile_1 = require("./requests/getImportPathForFile");
14
- const getPropertiesAtLocation_1 = require("./requests/getPropertiesAtLocation");
15
- const getQuickInfoAtPosition_1 = require("./requests/getQuickInfoAtPosition");
16
- const utils_1 = require("./utils");
17
- async function startNamedPipeServer(ts, info, language, projectKind) {
18
- let lastProjectVersion;
19
- const requestContext = {
20
- typescript: ts,
21
- languageService: info.languageService,
22
- languageServiceHost: info.languageServiceHost,
23
- language: language,
24
- isTsPlugin: true,
25
- getFileId: (fileName) => fileName,
26
- };
27
- const dataChunks = [];
28
- const currentData = new language_core_1.FileMap(false);
29
- const allConnections = new Set();
30
- const pendingRequests = new Set();
31
- const server = net.createServer(connection => {
32
- allConnections.add(connection);
33
- connection.on('end', () => {
34
- allConnections.delete(connection);
35
- });
36
- connection.on('data', buffer => {
37
- dataChunks.push(buffer);
38
- const text = dataChunks.toString();
39
- if (text.endsWith('\n\n')) {
40
- dataChunks.length = 0;
41
- const requests = text.split('\n\n');
42
- for (let json of requests) {
43
- json = json.trim();
44
- if (!json) {
45
- continue;
46
- }
47
- try {
48
- onRequest(connection, JSON.parse(json));
49
- }
50
- catch (e) {
51
- console.error('[Vue Named Pipe Server] JSON parse error:', e);
52
- }
53
- }
54
- }
55
- });
56
- connection.on('error', err => console.error('[Vue Named Pipe Server]', err.message));
57
- for (const [fileName, [componentNames, componentProps]] of currentData) {
58
- notify(connection, 'componentNamesUpdated', fileName, componentNames);
59
- for (const [name, props] of Object.entries(componentProps)) {
60
- notify(connection, 'componentPropsUpdated', fileName, [name, props]);
61
- }
62
- }
63
- });
64
- for (let i = 0; i < 10; i++) {
65
- const path = (0, utils_1.getServerPath)(projectKind, i);
66
- const socket = await connect(path, 100);
67
- if (typeof socket === 'object') {
68
- socket.end();
69
- }
70
- const namedPipeOccupied = typeof socket === 'object' || socket === 'timeout';
71
- if (namedPipeOccupied) {
72
- continue;
73
- }
74
- const success = await tryListen(server, path);
75
- if (success) {
76
- break;
77
- }
78
- }
79
- updateWhile();
80
- async function updateWhile() {
81
- while (true) {
82
- await sleep(500);
83
- const projectVersion = info.project.getProjectVersion();
84
- if (lastProjectVersion === projectVersion) {
85
- continue;
86
- }
87
- const connections = [...allConnections].filter(c => !c.destroyed);
88
- if (!connections.length) {
89
- continue;
90
- }
91
- const token = info.languageServiceHost.getCancellationToken?.();
92
- const openedScriptInfos = info.project.getRootScriptInfos().filter(info => info.isScriptOpen());
93
- if (!openedScriptInfos.length) {
94
- continue;
95
- }
96
- for (const scriptInfo of openedScriptInfos) {
97
- await sleep(10);
98
- if (token?.isCancellationRequested()) {
99
- break;
100
- }
101
- let data = currentData.get(scriptInfo.fileName);
102
- if (!data) {
103
- data = [[], {}];
104
- currentData.set(scriptInfo.fileName, data);
105
- }
106
- const [oldComponentNames, componentProps] = data;
107
- const newComponentNames = getComponentNames_1.getComponentNames.apply(requestContext, [scriptInfo.fileName]) ?? [];
108
- if (JSON.stringify(oldComponentNames) !== JSON.stringify(newComponentNames)) {
109
- data[0] = newComponentNames;
110
- for (const connection of connections) {
111
- notify(connection, 'componentNamesUpdated', scriptInfo.fileName, newComponentNames);
112
- }
113
- }
114
- for (const [name, props] of Object.entries(componentProps)) {
115
- await sleep(10);
116
- if (token?.isCancellationRequested()) {
117
- break;
118
- }
119
- const newProps = getComponentProps_1.getComponentProps.apply(requestContext, [scriptInfo.fileName, name]) ?? [];
120
- if (JSON.stringify(props) !== JSON.stringify(newProps)) {
121
- componentProps[name] = newProps;
122
- for (const connection of connections) {
123
- notify(connection, 'componentPropsUpdated', scriptInfo.fileName, [name, newProps]);
124
- }
125
- }
126
- }
127
- }
128
- lastProjectVersion = projectVersion;
129
- }
130
- }
131
- function sleep(ms) {
132
- return new Promise(resolve => setTimeout(resolve, ms));
133
- }
134
- function notify(connection, type, fileName, data) {
135
- connection.write(JSON.stringify([type, fileName, data]) + '\n\n');
136
- }
137
- function onRequest(connection, [seq, requestType, ...args]) {
138
- if (pendingRequests.has(seq)) {
139
- return;
140
- }
141
- setTimeout(() => pendingRequests.delete(seq), 500);
142
- pendingRequests.add(seq);
143
- let data;
144
- try {
145
- data = handleRequest(requestType, ...args);
146
- }
147
- catch {
148
- data = null;
149
- }
150
- connection.write(JSON.stringify([seq, data ?? null]) + '\n\n');
151
- }
152
- function handleRequest(requestType, ...args) {
153
- const fileName = args[0];
154
- if (requestType === 'projectInfo') {
155
- return {
156
- name: info.project.getProjectName(),
157
- kind: info.project.projectKind,
158
- currentDirectory: info.project.getCurrentDirectory(),
159
- };
160
- }
161
- else if (requestType === 'containsFile') {
162
- return info.project.containsFile(ts.server.toNormalizedPath(fileName));
163
- }
164
- else if (requestType === 'collectExtractProps') {
165
- return collectExtractProps_1.collectExtractProps.apply(requestContext, args);
166
- }
167
- else if (requestType === 'getImportPathForFile') {
168
- return getImportPathForFile_1.getImportPathForFile.apply(requestContext, args);
169
- }
170
- else if (requestType === 'getPropertiesAtLocation') {
171
- return getPropertiesAtLocation_1.getPropertiesAtLocation.apply(requestContext, args);
172
- }
173
- else if (requestType === 'getQuickInfoAtPosition') {
174
- return getQuickInfoAtPosition_1.getQuickInfoAtPosition.apply(requestContext, args);
175
- }
176
- else if (requestType === 'subscribeComponentProps') {
177
- const tag = args[1];
178
- const props = getComponentProps_1.getComponentProps.apply(requestContext, [fileName, tag]) ?? [];
179
- let data = currentData.get(fileName);
180
- if (!data) {
181
- data = [[], {}];
182
- currentData.set(fileName, data);
183
- }
184
- data[1][tag] = props;
185
- return props;
186
- }
187
- else if (requestType === 'getComponentEvents') {
188
- return getComponentEvents_1.getComponentEvents.apply(requestContext, args);
189
- }
190
- else if (requestType === 'getComponentDirectives') {
191
- return getComponentDirectives_1.getComponentDirectives.apply(requestContext, args);
192
- }
193
- else if (requestType === 'getElementAttrs') {
194
- return getElementAttrs_1.getElementAttrs.apply(requestContext, args);
195
- }
196
- console.warn('[Vue Named Pipe Server] Unknown request:', requestType);
197
- debugger;
198
- return undefined;
199
- }
200
- }
201
- function connect(namedPipePath, timeout) {
202
- return new Promise(resolve => {
203
- const socket = net.connect(namedPipePath);
204
- if (timeout) {
205
- socket.setTimeout(timeout);
206
- }
207
- const onConnect = () => {
208
- cleanup();
209
- resolve(socket);
210
- };
211
- const onError = (err) => {
212
- if (err.code === 'ECONNREFUSED') {
213
- try {
214
- console.log('[Vue Named Pipe Client] Deleting:', namedPipePath);
215
- fs.promises.unlink(namedPipePath);
216
- }
217
- catch { }
218
- }
219
- cleanup();
220
- resolve('error');
221
- socket.end();
222
- };
223
- const onTimeout = () => {
224
- cleanup();
225
- resolve('timeout');
226
- socket.end();
227
- };
228
- const cleanup = () => {
229
- socket.off('connect', onConnect);
230
- socket.off('error', onError);
231
- socket.off('timeout', onTimeout);
232
- };
233
- socket.on('connect', onConnect);
234
- socket.on('error', onError);
235
- socket.on('timeout', onTimeout);
236
- });
237
- }
238
- function tryListen(server, namedPipePath) {
239
- return new Promise(resolve => {
240
- const onSuccess = () => {
241
- server.off('error', onError);
242
- resolve(true);
243
- };
244
- const onError = (err) => {
245
- if (err.code === 'ECONNREFUSED') {
246
- try {
247
- console.log('[Vue Named Pipe Client] Deleting:', namedPipePath);
248
- fs.promises.unlink(namedPipePath);
249
- }
250
- catch { }
251
- }
252
- server.off('error', onError);
253
- server.close();
254
- resolve(false);
255
- };
256
- server.listen(namedPipePath, onSuccess);
257
- server.on('error', onError);
258
- });
259
- }
260
- //# sourceMappingURL=server.js.map
package/lib/utils.d.ts DELETED
@@ -1,31 +0,0 @@
1
- import { FileMap } from '@vue/language-core';
2
- import * as net from 'node:net';
3
- import type * as ts from 'typescript';
4
- import type { ComponentPropInfo } from './requests/getComponentProps';
5
- import type { NotificationData, ProjectInfo, RequestData } from './server';
6
- export { TypeScriptProjectHost } from '@volar/typescript';
7
- export declare function getServerPath(kind: ts.server.ProjectKind, id: number): string;
8
- declare class NamedPipeServer {
9
- path: string;
10
- connecting: boolean;
11
- projectInfo?: ProjectInfo;
12
- containsFileCache: Map<string, Promise<boolean | null | undefined>>;
13
- componentNamesAndProps: FileMap<Record<string, ComponentPropInfo[] | null>>;
14
- constructor(kind: ts.server.ProjectKind, id: number);
15
- containsFile(fileName: string): Promise<boolean | null | undefined> | undefined;
16
- getComponentProps(fileName: string, tag: string): Promise<ComponentPropInfo[] | null | undefined>;
17
- update(): void;
18
- connect(): void;
19
- close(): void;
20
- socket?: net.Socket;
21
- seq: number;
22
- dataChunks: Buffer[];
23
- requestHandlers: Map<number, (res: any) => void>;
24
- onData(chunk: Buffer): void;
25
- onNotification(type: NotificationData[0], fileName: string, data: any): void;
26
- sendRequest<T>(requestType: RequestData[1], fileName: string, ...args: any[]): Promise<T | null | undefined>;
27
- }
28
- export declare const configuredServers: NamedPipeServer[];
29
- export declare const inferredServers: NamedPipeServer[];
30
- export declare const onServerReady: (() => void)[];
31
- export declare function getBestServer(fileName: string): Promise<NamedPipeServer | undefined>;
package/lib/utils.js DELETED
@@ -1,250 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.onServerReady = exports.inferredServers = exports.configuredServers = void 0;
4
- exports.getServerPath = getServerPath;
5
- exports.getBestServer = getBestServer;
6
- const language_core_1 = require("@vue/language-core");
7
- const shared_1 = require("@vue/shared");
8
- const fs = require("node:fs");
9
- const net = require("node:net");
10
- const os = require("node:os");
11
- const path = require("node:path");
12
- const { version } = require('../package.json');
13
- const platform = os.platform();
14
- const pipeDir = platform === 'win32'
15
- ? `\\\\.\\pipe\\`
16
- : `/tmp/`;
17
- function getServerPath(kind, id) {
18
- if (kind === 1) {
19
- return `${pipeDir}vue-named-pipe-${version}-configured-${id}`;
20
- }
21
- else {
22
- return `${pipeDir}vue-named-pipe-${version}-inferred-${id}`;
23
- }
24
- }
25
- class NamedPipeServer {
26
- constructor(kind, id) {
27
- this.connecting = false;
28
- this.containsFileCache = new Map();
29
- this.componentNamesAndProps = new language_core_1.FileMap(false);
30
- this.seq = 0;
31
- this.dataChunks = [];
32
- this.requestHandlers = new Map();
33
- this.path = getServerPath(kind, id);
34
- }
35
- containsFile(fileName) {
36
- if (this.projectInfo) {
37
- if (!this.containsFileCache.has(fileName)) {
38
- this.containsFileCache.set(fileName, (async () => {
39
- const res = await this.sendRequest('containsFile', fileName);
40
- if (typeof res !== 'boolean') {
41
- // If the request fails, delete the cache
42
- this.containsFileCache.delete(fileName);
43
- }
44
- return res;
45
- })());
46
- }
47
- return this.containsFileCache.get(fileName);
48
- }
49
- }
50
- async getComponentProps(fileName, tag) {
51
- const componentAndProps = this.componentNamesAndProps.get(fileName);
52
- if (!componentAndProps) {
53
- return;
54
- }
55
- const props = componentAndProps[tag]
56
- ?? componentAndProps[(0, shared_1.camelize)(tag)]
57
- ?? componentAndProps[(0, shared_1.capitalize)((0, shared_1.camelize)(tag))];
58
- if (props) {
59
- return props;
60
- }
61
- return await this.sendRequest('subscribeComponentProps', fileName, tag);
62
- }
63
- update() {
64
- if (!this.connecting && !this.projectInfo) {
65
- this.connecting = true;
66
- this.connect();
67
- }
68
- }
69
- connect() {
70
- this.socket = net.connect(this.path);
71
- this.socket.on('data', this.onData.bind(this));
72
- this.socket.on('connect', async () => {
73
- const projectInfo = await this.sendRequest('projectInfo', '');
74
- if (projectInfo) {
75
- console.log('TSServer project ready:', projectInfo.name);
76
- this.projectInfo = projectInfo;
77
- this.containsFileCache.clear();
78
- exports.onServerReady.forEach(cb => cb());
79
- }
80
- else {
81
- this.close();
82
- }
83
- });
84
- this.socket.on('error', err => {
85
- if (err.code === 'ECONNREFUSED') {
86
- try {
87
- console.log('Deleteing invalid named pipe file:', this.path);
88
- fs.promises.unlink(this.path);
89
- }
90
- catch { }
91
- }
92
- this.close();
93
- });
94
- this.socket.on('timeout', () => {
95
- this.close();
96
- });
97
- }
98
- close() {
99
- this.connecting = false;
100
- this.projectInfo = undefined;
101
- this.socket?.end();
102
- }
103
- onData(chunk) {
104
- this.dataChunks.push(chunk);
105
- const data = Buffer.concat(this.dataChunks);
106
- const text = data.toString();
107
- if (text.endsWith('\n\n')) {
108
- this.dataChunks.length = 0;
109
- const results = text.split('\n\n');
110
- for (let result of results) {
111
- result = result.trim();
112
- if (!result) {
113
- continue;
114
- }
115
- try {
116
- const data = JSON.parse(result.trim());
117
- if (typeof data[0] === 'number') {
118
- const [seq, res] = data;
119
- this.requestHandlers.get(seq)?.(res);
120
- }
121
- else {
122
- const [type, fileName, res] = data;
123
- this.onNotification(type, fileName, res);
124
- }
125
- }
126
- catch (e) {
127
- console.error('JSON parse error:', e);
128
- }
129
- }
130
- }
131
- }
132
- onNotification(type, fileName, data) {
133
- // console.log(`[${type}] ${fileName} ${JSON.stringify(data)}`);
134
- if (type === 'componentNamesUpdated') {
135
- let components = this.componentNamesAndProps.get(fileName);
136
- if (!components) {
137
- components = {};
138
- this.componentNamesAndProps.set(fileName, components);
139
- }
140
- const newNames = data;
141
- const newNameSet = new Set(newNames);
142
- for (const name in components) {
143
- if (!newNameSet.has(name)) {
144
- delete components[name];
145
- }
146
- }
147
- for (const name of newNames) {
148
- if (!components[name]) {
149
- components[name] = null;
150
- }
151
- }
152
- }
153
- else if (type === 'componentPropsUpdated') {
154
- const components = this.componentNamesAndProps.get(fileName) ?? {};
155
- const [name, props] = data;
156
- if (name in components) {
157
- components[name] = props;
158
- }
159
- }
160
- else {
161
- console.error('Unknown notification type:', type);
162
- debugger;
163
- }
164
- }
165
- sendRequest(requestType, fileName, ...args) {
166
- return new Promise(resolve => {
167
- const seq = this.seq++;
168
- // console.time(`[${seq}] ${requestType} ${fileName}`);
169
- this.requestHandlers.set(seq, data => {
170
- // console.timeEnd(`[${seq}] ${requestType} ${fileName}`);
171
- this.requestHandlers.delete(seq);
172
- resolve(data);
173
- clearInterval(retryTimer);
174
- });
175
- const retry = () => {
176
- const data = [seq, requestType, fileName, ...args];
177
- this.socket.write(JSON.stringify(data) + '\n\n');
178
- };
179
- retry();
180
- const retryTimer = setInterval(retry, 1000);
181
- });
182
- }
183
- }
184
- exports.configuredServers = [];
185
- exports.inferredServers = [];
186
- exports.onServerReady = [];
187
- for (let i = 0; i < 10; i++) {
188
- exports.configuredServers.push(new NamedPipeServer(1, i));
189
- exports.inferredServers.push(new NamedPipeServer(0, i));
190
- }
191
- async function getBestServer(fileName) {
192
- for (const server of exports.configuredServers) {
193
- server.update();
194
- }
195
- let servers = (await Promise.all(exports.configuredServers.map(async (server) => {
196
- const projectInfo = server.projectInfo;
197
- if (!projectInfo) {
198
- return;
199
- }
200
- const containsFile = await server.containsFile(fileName);
201
- if (!containsFile) {
202
- return;
203
- }
204
- return server;
205
- }))).filter(server => !!server);
206
- // Sort servers by tsconfig
207
- servers.sort((a, b) => sortTSConfigs(fileName, a.projectInfo.name, b.projectInfo.name));
208
- if (servers.length) {
209
- // Return the first server
210
- return servers[0];
211
- }
212
- for (const server of exports.inferredServers) {
213
- server.update();
214
- }
215
- servers = (await Promise.all(exports.inferredServers.map(server => {
216
- const projectInfo = server.projectInfo;
217
- if (!projectInfo) {
218
- return;
219
- }
220
- // Check if the file is in the project's directory
221
- if (path.relative(projectInfo.currentDirectory, fileName).startsWith('..')) {
222
- return;
223
- }
224
- return server;
225
- }))).filter(server => !!server);
226
- // Sort servers by directory
227
- servers.sort((a, b) => b.projectInfo.currentDirectory.replace(/\\/g, '/').split('/').length
228
- - a.projectInfo.currentDirectory.replace(/\\/g, '/').split('/').length);
229
- if (servers.length) {
230
- // Return the first server
231
- return servers[0];
232
- }
233
- }
234
- function sortTSConfigs(file, a, b) {
235
- const inA = isFileInDir(file, path.dirname(a));
236
- const inB = isFileInDir(file, path.dirname(b));
237
- if (inA !== inB) {
238
- const aWeight = inA ? 1 : 0;
239
- const bWeight = inB ? 1 : 0;
240
- return bWeight - aWeight;
241
- }
242
- const aLength = a.split('/').length;
243
- const bLength = b.split('/').length;
244
- return bLength - aLength;
245
- }
246
- function isFileInDir(fileName, dir) {
247
- const relative = path.relative(dir, fileName);
248
- return !!relative && !relative.startsWith('..') && !path.isAbsolute(relative);
249
- }
250
- //# sourceMappingURL=utils.js.map