css-parse
Advanced tools
Comparing version 1.7.0 to 2.0.0
495
index.js
@@ -1,494 +0,1 @@ | ||
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 }, | ||
source: options.source | ||
}; | ||
whitespace(); | ||
return node; | ||
} | ||
} | ||
/** | ||
* Return `node`. | ||
*/ | ||
function positionNoop(node) { | ||
whitespace(); | ||
return node; | ||
} | ||
/** | ||
* Error `msg`. | ||
*/ | ||
function error(msg) { | ||
var err = new Error(msg + ' near line ' + lineno + ':' + column); | ||
err.filename = options.source; | ||
err.line = lineno; | ||
err.column = column; | ||
err.source = css; | ||
throw err; | ||
} | ||
/** | ||
* Parse stylesheet. | ||
*/ | ||
function stylesheet() { | ||
return { | ||
type: 'stylesheet', | ||
stylesheet: { | ||
rules: rules() | ||
} | ||
}; | ||
} | ||
/** | ||
* Opening brace. | ||
*/ | ||
function open() { | ||
return match(/^{\s*/); | ||
} | ||
/** | ||
* Closing brace. | ||
*/ | ||
function close() { | ||
return match(/^}/); | ||
} | ||
/** | ||
* Parse ruleset. | ||
*/ | ||
function rules() { | ||
var node; | ||
var rules = []; | ||
whitespace(); | ||
comments(rules); | ||
while (css.charAt(0) != '}' && (node = atrule() || rule())) { | ||
rules.push(node); | ||
comments(rules); | ||
} | ||
return rules; | ||
} | ||
/** | ||
* Match `re` and return captures. | ||
*/ | ||
function match(re) { | ||
var m = re.exec(css); | ||
if (!m) return; | ||
var str = m[0]; | ||
updatePosition(str); | ||
css = css.slice(str.length); | ||
return m; | ||
} | ||
/** | ||
* Parse whitespace. | ||
*/ | ||
function whitespace() { | ||
match(/^\s*/); | ||
} | ||
/** | ||
* Parse comments; | ||
*/ | ||
function comments(rules) { | ||
var c; | ||
rules = rules || []; | ||
while (c = comment()) rules.push(c); | ||
return rules; | ||
} | ||
/** | ||
* Parse comment. | ||
*/ | ||
function comment() { | ||
var pos = position(); | ||
if ('/' != css.charAt(0) || '*' != css.charAt(1)) return; | ||
var i = 2; | ||
while (null != css.charAt(i) && ('*' != css.charAt(i) || '/' != css.charAt(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 | ||
}); | ||
} | ||
/** | ||
* Parse selector. | ||
*/ | ||
function selector() { | ||
var m = match(/^([^{]+)/); | ||
if (!m) return; | ||
return trim(m[0]).split(/\s*,\s*/); | ||
} | ||
/** | ||
* Parse declaration. | ||
*/ | ||
function declaration() { | ||
var pos = position(); | ||
// prop | ||
var prop = match(/^(\*?[-#\/\*\w]+(\[[0-9a-z_-]+\])?)\s*/); | ||
if (!prop) return; | ||
prop = trim(prop[0]); | ||
// : | ||
if (!match(/^:\s*/)) return error("property missing ':'"); | ||
// val | ||
var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/); | ||
if (!val) return error('property missing value'); | ||
var ret = pos({ | ||
type: 'declaration', | ||
property: prop, | ||
value: trim(val[0]) | ||
}); | ||
// ; | ||
match(/^[;\s]*/); | ||
return ret; | ||
} | ||
/** | ||
* Parse declarations. | ||
*/ | ||
function declarations() { | ||
var decls = []; | ||
if (!open()) return error("missing '{'"); | ||
comments(decls); | ||
// declarations | ||
var decl; | ||
while (decl = declaration()) { | ||
decls.push(decl); | ||
comments(decls); | ||
} | ||
if (!close()) return error("missing '}'"); | ||
return decls; | ||
} | ||
/** | ||
* Parse keyframe. | ||
*/ | ||
function keyframe() { | ||
var m; | ||
var vals = []; | ||
var pos = position(); | ||
while (m = match(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/)) { | ||
vals.push(m[1]); | ||
match(/^,\s*/); | ||
} | ||
if (!vals.length) return; | ||
return pos({ | ||
type: 'keyframe', | ||
values: vals, | ||
declarations: declarations() | ||
}); | ||
} | ||
/** | ||
* Parse keyframes. | ||
*/ | ||
function atkeyframes() { | ||
var pos = position(); | ||
var m = match(/^@([-\w]+)?keyframes */); | ||
if (!m) return; | ||
var vendor = m[1]; | ||
// identifier | ||
var m = match(/^([-\w]+)\s*/); | ||
if (!m) return error("@keyframes missing name"); | ||
var name = m[1]; | ||
if (!open()) return error("@keyframes missing '{'"); | ||
var frame; | ||
var frames = comments(); | ||
while (frame = keyframe()) { | ||
frames.push(frame); | ||
frames = frames.concat(comments()); | ||
} | ||
if (!close()) return error("@keyframes missing '}'"); | ||
return pos({ | ||
type: 'keyframes', | ||
name: name, | ||
vendor: vendor, | ||
keyframes: frames | ||
}); | ||
} | ||
/** | ||
* Parse supports. | ||
*/ | ||
function atsupports() { | ||
var pos = position(); | ||
var m = match(/^@supports *([^{]+)/); | ||
if (!m) return; | ||
var supports = trim(m[1]); | ||
if (!open()) return error("@supports missing '{'"); | ||
var style = comments().concat(rules()); | ||
if (!close()) return error("@supports missing '}'"); | ||
return pos({ | ||
type: 'supports', | ||
supports: supports, | ||
rules: style | ||
}); | ||
} | ||
/** | ||
* Parse host. | ||
*/ | ||
function athost() { | ||
var pos = position(); | ||
var m = match(/^@host */); | ||
if (!m) return; | ||
if (!open()) return error("@host missing '{'"); | ||
var style = comments().concat(rules()); | ||
if (!close()) return error("@host missing '}'"); | ||
return pos({ | ||
type: 'host', | ||
rules: style | ||
}); | ||
} | ||
/** | ||
* Parse media. | ||
*/ | ||
function atmedia() { | ||
var pos = position(); | ||
var m = match(/^@media *([^{]+)/); | ||
if (!m) return; | ||
var media = trim(m[1]); | ||
if (!open()) return error("@media missing '{'"); | ||
var style = comments().concat(rules()); | ||
if (!close()) return error("@media missing '}'"); | ||
return pos({ | ||
type: 'media', | ||
media: media, | ||
rules: style | ||
}); | ||
} | ||
/** | ||
* Parse paged media. | ||
*/ | ||
function atpage() { | ||
var pos = position(); | ||
var m = match(/^@page */); | ||
if (!m) return; | ||
var sel = selector() || []; | ||
if (!open()) return error("@page missing '{'"); | ||
var decls = comments(); | ||
// declarations | ||
var decl; | ||
while (decl = declaration()) { | ||
decls.push(decl); | ||
decls = decls.concat(comments()); | ||
} | ||
if (!close()) return error("@page missing '}'"); | ||
return pos({ | ||
type: 'page', | ||
selectors: sel, | ||
declarations: decls | ||
}); | ||
} | ||
/** | ||
* Parse document. | ||
*/ | ||
function atdocument() { | ||
var pos = position(); | ||
var m = match(/^@([-\w]+)?document *([^{]+)/); | ||
if (!m) return; | ||
var vendor = trim(m[1]); | ||
var doc = trim(m[2]); | ||
if (!open()) return error("@document missing '{'"); | ||
var style = comments().concat(rules()); | ||
if (!close()) return error("@document missing '}'"); | ||
return pos({ | ||
type: 'document', | ||
document: doc, | ||
vendor: vendor, | ||
rules: style | ||
}); | ||
} | ||
/** | ||
* Parse import | ||
*/ | ||
function atimport() { | ||
return _atrule('import'); | ||
} | ||
/** | ||
* Parse charset | ||
*/ | ||
function atcharset() { | ||
return _atrule('charset'); | ||
} | ||
/** | ||
* Parse namespace | ||
*/ | ||
function atnamespace() { | ||
return _atrule('namespace') | ||
} | ||
/** | ||
* Parse non-block at-rules | ||
*/ | ||
function _atrule(name) { | ||
var pos = position(); | ||
var m = match(new RegExp('^@' + name + ' *([^;\\n]+);')); | ||
if (!m) return; | ||
var ret = { type: name }; | ||
ret[name] = trim(m[1]); | ||
return pos(ret); | ||
} | ||
/** | ||
* Parse at rule. | ||
*/ | ||
function atrule() { | ||
if (css[0] != '@') return; | ||
return atkeyframes() | ||
|| atmedia() | ||
|| atsupports() | ||
|| atimport() | ||
|| atcharset() | ||
|| atnamespace() | ||
|| atdocument() | ||
|| atpage() | ||
|| athost(); | ||
} | ||
/** | ||
* Parse rule. | ||
*/ | ||
function rule() { | ||
var pos = position(); | ||
var sel = selector(); | ||
if (!sel) return; | ||
comments(); | ||
return pos({ | ||
type: 'rule', | ||
selectors: sel, | ||
declarations: declarations() | ||
}); | ||
} | ||
return stylesheet(); | ||
}; | ||
/** | ||
* Trim `str`. | ||
*/ | ||
function trim(str) { | ||
return str ? str.replace(/^\s+|\s+$/g, '') : ''; | ||
} | ||
module.exports = require('css').parse; |
{ | ||
"name": "css-parse", | ||
"version": "1.7.0", | ||
"version": "2.0.0", | ||
"description": "CSS parser", | ||
"keywords": [ | ||
"css", | ||
"parser", | ||
"stylesheet" | ||
"main": "index", | ||
"files": [ | ||
"index.js" | ||
], | ||
"dependencies": { | ||
"css": "^2.0.0" | ||
}, | ||
"author": "TJ Holowaychuk <tj@vision-media.ca>", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"mocha": "*", | ||
"should": "*", | ||
"matcha": "~0.4.0", | ||
"bytes": "~0.2.1" | ||
}, | ||
"main": "index", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/visionmedia/css-parse.git" | ||
"url": "https://github.com/reworkcss/css-parse.git" | ||
}, | ||
"scripts": { | ||
"test": "make test" | ||
}, | ||
"files": [ | ||
"index.js" | ||
"keywords": [ | ||
"css", | ||
"parser", | ||
"stylesheet" | ||
] | ||
} |
133
Readme.md
@@ -1,4 +0,4 @@ | ||
# css-parse [![Build Status](https://travis-ci.org/visionmedia/css-parse.png)](https://travis-ci.org/visionmedia/css-parse) | ||
# css-parse | ||
JavaScript CSS parser for nodejs and the browser. | ||
JavaScript CSS parser for Node.js (exports the `parse` method of [css](https://github.com/reworkcss/css)) | ||
@@ -11,133 +11,6 @@ ## Installation | ||
````javascript | ||
var parse = require('css-parse'); | ||
Please see the [css](https://github.com/reworkcss/css) module documentation. | ||
// CSS input string | ||
var css = "body { \n background-color: #fff;\n }"; | ||
var output_obj = parse(css); | ||
// Position and Source parameters | ||
var output_obj_pos = parse(css, { position: true, source: 'file.css' }); | ||
// Print parsed object as CSS string | ||
console.log(JSON.stringify(output_obj, null, 2)); | ||
```` | ||
## Example | ||
css: | ||
```css | ||
body { | ||
background: #eee; | ||
color: #888; | ||
} | ||
``` | ||
parse tree: | ||
```json | ||
{ | ||
"type": "stylesheet", | ||
"stylesheet": { | ||
"rules": [ | ||
{ | ||
"type": "rule", | ||
"selectors": [ | ||
"body" | ||
], | ||
"declarations": [ | ||
{ | ||
"type": "declaration", | ||
"property": "background", | ||
"value": "#eee" | ||
}, | ||
{ | ||
"type": "declaration", | ||
"property": "color", | ||
"value": "#888" | ||
} | ||
] | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
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 | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
If you also pass in `source: 'path/to/original.css'`, that will be set | ||
on `node.position.source`. | ||
## Performance | ||
Parsed 15,000 lines of CSS (2mb) in 40ms on my macbook air. | ||
## Related | ||
[css-stringify](https://github.com/visionmedia/css-stringify "CSS-Stringify") | ||
[css-value](https://github.com/visionmedia/css-value "CSS-Value") | ||
## License | ||
MIT |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Trivial Package
Supply chain riskPackages less than 10 lines of code are easily copied into your own project and may not warrant the additional supply chain risk of an external dependency.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
0
721
1
1
1
16
3
+ Addedcss@^2.0.0
+ Addedatob@2.1.2(transitive)
+ Addedcss@2.2.4(transitive)
+ Addeddecode-uri-component@0.2.2(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedresolve-url@0.2.1(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedsource-map-resolve@0.5.3(transitive)
+ Addedsource-map-url@0.4.1(transitive)
+ Addedurix@0.1.0(transitive)