@zentryc5t/ts-plugin-for-bruno 1.0.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/README.md +9 -0
- package/out/index.js +124 -0
- package/out/index.js.map +1 -0
- package/package.json +12 -0
- package/src/index.ts +204 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## About the package
|
|
2
|
+
|
|
3
|
+
This directory provides an `npm` package for a Typescript language service plugin, that allows the Typescript server to handle code blocks from `Bruno` files just like real Javascript code. `Bruno` is an open source API client, see [online docs](https://docs.usebruno.com/) for more infos.
|
|
4
|
+
|
|
5
|
+
**Disclaimer: All Bruno names, brands, trademarks, service marks and logos are the property of Bruno.**
|
|
6
|
+
|
|
7
|
+
## Main Features
|
|
8
|
+
|
|
9
|
+
Only some of the intellisense features for `Bruno` files are provided by this npm package. For a fuller set of intellisense features, you can use the VS Code extension, that is built from the root folder of this git repository.
|
package/out/index.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const path_1 = require("path");
|
|
3
|
+
function init(_modules) {
|
|
4
|
+
function create(info) {
|
|
5
|
+
// Set up decorator object
|
|
6
|
+
const proxy = Object.create(null);
|
|
7
|
+
for (const k of Object.keys(info.languageService)) {
|
|
8
|
+
const x = info.languageService[k];
|
|
9
|
+
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
|
|
10
|
+
proxy[k] = (...args) => x.apply(info.languageService, args);
|
|
11
|
+
}
|
|
12
|
+
proxy.getSyntacticDiagnostics = (fileName) => {
|
|
13
|
+
return filterDefaultDiagnostics(info, fileName, info.languageService.getSyntacticDiagnostics(fileName));
|
|
14
|
+
};
|
|
15
|
+
proxy.getSemanticDiagnostics = (fileName) => {
|
|
16
|
+
return filterDefaultDiagnostics(info, fileName, info.languageService.getSemanticDiagnostics(fileName));
|
|
17
|
+
};
|
|
18
|
+
proxy.getSuggestionDiagnostics = (fileName) => {
|
|
19
|
+
const defaultDiagnostics = info.languageService.getSuggestionDiagnostics(fileName);
|
|
20
|
+
if (!isBrunoFile(fileName)) {
|
|
21
|
+
return defaultDiagnostics;
|
|
22
|
+
}
|
|
23
|
+
const allDiagnosticsForCodeBlocks = filterDefaultDiagnostics(info, fileName, defaultDiagnostics);
|
|
24
|
+
// The ts server always reports errors when importing a Javascript function in a .bru file.
|
|
25
|
+
return allDiagnosticsForCodeBlocks.filter(({ code, messageText, start }) => {
|
|
26
|
+
const scriptSnapshot = info.languageServiceHost.getScriptSnapshot(fileName);
|
|
27
|
+
// ToDo: Improve filtering, so that it is ensured that no valid diagnostics are filtered out by mistake.
|
|
28
|
+
return !(scriptSnapshot &&
|
|
29
|
+
scriptSnapshot.getText(0, start).includes("require(") &&
|
|
30
|
+
code == 7044 &&
|
|
31
|
+
typeof messageText == "string" &&
|
|
32
|
+
messageText.includes("better type may be inferred"));
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
// All hovers are provided by the extension implementation
|
|
36
|
+
proxy.getQuickInfoAtPosition = (fileName, position) => {
|
|
37
|
+
return isBrunoFile(fileName)
|
|
38
|
+
? undefined
|
|
39
|
+
: info.languageService.getQuickInfoAtPosition(fileName, position);
|
|
40
|
+
};
|
|
41
|
+
return proxy;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
create,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function filterDefaultDiagnostics(info, fileName, defaultDiagnostics) {
|
|
48
|
+
if (!isBrunoFile(fileName)) {
|
|
49
|
+
return defaultDiagnostics;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
let fileContent = undefined;
|
|
53
|
+
const scriptSnapshot = info.languageServiceHost.getScriptSnapshot(fileName);
|
|
54
|
+
if (scriptSnapshot) {
|
|
55
|
+
fileContent = scriptSnapshot.getText(0, scriptSnapshot.getLength());
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
fileContent = info.languageServiceHost.readFile(fileName);
|
|
59
|
+
}
|
|
60
|
+
if (!fileContent) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
const indizes = [];
|
|
64
|
+
for (const blockName of Object.values(TextBlockName)) {
|
|
65
|
+
const indizesForBlock = getTextBlockStartAndEndIndex(fileContent, blockName);
|
|
66
|
+
if (indizesForBlock) {
|
|
67
|
+
indizes.push({ blockName, ...indizesForBlock });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (indizes.length > 0) {
|
|
71
|
+
return defaultDiagnostics.filter(({ start, length }) => start != undefined &&
|
|
72
|
+
length != undefined &&
|
|
73
|
+
indizes.some(({ startIndex: blockStart, endIndex: blockEnd }) => start >= blockStart && start <= blockEnd) &&
|
|
74
|
+
// Do not show diagnostics for functions that are provided by Bruno at runtime
|
|
75
|
+
!["bru", "req", "res", "test", "expect"].includes(fileContent.substring(start, start + length)));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function getTextBlockStartAndEndIndex(fullTextContent, blockName) {
|
|
83
|
+
const openingBracketChar = "{";
|
|
84
|
+
const closingBracketChar = "}";
|
|
85
|
+
const startPattern = new RegExp(`^\\s*${blockName}\\s*${openingBracketChar}\\s*$`, "m");
|
|
86
|
+
const startMatches = startPattern.exec(fullTextContent);
|
|
87
|
+
if (!startMatches || startMatches.length == 0) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const contentStartIndex = startMatches.index + startMatches[0].indexOf(openingBracketChar) + 1;
|
|
91
|
+
const remainingDoc = fullTextContent.substring(contentStartIndex);
|
|
92
|
+
const remainingDocLength = remainingDoc.length;
|
|
93
|
+
let openBracketsOnBlockLevel = 1;
|
|
94
|
+
let remainingDocCurrentIndex = 0;
|
|
95
|
+
while (openBracketsOnBlockLevel > 0 &&
|
|
96
|
+
remainingDocCurrentIndex < remainingDocLength) {
|
|
97
|
+
const currentChar = remainingDoc.charAt(remainingDocCurrentIndex);
|
|
98
|
+
openBracketsOnBlockLevel +=
|
|
99
|
+
currentChar == openingBracketChar
|
|
100
|
+
? 1
|
|
101
|
+
: currentChar == closingBracketChar
|
|
102
|
+
? -1
|
|
103
|
+
: 0;
|
|
104
|
+
remainingDocCurrentIndex++;
|
|
105
|
+
}
|
|
106
|
+
if (openBracketsOnBlockLevel > 0) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
startIndex: contentStartIndex,
|
|
111
|
+
endIndex: remainingDocCurrentIndex + contentStartIndex,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function isBrunoFile(fileName) {
|
|
115
|
+
return (0, path_1.extname)(fileName) == ".bru";
|
|
116
|
+
}
|
|
117
|
+
var TextBlockName;
|
|
118
|
+
(function (TextBlockName) {
|
|
119
|
+
TextBlockName["Tests"] = "tests";
|
|
120
|
+
TextBlockName["PreRequestScript"] = "script:pre-request";
|
|
121
|
+
TextBlockName["PostResponseScript"] = "script:post-response";
|
|
122
|
+
})(TextBlockName || (TextBlockName = {}));
|
|
123
|
+
module.exports = init;
|
|
124
|
+
//# sourceMappingURL=index.js.map
|
package/out/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zentryc5t/ts-plugin-for-bruno",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./out/index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
},
|
|
8
|
+
"author": "zentryc5t",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"description": "",
|
|
11
|
+
"repository": {"url": "https://github.com/daniel-b92/bruno-vs-code-extension/tree/main/src/tsPlugin"}
|
|
12
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { extname } from "path";
|
|
2
|
+
import * as ts from "typescript/lib/tsserverlibrary";
|
|
3
|
+
|
|
4
|
+
function init(_modules: {
|
|
5
|
+
typescript: typeof import("typescript/lib/tsserverlibrary");
|
|
6
|
+
}) {
|
|
7
|
+
function create(info: ts.server.PluginCreateInfo) {
|
|
8
|
+
// Set up decorator object
|
|
9
|
+
const proxy: ts.LanguageService = Object.create(null);
|
|
10
|
+
|
|
11
|
+
for (const k of Object.keys(
|
|
12
|
+
info.languageService
|
|
13
|
+
) as (keyof ts.LanguageService)[]) {
|
|
14
|
+
const x = info.languageService[k]!;
|
|
15
|
+
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
|
|
16
|
+
proxy[k] = (...args: unknown[]) => x.apply(info.languageService, args);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
proxy.getSyntacticDiagnostics = (fileName) => {
|
|
20
|
+
return filterDefaultDiagnostics(
|
|
21
|
+
info,
|
|
22
|
+
fileName,
|
|
23
|
+
info.languageService.getSyntacticDiagnostics(fileName)
|
|
24
|
+
) as ts.DiagnosticWithLocation[];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
proxy.getSemanticDiagnostics = (fileName) => {
|
|
28
|
+
return filterDefaultDiagnostics(
|
|
29
|
+
info,
|
|
30
|
+
fileName,
|
|
31
|
+
info.languageService.getSemanticDiagnostics(fileName)
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
proxy.getSuggestionDiagnostics = (fileName) => {
|
|
36
|
+
const defaultDiagnostics =
|
|
37
|
+
info.languageService.getSuggestionDiagnostics(fileName);
|
|
38
|
+
|
|
39
|
+
if (!isBrunoFile(fileName)) {
|
|
40
|
+
return defaultDiagnostics;
|
|
41
|
+
}
|
|
42
|
+
const allDiagnosticsForCodeBlocks = filterDefaultDiagnostics(
|
|
43
|
+
info,
|
|
44
|
+
fileName,
|
|
45
|
+
defaultDiagnostics
|
|
46
|
+
) as ts.DiagnosticWithLocation[];
|
|
47
|
+
|
|
48
|
+
// The ts server always reports errors when importing a Javascript function in a .bru file.
|
|
49
|
+
return allDiagnosticsForCodeBlocks.filter(
|
|
50
|
+
({ code, messageText, start }) => {
|
|
51
|
+
const scriptSnapshot =
|
|
52
|
+
info.languageServiceHost.getScriptSnapshot(fileName);
|
|
53
|
+
|
|
54
|
+
// ToDo: Improve filtering, so that it is ensured that no valid diagnostics are filtered out by mistake.
|
|
55
|
+
return !(
|
|
56
|
+
scriptSnapshot &&
|
|
57
|
+
scriptSnapshot.getText(0, start).includes("require(") &&
|
|
58
|
+
code == 7044 &&
|
|
59
|
+
typeof messageText == "string" &&
|
|
60
|
+
messageText.includes("better type may be inferred")
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// All hovers are provided by the extension implementation
|
|
67
|
+
proxy.getQuickInfoAtPosition = (fileName, position) => {
|
|
68
|
+
return isBrunoFile(fileName)
|
|
69
|
+
? undefined
|
|
70
|
+
: info.languageService.getQuickInfoAtPosition(
|
|
71
|
+
fileName,
|
|
72
|
+
position
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return proxy;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
create,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function filterDefaultDiagnostics(
|
|
85
|
+
info: ts.server.PluginCreateInfo,
|
|
86
|
+
fileName: string,
|
|
87
|
+
defaultDiagnostics: (ts.Diagnostic | ts.DiagnosticWithLocation)[]
|
|
88
|
+
) {
|
|
89
|
+
if (!isBrunoFile(fileName)) {
|
|
90
|
+
return defaultDiagnostics;
|
|
91
|
+
} else {
|
|
92
|
+
let fileContent: string | undefined = undefined;
|
|
93
|
+
const scriptSnapshot =
|
|
94
|
+
info.languageServiceHost.getScriptSnapshot(fileName);
|
|
95
|
+
|
|
96
|
+
if (scriptSnapshot) {
|
|
97
|
+
fileContent = scriptSnapshot.getText(0, scriptSnapshot.getLength());
|
|
98
|
+
} else {
|
|
99
|
+
fileContent = info.languageServiceHost.readFile(fileName);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!fileContent) {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const indizes: {
|
|
107
|
+
blockName: string;
|
|
108
|
+
startIndex: number;
|
|
109
|
+
endIndex: number;
|
|
110
|
+
}[] = [];
|
|
111
|
+
|
|
112
|
+
for (const blockName of Object.values(TextBlockName)) {
|
|
113
|
+
const indizesForBlock = getTextBlockStartAndEndIndex(
|
|
114
|
+
fileContent,
|
|
115
|
+
blockName
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (indizesForBlock) {
|
|
119
|
+
indizes.push({ blockName, ...indizesForBlock });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (indizes.length > 0) {
|
|
124
|
+
return defaultDiagnostics.filter(
|
|
125
|
+
({ start, length }) =>
|
|
126
|
+
start != undefined &&
|
|
127
|
+
length != undefined &&
|
|
128
|
+
indizes.some(
|
|
129
|
+
({ startIndex: blockStart, endIndex: blockEnd }) =>
|
|
130
|
+
start >= blockStart && start <= blockEnd
|
|
131
|
+
) &&
|
|
132
|
+
// Do not show diagnostics for functions that are provided by Bruno at runtime
|
|
133
|
+
!["bru", "req", "res", "test", "expect"].includes(
|
|
134
|
+
fileContent.substring(start, start + length)
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getTextBlockStartAndEndIndex(
|
|
144
|
+
fullTextContent: string,
|
|
145
|
+
blockName: TextBlockName
|
|
146
|
+
) {
|
|
147
|
+
const openingBracketChar = "{";
|
|
148
|
+
const closingBracketChar = "}";
|
|
149
|
+
|
|
150
|
+
const startPattern = new RegExp(
|
|
151
|
+
`^\\s*${blockName}\\s*${openingBracketChar}\\s*$`,
|
|
152
|
+
"m"
|
|
153
|
+
);
|
|
154
|
+
const startMatches = startPattern.exec(fullTextContent);
|
|
155
|
+
|
|
156
|
+
if (!startMatches || startMatches.length == 0) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const contentStartIndex =
|
|
161
|
+
startMatches.index + startMatches[0].indexOf(openingBracketChar) + 1;
|
|
162
|
+
|
|
163
|
+
const remainingDoc = fullTextContent.substring(contentStartIndex);
|
|
164
|
+
const remainingDocLength = remainingDoc.length;
|
|
165
|
+
let openBracketsOnBlockLevel = 1;
|
|
166
|
+
let remainingDocCurrentIndex = 0;
|
|
167
|
+
|
|
168
|
+
while (
|
|
169
|
+
openBracketsOnBlockLevel > 0 &&
|
|
170
|
+
remainingDocCurrentIndex < remainingDocLength
|
|
171
|
+
) {
|
|
172
|
+
const currentChar = remainingDoc.charAt(remainingDocCurrentIndex);
|
|
173
|
+
|
|
174
|
+
openBracketsOnBlockLevel +=
|
|
175
|
+
currentChar == openingBracketChar
|
|
176
|
+
? 1
|
|
177
|
+
: currentChar == closingBracketChar
|
|
178
|
+
? -1
|
|
179
|
+
: 0;
|
|
180
|
+
|
|
181
|
+
remainingDocCurrentIndex++;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (openBracketsOnBlockLevel > 0) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
startIndex: contentStartIndex,
|
|
190
|
+
endIndex: remainingDocCurrentIndex + contentStartIndex,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function isBrunoFile(fileName: string) {
|
|
195
|
+
return extname(fileName) == ".bru";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
enum TextBlockName {
|
|
199
|
+
Tests = "tests",
|
|
200
|
+
PreRequestScript = "script:pre-request",
|
|
201
|
+
PostResponseScript = "script:post-response",
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export = init;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"target": "es2020",
|
|
5
|
+
"lib": ["es2020"],
|
|
6
|
+
"outDir": "out",
|
|
7
|
+
"sourceMap": true,
|
|
8
|
+
"strict": true,
|
|
9
|
+
"rootDir": "src",
|
|
10
|
+
|
|
11
|
+
"allowUnreachableCode": false,
|
|
12
|
+
"noUnusedLocals": true,
|
|
13
|
+
"noUnusedParameters": true,
|
|
14
|
+
"strictFunctionTypes": true,
|
|
15
|
+
"strictNullChecks": true,
|
|
16
|
+
"strictPropertyInitialization": true
|
|
17
|
+
},
|
|
18
|
+
"exclude": ["node_modules", ".vscode-test"]
|
|
19
|
+
}
|