Skip to content

Commit 14c534a

Browse files
committed
Added validation
1 parent 3bb5178 commit 14c534a

File tree

6 files changed

+75
-121
lines changed

6 files changed

+75
-121
lines changed

CHANGELOG.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
All notable changes to the extension will be documented in this file.
44

5-
## [1.4.0] -
5+
## [1.4.0] - 2020-12-26
66

7+
- Added validation.
78
- Added @extends('base') tag for inheritance.
8-
- Added [CSS: Validate Attributes] command.
9-
- Added [CSS: Clear Cache] command.
10-
- Added integration tests.
9+
- Added integration test.
1110

1211
## [1.3.3] - 2020-12-22
1312

README.md

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,6 @@ Extension can be configured to support any language where it makes sense such as
163163

164164
This setting is application scoped and changing the setting requires restarting VS Code.
165165

166-
## Commands
167-
168-
### Validate Attributes
169-
170-
Validates all `id` and `class` attributes in the document.
171-
172-
### Clear Cache
173-
174-
Clears cache and disposes file watchers.
175-
176166
## Installation
177167

178168
Extension can be installed from [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=ecmel.vscode-html-css).

package.json

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,7 @@
5151
"scope": "resource"
5252
}
5353
}
54-
},
55-
"commands": [
56-
{
57-
"command": "vscode-html-css.validate",
58-
"title": "CSS: Validate Attributes"
59-
},
60-
{
61-
"command": "vscode-html-css.dispose",
62-
"title": "CSS: Clear Cache"
63-
}
64-
]
54+
}
6555
},
6656
"main": "./dist/extension.js",
6757
"scripts": {

src/commands.ts

Lines changed: 0 additions & 83 deletions
This file was deleted.

src/completion.ts

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import {
88
CompletionItemKind,
99
CompletionItemProvider,
1010
CompletionList,
11+
Diagnostic,
12+
DiagnosticSeverity,
1113
Disposable,
14+
languages,
1215
Position,
1316
ProviderResult,
1417
Range,
@@ -24,17 +27,24 @@ export class ClassCompletionItemProvider implements CompletionItemProvider, Disp
2427
readonly cache = new Map<string, Map<string, CompletionItem>>();
2528
readonly extends = new Map<string, Set<string>>();
2629
readonly watchers = new Map<string, Disposable>();
30+
readonly collection = languages.createDiagnosticCollection("vscode-html-css");
2731
readonly isRemote = /^https?:\/\//i;
2832
readonly canComplete = /(id|class|className)\s*=\s*("|')(?:(?!\2).)*$/si;
2933
readonly findLinkRel = /rel\s*=\s*("|')((?:(?!\1).)+)\1/si;
3034
readonly findLinkHref = /href\s*=\s*("|')((?:(?!\1).)+)\1/si;
3135
readonly findExtended = /(?:{{<|{%\s*extends|@extends\s*\()\s*("|')?([./A-Za-z_0-9\\\-]+)\1\s*(?:\)|%}|}})/i;
3236

33-
dispose() {
34-
for (const watcher of this.watchers.values()) {
35-
watcher.dispose();
36-
}
37+
constructor() {
38+
let debounce: NodeJS.Timeout;
3739

40+
this.watchers.set("changed", workspace.onDidChangeTextDocument(e => {
41+
clearTimeout(debounce);
42+
debounce = setTimeout(() => this.validate(e.document), 1000);
43+
}));
44+
}
45+
46+
dispose() {
47+
this.watchers.forEach(v => v.dispose());
3848
this.cache.clear();
3949
this.extends.clear();
4050
this.watchers.clear();
@@ -283,4 +293,59 @@ export class ClassCompletionItemProvider implements CompletionItemProvider, Disp
283293
}
284294
});
285295
}
296+
297+
validate(document: TextDocument) {
298+
const uri = document.uri;
299+
const text = document.getText();
300+
301+
this.findAll(uri, text).then(sets => {
302+
const ids = new Set<string>();
303+
const classes = new Set<string>();
304+
305+
sets.forEach(set => set.forEach(key => this.getItems(key)?.forEach((v, k) => {
306+
if (v.kind === CompletionItemKind.Value) {
307+
ids.add(k);
308+
} else {
309+
classes.add(k);
310+
}
311+
})));
312+
313+
const diagnostics: Diagnostic[] = [];
314+
const findAttribute = /(id|class|className)\s*=\s*("|')(.+?)\2/gsi;
315+
316+
let attribute;
317+
318+
while ((attribute = findAttribute.exec(text)) !== null) {
319+
const offset = findAttribute.lastIndex
320+
- attribute[3].length
321+
+ attribute[3].indexOf(attribute[2]);
322+
323+
const findValue = /([^\s]+)/gi;
324+
325+
let value;
326+
327+
while ((value = findValue.exec(attribute[3])) !== null) {
328+
const anchor = findValue.lastIndex + offset;
329+
const end = document.positionAt(anchor);
330+
const start = document.positionAt(anchor - value[1].length);
331+
332+
if (attribute[1] === "id") {
333+
if (!ids.has(value[1])) {
334+
diagnostics.push(new Diagnostic(new Range(start, end),
335+
`CSS id selector '${value[1]}' not found.`,
336+
DiagnosticSeverity.Warning));
337+
}
338+
} else {
339+
if (!classes.has(value[1])) {
340+
diagnostics.push(new Diagnostic(new Range(start, end),
341+
`CSS class selector '${value[1]}' not found.`,
342+
DiagnosticSeverity.Warning));
343+
}
344+
}
345+
}
346+
}
347+
348+
this.collection.set(uri, diagnostics);
349+
});
350+
}
286351
}

src/extension.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
1-
import { validate, dispose } from "./commands";
21
import { ClassCompletionItemProvider } from "./completion";
32
import { ExtensionContext, languages, workspace, commands } from "vscode";
43

54
export function activate(context: ExtensionContext) {
6-
75
const config = workspace.getConfiguration("css");
86
const enabledLanguages = config.get<string[]>("enabledLanguages", ["html"]);
9-
const triggerCharacters = ["\"", "'"];
10-
117
const provider = new ClassCompletionItemProvider();
128

139
context.subscriptions.push(
1410
languages.registerCompletionItemProvider(
1511
enabledLanguages,
16-
provider,
17-
...triggerCharacters
12+
provider
1813
),
19-
provider,
20-
commands.registerCommand("vscode-html-css.validate", validate(provider)),
21-
commands.registerCommand("vscode-html-css.dispose", dispose(provider))
14+
provider
2215
);
2316
}
2417

0 commit comments

Comments
 (0)