@vue/typescript-plugin 2.1.10 → 2.2.2
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/lib/client.d.ts +9 -12
- package/lib/client.js +30 -66
- package/lib/common.js +11 -10
- package/lib/index.d.ts +3 -0
- package/lib/index.js +39 -0
- package/lib/requests/collectExtractProps.js +9 -5
- package/lib/requests/componentInfos.d.ts +7 -4
- package/lib/requests/componentInfos.js +77 -62
- package/lib/requests/getComponentDirectives.d.ts +2 -0
- package/lib/requests/getComponentDirectives.js +22 -0
- package/lib/requests/getComponentEvents.d.ts +2 -0
- package/lib/requests/getComponentEvents.js +48 -0
- package/lib/requests/getComponentNames.d.ts +5 -0
- package/lib/requests/getComponentNames.js +26 -0
- package/lib/requests/getComponentProps.d.ts +9 -0
- package/lib/requests/getComponentProps.js +102 -0
- package/lib/requests/getElementAttrs.d.ts +2 -0
- package/lib/requests/getElementAttrs.js +29 -0
- package/lib/requests/getSlotNames.d.ts +6 -0
- package/lib/requests/getSlotNames.js +30 -0
- package/lib/requests/goToDefinition.d.ts +2 -0
- package/lib/requests/goToDefinition.js +26 -0
- package/lib/requests/types.d.ts +1 -1
- package/lib/requests/utils.d.ts +8 -0
- package/lib/requests/utils.js +67 -0
- package/lib/server.d.ts +18 -5
- package/lib/server.js +209 -73
- package/lib/utils.d.ts +29 -14
- package/lib/utils.js +192 -188
- package/package.json +5 -5
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RequestContext } from './types';
|
|
2
|
+
export interface ComponentPropInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
deprecated?: boolean;
|
|
6
|
+
commentMarkdown?: string;
|
|
7
|
+
values?: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function getComponentProps(this: RequestContext, fileName: string, tag: string): ComponentPropInfo[] | undefined;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getComponentProps = getComponentProps;
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
function getComponentProps(fileName, tag) {
|
|
7
|
+
const { typescript: ts, language, languageService, getFileId } = this;
|
|
8
|
+
const volarFile = language.scripts.get(getFileId(fileName));
|
|
9
|
+
if (!(volarFile?.generated?.root instanceof language_core_1.VueVirtualCode)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const vueCode = volarFile.generated.root;
|
|
13
|
+
const program = languageService.getProgram();
|
|
14
|
+
const checker = program.getTypeChecker();
|
|
15
|
+
const components = (0, utils_1.getVariableType)(ts, languageService, vueCode, '__VLS_components');
|
|
16
|
+
if (!components) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const componentType = (0, utils_1.getComponentType)(ts, languageService, vueCode, components, fileName, tag);
|
|
20
|
+
if (!componentType) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const result = new Map();
|
|
24
|
+
for (const sig of componentType.getCallSignatures()) {
|
|
25
|
+
const propParam = sig.parameters[0];
|
|
26
|
+
if (propParam) {
|
|
27
|
+
const propsType = checker.getTypeOfSymbolAtLocation(propParam, components.node);
|
|
28
|
+
const props = propsType.getProperties();
|
|
29
|
+
for (const prop of props) {
|
|
30
|
+
const name = prop.name;
|
|
31
|
+
const required = !(prop.flags & ts.SymbolFlags.Optional) || undefined;
|
|
32
|
+
const { content: commentMarkdown, deprecated } = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags());
|
|
33
|
+
result.set(name, {
|
|
34
|
+
name,
|
|
35
|
+
required,
|
|
36
|
+
deprecated,
|
|
37
|
+
commentMarkdown
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const sig of componentType.getConstructSignatures()) {
|
|
43
|
+
const instanceType = sig.getReturnType();
|
|
44
|
+
const propsSymbol = instanceType.getProperty('$props');
|
|
45
|
+
if (propsSymbol) {
|
|
46
|
+
const propsType = checker.getTypeOfSymbolAtLocation(propsSymbol, components.node);
|
|
47
|
+
const props = propsType.getProperties();
|
|
48
|
+
for (const prop of props) {
|
|
49
|
+
if (prop.flags & ts.SymbolFlags.Method) { // #2443
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const name = prop.name;
|
|
53
|
+
const required = !(prop.flags & ts.SymbolFlags.Optional) || undefined;
|
|
54
|
+
const { content: commentMarkdown, deprecated } = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags());
|
|
55
|
+
result.set(name, {
|
|
56
|
+
name,
|
|
57
|
+
required,
|
|
58
|
+
deprecated,
|
|
59
|
+
commentMarkdown
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return [...result.values()];
|
|
65
|
+
}
|
|
66
|
+
function generateCommentMarkdown(parts, jsDocTags) {
|
|
67
|
+
const parsedComment = _symbolDisplayPartsToMarkdown(parts);
|
|
68
|
+
const parsedJsDoc = _jsDocTagInfoToMarkdown(jsDocTags);
|
|
69
|
+
const content = [parsedComment, parsedJsDoc].filter(str => !!str).join('\n\n');
|
|
70
|
+
const deprecated = jsDocTags.some(tag => tag.name === 'deprecated');
|
|
71
|
+
return {
|
|
72
|
+
content,
|
|
73
|
+
deprecated
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function _symbolDisplayPartsToMarkdown(parts) {
|
|
77
|
+
return parts.map(part => {
|
|
78
|
+
switch (part.kind) {
|
|
79
|
+
case 'keyword':
|
|
80
|
+
return `\`${part.text}\``;
|
|
81
|
+
case 'functionName':
|
|
82
|
+
return `**${part.text}**`;
|
|
83
|
+
default:
|
|
84
|
+
return part.text;
|
|
85
|
+
}
|
|
86
|
+
}).join('');
|
|
87
|
+
}
|
|
88
|
+
function _jsDocTagInfoToMarkdown(jsDocTags) {
|
|
89
|
+
return jsDocTags.map(tag => {
|
|
90
|
+
const tagName = `*@${tag.name}*`;
|
|
91
|
+
const tagText = tag.text?.map(t => {
|
|
92
|
+
if (t.kind === 'parameterName') {
|
|
93
|
+
return `\`${t.text}\``;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return t.text;
|
|
97
|
+
}
|
|
98
|
+
}).join('') || '';
|
|
99
|
+
return `${tagName} ${tagText}`;
|
|
100
|
+
}).join('\n\n');
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=getComponentProps.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getElementAttrs = getElementAttrs;
|
|
4
|
+
const vue = require("@vue/language-core");
|
|
5
|
+
function getElementAttrs(fileName, tagName) {
|
|
6
|
+
const { typescript: ts, language, languageService, getFileId } = this;
|
|
7
|
+
const volarFile = language.scripts.get(getFileId(fileName));
|
|
8
|
+
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
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
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=getElementAttrs.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSlotNames = getSlotNames;
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
function getSlotNames(fileName) {
|
|
6
|
+
const { typescript: ts, language, languageService, getFileId } = this;
|
|
7
|
+
const sourceScript = language.scripts.get(getFileId(fileName));
|
|
8
|
+
if (!sourceScript?.generated) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const root = sourceScript.generated.root;
|
|
12
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const program = languageService.getProgram();
|
|
16
|
+
const tsSourceFile = program.getSourceFile(fileName);
|
|
17
|
+
if (!tsSourceFile) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const checker = program.getTypeChecker();
|
|
21
|
+
const typeNode = tsSourceFile.statements
|
|
22
|
+
.filter(ts.isTypeAliasDeclaration)
|
|
23
|
+
.find(node => node.name.getText() === '__VLS_Slots');
|
|
24
|
+
if (typeNode) {
|
|
25
|
+
const attrs = checker.getTypeFromTypeNode(typeNode.type).getProperties();
|
|
26
|
+
return attrs.map(attr => attr.name);
|
|
27
|
+
}
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=getSlotNames.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.goToDefinition = goToDefinition;
|
|
4
|
+
const vue = require("@vue/language-core");
|
|
5
|
+
const componentInfos_1 = require("./componentInfos");
|
|
6
|
+
function goToDefinition(fileName, tag) {
|
|
7
|
+
const { typescript: ts, language, languageService, getFileId } = this;
|
|
8
|
+
const volarFile = language.scripts.get(getFileId(fileName));
|
|
9
|
+
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const vueCode = volarFile.generated.root;
|
|
13
|
+
const components = (0, componentInfos_1.getVariableType)(ts, languageService, vueCode, '__VLS_components');
|
|
14
|
+
if (!components) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
const componentType = (0, componentInfos_1.getComponentType)(ts, languageService, vueCode, components, fileName, tag);
|
|
18
|
+
if (!componentType) {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
const decls = componentType.symbol.declarations ?? [];
|
|
22
|
+
for (const decl of decls) {
|
|
23
|
+
return decl.getSourceFile().fileName;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=goToDefinition.js.map
|
package/lib/requests/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Language } from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
3
|
export interface RequestContext<T = any> {
|
|
4
|
-
typescript: typeof
|
|
4
|
+
typescript: typeof ts;
|
|
5
5
|
languageService: ts.LanguageService;
|
|
6
6
|
languageServiceHost: ts.LanguageServiceHost;
|
|
7
7
|
language: Language<T>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { VueVirtualCode } from '@vue/language-core';
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
|
+
export declare function getComponentType(ts: typeof import('typescript'), languageService: ts.LanguageService, vueCode: VueVirtualCode, components: NonNullable<ReturnType<typeof getVariableType>>, fileName: string, tag: string): ts.Type | undefined;
|
|
4
|
+
export declare function getSelfComponentName(fileName: string): Capitalize<string>;
|
|
5
|
+
export declare function getVariableType(ts: typeof import('typescript'), languageService: ts.LanguageService, vueCode: VueVirtualCode, name: string): {
|
|
6
|
+
node: ts.Node;
|
|
7
|
+
type: ts.Type;
|
|
8
|
+
} | undefined;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getComponentType = getComponentType;
|
|
4
|
+
exports.getSelfComponentName = getSelfComponentName;
|
|
5
|
+
exports.getVariableType = getVariableType;
|
|
6
|
+
const shared_1 = require("@vue/shared");
|
|
7
|
+
const path = require("node:path");
|
|
8
|
+
function getComponentType(ts, languageService, vueCode, components, fileName, tag) {
|
|
9
|
+
const program = languageService.getProgram();
|
|
10
|
+
const checker = program.getTypeChecker();
|
|
11
|
+
const name = tag.split('.');
|
|
12
|
+
let componentSymbol = components.type.getProperty(name[0])
|
|
13
|
+
?? components.type.getProperty((0, shared_1.camelize)(name[0]))
|
|
14
|
+
?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
|
|
15
|
+
let componentType;
|
|
16
|
+
if (!componentSymbol) {
|
|
17
|
+
const name = getSelfComponentName(fileName);
|
|
18
|
+
if (name === (0, shared_1.capitalize)((0, shared_1.camelize)(tag))) {
|
|
19
|
+
componentType = getVariableType(ts, languageService, vueCode, '__VLS_self')?.type;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
24
|
+
for (let i = 1; i < name.length; i++) {
|
|
25
|
+
componentSymbol = componentType.getProperty(name[i]);
|
|
26
|
+
if (componentSymbol) {
|
|
27
|
+
componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return componentType;
|
|
32
|
+
}
|
|
33
|
+
function getSelfComponentName(fileName) {
|
|
34
|
+
const baseName = path.basename(fileName);
|
|
35
|
+
return (0, shared_1.capitalize)((0, shared_1.camelize)(baseName.slice(0, baseName.lastIndexOf('.'))));
|
|
36
|
+
}
|
|
37
|
+
function getVariableType(ts, languageService, vueCode, name) {
|
|
38
|
+
const program = languageService.getProgram();
|
|
39
|
+
let tsSourceFile;
|
|
40
|
+
if (tsSourceFile = program.getSourceFile(vueCode.fileName)) {
|
|
41
|
+
const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
|
|
42
|
+
const checker = program.getTypeChecker();
|
|
43
|
+
if (checker && node) {
|
|
44
|
+
return {
|
|
45
|
+
node: node,
|
|
46
|
+
type: checker.getTypeAtLocation(node),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function searchVariableDeclarationNode(ts, sourceFile, name) {
|
|
52
|
+
let componentsNode;
|
|
53
|
+
walk(sourceFile);
|
|
54
|
+
return componentsNode;
|
|
55
|
+
function walk(node) {
|
|
56
|
+
if (componentsNode) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
else if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
|
|
60
|
+
componentsNode = node;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
node.forEachChild(walk);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=utils.js.map
|
package/lib/server.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Language } from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
+
];
|
|
7
20
|
export interface ProjectInfo {
|
|
8
21
|
name: string;
|
|
9
22
|
kind: ts.server.ProjectKind;
|
package/lib/server.js
CHANGED
|
@@ -1,91 +1,69 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.startNamedPipeServer = startNamedPipeServer;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const net = require("node:net");
|
|
6
7
|
const collectExtractProps_1 = require("./requests/collectExtractProps");
|
|
7
|
-
const
|
|
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");
|
|
8
13
|
const getImportPathForFile_1 = require("./requests/getImportPathForFile");
|
|
9
14
|
const getPropertiesAtLocation_1 = require("./requests/getPropertiesAtLocation");
|
|
10
15
|
const getQuickInfoAtPosition_1 = require("./requests/getQuickInfoAtPosition");
|
|
11
16
|
const utils_1 = require("./utils");
|
|
12
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();
|
|
13
31
|
const server = net.createServer(connection => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
kind: info.project.projectKind,
|
|
37
|
-
currentDirectory: info.project.getCurrentDirectory(),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
else if (request.type === 'collectExtractProps') {
|
|
41
|
-
const result = collectExtractProps_1.collectExtractProps.apply(requestContext, request.args);
|
|
42
|
-
sendResponse(result);
|
|
43
|
-
}
|
|
44
|
-
else if (request.type === 'getImportPathForFile') {
|
|
45
|
-
const result = getImportPathForFile_1.getImportPathForFile.apply(requestContext, request.args);
|
|
46
|
-
sendResponse(result);
|
|
47
|
-
}
|
|
48
|
-
else if (request.type === 'getPropertiesAtLocation') {
|
|
49
|
-
const result = getPropertiesAtLocation_1.getPropertiesAtLocation.apply(requestContext, request.args);
|
|
50
|
-
sendResponse(result);
|
|
51
|
-
}
|
|
52
|
-
else if (request.type === 'getQuickInfoAtPosition') {
|
|
53
|
-
const result = getQuickInfoAtPosition_1.getQuickInfoAtPosition.apply(requestContext, request.args);
|
|
54
|
-
sendResponse(result);
|
|
55
|
-
}
|
|
56
|
-
// Component Infos
|
|
57
|
-
else if (request.type === 'getComponentProps') {
|
|
58
|
-
const result = componentInfos_1.getComponentProps.apply(requestContext, request.args);
|
|
59
|
-
sendResponse(result);
|
|
60
|
-
}
|
|
61
|
-
else if (request.type === 'getComponentEvents') {
|
|
62
|
-
const result = componentInfos_1.getComponentEvents.apply(requestContext, request.args);
|
|
63
|
-
sendResponse(result);
|
|
64
|
-
}
|
|
65
|
-
else if (request.type === 'getTemplateContextProps') {
|
|
66
|
-
const result = componentInfos_1.getTemplateContextProps.apply(requestContext, request.args);
|
|
67
|
-
sendResponse(result);
|
|
68
|
-
}
|
|
69
|
-
else if (request.type === 'getComponentNames') {
|
|
70
|
-
const result = componentInfos_1.getComponentNames.apply(requestContext, request.args);
|
|
71
|
-
sendResponse(result);
|
|
72
|
-
}
|
|
73
|
-
else if (request.type === 'getElementAttrs') {
|
|
74
|
-
const result = componentInfos_1.getElementAttrs.apply(requestContext, request.args);
|
|
75
|
-
sendResponse(result);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
console.warn('[Vue Named Pipe Server] Unknown request type:', request.type);
|
|
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
|
+
}
|
|
79
54
|
}
|
|
80
55
|
});
|
|
81
56
|
connection.on('error', err => console.error('[Vue Named Pipe Server]', err.message));
|
|
82
|
-
|
|
83
|
-
connection
|
|
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
|
+
}
|
|
84
62
|
}
|
|
85
63
|
});
|
|
86
|
-
for (let i = 0; i <
|
|
87
|
-
const path = (0, utils_1.
|
|
88
|
-
const socket = await
|
|
64
|
+
for (let i = 0; i < 10; i++) {
|
|
65
|
+
const path = (0, utils_1.getServerPath)(projectKind, i);
|
|
66
|
+
const socket = await connect(path, 100);
|
|
89
67
|
if (typeof socket === 'object') {
|
|
90
68
|
socket.end();
|
|
91
69
|
}
|
|
@@ -98,6 +76,164 @@ async function startNamedPipeServer(ts, info, language, projectKind) {
|
|
|
98
76
|
break;
|
|
99
77
|
}
|
|
100
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
|
+
});
|
|
101
237
|
}
|
|
102
238
|
function tryListen(server, namedPipePath) {
|
|
103
239
|
return new Promise(resolve => {
|