Skip to content

Commit 25e8fde

Browse files
(compressor) Updates
1 parent 31d37c6 commit 25e8fde

File tree

2 files changed

+69
-46
lines changed

2 files changed

+69
-46
lines changed

src/compress.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const fs = require('fs');
2828
const path = require('path');
2929

3030
const deployDir = process.argv[2] || __dirname;
31-
const parseCSS = require('./modules/parse/css.js');
31+
const parseCSS = require('./modules/ast/css.js');
3232

3333
function compressFile(filePath) {
3434
let content = fs.readFileSync(filePath, 'utf8');

src/modules/parse/css.js renamed to src/modules/ast/css.js

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,94 +26,120 @@ SOFTWARE.
2626

2727
exports.JSON = function(cssText) {
2828
const cleanedCSS = cssText.replace(/\/\*[\s\S]*?\*\//g, '');
29-
3029
let index = 0;
30+
const length = cleanedCSS.length;
3131

3232
function skipWhitespace() {
33-
while (/\s/.test(cleanedCSS[index])) index++;
33+
while (index < length && /\s/.test(cleanedCSS[index])) index++;
3434
}
3535

36-
function parseRules() {
37-
const rules = [];
36+
function peek() {
37+
return cleanedCSS[index];
38+
}
3839

39-
while (index < cleanedCSS.length) {
40-
skipWhitespace();
40+
function consume() {
41+
return cleanedCSS[index++];
42+
}
4143

42-
if (cleanedCSS[index] === '}') {
43-
index++;
44-
break;
45-
}
44+
const stack = [];
45+
const rules = [];
4646

47-
if (cleanedCSS[index] === '@') {
48-
rules.push(parseAtRule());
49-
} else {
50-
rules.push(parseSelectorOrNested());
51-
}
47+
while (index < length) {
48+
skipWhitespace();
49+
50+
if (index >= length) break;
51+
52+
const char = peek();
53+
54+
if (char === '}') {
55+
index++;
56+
if (stack.length > 0) stack.pop();
57+
continue;
5258
}
5359

54-
return rules;
60+
if (char === '@') {
61+
rules.push(parseAtRule());
62+
} else {
63+
rules.push(parseSelectorOrNested());
64+
}
5565
}
5666

5767
function parseAtRule() {
5868
let start = index;
59-
while (index < cleanedCSS.length && cleanedCSS[index] !== '{' && cleanedCSS[index] !== ';') {
69+
while (index < length && cleanedCSS[index] !== '{' && cleanedCSS[index] !== ';') {
6070
index++;
6171
}
6272
const atRuleHeader = cleanedCSS.slice(start, index).trim();
6373

6474
if (cleanedCSS[index] === '{') {
6575
index++;
66-
const nestedRules = parseRules();
67-
return {
68-
type: 'at-rule',
69-
name: atRuleHeader,
70-
rules: nestedRules
71-
};
76+
const nestedRules = [];
77+
stack.push({ type: 'at-rule', name: atRuleHeader, rules: nestedRules });
78+
79+
while (index < length) {
80+
skipWhitespace();
81+
if (peek() === '}') {
82+
index++;
83+
break;
84+
}
85+
nestedRules.push(parseSelectorOrNested());
86+
}
87+
88+
return { type: 'at-rule', name: atRuleHeader, rules: nestedRules };
89+
7290
} else if (cleanedCSS[index] === ';') {
7391
index++;
74-
return {
75-
type: 'at-rule',
76-
name: atRuleHeader,
77-
rules: []
78-
};
92+
return { type: 'at-rule', name: atRuleHeader, rules: [] };
7993
}
94+
8095
return { type: 'at-rule', name: atRuleHeader, rules: [] };
8196
}
8297

8398
function parseSelectorOrNested() {
8499
let start = index;
85-
while (index < cleanedCSS.length && cleanedCSS[index] !== '{' && cleanedCSS[index] !== '}') {
100+
while (
101+
index < length &&
102+
cleanedCSS[index] !== '{' &&
103+
cleanedCSS[index] !== '}'
104+
) {
86105
index++;
87106
}
107+
88108
const selectorText = cleanedCSS.slice(start, index).trim();
89109

90110
if (cleanedCSS[index] === '{') {
91111
index++;
92112

93113
skipWhitespace();
94-
114+
95115
if (/^[.#a-zA-Z0-9\-\s,:]+$/.test(selectorText)) {
96116
const selectors = selectorText.split(',').map(s => s.trim());
97-
98117
const properties = {};
99-
while (true) {
118+
const nestedRules = [];
119+
120+
while (index < length) {
100121
skipWhitespace();
101-
if (cleanedCSS[index] === '}') {
122+
if (peek() === '}') {
102123
index++;
103124
break;
104125
}
105-
if (cleanedCSS[index] === '@') {
106-
const atRule = parseAtRule();
107-
return { type: 'rule', selectors, properties, nestedRules: [atRule] };
108-
}
109126

127+
if (peek() === '@') {
128+
nestedRules.push(parseAtRule());
129+
continue;
130+
}
131+
110132
let propStart = index;
111-
while (index < cleanedCSS.length && cleanedCSS[index] !== ';' && cleanedCSS[index] !== '}') {
133+
while (
134+
index < length &&
135+
cleanedCSS[index] !== ';' &&
136+
cleanedCSS[index] !== '}'
137+
) {
112138
index++;
113139
}
114140

115141
const line = cleanedCSS.slice(propStart, index).trim();
116-
142+
117143
if (!line) break;
118144

119145
if (line.includes(':')) {
@@ -123,12 +149,10 @@ exports.JSON = function(cssText) {
123149
} else if (cleanedCSS[index] === '}') {
124150
index++;
125151
break;
126-
} else if (/^[.#a-zA-Z0-9\-\s,:]+$/.test(line)) {
127-
break;
128152
}
129153
}
130-
131-
return { type: 'rule', selectors, properties };
154+
155+
return { type: 'rule', selectors, properties, nestedRules };
132156

133157
} else {
134158
return null;
@@ -139,6 +163,5 @@ exports.JSON = function(cssText) {
139163
}
140164
}
141165

142-
const ast = parseRules();
143-
return ast;
166+
return rules;
144167
}

0 commit comments

Comments
 (0)