Skip to content

Commit 4aa7cb9

Browse files
committed
Add ICSS class and support to CSS Statments
1 parent 2382f1d commit 4aa7cb9

File tree

2 files changed

+137
-44
lines changed

2 files changed

+137
-44
lines changed

index.html

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,42 @@
1111
<meta name="application-name" content="CSSObject.js">
1212
<title>CSSObject.js | KugiHaito</title>
1313
<style>
14+
15+
@import "style.css";
16+
@import url(url_to_font_or_css);
17+
1418
* {
1519
margin: 0;
1620
padding: 0;
1721
box-sizing: border-box;
1822

1923
}
2024

25+
@keyframes mymove {
26+
from {top: 0px;}
27+
to {top: 200px;}
28+
}
29+
2130
body {
22-
margin: 20px 40px;
31+
padding: 20px 40px;
2332
}
2433

25-
span {color: #212121;margin: 5px 0;}
34+
@font-face {
35+
font-family: "Open Sans";
36+
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
37+
}
38+
39+
p, span {color: #212121;margin: 5px 0;}
40+
41+
@media (max-width: 760px) {
42+
body {
43+
padding: 10px 20px;
44+
}
45+
46+
p, span {
47+
margin: 0;
48+
}
49+
}
2650

2751
.btn{
2852
color:white;

parsercss.js

Lines changed: 111 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
/**
2-
* ParserCSS Class
3-
*/
4-
class Parser {
1+
class ICSSStatments {
2+
static get IMPORT() { return 'import' }
3+
static get MEDIA() { return 'media' }
4+
static get KEYFRAME() { return 'keyframe' }
5+
static get FONT_FACE() { return 'font-face' }
6+
}
57

8+
class ICSS {
69
static get EMPTY() { return '' }
710

811
static get DOTS() { return ':' }
@@ -19,6 +22,8 @@ class Parser {
1922

2023
static get END_BRACKET() { return ')' }
2124

25+
static get DOUBLE_END_BRACKETS() { return '}}' }
26+
2227
static get END_BRACKET_RULE() { return ');' }
2328

2429
static get DATA_URI() { return 'data:' }
@@ -35,14 +40,27 @@ class Parser {
3540
let re = new RegExp(Object.keys(obj).join('|'), 'g')
3641
return str.replace(re, i => obj[i])
3742
}
43+
}
3844

45+
/**
46+
* ParserCSS Class
47+
*/
48+
class Parser {
49+
50+
/**
51+
* Initializate Parser
52+
* @param string css (optional)
53+
* @return object Parser
54+
*/
3955
constructor(css) {
4056
this.css = css
57+
this.clearCode()
4158
this.parseCSS()
4259

4360
delete this.rules
4461
delete this.query
45-
return this.blocks
62+
delete this.blockRules
63+
return this
4664
}
4765

4866
/**
@@ -52,12 +70,13 @@ class Parser {
5270
*/
5371
parseCSS(css = '') {
5472
this.blocks = []
55-
this.css = (css != Parser.EMPTY)? css:this.css
56-
this.blocksRule = this.clearCode().split(Parser.END_BLOCK)
73+
this.css = (css != ICSS.EMPTY)? css:this.css
74+
this.blocksRule = this.parseCSSStatments()
75+
.split(ICSS.END_BLOCK)
5776
this.blocksRule.pop()
5877

5978
this.blocksRule.map(block => {
60-
[this.query, this.rules] = block.split(Parser.BEGIN_BLOCK)
79+
[this.query, this.rules] = block.split(ICSS.BEGIN_BLOCK)
6180

6281
this.blocks.push({
6382
query: this.query.trim(),
@@ -76,50 +95,106 @@ class Parser {
7695
*/
7796
parseCSSBlock(rules = '') {
7897
this.blockRules = []
79-
this.rules = (rules != Parser.EMPTY)? rules : this.rules
80-
this.rules = this.parseCSSRules().split(Parser.SEMICOLON)
98+
this.rules = (rules != ICSS.EMPTY)? rules : this.rules
99+
this.rules = this.parseCSSRules().split(ICSS.SEMICOLON)
81100
this.rules.pop()
82101

83102
this.rules.map(decl => {
84-
let [prop, value] = decl.split(Parser.DOTS).map(i => i.trim())
85-
if (prop != Parser.EMPTY && value != Parser.EMPTY)
86-
this.blockRules.push(new Rule(prop, Parser.REGEX_REPLACE(value, Parser.DATA_URI_VALUES)))
103+
let [prop, value] = decl.split(ICSS.DOTS).map(i => i.trim())
104+
if (prop != ICSS.EMPTY && value != ICSS.EMPTY)
105+
this.blockRules.push(new Rule(prop, ICSS.REGEX_REPLACE(value, ICSS.DATA_URI_VALUES)))
87106
})
88107

89108
return this.blockRules
90109
}
91110

111+
112+
parseCSSStatments() {
113+
this.statments = {imports:[], medias:[], keyframes:[], font_faces:[]}
114+
this.css.split('@').map(blocklines => {
115+
let blockline = Object.keys(this.statments)
116+
.map(s => ICSS.REGEX_REPLACE(s, {'s':'', '_':'-'}))
117+
.filter(statment => blocklines.startsWith(statment))
118+
119+
if (blockline.length > 0) {
120+
let statment = `${blockline[0].replace('-', '_')}s`
121+
122+
if (blockline[0] == ICSSStatments.IMPORT) {
123+
console.log(this.css)
124+
this.css = this.css.replace(`@${blocklines.split(ICSS.SEMICOLON)[0]};`, ICSS.EMPTY)
125+
let path_or_url = blocklines
126+
.split(ICSS.SEMICOLON)[0]
127+
.split(blockline[0])[1].trim()
128+
129+
if (path_or_url.startsWith('"')) {
130+
path_or_url = path_or_url.replace(new RegExp('"', 'g'), ICSS.EMPTY)
131+
}
132+
133+
this.statments[statment].push(path_or_url)
134+
} else if (blockline[0] == ICSSStatments.FONT_FACE) {
135+
this.css = this.css.replace(`@${blocklines.split(ICSS.END_BLOCK)[0]}}`, ICSS.EMPTY)
136+
let rules = blocklines.split(ICSS.BEGIN_BLOCK)[1]
137+
.split(ICSS.END_BLOCK)[0].trim()
138+
rules = rules.split(ICSS.SEMICOLON).map(r => {
139+
if (r != ""){
140+
let [p, v] = r.split(ICSS.DOTS)
141+
return (new Rule(p, v.trim().replace(new RegExp('"', 'g'), ICSS.EMPTY)))
142+
}}).filter(r => r != undefined)
143+
144+
this.statments[statment].push(rules)
145+
} else {
146+
let mediaBlocks = []
147+
let lines = blocklines.split(ICSS.DOUBLE_END_BRACKETS)[0]
148+
this.css = this.css.replace(`@${lines}}}`, ICSS.EMPTY)
149+
let mediaQuery = lines.substring(0, lines.indexOf(ICSS.BEGIN_BLOCK)-1)
150+
lines = lines.substring(lines.indexOf(ICSS.BEGIN_BLOCK)+1)
151+
.split(ICSS.END_BLOCK)
152+
153+
lines.map(block => {
154+
let [query, rules] = block.split(ICSS.BEGIN_BLOCK)
155+
156+
mediaBlocks.push({
157+
query: query.trim(),
158+
selectors: query.trim().split(ICSS.COMMA).map(s => s.trim()),
159+
rules: rules.split(ICSS.SEMICOLON).map(r => {
160+
if (r != ""){
161+
let [p, v] = r.split(ICSS.DOTS)
162+
return (new Rule(p, v))
163+
}}).filter(r => r != undefined)
164+
})
165+
})
166+
this.statments[statment].push({query: mediaQuery, blocks: mediaBlocks})
167+
}
168+
}})
169+
170+
return this.css
171+
}
172+
92173
/**
93174
* parse css rules
94175
* @param string css rules
95176
* @return string
96177
*/
97178
parseCSSRules() {
98-
let params = {}
99-
return this.rules
100-
.split(Parser.BREAK_LINE)
101-
.filter(d => d != Parser.EMPTY)
179+
return this.rules.split(ICSS.BREAK_LINE)
180+
.filter(d => d != ICSS.EMPTY)
102181
.map(decl => {
103-
if (decl.includes(Parser.END_BRACKET_RULE)) {
182+
if (decl.includes(ICSS.END_BRACKET_RULE)) {
104183
let [p_keys, match, params, d] = [[], [], {}, decl]
105-
while (match = Parser.REGEX_BRACKETS.exec(d)) {
184+
while (match = ICSS.REGEX_BRACKETS.exec(d)) {
106185
p_keys.push(match[1])
107186
d = d.replace(match[1], '')
108187
}
109188
p_keys.map(p => {
110-
if (p.includes(Parser.DATA_URI)) {
111-
params[p] = Parser.REGEX_REPLACE(p, Parser.DATA_URI_KEYS)
112-
decl = Parser.REGEX_REPLACE(decl, params)
189+
if (p.includes(ICSS.DATA_URI)) {
190+
params[p] = ICSS.REGEX_REPLACE(p, ICSS.DATA_URI_KEYS)
191+
decl = ICSS.REGEX_REPLACE(decl, params)
113192
}
114-
})
193+
})
115194
}
116195

117196
return decl.trim()
118197
}).join('')
119-
// this.rules.pop()
120-
// console.log(this.rules)
121-
// this.rules = this.rule.join('')
122-
return this.rules
123198
}
124199

125200
/**
@@ -129,7 +204,7 @@ class Parser {
129204
parseCSSQuery() {
130205
return this.query
131206
.trim()
132-
.split(Parser.COMMA)
207+
.split(ICSS.COMMA)
133208
.map(s => s.trim())
134209
}
135210

@@ -139,9 +214,8 @@ class Parser {
139214
* @return string css
140215
*/
141216
clearCode(css = '') {
142-
console.log(this.css)
143-
this.css = ((css != Parser.EMPTY)? css:this.css).replace(Parser.REGEX_COMMENTS, Parser.EMPTY)
144-
return Parser.REGEX_REPLACE(this.css, {'\n': '', '\t': ''})
217+
this.css = ICSS.REGEX_REPLACE((((css != ICSS.EMPTY)? css:this.css).replace(ICSS.REGEX_COMMENTS, ICSS.EMPTY)), {'\n': '', '\t': ''})
218+
return this.css
145219
}
146220
}
147221

@@ -170,21 +244,16 @@ class Rule {
170244
*/
171245
set(value) {
172246
this.value = value
173-
if (this.value.includes(Parser.END_BRACKET)) {
174-
let str = Parser.REGEX_BRACKETS.exec(this.value)[1]
247+
if (this.value.includes(ICSS.END_BRACKET)) {
248+
let str = ICSS.REGEX_BRACKETS.exec(this.value)[1]
175249
this.detail = {}
176-
this.detail.args = str.split(Parser.COMMA).map(p => p.trim())
177-
this.detail.func = this.value.trim().replace(`(${str})`, Parser.EMPTY)
250+
this.detail.args = str.split(ICSS.COMMA).map(p => p.trim())
251+
this.detail.func = this.value.trim().replace(`(${str})`, ICSS.EMPTY)
178252
}
179253
return this.value
180254
}
181255
}
182256

183257

184-
window.onload = () => {
185-
186-
let cssText = document.styleSheets[0].ownerNode.innerText
187-
let parsed = (new Parser).parseCSS(cssText)
188-
console.log(parsed)
189-
190-
}
258+
let cssText = document.styleSheets[0].ownerNode.innerText
259+
console.log(new Parser(cssText))

0 commit comments

Comments
 (0)