Comparing version 1.3.0 to 1.4.0
{ | ||
"name": "css-parse", | ||
"repo": "visionmedia/css-parse", | ||
"version": "1.3.0", | ||
"version": "1.4.0", | ||
"description": "CSS parser", | ||
@@ -6,0 +6,0 @@ "keywords": ["css", "parser", "stylesheet"], |
1.4.0 / 2013-05-22 | ||
================== | ||
* add `position` option support | ||
* add .type to all nodes. Closes #18 | ||
* fix comments within rulesets. Closes #30 | ||
* fix handling of unterminated comment. Closes #24 | ||
1.3.0 / 2013-05-21 | ||
@@ -3,0 +11,0 @@ ================== |
223
index.js
module.exports = function(css){ | ||
module.exports = function(css, options){ | ||
options = options || {}; | ||
/** | ||
* Positional. | ||
*/ | ||
var lineno = 1; | ||
var column = 1; | ||
/** | ||
* Update lineno and column based on `str`. | ||
*/ | ||
function updatePosition(str) { | ||
var lines = str.match(/\n/g); | ||
if (lines) lineno += lines.length; | ||
var i = str.lastIndexOf('\n'); | ||
column = ~i ? str.length - i : column + str.length; | ||
} | ||
/** | ||
* Mark position and patch `node.position`. | ||
*/ | ||
function position() { | ||
var start = { line: lineno, column: column }; | ||
if (!options.position) return positionNoop; | ||
return function(node){ | ||
node.position = { | ||
start: start, | ||
end: { line: lineno, column: column } | ||
}; | ||
whitespace(); | ||
return node; | ||
} | ||
} | ||
/** | ||
* Return `node`. | ||
*/ | ||
function positionNoop(node) { | ||
whitespace(); | ||
return node; | ||
} | ||
/** | ||
* Parse stylesheet. | ||
@@ -9,3 +56,8 @@ */ | ||
function stylesheet() { | ||
return { stylesheet: { rules: rules() }}; | ||
return { | ||
type: 'stylesheet', | ||
stylesheet: { | ||
rules: rules() | ||
} | ||
}; | ||
} | ||
@@ -26,3 +78,3 @@ | ||
function close() { | ||
return match(/^}\s*/); | ||
return match(/^}/); | ||
} | ||
@@ -53,3 +105,5 @@ | ||
if (!m) return; | ||
css = css.slice(m[0].length); | ||
var str = m[0]; | ||
updatePosition(str); | ||
css = css.slice(str.length); | ||
return m; | ||
@@ -71,4 +125,4 @@ } | ||
function comments(rules) { | ||
var c; | ||
rules = rules || []; | ||
var c; | ||
while (c = comment()) rules.push(c); | ||
@@ -83,11 +137,19 @@ return rules; | ||
function comment() { | ||
if ('/' == css[0] && '*' == css[1]) { | ||
var i = 2; | ||
while ('*' != css[i] || '/' != css[i + 1]) ++i; | ||
i += 2; | ||
var comment = css.slice(2, i - 2); | ||
css = css.slice(i); | ||
whitespace(); | ||
return { comment: comment }; | ||
} | ||
var pos = position(); | ||
if ('/' != css[0] || '*' != css[1]) return; | ||
var i = 2; | ||
while (null != css[i] && ('*' != css[i] || '/' != css[i + 1])) ++i; | ||
i += 2; | ||
var str = css.slice(2, i - 2); | ||
column += 2; | ||
updatePosition(str); | ||
css = css.slice(i); | ||
column += 2; | ||
return pos({ | ||
type: 'comment', | ||
comment: str | ||
}); | ||
} | ||
@@ -110,2 +172,4 @@ | ||
function declaration() { | ||
var pos = position(); | ||
// prop | ||
@@ -120,10 +184,35 @@ var prop = match(/^(\*?[-\w]+)\s*/); | ||
// val | ||
var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)\s*/); | ||
var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/); | ||
if (!val) return; | ||
val = val[0].trim(); | ||
var ret = pos({ | ||
type: 'declaration', | ||
property: prop, | ||
value: val[0].trim() | ||
}); | ||
// ; | ||
match(/^[;\s]*/); | ||
return ret; | ||
} | ||
return { property: prop, value: val }; | ||
/** | ||
* Parse declarations. | ||
*/ | ||
function declarations() { | ||
var decls = []; | ||
if (!open()) return; | ||
comments(decls); | ||
// declarations | ||
var decl; | ||
while (decl = declaration()) { | ||
decls.push(decl); | ||
comments(decls); | ||
} | ||
if (!close()) return; | ||
return decls; | ||
} | ||
@@ -138,2 +227,3 @@ | ||
var vals = []; | ||
var pos = position(); | ||
@@ -147,6 +237,7 @@ while (m = match(/^(from|to|\d+%|\.\d+%|\d+\.\d+%)\s*/)) { | ||
return { | ||
return pos({ | ||
type: 'keyframe', | ||
values: vals, | ||
declarations: declarations() | ||
}; | ||
}); | ||
} | ||
@@ -159,3 +250,5 @@ | ||
function atkeyframes() { | ||
var pos = position(); | ||
var m = match(/^@([-\w]+)?keyframes */); | ||
if (!m) return; | ||
@@ -181,7 +274,8 @@ var vendor = m[1]; | ||
return { | ||
return pos({ | ||
type: 'keyframes', | ||
name: name, | ||
vendor: vendor, | ||
keyframes: frames | ||
}; | ||
}); | ||
} | ||
@@ -194,3 +288,5 @@ | ||
function atsupports() { | ||
var pos = position(); | ||
var m = match(/^@supports *([^{]+)/); | ||
if (!m) return; | ||
@@ -206,3 +302,7 @@ var supports = m[1].trim(); | ||
return { supports: supports, rules: style }; | ||
return pos({ | ||
type: 'supports', | ||
supports: supports, | ||
rules: style | ||
}); | ||
} | ||
@@ -215,3 +315,5 @@ | ||
function atmedia() { | ||
var pos = position(); | ||
var m = match(/^@media *([^{]+)/); | ||
if (!m) return; | ||
@@ -227,3 +329,7 @@ var media = m[1].trim(); | ||
return { media: media, rules: style }; | ||
return pos({ | ||
type: 'media', | ||
media: media, | ||
rules: style | ||
}); | ||
} | ||
@@ -236,2 +342,3 @@ | ||
function atpage() { | ||
var pos = position(); | ||
var m = match(/^@page */); | ||
@@ -248,3 +355,3 @@ if (!m) return; | ||
var decl; | ||
while (decl = declaration() || atmargin()) { | ||
while (decl = declaration()) { | ||
decls.push(decl); | ||
@@ -256,7 +363,7 @@ comments(); | ||
return { | ||
type: "page", | ||
return pos({ | ||
type: 'page', | ||
selectors: sel, | ||
declarations: decls | ||
}; | ||
}); | ||
} | ||
@@ -269,4 +376,6 @@ | ||
function atdocument() { | ||
var pos = position(); | ||
var m = match(/^@([-\w]+)?document *([^{]+)/); | ||
if (!m) return; | ||
var vendor = m[1].trim(); | ||
@@ -282,25 +391,11 @@ var doc = m[2].trim(); | ||
return { | ||
return pos({ | ||
type: 'document', | ||
document: doc, | ||
vendor: vendor, | ||
rules: style | ||
}; | ||
}); | ||
} | ||
/** | ||
* Parse margin at-rules | ||
*/ | ||
function atmargin() { | ||
var m = match(/^@([a-z\-]+) */); | ||
if (!m) return; | ||
var type = m[1] | ||
return { | ||
type: type, | ||
declarations: declarations() | ||
} | ||
} | ||
/** | ||
* Parse import | ||
@@ -310,3 +405,3 @@ */ | ||
function atimport() { | ||
return _atrule('import') | ||
return _atrule('import'); | ||
} | ||
@@ -335,31 +430,11 @@ | ||
function _atrule(name) { | ||
var m = match(new RegExp('^@' + name + ' *([^;\\n]+);\\s*')); | ||
var pos = position(); | ||
var m = match(new RegExp('^@' + name + ' *([^;\\n]+);')); | ||
if (!m) return; | ||
var ret = {} | ||
var ret = { type: name }; | ||
ret[name] = m[1].trim(); | ||
return ret; | ||
return pos(ret); | ||
} | ||
/** | ||
* Parse declarations. | ||
*/ | ||
function declarations() { | ||
var decls = []; | ||
if (!open()) return; | ||
comments(); | ||
// declarations | ||
var decl; | ||
while (decl = declaration()) { | ||
decls.push(decl); | ||
comments(); | ||
} | ||
if (!close()) return; | ||
return decls; | ||
} | ||
/** | ||
* Parse at rule. | ||
@@ -384,6 +459,13 @@ */ | ||
function rule() { | ||
var pos = position(); | ||
var sel = selector(); | ||
if (!sel) return; | ||
comments(); | ||
return { selectors: sel, declarations: declarations() }; | ||
return pos({ | ||
type: 'rule', | ||
selectors: sel, | ||
declarations: declarations() | ||
}); | ||
} | ||
@@ -393,1 +475,2 @@ | ||
}; | ||
{ | ||
"name": "css-parse", | ||
"version": "1.3.0", | ||
"version": "1.4.0", | ||
"description": "CSS parser", | ||
@@ -5,0 +5,0 @@ "keywords": ["css", "parser", "stylesheet"], |
115
Readme.md
# css-parse | ||
CSS parser. | ||
JavaScript CSS parser for nodejs and the browser. | ||
## Example | ||
js: | ||
css: | ||
```js | ||
var parse = require('css-parse') | ||
parse('tobi { name: "tobi" }') | ||
```css | ||
body { | ||
background: #eee; | ||
color: #888; | ||
} | ||
``` | ||
object returned: | ||
parse tree: | ||
```json | ||
{ | ||
"type": "stylesheet", | ||
"stylesheet": { | ||
"rules": [ | ||
{ | ||
"selectors": ["tobi"], | ||
"type": "rule", | ||
"selectors": [ | ||
"body" | ||
], | ||
"declarations": [ | ||
{ | ||
"property": "name", | ||
"value": "tobi" | ||
"type": "declaration", | ||
"property": "background", | ||
"value": "#eee" | ||
}, | ||
{ | ||
"type": "declaration", | ||
"property": "color", | ||
"value": "#888" | ||
} | ||
@@ -35,2 +47,62 @@ ] | ||
parse tree with `.position` enabled: | ||
```json | ||
{ | ||
"type": "stylesheet", | ||
"stylesheet": { | ||
"rules": [ | ||
{ | ||
"type": "rule", | ||
"selectors": [ | ||
"body" | ||
], | ||
"declarations": [ | ||
{ | ||
"type": "declaration", | ||
"property": "background", | ||
"value": "#eee", | ||
"position": { | ||
"start": { | ||
"line": 3, | ||
"column": 3 | ||
}, | ||
"end": { | ||
"line": 3, | ||
"column": 19 | ||
} | ||
} | ||
}, | ||
{ | ||
"type": "declaration", | ||
"property": "color", | ||
"value": "#888", | ||
"position": { | ||
"start": { | ||
"line": 4, | ||
"column": 3 | ||
}, | ||
"end": { | ||
"line": 4, | ||
"column": 14 | ||
} | ||
} | ||
} | ||
], | ||
"position": { | ||
"start": { | ||
"line": 2, | ||
"column": 1 | ||
}, | ||
"end": { | ||
"line": 5, | ||
"column": 2 | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
## Performance | ||
@@ -40,25 +112,4 @@ | ||
## License | ||
## License | ||
(The MIT License) | ||
Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca> | ||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
'Software'), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
MIT |
Sorry, the diff of this file is not supported yet
10579
359
114