@herb-tools/language-server 0.8.3 → 0.8.5
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 +15 -34
- package/dist/diagnostics.js +229 -0
- package/dist/diagnostics.js.map +1 -1
- package/dist/document_save_service.js +18 -1
- package/dist/document_save_service.js.map +1 -1
- package/dist/formatting_service.js +3 -0
- package/dist/formatting_service.js.map +1 -1
- package/dist/herb-language-server.js +6170 -5684
- package/dist/herb-language-server.js.map +1 -1
- package/dist/index.cjs +254 -6
- package/dist/index.cjs.map +1 -1
- package/dist/server.js +2 -3
- package/dist/server.js.map +1 -1
- package/dist/settings.js +2 -1
- package/dist/settings.js.map +1 -1
- package/dist/types/diagnostics.d.ts +35 -1
- package/dist/types/document_save_service.d.ts +9 -0
- package/package.json +5 -5
- package/src/diagnostics.ts +299 -1
- package/src/document_save_service.ts +20 -1
- package/src/formatting_service.ts +3 -0
- package/src/server.ts +2 -6
- package/src/settings.ts +2 -1
- package/CHANGELOG.md +0 -7
- package/dist/config.js +0 -73
- package/dist/config.js.map +0 -1
- package/dist/types/config.d.ts +0 -34
- package/src/config.ts +0 -109
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAEhB,kCAAkC,EAClC,iCAAiC,EACjC,oBAAoB,EACpB,sBAAsB,EAMtB,cAAc,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/settings.js
CHANGED
|
@@ -52,7 +52,8 @@ export class Settings {
|
|
|
52
52
|
mergeSettings(userSettings, projectConfig) {
|
|
53
53
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
54
54
|
const settings = userSettings || this.defaultSettings;
|
|
55
|
-
|
|
55
|
+
const hasConfigFile = projectConfig ? Config.exists(projectConfig.projectPath) : false;
|
|
56
|
+
if (!projectConfig || !hasConfigFile) {
|
|
56
57
|
return {
|
|
57
58
|
trace: settings.trace,
|
|
58
59
|
linter: {
|
package/dist/settings.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAkBzC,MAAM,OAAO,QAAQ;IAyBnB,YAAY,MAAwB,EAAE,UAAsB;;QAxB5D,oBAAe,GAAyB;YACtC,MAAM,EAAE;gBACN,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,IAAI;aAChB;YACD,SAAS,EAAE;gBACT,OAAO,EAAE,KAAK;gBACd,WAAW,EAAE,oBAAoB,CAAC,WAAW;gBAC7C,aAAa,EAAE,oBAAoB,CAAC,aAAa;aAClD;SACF,CAAA;QACD,mBAAc,GAAyB,IAAI,CAAC,eAAe,CAAA;QAC3D,qBAAgB,GAAgD,IAAI,GAAG,EAAE,CAAA;QAGzE,+BAA0B,GAAG,KAAK,CAAA;QAClC,iCAA4B,GAAG,KAAK,CAAA;QACpC,8CAAyC,GAAG,KAAK,CAAA;QACjD,8BAAyB,GAAG,KAAK,CAAA;QAO/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAA;QACvC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,CAAC,0BAA0B,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;QAChH,IAAI,CAAC,yBAAyB,GAAG,CAAC,CAAC,CAAC,MAAA,IAAI,CAAC,YAAY,CAAC,MAAM,0CAAE,YAAY,CAAC,CAAA;QAE3E,IAAI,CAAC,4BAA4B,GAAG,CAAC,CAAC,CACpC,IAAI,CAAC,YAAY,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,gBAAgB,CAC9E,CAAA;QAED,IAAI,CAAC,yCAAyC,GAAG,CAAC,CAAC,CACjD,IAAI,CAAC,YAAY,CAAC,YAAY;YAC9B,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,kBAAkB;YACjD,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,kBAAkB,CAAC,kBAAkB,CACrE,CAAA;IACH,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,MAAe;QAC3C,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,aAAa,GAAG,MAAM,CAAA;YAC3B,OAAM;QACR,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,aAAa,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QAC5E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAA;YACvE,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;QAChC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,MAAe;QACxC,MAAM,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAA;QAE1C,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAA;IAC/B,CAAC;IAED,2DAA2D;IACnD,aAAa,CAAC,YAAyC,EAAE,aAAsB;;QACrF,MAAM,QAAQ,GAAG,YAAY,IAAI,IAAI,CAAC,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
2
|
-
import { Connection } from "vscode-languageserver/node";
|
|
2
|
+
import { Connection, Diagnostic } from "vscode-languageserver/node";
|
|
3
|
+
import { Visitor } from "@herb-tools/core";
|
|
4
|
+
import type { ERBCaseNode, ERBCaseMatchNode, ERBIfNode, ERBElseNode, ERBUnlessNode, ERBForNode, ERBWhileNode, ERBUntilNode, ERBWhenNode, ERBBeginNode, ERBRescueNode, ERBEnsureNode, ERBBlockNode, ERBInNode } from "@herb-tools/core";
|
|
3
5
|
import { ParserService } from "./parser_service";
|
|
4
6
|
import { LinterService } from "./linter_service";
|
|
5
7
|
import { DocumentService } from "./document_service";
|
|
@@ -13,7 +15,39 @@ export declare class Diagnostics {
|
|
|
13
15
|
private diagnostics;
|
|
14
16
|
constructor(connection: Connection, documentService: DocumentService, parserService: ParserService, linterService: LinterService, configService: ConfigService);
|
|
15
17
|
validate(textDocument: TextDocument): Promise<void>;
|
|
18
|
+
private getUnreachableCodeDiagnostics;
|
|
16
19
|
refreshDocument(document: TextDocument): Promise<void>;
|
|
17
20
|
refreshAllDocuments(): Promise<void>;
|
|
18
21
|
private sendDiagnosticsFor;
|
|
19
22
|
}
|
|
23
|
+
export declare class UnreachableCodeCollector extends Visitor {
|
|
24
|
+
diagnostics: Diagnostic[];
|
|
25
|
+
private processedIfNodes;
|
|
26
|
+
private processedElseNodes;
|
|
27
|
+
visitERBCaseNode(node: ERBCaseNode): void;
|
|
28
|
+
visitERBCaseMatchNode(node: ERBCaseMatchNode): void;
|
|
29
|
+
visitERBIfNode(node: ERBIfNode): void;
|
|
30
|
+
visitERBElseNode(node: ERBElseNode): void;
|
|
31
|
+
visitERBUnlessNode(node: ERBUnlessNode): void;
|
|
32
|
+
visitERBForNode(node: ERBForNode): void;
|
|
33
|
+
visitERBWhileNode(node: ERBWhileNode): void;
|
|
34
|
+
visitERBUntilNode(node: ERBUntilNode): void;
|
|
35
|
+
visitERBWhenNode(node: ERBWhenNode): void;
|
|
36
|
+
visitERBBeginNode(node: ERBBeginNode): void;
|
|
37
|
+
visitERBRescueNode(node: ERBRescueNode): void;
|
|
38
|
+
visitERBEnsureNode(node: ERBEnsureNode): void;
|
|
39
|
+
visitERBBlockNode(node: ERBBlockNode): void;
|
|
40
|
+
visitERBInNode(node: ERBInNode): void;
|
|
41
|
+
private checkUnreachableChildren;
|
|
42
|
+
private checkEmptyStatements;
|
|
43
|
+
private checkEmptyStatementsWithEndLocation;
|
|
44
|
+
private addDiagnostic;
|
|
45
|
+
private statementsHaveContent;
|
|
46
|
+
private checkAndMarkElseClause;
|
|
47
|
+
private markIfChainAsProcessed;
|
|
48
|
+
private markElseNodesInIfChain;
|
|
49
|
+
private traverseSubsequentNodes;
|
|
50
|
+
private checkIfChainParts;
|
|
51
|
+
private isEntireIfChainEmpty;
|
|
52
|
+
private toZeroBased;
|
|
53
|
+
}
|
|
@@ -9,5 +9,14 @@ export declare class DocumentSaveService {
|
|
|
9
9
|
private autofixService;
|
|
10
10
|
private formattingService;
|
|
11
11
|
constructor(connection: Connection, settings: Settings, autofixService: AutofixService, formattingService: FormattingService);
|
|
12
|
+
/**
|
|
13
|
+
* Apply only autofix edits on save.
|
|
14
|
+
* Called by willSaveWaitUntil - formatting is handled separately by editor.formatOnSave
|
|
15
|
+
*/
|
|
16
|
+
applyFixes(document: TextDocument): Promise<TextEdit[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Apply autofix and formatting.
|
|
19
|
+
* Called by onDocumentFormatting (manual format or editor.formatOnSave)
|
|
20
|
+
*/
|
|
12
21
|
applyFixesAndFormatting(document: TextDocument, reason: TextDocumentSaveReason): Promise<TextEdit[]>;
|
|
13
22
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herb-tools/language-server",
|
|
3
3
|
"description": "Herb HTML+ERB Language Tools and Language Server Protocol integration.",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.5",
|
|
5
5
|
"author": "Marco Roth",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"engines": {
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"dist/"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@herb-tools/config": "0.8.
|
|
49
|
-
"@herb-tools/formatter": "0.8.
|
|
50
|
-
"@herb-tools/linter": "0.8.
|
|
51
|
-
"@herb-tools/node-wasm": "0.8.
|
|
48
|
+
"@herb-tools/config": "0.8.5",
|
|
49
|
+
"@herb-tools/formatter": "0.8.5",
|
|
50
|
+
"@herb-tools/linter": "0.8.5",
|
|
51
|
+
"@herb-tools/node-wasm": "0.8.5",
|
|
52
52
|
"dedent": "^1.7.0",
|
|
53
53
|
"vscode-languageserver": "^9.0.1",
|
|
54
54
|
"vscode-languageserver-textdocument": "^1.0.12"
|
package/src/diagnostics.ts
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
import { TextDocument } from "vscode-languageserver-textdocument"
|
|
2
|
-
import { Connection, Diagnostic } from "vscode-languageserver/node"
|
|
2
|
+
import { Connection, Diagnostic, DiagnosticSeverity, DiagnosticTag } from "vscode-languageserver/node"
|
|
3
|
+
import { Visitor } from "@herb-tools/core"
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
Node,
|
|
7
|
+
ERBCaseNode,
|
|
8
|
+
ERBCaseMatchNode,
|
|
9
|
+
ERBIfNode,
|
|
10
|
+
ERBElseNode,
|
|
11
|
+
ERBUnlessNode,
|
|
12
|
+
ERBForNode,
|
|
13
|
+
ERBWhileNode,
|
|
14
|
+
ERBUntilNode,
|
|
15
|
+
ERBWhenNode,
|
|
16
|
+
ERBBeginNode,
|
|
17
|
+
ERBRescueNode,
|
|
18
|
+
ERBEnsureNode,
|
|
19
|
+
ERBBlockNode,
|
|
20
|
+
ERBInNode,
|
|
21
|
+
} from "@herb-tools/core"
|
|
22
|
+
|
|
23
|
+
import { isHTMLTextNode } from "@herb-tools/core"
|
|
3
24
|
|
|
4
25
|
import { ParserService } from "./parser_service"
|
|
5
26
|
import { LinterService } from "./linter_service"
|
|
@@ -36,10 +57,12 @@ export class Diagnostics {
|
|
|
36
57
|
} else {
|
|
37
58
|
const parseResult = this.parserService.parseDocument(textDocument)
|
|
38
59
|
const lintResult = await this.linterService.lintDocument(textDocument)
|
|
60
|
+
const unreachableCodeDiagnostics = this.getUnreachableCodeDiagnostics(parseResult.document)
|
|
39
61
|
|
|
40
62
|
allDiagnostics = [
|
|
41
63
|
...parseResult.diagnostics,
|
|
42
64
|
...lintResult.diagnostics,
|
|
65
|
+
...unreachableCodeDiagnostics,
|
|
43
66
|
]
|
|
44
67
|
}
|
|
45
68
|
|
|
@@ -47,6 +70,12 @@ export class Diagnostics {
|
|
|
47
70
|
this.sendDiagnosticsFor(textDocument)
|
|
48
71
|
}
|
|
49
72
|
|
|
73
|
+
private getUnreachableCodeDiagnostics(document: Node): Diagnostic[] {
|
|
74
|
+
const collector = new UnreachableCodeCollector()
|
|
75
|
+
collector.visit(document)
|
|
76
|
+
return collector.diagnostics
|
|
77
|
+
}
|
|
78
|
+
|
|
50
79
|
async refreshDocument(document: TextDocument) {
|
|
51
80
|
await this.validate(document)
|
|
52
81
|
}
|
|
@@ -67,3 +96,272 @@ export class Diagnostics {
|
|
|
67
96
|
this.diagnostics.delete(textDocument)
|
|
68
97
|
}
|
|
69
98
|
}
|
|
99
|
+
|
|
100
|
+
export class UnreachableCodeCollector extends Visitor {
|
|
101
|
+
diagnostics: Diagnostic[] = []
|
|
102
|
+
private processedIfNodes: Set<ERBIfNode> = new Set()
|
|
103
|
+
private processedElseNodes: Set<ERBElseNode> = new Set()
|
|
104
|
+
|
|
105
|
+
visitERBCaseNode(node: ERBCaseNode): void {
|
|
106
|
+
this.checkUnreachableChildren(node.children)
|
|
107
|
+
this.checkAndMarkElseClause(node.else_clause)
|
|
108
|
+
this.visitChildNodes(node)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
visitERBCaseMatchNode(node: ERBCaseMatchNode): void {
|
|
112
|
+
this.checkUnreachableChildren(node.children)
|
|
113
|
+
this.checkAndMarkElseClause(node.else_clause)
|
|
114
|
+
this.visitChildNodes(node)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
visitERBIfNode(node: ERBIfNode): void {
|
|
118
|
+
if (this.processedIfNodes.has(node)) {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.markIfChainAsProcessed(node)
|
|
123
|
+
|
|
124
|
+
this.markElseNodesInIfChain(node)
|
|
125
|
+
|
|
126
|
+
const entireChainEmpty = this.isEntireIfChainEmpty(node)
|
|
127
|
+
|
|
128
|
+
if (entireChainEmpty) {
|
|
129
|
+
this.checkEmptyStatements(node, node.statements, "if")
|
|
130
|
+
} else {
|
|
131
|
+
this.checkIfChainParts(node)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.visitChildNodes(node)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
visitERBElseNode(node: ERBElseNode): void {
|
|
138
|
+
if (this.processedElseNodes.has(node)) {
|
|
139
|
+
this.visitChildNodes(node)
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.checkEmptyStatements(node, node.statements, "else")
|
|
144
|
+
this.visitChildNodes(node)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
visitERBUnlessNode(node: ERBUnlessNode): void {
|
|
148
|
+
const unlessHasContent = this.statementsHaveContent(node.statements)
|
|
149
|
+
const elseHasContent = node.else_clause && this.statementsHaveContent(node.else_clause.statements)
|
|
150
|
+
|
|
151
|
+
if (node.else_clause) {
|
|
152
|
+
this.processedElseNodes.add(node.else_clause)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const entireBlockEmpty = !unlessHasContent && !elseHasContent
|
|
156
|
+
|
|
157
|
+
if (entireBlockEmpty) {
|
|
158
|
+
this.checkEmptyStatements(node, node.statements, "unless")
|
|
159
|
+
} else {
|
|
160
|
+
if (!unlessHasContent) {
|
|
161
|
+
this.checkEmptyStatementsWithEndLocation(node, node.statements, "unless", node.else_clause)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (node.else_clause && !elseHasContent) {
|
|
165
|
+
this.checkEmptyStatements(node.else_clause, node.else_clause.statements, "else")
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this.visitChildNodes(node)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
visitERBForNode(node: ERBForNode): void {
|
|
173
|
+
this.checkEmptyStatements(node, node.statements, "for")
|
|
174
|
+
this.visitChildNodes(node)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
visitERBWhileNode(node: ERBWhileNode): void {
|
|
178
|
+
this.checkEmptyStatements(node, node.statements, "while")
|
|
179
|
+
this.visitChildNodes(node)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
visitERBUntilNode(node: ERBUntilNode): void {
|
|
183
|
+
this.checkEmptyStatements(node, node.statements, "until")
|
|
184
|
+
this.visitChildNodes(node)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
visitERBWhenNode(node: ERBWhenNode): void {
|
|
188
|
+
this.checkEmptyStatements(node, node.statements, "when")
|
|
189
|
+
this.visitChildNodes(node)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
visitERBBeginNode(node: ERBBeginNode): void {
|
|
193
|
+
this.checkEmptyStatements(node, node.statements, "begin")
|
|
194
|
+
this.visitChildNodes(node)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
visitERBRescueNode(node: ERBRescueNode): void {
|
|
198
|
+
this.checkEmptyStatements(node, node.statements, "rescue")
|
|
199
|
+
this.visitChildNodes(node)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
visitERBEnsureNode(node: ERBEnsureNode): void {
|
|
203
|
+
this.checkEmptyStatements(node, node.statements, "ensure")
|
|
204
|
+
this.visitChildNodes(node)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
visitERBBlockNode(node: ERBBlockNode): void {
|
|
208
|
+
this.checkEmptyStatements(node, node.body, "block")
|
|
209
|
+
this.visitChildNodes(node)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
visitERBInNode(node: ERBInNode): void {
|
|
213
|
+
this.checkEmptyStatements(node, node.statements, "in")
|
|
214
|
+
this.visitChildNodes(node)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private checkUnreachableChildren(children: Node[]): void {
|
|
218
|
+
for (const child of children) {
|
|
219
|
+
if (isHTMLTextNode(child) && child.content.trim() === "") {
|
|
220
|
+
continue
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
this.addDiagnostic(
|
|
224
|
+
child.location,
|
|
225
|
+
"Unreachable code: content between case and when/in is never executed"
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private checkEmptyStatements(node: Node, statements: Node[], blockType: string): void {
|
|
231
|
+
this.checkEmptyStatementsWithEndLocation(node, statements, blockType, null)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private checkEmptyStatementsWithEndLocation(node: Node, statements: Node[], blockType: string, subsequentNode: Node | null): void {
|
|
235
|
+
if (this.statementsHaveContent(statements)) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const startLocation = node.location.start
|
|
240
|
+
const endLocation = subsequentNode
|
|
241
|
+
? subsequentNode.location.start
|
|
242
|
+
: node.location.end
|
|
243
|
+
|
|
244
|
+
this.addDiagnostic(
|
|
245
|
+
{ start: startLocation, end: endLocation },
|
|
246
|
+
`Empty ${blockType} block: this control flow statement has no content`
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private addDiagnostic(location: { start: { line: number; column: number }, end: { line: number; column: number } }, message: string): void {
|
|
251
|
+
const diagnostic: Diagnostic = {
|
|
252
|
+
range: {
|
|
253
|
+
start: {
|
|
254
|
+
line: this.toZeroBased(location.start.line),
|
|
255
|
+
character: location.start.column
|
|
256
|
+
},
|
|
257
|
+
end: {
|
|
258
|
+
line: this.toZeroBased(location.end.line),
|
|
259
|
+
character: location.end.column
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
message,
|
|
263
|
+
severity: DiagnosticSeverity.Hint,
|
|
264
|
+
tags: [DiagnosticTag.Unnecessary],
|
|
265
|
+
source: "Herb Language Server"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.diagnostics.push(diagnostic)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private statementsHaveContent(statements: Node[]): boolean {
|
|
272
|
+
return statements.some(statement => {
|
|
273
|
+
if (isHTMLTextNode(statement)) {
|
|
274
|
+
return statement.content.trim() !== ""
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return true
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private checkAndMarkElseClause(elseClause: ERBElseNode | null): void {
|
|
282
|
+
if (!elseClause) {
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
this.processedElseNodes.add(elseClause)
|
|
287
|
+
if (!this.statementsHaveContent(elseClause.statements)) {
|
|
288
|
+
this.checkEmptyStatements(elseClause, elseClause.statements, "else")
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private markIfChainAsProcessed(node: ERBIfNode): void {
|
|
293
|
+
this.processedIfNodes.add(node)
|
|
294
|
+
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
295
|
+
if (current.type === 'AST_ERB_IF_NODE') {
|
|
296
|
+
this.processedIfNodes.add(current as ERBIfNode)
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private markElseNodesInIfChain(node: ERBIfNode): void {
|
|
302
|
+
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
303
|
+
if (current.type === 'AST_ERB_ELSE_NODE') {
|
|
304
|
+
this.processedElseNodes.add(current as ERBElseNode)
|
|
305
|
+
}
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private traverseSubsequentNodes(startNode: Node | null, callback: (node: Node) => void): void {
|
|
310
|
+
let current = startNode
|
|
311
|
+
while (current) {
|
|
312
|
+
callback(current)
|
|
313
|
+
|
|
314
|
+
if ('subsequent' in current) {
|
|
315
|
+
current = (current as any).subsequent
|
|
316
|
+
} else {
|
|
317
|
+
break
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private checkIfChainParts(node: ERBIfNode): void {
|
|
323
|
+
if (!this.statementsHaveContent(node.statements)) {
|
|
324
|
+
this.checkEmptyStatementsWithEndLocation(node, node.statements, "if", node.subsequent)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
328
|
+
if (!('statements' in current) || !Array.isArray((current as any).statements)) {
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (this.statementsHaveContent((current as any).statements)) {
|
|
333
|
+
return
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const blockType = current.type === 'AST_ERB_IF_NODE' ? 'elsif' : 'else'
|
|
337
|
+
const nextSubsequent = 'subsequent' in current ? (current as any).subsequent : null
|
|
338
|
+
|
|
339
|
+
if (nextSubsequent) {
|
|
340
|
+
this.checkEmptyStatementsWithEndLocation(current, (current as any).statements, blockType, nextSubsequent)
|
|
341
|
+
} else {
|
|
342
|
+
this.checkEmptyStatements(current, (current as any).statements, blockType)
|
|
343
|
+
}
|
|
344
|
+
})
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private isEntireIfChainEmpty(node: ERBIfNode): boolean {
|
|
348
|
+
if (this.statementsHaveContent(node.statements)) {
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
let hasContent = false
|
|
353
|
+
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
354
|
+
if ('statements' in current && Array.isArray((current as any).statements)) {
|
|
355
|
+
if (this.statementsHaveContent((current as any).statements)) {
|
|
356
|
+
hasContent = true
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
return !hasContent
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private toZeroBased(line: number): number {
|
|
365
|
+
return line - 1
|
|
366
|
+
}
|
|
367
|
+
}
|
|
@@ -18,12 +18,31 @@ export class DocumentSaveService {
|
|
|
18
18
|
this.formattingService = formattingService
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Apply only autofix edits on save.
|
|
23
|
+
* Called by willSaveWaitUntil - formatting is handled separately by editor.formatOnSave
|
|
24
|
+
*/
|
|
25
|
+
async applyFixes(document: TextDocument): Promise<TextEdit[]> {
|
|
26
|
+
const settings = await this.settings.getDocumentSettings(document.uri)
|
|
27
|
+
const fixOnSave = settings?.linter?.fixOnSave !== false
|
|
28
|
+
|
|
29
|
+
this.connection.console.log(`[DocumentSave] applyFixes fixOnSave=${fixOnSave}`)
|
|
30
|
+
|
|
31
|
+
if (!fixOnSave) return []
|
|
32
|
+
|
|
33
|
+
return this.autofixService.autofix(document)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Apply autofix and formatting.
|
|
38
|
+
* Called by onDocumentFormatting (manual format or editor.formatOnSave)
|
|
39
|
+
*/
|
|
21
40
|
async applyFixesAndFormatting(document: TextDocument, reason: TextDocumentSaveReason): Promise<TextEdit[]> {
|
|
22
41
|
const settings = await this.settings.getDocumentSettings(document.uri)
|
|
23
42
|
const fixOnSave = settings?.linter?.fixOnSave !== false
|
|
24
43
|
const formatterEnabled = settings?.formatter?.enabled ?? false
|
|
25
44
|
|
|
26
|
-
this.connection.console.log(`[DocumentSave] fixOnSave=${fixOnSave}, formatterEnabled=${formatterEnabled}`)
|
|
45
|
+
this.connection.console.log(`[DocumentSave] applyFixesAndFormatting fixOnSave=${fixOnSave}, formatterEnabled=${formatterEnabled}`)
|
|
27
46
|
|
|
28
47
|
let autofixEdits: TextEdit[] = []
|
|
29
48
|
|
|
@@ -210,6 +210,9 @@ export class FormattingService {
|
|
|
210
210
|
if (filePath.endsWith('.herb.yml')) return false
|
|
211
211
|
if (!this.config) return true
|
|
212
212
|
|
|
213
|
+
const hasConfigFile = Config.exists(this.config.projectPath)
|
|
214
|
+
if (!hasConfigFile) return true
|
|
215
|
+
|
|
213
216
|
const relativePath = filePath.replace('file://', '').replace(this.project.projectPath + '/', '')
|
|
214
217
|
|
|
215
218
|
return this.config.isFormatterEnabledForPath(relativePath)
|
package/src/server.ts
CHANGED
|
@@ -12,15 +12,12 @@ import {
|
|
|
12
12
|
DocumentRangeFormattingParams,
|
|
13
13
|
CodeActionParams,
|
|
14
14
|
CodeActionKind,
|
|
15
|
-
TextEdit,
|
|
16
15
|
} from "vscode-languageserver/node"
|
|
17
16
|
|
|
18
17
|
import { Service } from "./service"
|
|
19
18
|
import { PersonalHerbSettings } from "./settings"
|
|
20
19
|
import { Config } from "@herb-tools/config"
|
|
21
20
|
|
|
22
|
-
import type { TextDocument } from "vscode-languageserver-textdocument"
|
|
23
|
-
|
|
24
21
|
export class Server {
|
|
25
22
|
private service!: Service
|
|
26
23
|
private connection: Connection
|
|
@@ -37,7 +34,7 @@ export class Server {
|
|
|
37
34
|
await this.service.init()
|
|
38
35
|
|
|
39
36
|
this.service.documentService.documents.onWillSaveWaitUntil(async (event) => {
|
|
40
|
-
return this.service.documentSaveService.
|
|
37
|
+
return this.service.documentSaveService.applyFixes(event.document)
|
|
41
38
|
})
|
|
42
39
|
|
|
43
40
|
const result: InitializeResult = {
|
|
@@ -89,7 +86,6 @@ export class Server {
|
|
|
89
86
|
watchers: [
|
|
90
87
|
...patterns,
|
|
91
88
|
{ globPattern: `**/.herb.yml` },
|
|
92
|
-
{ globPattern: `**/**/.herb-lsp/config.json` },
|
|
93
89
|
{ globPattern: `**/.herb/rules/**/*.mjs` },
|
|
94
90
|
{ globPattern: `**/.herb/rewriters/**/*.mjs` },
|
|
95
91
|
],
|
|
@@ -119,7 +115,7 @@ export class Server {
|
|
|
119
115
|
|
|
120
116
|
this.connection.onDidChangeWatchedFiles(async (params) => {
|
|
121
117
|
for (const event of params.changes) {
|
|
122
|
-
const isConfigChange = event.uri.endsWith("/.herb.yml")
|
|
118
|
+
const isConfigChange = event.uri.endsWith("/.herb.yml")
|
|
123
119
|
const isCustomRuleChange = event.uri.includes("/.herb/rules/")
|
|
124
120
|
const isCustomRewriterChange = event.uri.includes("/.herb/rewriters/")
|
|
125
121
|
|
package/src/settings.ts
CHANGED
|
@@ -87,8 +87,9 @@ export class Settings {
|
|
|
87
87
|
// TODO: ideally we can just use Config all the way through
|
|
88
88
|
private mergeSettings(userSettings: PersonalHerbSettings | null, projectConfig?: Config): PersonalHerbSettings {
|
|
89
89
|
const settings = userSettings || this.defaultSettings
|
|
90
|
+
const hasConfigFile = projectConfig ? Config.exists(projectConfig.projectPath) : false
|
|
90
91
|
|
|
91
|
-
if (!projectConfig) {
|
|
92
|
+
if (!projectConfig || !hasConfigFile) {
|
|
92
93
|
return {
|
|
93
94
|
trace: settings.trace,
|
|
94
95
|
linter: {
|
package/CHANGELOG.md
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
## 0.3.1 (2025-06-23)
|
|
2
|
-
|
|
3
|
-
This was a version bump only for @herb-tools/language-server to align it with other projects, there were no code changes.
|
|
4
|
-
|
|
5
|
-
## 0.3.0 (2025-06-21)
|
|
6
|
-
|
|
7
|
-
This was a version bump only for @herb-tools/language-server to align it with other projects, there were no code changes.
|
package/dist/config.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { version } from "../package.json";
|
|
3
|
-
import { promises as fs } from "fs";
|
|
4
|
-
export class Config {
|
|
5
|
-
constructor(projectPath, config) {
|
|
6
|
-
this.path = Config.configPathFromProjectPath(projectPath);
|
|
7
|
-
this.config = config;
|
|
8
|
-
}
|
|
9
|
-
get version() {
|
|
10
|
-
return this.config.version;
|
|
11
|
-
}
|
|
12
|
-
get createdAt() {
|
|
13
|
-
return new Date(this.config.createdAt);
|
|
14
|
-
}
|
|
15
|
-
get updatedAt() {
|
|
16
|
-
return new Date(this.config.updatedAt);
|
|
17
|
-
}
|
|
18
|
-
get options() {
|
|
19
|
-
return this.config.options;
|
|
20
|
-
}
|
|
21
|
-
toJSON() {
|
|
22
|
-
return JSON.stringify(this.config, null, " ");
|
|
23
|
-
}
|
|
24
|
-
updateTimestamp() {
|
|
25
|
-
this.config.updatedAt = new Date().toISOString();
|
|
26
|
-
}
|
|
27
|
-
updateVersion() {
|
|
28
|
-
this.config.version = version;
|
|
29
|
-
}
|
|
30
|
-
async write() {
|
|
31
|
-
this.updateVersion();
|
|
32
|
-
this.updateTimestamp();
|
|
33
|
-
const folder = path.dirname(this.path);
|
|
34
|
-
fs.stat(folder)
|
|
35
|
-
.then(() => { })
|
|
36
|
-
.catch(async () => await fs.mkdir(folder))
|
|
37
|
-
.finally(async () => await fs.writeFile(this.path, this.toJSON()));
|
|
38
|
-
}
|
|
39
|
-
async read() {
|
|
40
|
-
return await fs.readFile(this.path, "utf8");
|
|
41
|
-
}
|
|
42
|
-
static configPathFromProjectPath(projectPath) {
|
|
43
|
-
return path.join(projectPath, this.configPath);
|
|
44
|
-
}
|
|
45
|
-
static async fromPathOrNew(projectPath) {
|
|
46
|
-
try {
|
|
47
|
-
return await this.fromPath(projectPath);
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
return Config.newConfig(projectPath);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
static async fromPath(projectPath) {
|
|
54
|
-
const configPath = Config.configPathFromProjectPath(projectPath);
|
|
55
|
-
try {
|
|
56
|
-
const config = JSON.parse(await fs.readFile(configPath, "utf8"));
|
|
57
|
-
return new Config(projectPath, config);
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
throw new Error(`Error reading config file at: ${configPath}. Error: ${error.message}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
static newConfig(projectPath) {
|
|
64
|
-
return new Config(projectPath, {
|
|
65
|
-
version,
|
|
66
|
-
createdAt: new Date().toISOString(),
|
|
67
|
-
updatedAt: new Date().toISOString(),
|
|
68
|
-
options: {}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
Config.configPath = ".herb-lsp/config.json";
|
|
73
|
-
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAiBA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAA;AAEnC,MAAM,OAAO,MAAM;IAMjB,YAAY,WAAmB,EAAE,MAAqB;QACpD,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;QACzD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA;IAC5B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA;IAC5B,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IAChD,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAClD,CAAC;IAEO,aAAa;QACnB,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,aAAa,EAAE,CAAA;QACpB,IAAI,CAAC,eAAe,EAAE,CAAA;QAEtB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAEtC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;aACZ,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;aACd,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;aACzC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACtE,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC7C,CAAC;IAED,MAAM,CAAC,yBAAyB,CAAC,WAAmB;QAClD,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;IAChD,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,WAAmB;QAC5C,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAmB;QACvC,MAAM,UAAU,GAAG,MAAM,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;QAEhE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;YAEhE,OAAO,IAAI,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QACxC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,iCAAiC,UAAU,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACzF,CAAC;IACH,CAAC;IAED,MAAM,CAAC,SAAS,CAAC,WAAmB;QAClC,OAAO,IAAI,MAAM,CAAC,WAAW,EAAE;YAC7B,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,EAAE;SACZ,CAAC,CAAA;IACJ,CAAC;;AArFM,iBAAU,GAAG,uBAAuB,CAAA"}
|