Skip to content

Commit 3c7d211

Browse files
committed
Add Selector and Pseudo class and support to many functions values
1 parent 4aa7cb9 commit 3c7d211

File tree

1 file changed

+121
-41
lines changed

1 file changed

+121
-41
lines changed

parsercss.js

Lines changed: 121 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,48 @@
1+
/**
2+
* ICSS Staments Interface
3+
*/
14
class ICSSStatments {
25
static get IMPORT() { return 'import' }
36
static get MEDIA() { return 'media' }
47
static get KEYFRAME() { return 'keyframe' }
58
static get FONT_FACE() { return 'font-face' }
69
}
710

11+
/**
12+
* ICSS Symbols Interface
13+
*/
814
class ICSS {
915
static get EMPTY() { return '' }
10-
1116
static get DOTS() { return ':' }
12-
1317
static get COMMA() { return ',' }
14-
1518
static get SEMICOLON() { return ';' }
16-
1719
static get BREAK_LINE() { return '\n' }
18-
1920
static get BEGIN_BLOCK() { return '{' }
20-
2121
static get END_BLOCK() { return '}' }
22-
22+
static get BEGIN_BRACKET() { return '(' }
2323
static get END_BRACKET() { return ')' }
24-
2524
static get DOUBLE_END_BRACKETS() { return '}}' }
26-
2725
static get END_BRACKET_RULE() { return ');' }
28-
2926
static get DATA_URI() { return 'data:' }
30-
3127
static get DATA_URI_KEYS() { return {':': '=', ';': '&'} }
32-
3328
static get DATA_URI_VALUES() { return {'=': ':', '&': ';'} }
34-
3529
static get REGEX_COMMENTS() { return /\/\*(\r|\n|.)*\*\//g }
36-
3730
static get REGEX_BRACKETS() { return /\(([^)]+)\)/ }
38-
3931
static REGEX_REPLACE(str, obj) {
40-
let re = new RegExp(Object.keys(obj).join('|'), 'g')
41-
return str.replace(re, i => obj[i])
32+
let re = new RegExp(Object.keys(obj).join('|'), 'g')
33+
return str.replace(re, i => obj[i])
4234
}
4335
}
4436

37+
4538
/**
4639
* ParserCSS Class
4740
*/
4841
class Parser {
49-
42+
5043
/**
5144
* Initializate Parser
52-
* @param string css (optional)
45+
* @param string css
5346
* @return object Parser
5447
*/
5548
constructor(css) {
@@ -59,6 +52,7 @@ class Parser {
5952

6053
delete this.rules
6154
delete this.query
55+
delete this.blocksRule
6256
delete this.blockRules
6357
return this
6458
}
@@ -109,6 +103,10 @@ class Parser {
109103
}
110104

111105

106+
/**
107+
* Parse CSS Statments
108+
* @return string css
109+
*/
112110
parseCSSStatments() {
113111
this.statments = {imports:[], medias:[], keyframes:[], font_faces:[]}
114112
this.css.split('@').map(blocklines => {
@@ -120,7 +118,6 @@ class Parser {
120118
let statment = `${blockline[0].replace('-', '_')}s`
121119

122120
if (blockline[0] == ICSSStatments.IMPORT) {
123-
console.log(this.css)
124121
this.css = this.css.replace(`@${blocklines.split(ICSS.SEMICOLON)[0]};`, ICSS.EMPTY)
125122
let path_or_url = blocklines
126123
.split(ICSS.SEMICOLON)[0]
@@ -152,7 +149,6 @@ class Parser {
152149

153150
lines.map(block => {
154151
let [query, rules] = block.split(ICSS.BEGIN_BLOCK)
155-
156152
mediaBlocks.push({
157153
query: query.trim(),
158154
selectors: query.trim().split(ICSS.COMMA).map(s => s.trim()),
@@ -198,28 +194,80 @@ class Parser {
198194
}
199195

200196
/**
201-
* parse css selectors
202-
* @return array Selector
203-
*/
197+
* parse css selectors
198+
* @return array Selector
199+
*/
204200
parseCSSQuery() {
205-
return this.query
206-
.trim()
201+
return this.query.trim()
207202
.split(ICSS.COMMA)
208-
.map(s => s.trim())
203+
.map(s => new Selector(s.trim()))
209204
}
210205

211206
/**
212207
* clear code and remove comments
213208
* @param string css
214209
* @return string css
215-
*/
210+
*/
216211
clearCode(css = '') {
217-
this.css = ICSS.REGEX_REPLACE((((css != ICSS.EMPTY)? css:this.css).replace(ICSS.REGEX_COMMENTS, ICSS.EMPTY)), {'\n': '', '\t': ''})
212+
this.css = ICSS.REGEX_REPLACE((((css != ICSS.EMPTY)? css:this.css)
213+
.replace(ICSS.REGEX_COMMENTS, ICSS.EMPTY)), {'\n': '', '\t': ''})
218214
return this.css
219215
}
220216
}
221217

222218

219+
/**
220+
* Selector Class
221+
* selector object for query selectors
222+
*/
223+
class Selector {
224+
225+
constructor(s) {
226+
this.selector = s
227+
return this.selector
228+
}
229+
230+
set selector(s) {
231+
let chars = {
232+
"#": 'IDSelector',
233+
".": 'ClassSelector',
234+
"[": 'AttrSelector',
235+
":": 'PseudoSelector',
236+
"::": 'PseudoElementSelector',
237+
};let signs = Object.keys(chars);
238+
239+
this.type = (signs.includes(s.substr(0, 2)) || signs.includes(s[0]))?
240+
chars[signs.filter(i => s.substr(0, 2) == i)[0] || signs.filter(i => s[0] == i)]:'HTMLElement'
241+
242+
let sel = s.replace(Object.entries(chars).map(([k, v]) => (v == this.type)?k:'').filter(f => f != "")[0], '')
243+
Pseudo._indexs.map(p => {
244+
if (sel.includes(p))
245+
this.pseudo = new Pseudo(p + sel.split(p)[(this.type == 'PseudoElementSelector')? 2:1])
246+
})
247+
}
248+
}
249+
250+
251+
/**
252+
* Pseudo Class
253+
* pseudo object for query selectors
254+
*/
255+
class Pseudo {
256+
257+
constructor(pseudo) {
258+
this._pseudo = pseudo
259+
this.type = (pseudo[1] == ':')? 'PseudoElement':(pseudo[0] == ':')? 'PseudoClass':'PseudoEvent'
260+
}
261+
262+
get pseudo() {
263+
return this._pseudo.replace((this._pseudo[1] == ':')? '::':(this._pseudo[0] == ':')? ':':'@', '')
264+
}
265+
266+
static get _indexs() {
267+
return [':', '::', '@']
268+
}
269+
}
270+
223271
/**
224272
* Rule Class
225273
*/
@@ -233,24 +281,56 @@ class Rule {
233281
*/
234282
constructor(prop, value) {
235283
this.prop = prop
236-
this.value = this.set(value)
284+
this.value = value
237285

238286
return this
239287
}
240288

241289
/**
242-
* set details of value rule
243-
* @return object
244-
*/
245-
set(value) {
246-
this.value = value
247-
if (this.value.includes(ICSS.END_BRACKET)) {
248-
let str = ICSS.REGEX_BRACKETS.exec(this.value)[1]
249-
this.detail = {}
250-
this.detail.args = str.split(ICSS.COMMA).map(p => p.trim())
251-
this.detail.func = this.value.trim().replace(`(${str})`, ICSS.EMPTY)
290+
* get property of rule
291+
* @return string property
292+
*/
293+
get property() {
294+
return this.prop
295+
}
296+
297+
/**
298+
* get value of rule
299+
* @return string value
300+
*/
301+
get value() {
302+
return this._value.value
303+
}
304+
305+
/**
306+
* set value and details of rule
307+
* @param string val
308+
*/
309+
set value(val) {
310+
311+
let func_values = []
312+
313+
if (val.includes(ICSS.END_BRACKET)) {
314+
let value = val.split(ICSS.END_BRACKET).map(s => s.trim());value.pop()
315+
let functions = value.map(s => {
316+
let [ func, values ] = s.split(ICSS.BEGIN_BRACKET).map(s => s.trim());let f = {}
317+
f[func.replaceAll('-', '_')] = (values.includes(ICSS.DATA_URI))?
318+
[ values ]:values.split(ICSS.COMMA).map(v => v.trim().split(' '))
319+
320+
func_values.push(values)
321+
return f
322+
})
323+
324+
this.details = { functions }
252325
}
253-
return this.value
326+
327+
// trying support to many values of property
328+
// if (func_values.length > 0) {
329+
// let v = val.replace(new RegExp(func_values.join('|'), 'g'), '')
330+
// let values = v.split(ICSS.COMMA).map(s => s.trim())
331+
// }
332+
333+
this._value = Object.assign({value: val }, this.details)
254334
}
255335
}
256336

0 commit comments

Comments
 (0)