-
Notifications
You must be signed in to change notification settings - Fork 0
/
extension.js
127 lines (106 loc) · 2.93 KB
/
extension.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
const vscode = require("vscode");
const path = require("path");
const cssTree = require("css-tree");
const scssTree = require("scss-parser");
const queryAst = require("query-ast");
class CSSSense {
constructor() {
this.context = null;
this.provider = null;
}
activate(context) {
this.context = context;
this.createProvider();
}
deactivate() {}
getSelectors(document) {
const _this = this;
const cssUri = this.getCSSUri(document.getText(), document);
if (cssUri === null) {
return new vscode.CompletionList();
}
return this.loadUri(cssUri).then(function(a) {
const selectorArray = a
.flat()
.filter(_this.unique)
.sort();
return new vscode.CompletionList(
selectorArray.map(_this.completionListItemFromString)
);
});
}
completionListItemFromString(str) {
return new vscode.CompletionItem(str, vscode.CompletionItemKind.Property);
}
getCSSUri(txt, document) {
const m = txt.match(/import styles from (?:'|")(.*)(?:'|");/);
if (m === null) {
return null;
}
return path.join(path.dirname(document.fileName), m[1]);
}
loadUri(uri) {
const _this = this;
return new Promise(function(resolve, reject) {
vscode.workspace.openTextDocument(uri).then(document => {
const filetype = document.languageId;
const text = document.getText();
resolve(_this.parseSelectors(filetype, text));
});
});
}
unique(value, index, self) {
return self.indexOf(value) === index;
}
parseSelectors(filetype, text) {
if (filetype === "css") {
return this.parseCSS(text);
}
if (filetype === "scss") {
return this.parseSCSS(text);
}
return [];
}
parseCSS(text) {
let r = [];
const ast = cssTree.parse(text);
cssTree.walk(ast, function(node) {
if (node.type === "ClassSelector") {
r.push(node.name);
}
});
return r;
}
parseSCSS(text) {
let r = [];
const ast = scssTree.parse(text);
const $ = queryAst(ast);
return r.concat(
$("class").map(cls => {
return cls.toJSON().value[0].value;
})
);
}
createProvider() {
const _this = this;
const provider = vscode.languages.registerCompletionItemProvider(
[{ language: "javascriptreact" }, { language: "typescriptreact" }],
{
provideCompletionItems(document, position) {
let linePrefix = document
.lineAt(position)
.text.substr(0, position.character);
if (!linePrefix.endsWith("styles.")) {
return undefined;
}
return _this.getSelectors(document);
}
},
"." // triggered whenever a '.' is being typed
);
this.context.subscriptions.push(provider);
}
}
const cssSense = new CSSSense();
module.exports.activate = cssSense.activate.bind(cssSense);
module.exports.deactivate = cssSense.deactivate.bind(cssSense);