@herb-tools/language-server 0.9.0 → 0.9.1

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.
@@ -1,7 +1,5 @@
1
1
  import { TextDocument } from "vscode-languageserver-textdocument";
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";
2
+ import { Connection } from "vscode-languageserver/node";
5
3
  import { ParserService } from "./parser_service";
6
4
  import { LinterService } from "./linter_service";
7
5
  import { DocumentService } from "./document_service";
@@ -15,38 +13,7 @@ export declare class Diagnostics {
15
13
  private diagnostics;
16
14
  constructor(connection: Connection, documentService: DocumentService, parserService: ParserService, linterService: LinterService, configService: ConfigService);
17
15
  validate(textDocument: TextDocument): Promise<void>;
18
- private getUnreachableCodeDiagnostics;
19
16
  refreshDocument(document: TextDocument): Promise<void>;
20
17
  refreshAllDocuments(): Promise<void>;
21
18
  private sendDiagnosticsFor;
22
19
  }
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
- }
@@ -1,6 +1,8 @@
1
- import { DiagnosticSeverity } from "vscode-languageserver/node";
1
+ import { DiagnosticSeverity, DiagnosticTag } from "vscode-languageserver/node";
2
2
  import type { LintSeverity } from "@herb-tools/linter";
3
+ import type { DiagnosticSeverity as HerbDiagnosticSeverity, DiagnosticTag as HerbDiagnosticTag } from "@herb-tools/core";
3
4
  export declare function camelize(value: string): string;
4
5
  export declare function dasherize(value: string): string;
5
6
  export declare function capitalize(value: string): string;
6
- export declare function lintToDignosticSeverity(severity: LintSeverity): DiagnosticSeverity;
7
+ export declare function lintToDignosticSeverity(severity: LintSeverity | HerbDiagnosticSeverity): DiagnosticSeverity;
8
+ export declare function lintToDignosticTags(tags?: HerbDiagnosticTag[]): DiagnosticTag[];
package/dist/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DiagnosticSeverity } from "vscode-languageserver/node";
1
+ import { DiagnosticSeverity, DiagnosticTag } from "vscode-languageserver/node";
2
2
  export function camelize(value) {
3
3
  return value.replace(/(?:[_-])([a-z0-9])/g, (_, char) => char.toUpperCase());
4
4
  }
@@ -16,4 +16,15 @@ export function lintToDignosticSeverity(severity) {
16
16
  case "hint": return DiagnosticSeverity.Hint;
17
17
  }
18
18
  }
19
+ export function lintToDignosticTags(tags) {
20
+ if (!tags)
21
+ return [];
22
+ return tags.flatMap(tag => {
23
+ switch (tag) {
24
+ case "unnecessary": return [DiagnosticTag.Unnecessary];
25
+ case "deprecated": return [DiagnosticTag.Deprecated];
26
+ default: return [];
27
+ }
28
+ });
29
+ }
19
30
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAG/D,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;AAC9E,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAAsB;IAC5D,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,OAAO,CAAC,CAAC,OAAO,kBAAkB,CAAC,KAAK,CAAA;QAC7C,KAAK,SAAS,CAAC,CAAC,OAAO,kBAAkB,CAAC,OAAO,CAAA;QACjD,KAAK,MAAM,CAAC,CAAC,OAAO,kBAAkB,CAAC,WAAW,CAAA;QAClD,KAAK,MAAM,CAAC,CAAC,OAAO,kBAAkB,CAAC,IAAI,CAAA;IAC7C,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAI9E,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;AAC9E,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAA+C;IACrF,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,OAAO,CAAC,CAAC,OAAO,kBAAkB,CAAC,KAAK,CAAA;QAC7C,KAAK,SAAS,CAAC,CAAC,OAAO,kBAAkB,CAAC,OAAO,CAAA;QACjD,KAAK,MAAM,CAAC,CAAC,OAAO,kBAAkB,CAAC,WAAW,CAAA;QAClD,KAAK,MAAM,CAAC,CAAC,OAAO,kBAAkB,CAAC,IAAI,CAAA;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAA0B;IAC5D,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAA;IAEpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;QACxB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,aAAa,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAA;YACtD,KAAK,YAAY,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAA;YACpD,OAAO,CAAC,CAAC,OAAO,EAAE,CAAA;QACpB,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
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.9.0",
4
+ "version": "0.9.1",
5
5
  "author": "Marco Roth",
6
6
  "license": "MIT",
7
7
  "engines": {
@@ -45,12 +45,12 @@
45
45
  "dist/"
46
46
  ],
47
47
  "dependencies": {
48
- "@herb-tools/config": "0.9.0",
49
- "@herb-tools/formatter": "0.9.0",
50
- "@herb-tools/linter": "0.9.0",
51
- "@herb-tools/node-wasm": "0.9.0",
52
- "@herb-tools/printer": "0.9.0",
53
- "@herb-tools/rewriter": "0.9.0",
48
+ "@herb-tools/config": "0.9.1",
49
+ "@herb-tools/formatter": "0.9.1",
50
+ "@herb-tools/linter": "0.9.1",
51
+ "@herb-tools/node-wasm": "0.9.1",
52
+ "@herb-tools/printer": "0.9.1",
53
+ "@herb-tools/rewriter": "0.9.1",
54
54
  "dedent": "^1.7.0",
55
55
  "vscode-languageserver": "^9.0.1",
56
56
  "vscode-languageserver-textdocument": "^1.0.12"
@@ -1,33 +1,10 @@
1
1
  import { TextDocument } from "vscode-languageserver-textdocument"
2
- import { Connection, Diagnostic, DiagnosticSeverity, DiagnosticTag } from "vscode-languageserver/node"
3
- import { Visitor } from "@herb-tools/core"
4
-
5
- import type {
6
- Node,
7
- SerializedLocation,
8
- ERBCaseNode,
9
- ERBCaseMatchNode,
10
- ERBIfNode,
11
- ERBElseNode,
12
- ERBUnlessNode,
13
- ERBForNode,
14
- ERBWhileNode,
15
- ERBUntilNode,
16
- ERBWhenNode,
17
- ERBBeginNode,
18
- ERBRescueNode,
19
- ERBEnsureNode,
20
- ERBBlockNode,
21
- ERBInNode,
22
- } from "@herb-tools/core"
23
-
24
- import { isHTMLTextNode, isERBIfNode, isERBElseNode } from "@herb-tools/core"
2
+ import { Connection, Diagnostic } from "vscode-languageserver/node"
25
3
 
26
4
  import { ParserService } from "./parser_service"
27
5
  import { LinterService } from "./linter_service"
28
6
  import { DocumentService } from "./document_service"
29
7
  import { ConfigService } from "./config_service"
30
- import { lspRangeFromLocation } from "./range_utils"
31
8
 
32
9
  export class Diagnostics {
33
10
  private readonly connection: Connection
@@ -59,12 +36,10 @@ export class Diagnostics {
59
36
  } else {
60
37
  const parseResult = this.parserService.parseDocument(textDocument)
61
38
  const lintResult = await this.linterService.lintDocument(textDocument)
62
- const unreachableCodeDiagnostics = this.getUnreachableCodeDiagnostics(parseResult.document)
63
39
 
64
40
  allDiagnostics = [
65
41
  ...parseResult.diagnostics,
66
42
  ...lintResult.diagnostics,
67
- ...unreachableCodeDiagnostics,
68
43
  ]
69
44
  }
70
45
 
@@ -72,12 +47,6 @@ export class Diagnostics {
72
47
  this.sendDiagnosticsFor(textDocument)
73
48
  }
74
49
 
75
- private getUnreachableCodeDiagnostics(document: Node): Diagnostic[] {
76
- const collector = new UnreachableCodeCollector()
77
- collector.visit(document)
78
- return collector.diagnostics
79
- }
80
-
81
50
  async refreshDocument(document: TextDocument) {
82
51
  await this.validate(document)
83
52
  }
@@ -98,262 +67,3 @@ export class Diagnostics {
98
67
  this.diagnostics.delete(textDocument)
99
68
  }
100
69
  }
101
-
102
- export class UnreachableCodeCollector extends Visitor {
103
- diagnostics: Diagnostic[] = []
104
- private processedIfNodes: Set<ERBIfNode> = new Set()
105
- private processedElseNodes: Set<ERBElseNode> = new Set()
106
-
107
- visitERBCaseNode(node: ERBCaseNode): void {
108
- this.checkUnreachableChildren(node.children)
109
- this.checkAndMarkElseClause(node.else_clause)
110
- this.visitChildNodes(node)
111
- }
112
-
113
- visitERBCaseMatchNode(node: ERBCaseMatchNode): void {
114
- this.checkUnreachableChildren(node.children)
115
- this.checkAndMarkElseClause(node.else_clause)
116
- this.visitChildNodes(node)
117
- }
118
-
119
- visitERBIfNode(node: ERBIfNode): void {
120
- if (this.processedIfNodes.has(node)) {
121
- return
122
- }
123
-
124
- this.markIfChainAsProcessed(node)
125
-
126
- this.markElseNodesInIfChain(node)
127
-
128
- const entireChainEmpty = this.isEntireIfChainEmpty(node)
129
-
130
- if (entireChainEmpty) {
131
- this.checkEmptyStatements(node, node.statements, "if")
132
- } else {
133
- this.checkIfChainParts(node)
134
- }
135
-
136
- this.visitChildNodes(node)
137
- }
138
-
139
- visitERBElseNode(node: ERBElseNode): void {
140
- if (this.processedElseNodes.has(node)) {
141
- this.visitChildNodes(node)
142
- return
143
- }
144
-
145
- this.checkEmptyStatements(node, node.statements, "else")
146
- this.visitChildNodes(node)
147
- }
148
-
149
- visitERBUnlessNode(node: ERBUnlessNode): void {
150
- const unlessHasContent = this.statementsHaveContent(node.statements)
151
- const elseHasContent = node.else_clause && this.statementsHaveContent(node.else_clause.statements)
152
-
153
- if (node.else_clause) {
154
- this.processedElseNodes.add(node.else_clause)
155
- }
156
-
157
- const entireBlockEmpty = !unlessHasContent && !elseHasContent
158
-
159
- if (entireBlockEmpty) {
160
- this.checkEmptyStatements(node, node.statements, "unless")
161
- } else {
162
- if (!unlessHasContent) {
163
- this.checkEmptyStatementsWithEndLocation(node, node.statements, "unless", node.else_clause)
164
- }
165
-
166
- if (node.else_clause && !elseHasContent) {
167
- this.checkEmptyStatements(node.else_clause, node.else_clause.statements, "else")
168
- }
169
- }
170
-
171
- this.visitChildNodes(node)
172
- }
173
-
174
- visitERBForNode(node: ERBForNode): void {
175
- this.checkEmptyStatements(node, node.statements, "for")
176
- this.visitChildNodes(node)
177
- }
178
-
179
- visitERBWhileNode(node: ERBWhileNode): void {
180
- this.checkEmptyStatements(node, node.statements, "while")
181
- this.visitChildNodes(node)
182
- }
183
-
184
- visitERBUntilNode(node: ERBUntilNode): void {
185
- this.checkEmptyStatements(node, node.statements, "until")
186
- this.visitChildNodes(node)
187
- }
188
-
189
- visitERBWhenNode(node: ERBWhenNode): void {
190
- if (!node.then_keyword) {
191
- this.checkEmptyStatements(node, node.statements, "when")
192
- }
193
-
194
- this.visitChildNodes(node)
195
- }
196
-
197
- visitERBBeginNode(node: ERBBeginNode): void {
198
- this.checkEmptyStatements(node, node.statements, "begin")
199
- this.visitChildNodes(node)
200
- }
201
-
202
- visitERBRescueNode(node: ERBRescueNode): void {
203
- this.checkEmptyStatements(node, node.statements, "rescue")
204
- this.visitChildNodes(node)
205
- }
206
-
207
- visitERBEnsureNode(node: ERBEnsureNode): void {
208
- this.checkEmptyStatements(node, node.statements, "ensure")
209
- this.visitChildNodes(node)
210
- }
211
-
212
- visitERBBlockNode(node: ERBBlockNode): void {
213
- this.checkEmptyStatements(node, node.body, "block")
214
- this.visitChildNodes(node)
215
- }
216
-
217
- visitERBInNode(node: ERBInNode): void {
218
- if (!node.then_keyword) {
219
- this.checkEmptyStatements(node, node.statements, "in")
220
- }
221
-
222
- this.visitChildNodes(node)
223
- }
224
-
225
- private checkUnreachableChildren(children: Node[]): void {
226
- for (const child of children) {
227
- if (isHTMLTextNode(child) && child.content.trim() === "") {
228
- continue
229
- }
230
-
231
- this.addDiagnostic(
232
- child.location,
233
- "Unreachable code: content between case and when/in is never executed"
234
- )
235
- }
236
- }
237
-
238
- private checkEmptyStatements(node: Node, statements: Node[], blockType: string): void {
239
- this.checkEmptyStatementsWithEndLocation(node, statements, blockType, null)
240
- }
241
-
242
- private checkEmptyStatementsWithEndLocation(node: Node, statements: Node[], blockType: string, subsequentNode: Node | null): void {
243
- if (this.statementsHaveContent(statements)) {
244
- return
245
- }
246
-
247
- const startLocation = node.location.start
248
- const endLocation = subsequentNode
249
- ? subsequentNode.location.start
250
- : node.location.end
251
-
252
- this.addDiagnostic(
253
- { start: startLocation, end: endLocation },
254
- `Empty ${blockType} block: this control flow statement has no content`
255
- )
256
- }
257
-
258
- private addDiagnostic(location: SerializedLocation, message: string): void {
259
- const diagnostic: Diagnostic = {
260
- range: lspRangeFromLocation(location),
261
- message,
262
- severity: DiagnosticSeverity.Hint,
263
- tags: [DiagnosticTag.Unnecessary],
264
- source: "Herb Language Server"
265
- }
266
-
267
- this.diagnostics.push(diagnostic)
268
- }
269
-
270
- private statementsHaveContent(statements: Node[]): boolean {
271
- return statements.some(statement => {
272
- if (isHTMLTextNode(statement)) {
273
- return statement.content.trim() !== ""
274
- }
275
-
276
- return true
277
- })
278
- }
279
-
280
- private checkAndMarkElseClause(elseClause: ERBElseNode | null): void {
281
- if (!elseClause) {
282
- return
283
- }
284
-
285
- this.processedElseNodes.add(elseClause)
286
- if (!this.statementsHaveContent(elseClause.statements)) {
287
- this.checkEmptyStatements(elseClause, elseClause.statements, "else")
288
- }
289
- }
290
-
291
- private markIfChainAsProcessed(node: ERBIfNode): void {
292
- this.processedIfNodes.add(node)
293
- this.traverseSubsequentNodes(node.subsequent, (current) => {
294
- if (isERBIfNode(current)) {
295
- this.processedIfNodes.add(current)
296
- }
297
- })
298
- }
299
-
300
- private markElseNodesInIfChain(node: ERBIfNode): void {
301
- this.traverseSubsequentNodes(node.subsequent, (current) => {
302
- if (isERBElseNode(current)) {
303
- this.processedElseNodes.add(current)
304
- }
305
- })
306
- }
307
-
308
- private traverseSubsequentNodes(startNode: Node | null, callback: (node: ERBIfNode | ERBElseNode) => void): void {
309
- let current: Node | null = startNode
310
- while (current) {
311
- if (isERBIfNode(current)) {
312
- callback(current)
313
- current = current.subsequent
314
- } else if (isERBElseNode(current)) {
315
- callback(current)
316
- break
317
- } else {
318
- break
319
- }
320
- }
321
- }
322
-
323
- private checkIfChainParts(node: ERBIfNode): void {
324
- if (!this.statementsHaveContent(node.statements)) {
325
- this.checkEmptyStatementsWithEndLocation(node, node.statements, "if", node.subsequent)
326
- }
327
-
328
- this.traverseSubsequentNodes(node.subsequent, (current) => {
329
- if (this.statementsHaveContent(current.statements)) {
330
- return
331
- }
332
-
333
- const blockType = isERBIfNode(current) ? 'elsif' : 'else'
334
- const nextSubsequent = isERBIfNode(current) ? current.subsequent : null
335
-
336
- if (nextSubsequent) {
337
- this.checkEmptyStatementsWithEndLocation(current, current.statements, blockType, nextSubsequent)
338
- } else {
339
- this.checkEmptyStatements(current, current.statements, blockType)
340
- }
341
- })
342
- }
343
-
344
- private isEntireIfChainEmpty(node: ERBIfNode): boolean {
345
- if (this.statementsHaveContent(node.statements)) {
346
- return false
347
- }
348
-
349
- let hasContent = false
350
- this.traverseSubsequentNodes(node.subsequent, (current) => {
351
- if (this.statementsHaveContent(current.statements)) {
352
- hasContent = true
353
- }
354
- })
355
-
356
- return !hasContent
357
- }
358
-
359
- }
@@ -8,7 +8,7 @@ import { Config } from "@herb-tools/config"
8
8
 
9
9
  import { Settings } from "./settings"
10
10
  import { Project } from "./project"
11
- import { lintToDignosticSeverity } from "./utils"
11
+ import { lintToDignosticSeverity, lintToDignosticTags } from "./utils"
12
12
  import { lspRangeFromLocation } from "./range_utils"
13
13
 
14
14
  const OPEN_CONFIG_ACTION = 'Open .herb.yml'
@@ -179,7 +179,7 @@ export class LinterService {
179
179
  : ruleDocumentationUrl(offense.rule)
180
180
  }
181
181
 
182
- return {
182
+ const diagnostic: Diagnostic = {
183
183
  source: this.source,
184
184
  severity: lintToDignosticSeverity(offense.severity),
185
185
  range,
@@ -188,6 +188,14 @@ export class LinterService {
188
188
  data: { rule: offense.rule },
189
189
  codeDescription
190
190
  }
191
+
192
+ const tags = lintToDignosticTags(offense.tags)
193
+
194
+ if (tags.length > 0) {
195
+ diagnostic.tags = tags
196
+ }
197
+
198
+ return diagnostic
191
199
  })
192
200
 
193
201
  return { diagnostics }
package/src/server.ts CHANGED
@@ -186,6 +186,9 @@ export class Server {
186
186
 
187
187
  if (!document) return []
188
188
 
189
+ const parseResult = this.service.parserService.parseDocument(document)
190
+ if (parseResult.diagnostics.length > 0) return []
191
+
189
192
  const diagnostics = params.context.diagnostics
190
193
  const documentText = document.getText()
191
194
 
package/src/utils.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { DiagnosticSeverity } from "vscode-languageserver/node"
1
+ import { DiagnosticSeverity, DiagnosticTag } from "vscode-languageserver/node"
2
2
  import type { LintSeverity } from "@herb-tools/linter"
3
+ import type { DiagnosticSeverity as HerbDiagnosticSeverity, DiagnosticTag as HerbDiagnosticTag } from "@herb-tools/core"
3
4
 
4
5
  export function camelize(value: string) {
5
6
  return value.replace(/(?:[_-])([a-z0-9])/g, (_, char) => char.toUpperCase())
@@ -13,7 +14,7 @@ export function capitalize(value: string) {
13
14
  return value.charAt(0).toUpperCase() + value.slice(1)
14
15
  }
15
16
 
16
- export function lintToDignosticSeverity(severity: LintSeverity): DiagnosticSeverity {
17
+ export function lintToDignosticSeverity(severity: LintSeverity | HerbDiagnosticSeverity): DiagnosticSeverity {
17
18
  switch (severity) {
18
19
  case "error": return DiagnosticSeverity.Error
19
20
  case "warning": return DiagnosticSeverity.Warning
@@ -21,3 +22,15 @@ export function lintToDignosticSeverity(severity: LintSeverity): DiagnosticSever
21
22
  case "hint": return DiagnosticSeverity.Hint
22
23
  }
23
24
  }
25
+
26
+ export function lintToDignosticTags(tags?: HerbDiagnosticTag[]): DiagnosticTag[] {
27
+ if (!tags) return []
28
+
29
+ return tags.flatMap(tag => {
30
+ switch (tag) {
31
+ case "unnecessary": return [DiagnosticTag.Unnecessary]
32
+ case "deprecated": return [DiagnosticTag.Deprecated]
33
+ default: return []
34
+ }
35
+ })
36
+ }