Skip to content

Commit

Permalink
Merge 966b5fb into fdeff81
Browse files Browse the repository at this point in the history
  • Loading branch information
nuintun committed Apr 22, 2014
2 parents fdeff81 + 966b5fb commit fed9f08
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 39 deletions.
92 changes: 58 additions & 34 deletions lib/css.js
Expand Up @@ -4,72 +4,80 @@
*
* Hsiaoming Yang <me@lepture.com>
*/
var splitLineRE = /\r\n|\r|\n/;
var endblockRE = /\/\*!\s*endblock(\s+[^\*]*)?\s*\*\/$/;
var importUriRE = /^@import\s+(?:url\()(['"]?)(.+?)\1\)?\s*;?$|^@import\s+(['"])(.+?)\3\s*;?$/;
var formatKeywordRE = /([\r\n]*\/\*!\s*(import|block|endblock|define).*?\s*\*\/[\r\n]*)/g;
var formatImportRE = /([\r\n]*@import\s+(?:url\()(['"])*.+?\2\)\s*;?[\r\n]*|[\r\n]*@import\s+(['"]).+?\3\s*;?[\r\n]*)/g;

/*
* parse code into a tree
*/
exports.parse = function(code) {
var lines = code.split(/\r\n|\r|\n/);
var isStarted = false;
var id, line;

// clean blank lines
while (!isStarted && lines.length) {
line = lines[0];
if (line.trim()) {
isStarted = true;
id = match(line, 'define');
if (id) {
lines = lines.slice(1);
}
} else {
lines = lines.slice(1);
}
}
// format import and comments keyword
code = code
.replace(formatImportRE, '\n$1\n')
.replace(formatKeywordRE, '\n$1\n')
.trim();

var id;
var node = {};
var lines = code.split(splitLineRE);

id = match(lines[0], 'define');

if (id) {
lines = lines.slice(1);
}


if (id) {
node.id = id;
}

node.type = 'block';
node.code = parseBlock(lines.join('\n'));

return [node];
};

function match(text, key) {
// /*! key value */
var re = new RegExp('^\\/\\*!\\s*' + key + '\\s+(.*?)\\s*\\*\\/$');
var m = text.match(re);
var m = text.trim().match(re);

if (!m) return;

return m[1];
}

/*
* recursive parse a block type code
*/
function parseBlock(code) {
var lines = code.split(/\r\n|\r|\n/);
var lines = code.split(splitLineRE);
var tree = [];

var stringNode = {
type: 'string',
code: ''
};
var blockNode = {};
var blockDepth = 0;


while (lines.length) {
parseInBlock();
}

function pushStringNode() {
if (!stringNode.code) return;
var text = stringNode.code.replace(/^\n+/, '');
text = text.replace(/\n+$/, '');

var text = stringNode.code.trim();

if (text) {
stringNode.code = text;
tree.push(stringNode);
}

stringNode = {
type: 'string',
code: ''
Expand All @@ -80,13 +88,13 @@ function parseBlock(code) {
if (blockDepth !== 0) return;

var text = lines.shift();
var re = /^@import\s+(?:url\()?(\'|\")([^\)]+)\1\)?;?\s*$/;

var m = match(text, 'import');

if (!m) {
m = text.match(re);
m = m ? m[2]: null;
m = text.trim().match(importUriRE);
m = m ? m[2] || m[4] : null;
}

if (m) {
pushStringNode();
tree.push({
Expand All @@ -101,8 +109,10 @@ function parseBlock(code) {
function parseInBlock() {
var text = lines[0];
var start = match(text, 'block');

if (start) {
lines = lines.slice(1);

if (blockDepth === 0) {
pushStringNode();
blockNode.id = start;
Expand All @@ -111,19 +121,22 @@ function parseBlock(code) {
} else {
blockNode.code = [blockNode.code, text].join('\n');
}

blockDepth++;
return;
}
/*! endblock id */
var re = /\/\*!\s*endblock(\s+[^\*]*)?\s*\*\/$/;
var end = text.match(re);
var end = text.match(endblockRE);

if (end) {
blockDepth--;

if (blockDepth < 0) {
throw new Error('block indent error.');
throw new SyntaxError('block indent error.');
}

lines = lines.slice(1);

if (blockDepth === 0) {
blockNode.code = parseBlock(blockNode.code);
tree.push(blockNode);
Expand All @@ -132,8 +145,10 @@ function parseBlock(code) {
} else {
blockNode.code = [blockNode.code, text].join('\n');
}

return;
}

if (blockDepth > 0) {
lines = lines.slice(1);
blockNode.code = [blockNode.code, text].join('\n');
Expand All @@ -143,10 +158,11 @@ function parseBlock(code) {
}

if (blockDepth !== 0) {
throw new Error('block not finished.');
throw new SyntaxError('block not finished.');
}

pushStringNode();

return tree;
}

Expand All @@ -168,6 +184,7 @@ exports.walk = function(code, fn) {
});
}
}

walk(code);
};

Expand All @@ -185,21 +202,26 @@ exports.stringify = function(code, filter) {
code.forEach(function(node) {
if (filter) {
var ret = filter(node, parent);

if (ret === false) {
return;
}

if (ret && ret.type) {
node = ret;
}
}

if (node.type === 'string') {
cursor = [cursor, node.code].join('\n');
return;
}

if (node.type === 'import') {
cursor = [cursor, '/*! import ' + node.id + ' */'].join('\n');
return;
}

if (node.type === 'block' && node.id) {
cursor = [
cursor,
Expand All @@ -211,13 +233,15 @@ exports.stringify = function(code, filter) {
].join('\n');
return;
}
if (node.type === 'block' && ! node.id) {

if (node.type === 'block' && !node.id) {
cursor = print(node.code, node);
}
});
cursor = cursor.replace(/^\n+/, '');
cursor = cursor.replace(/\n+$/, '');

cursor = cursor.trim();
cursor = cursor.replace(/\n{3,}/g, '\n\n');

return cursor;
}

Expand Down
4 changes: 1 addition & 3 deletions tests/css-cases/compressed.css
@@ -1,3 +1 @@
body {color: red}

a {color: black}
@import url(a);body {color: red}/*! block b *//*! import c */a {color: black}/*! endblock */
22 changes: 20 additions & 2 deletions tests/css-cases/compressed.json
Expand Up @@ -2,10 +2,28 @@
{
"type": "block",
"code": [
{
"id": "a",
"type": "import"
},
{
"type": "string",
"code": "body {color: red}\n\na {color: black}"
"code": "body {color: red}"
},
{
"id": "b",
"type": "block",
"code": [
{
"id": "c",
"type": "import"
},
{
"type": "string",
"code": "a {color: black}"
}
]
}
]
}
]
]

0 comments on commit fed9f08

Please sign in to comment.