Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

postcss

Package Overview
Dependencies
Maintainers
1
Versions
261
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

ChangeLog.md

17

lib/at-rule.js

@@ -35,15 +35,18 @@ (function() {

AtRule.prototype.toString = function(last) {
var name, semicolon;
name = (this.before || '') + '@' + this.name;
AtRule.prototype.stringify = function(builder, last) {
var params, semicolon;
if (this.rules || this.decls) {
return name + this._params.stringify({
params = this._params.stringify({
before: ' ',
after: ' '
}) + this.stringifyContent();
});
return this.stringifyBlock(builder, '@' + this.name + params + '{');
} else {
if (this.before) {
builder(this.before);
}
semicolon = !last || this.semicolon ? ';' : '';
return name + this._params.stringify({
return builder('@' + this.name + this._params.stringify({
before: ' '
}) + semicolon;
}) + semicolon, this);
}

@@ -50,0 +53,0 @@ };

@@ -18,24 +18,31 @@ (function() {

Container.prototype.stringifyContent = function(brackets) {
var inside,
Container.prototype.stringifyContent = function(builder) {
var last,
_this = this;
if (brackets == null) {
brackets = true;
}
if (!this.rules && !this.decls) {
return;
}
inside = this.rules ? this.rules.map(function(rule, i) {
return rule.toString(_this.rules.length - 1 === i);
}).join('') : this.decls ? this.decls.map(function(i) {
return i.toString();
}).join(';') + (this.semicolon ? ';' : '') : void 0;
if (this.after != null) {
inside += this.after;
if (this.rules) {
last = this.rules.length - 1;
return this.rules.map(function(rule, i) {
return rule.stringify(builder, last === i);
});
} else if (this.decls) {
last = this.decls.length - 1;
return this.decls.map(function(decl, i) {
return decl.stringify(builder, last !== i || _this.semicolon);
});
}
if (brackets) {
return '{' + inside + '}';
} else {
return inside;
};
Container.prototype.stringifyBlock = function(builder, start) {
if (this.before) {
builder(this.before);
}
builder(start, this, 'start');
this.stringifyContent(builder);
if (this.after) {
builder(this.after);
}
return builder('}', this, 'end');
};

@@ -42,0 +49,0 @@

@@ -20,8 +20,24 @@ (function() {

Declaration.prototype.toString = function() {
return (this.before || '') + this.prop + (this.between || '') + ':' + this._value.stringify({
Declaration.prototype.stringify = function(builder, semicolon) {
var string;
if (this.before) {
builder(this.before);
}
string = this.prop + (this.between || '') + ':' + this._value.stringify({
before: ' '
});
if (semicolon) {
string += ';';
}
return builder(string, this);
};
Declaration.prototype.removeSelf = function() {
if (!this.parent) {
return;
}
this.parent.remove(this);
return this;
};
Declaration.prototype.clone = function(obj) {

@@ -28,0 +44,0 @@ var cloned;

@@ -69,3 +69,3 @@ (function() {

Node.prototype.remove = function() {
Node.prototype.removeSelf = function() {
if (!this.parent) {

@@ -78,2 +78,12 @@ return;

Node.prototype.toString = function() {
var builder, result;
result = '';
builder = function(str) {
return result += str;
};
this.stringify(builder);
return result;
};
Node.prototype.clone = function(overrides) {

@@ -80,0 +90,0 @@ var cloned, name, value;

@@ -17,4 +17,4 @@ (function() {

Parser = (function() {
function Parser(source, options) {
this.options = options;
function Parser(source, opts) {
this.opts = opts;
this.source = source.toString();

@@ -28,2 +28,3 @@ this.root = new Root();

this.line = 1;
this.lines = [];
this.column = 0;

@@ -112,3 +113,3 @@ this.buffer = '';

Parser.prototype.inAtrule = function(finish) {
Parser.prototype.inAtrule = function(close) {
if (this.inside('atrule-name')) {

@@ -120,5 +121,5 @@ if (this.space()) {

this.setType('atrule-param');
} else if (this.letter === ';' || this.letter === '{' || finish) {
} else if (this.letter === ';' || this.letter === '{' || close) {
this.checkAtruleName();
this.endAtruleParams(finish);
this.endAtruleParams();
} else {

@@ -129,5 +130,5 @@ this.current.name += this.letter;

} else if (this.inside('atrule-param')) {
if (this.letter === ';' || this.letter === '{' || finish) {
if (this.letter === ';' || this.letter === '{' || close) {
this.current.params = new Raw(this.prevBuffer(), this.trim(this.trimmed));
this.endAtruleParams(finish);
this.endAtruleParams();
} else {

@@ -172,3 +173,2 @@ this.trimmed += this.letter;

Parser.prototype.isBlockEnd = function() {
var after, start;
if (this.letter === '}') {

@@ -179,7 +179,5 @@ if (this.parents.length === 1) {

if (this.inside('value')) {
start = this.buffer.search(/\s*\}$/);
after = this.buffer.slice(start, -1);
this.buffer = this.buffer.slice(0, +start + 1 || 9e9);
this.inValue(true);
this.current.after = after;
this.fixEnd(function() {
return this.inValue('close');
});
} else {

@@ -230,3 +228,3 @@ if (this.semicolon) {

Parser.prototype.inValue = function(finish) {
Parser.prototype.inValue = function(close) {
if (this.inside('value')) {

@@ -238,3 +236,3 @@ if (this.letter === '(') {

}
if ((this.letter === ';' && !this.inBrackets) || finish) {
if ((this.letter === ';' && !this.inBrackets) || close) {
if (this.letter === ';') {

@@ -260,10 +258,12 @@ this.semicolon = true;

if (this.inside('atrule-param') || this.inside('atrule-name')) {
this.inAtrule(true);
this.fixEnd(function() {
return this.inAtrule('close');
});
}
if (this.parents.length > 1) {
return this.error('Unclosed block', this.current.line, this.current.column);
return this.error('Unclosed block', this.current.source.start);
} else if (this.inside('comment')) {
return this.error('Unclosed comment', this.commentPos.line, this.commentPos.column);
return this.error('Unclosed comment', this.commentPos);
} else if (this.quote) {
return this.error('Unclosed quote', this.quotePos.line, this.quotePos.column);
return this.error('Unclosed quote', this.quotePos);
} else {

@@ -274,10 +274,10 @@ return this.root.after = this.buffer;

Parser.prototype.error = function(message, line, column) {
if (line == null) {
line = this.line;
Parser.prototype.error = function(message, position) {
if (position == null) {
position = {
line: this.line,
column: this.column
};
}
if (column == null) {
column = this.column;
}
throw new SyntexError(message, this.source, line, column, this.options.file);
throw new SyntexError(message, this.source, position, this.opts.from);
};

@@ -291,2 +291,3 @@

if (this.letter === "\n") {
this.lines[this.line] = this.column - 1;
this.line += 1;

@@ -317,9 +318,48 @@ return this.column = 0;

this.current = node;
node.line = this.line;
node.column = this.column;
node.before = this.buffer.slice(0, -1);
this.current.source = {
start: {
line: this.line,
column: this.column
}
};
if (this.opts.from) {
this.current.source.file = this.opts.from;
}
this.current.before = this.buffer.slice(0, -1);
return this.buffer = '';
};
Parser.prototype.fixEnd = function(callback) {
var after, all, el, last, lines, start;
if (this.letter === '}') {
start = this.buffer.search(/\s*\}$/);
after = this.buffer.slice(start, -1);
} else {
start = this.buffer.search(/\s*$/);
after = this.buffer.slice(start);
}
this.buffer = this.buffer.slice(0, +start + 1 || 9e9);
el = this.current;
callback.apply(this);
lines = after.match(/\n/g);
if (lines) {
el.source.end.line -= lines.length;
all = this.lines[el.source.end.line];
last = after.indexOf("\n");
if (last === -1) {
last = after.length;
}
el.source.end.column = all - last;
} else {
el.source.end.column -= after.length;
}
this.current.after = after;
return this.buffer = after;
};
Parser.prototype.pop = function() {
this.current.source.end = {
line: this.line,
column: this.column
};
this.popType();

@@ -356,3 +396,3 @@ this.parents.pop();

Parser.prototype.endAtruleParams = function(finish) {
Parser.prototype.endAtruleParams = function() {
var type;

@@ -368,6 +408,3 @@ if (this.letter === '{') {

}
this.pop();
if (this.letter !== ';') {
return this.buffer = this.letter;
}
return this.pop();
}

@@ -390,8 +427,8 @@ };

module.exports = function(source, options) {
module.exports = function(source, opts) {
var parser;
if (options == null) {
options = {};
if (opts == null) {
opts = {};
}
parser = new Parser(source, options);
parser = new Parser(source, opts);
parser.loop();

@@ -398,0 +435,0 @@ return parser.root;

(function() {
var PostCSS, Root, postcss,
var AtRule, Declaration, PostCSS, Result, Root, Rule, generateMap, postcss,
__slice = [].slice;
generateMap = require('./generate-map');
Declaration = require('./declaration');
AtRule = require('./at-rule');
Result = require('./result');
Rule = require('./rule');
Root = require('./root');

@@ -17,8 +27,8 @@

PostCSS.prototype.process = function(css, options) {
PostCSS.prototype.process = function(css, opts) {
var parsed, processor, returned, _i, _len, _ref;
if (options == null) {
options = {};
if (opts == null) {
opts = {};
}
parsed = postcss.parse(css, options);
parsed = postcss.parse(css, opts);
_ref = this.processors;

@@ -32,3 +42,7 @@ for (_i = 0, _len = _ref.length; _i < _len; _i++) {

}
return parsed.toString();
if (opts.map) {
return generateMap(parsed, opts);
} else {
return new Result(parsed, parsed.toString());
}
};

@@ -48,4 +62,20 @@

postcss.decl = function(defaults) {
return new Declaration(defaults);
};
postcss.atRule = function(defaults) {
return new AtRule(defaults);
};
postcss.rule = function(defaults) {
return new Rule(defaults);
};
postcss.root = function(defaults) {
return new Root(defaults);
};
module.exports = postcss;
}).call(this);

@@ -25,4 +25,7 @@ (function() {

Root.prototype.toString = function() {
return this.stringifyContent(false);
Root.prototype.stringify = function(builder) {
this.stringifyContent(builder);
if (this.after) {
return builder(this.after);
}
};

@@ -29,0 +32,0 @@

@@ -20,6 +20,6 @@ (function() {

Rule.prototype.toString = function() {
return (this.before || '') + this._selector.stringify({
Rule.prototype.stringify = function(builder) {
return this.stringifyBlock(builder, this._selector.stringify({
after: ' '
}) + this.stringifyContent();
}) + '{');
};

@@ -26,0 +26,0 @@

@@ -9,8 +9,9 @@ (function() {

function SyntaxError(text, source, line, column, file) {
function SyntaxError(text, source, pos, file) {
this.source = source;
this.line = line;
this.column = column;
this.file = file;
this.message = "Can't parse CSS: " + text + " at line " + this.line + ":" + this.column;
this.line = pos.line;
this.column = pos.column;
this.message = "Can't parse CSS: " + text;
this.message += " at line " + pos.line + ":" + pos.column;
if (this.file) {

@@ -17,0 +18,0 @@ this.message += " in " + this.file;

{
"name": "postcss",
"version": "0.1.0",
"version": "0.2.0",
"description": "Framework for CSS postprocessors",

@@ -13,2 +13,3 @@ "keywords": ["css", "parser", "postproccessor"],

"dependencies": {
"source-map": "*"
},

@@ -18,4 +19,4 @@ "devDependencies": {

"fs-extra": "0.8.1",
"should": "2.0.2",
"mocha": "1.14.0"
"should": "2.1.1",
"mocha": "1.15.1"
},

@@ -22,0 +23,0 @@ "main": "lib/postcss",

# PostCSS
PostCSS is a framework for CSS postprocessors. You get a custom JS function
to modify CSS, and PostCSS parses CSS, gives you usable JS API to edit CSS node
tree and then save modified node tree to new CSS.
PostCSS is a framework for CSS postprocessors,
to modify CSS by your JS function.
For example, let's fix forgotten `content` propery in `::before` and `::after`:
It takes care of most common CSS tool tasks:
1. parses CSS;
2. gives you usable JS API to edit CSS node tree;
3. saves modified node tree to new CSS;
4. generates (or modifies existent) source map for your changes;
You can use this framework to write you own:
* CSS minifier or beautifizer.
* Grunt plugin to generate sprites, include `data-uri` images
or any other works.
* Text editor plugin to automate CSS routine.
* Command-line CSS tool.
Sponsored by [Evil Martians](http://evilmartians.com/).
## Build with PostCSS
* [Autoprefixer](https://github.com/ai/autoprefixer)
* [grunt-pixrem](https://github.com/robwierzbowski/grunt-pixrem)
## Quick Example
Let’s fix forgotten `content` property in `::before` and `::after`:
```js
var postcss = require('postcss');
var postprocessor = postcss(function (css) {
var contenter = postcss(function (css) {
css.eachRule(function (rule) {
if ( rule.selector.match(/::(before|after)/) ) {
// In every ::before/::after rule
var good = rule.some(function (i) {
return i.prop == 'content';
});
// Did we forget content property?
var good = rule.some(function (i) { return i.prop == 'content'; });
if ( !good ) {
// Add content: '' if we forget it
rule.prepend({ prop: 'content', value: '""' });

@@ -33,11 +58,10 @@ }

width: 10px;
height: 10px;
background: black
height: 10px
}
```
will be fixed by our new `postprocessor`:
will be fixed by our new `contenter`:
```js
var fixed = postprocessor.process(css);
var fixed = contenter.process(css).css;
```

@@ -51,31 +75,499 @@

width: 10px;
height: 10px;
background: black
height: 10px
}
```
Sponsored by [Evil Martians](http://evilmartians.com/).
## Features
### Source Map
PostCSS generates source map for its transformations:
```js
result = processor.process(css, { map: true, from: 'from.css', to: 'to.css' });
result.css // String with processed CSS
result.map // Source map
```
And modifies source map from previous step (like Sass preprocessor):
```js
var sassMap = fs.readFileSync('from.sass.map');
processor.process(css, { map: sassMap, from: 'from.sass.css', to: 'to.css' });
```
### Preserves code formatting and indentations
PostCSS saves all spaces if you don’t change CSS node and try to copy your
coding style if you modify it.
PostCSS will not change any byte of rule if you don't modify node:
### Parses everything
```js
postcss(function (css) { }).process(css).css == css;
```
In addition to the unit tests, PostCSS has integration tests to check
CSS parser on real-world sites. Right now parser is tested on GitHub, Twitter,
Bootstrap and Habrahabr styles.
And when you modify CSS nodes, PostCSS will try to copy coding style:
Also PostCSS parser is very flexible and, for example, can parse any custom
or future at-rules, instead of built-in list.
```js
contenter.process("a::before{color: black}")
// a::before{content: '';color: black}
### High-level API
contenter.process("a::before {\n color: black;\n }")
// a::before {
// content: '';
// color: black;
// }
```
PostCSS is not only parser and stringifier. It contains useful tools, which
can be used in most of postprocessor:
## Why PostCSS Better Than …
1. Safe iterator, which allow to change list inside iteration.
2. Module to split value list by spaces or commas.
### Preprocessors
Preprocessors (like Sass or Stylus) give us special language with variables,
mixins, statements and compile it to CSS. Compass, nib and other mixins
libraries use this languages to work with prefixes, sprites and inline images.
But Sass and Stylus languages were created to be syntax-sugar for CSS.
Writing really complicated programs using preporcessor languages is very difficult.
[Autoprefixer] is absolutely impossible on Sass.
PostCSS gives you comfort and power of JS or CoffeeScript to working with CSS.
You can do really magic things with wide range of [npm] libraries.
But postprocessors are not enemies for preprocessors. Sass and Stylus is still
the best way to improve readability and add some syntax sugar to CSS. You can easily combine preprocessors and postprocessors.
[Autoprefixer]: https://github.com/ai/autoprefixer
[npm]: https://npmjs.org/
### RegExp
Some Grunt plugins modify CSS with regular expressions. But CSS parser and
node tree are much safer way to edit CSS. Also regexps will break source maps
generated by preprocessors.
### CSS Parsers
There are a lot of good CSS parsers, like [Gonzales]. But they help you only
with first step.
Unlike them PostCSS gives you useful high level API (for example,
safe iterators) and changes source map generator (or modifier for existing
source map from preprocessors).
[Gonzales]: https://github.com/css/gonzales
### Rework
[Rework] was a first CSS postprocessors framework. PostCSS is very similar
to it.
But Rework has no high level API and rewrite your CSS code style
and indentations. So it can’t be used in text editor plugins.
Unlike it PostCSS preserves all spaces and code formatting.
If you don't change rule, output will be byte‑to‑byte equal.
[Rework]: https://github.com/visionmedia/rework
## Usage
### Processor
Function `postcss(fn)` creates processor by your function:
```js
var postcss = require('postcss');
var processor = postcss(function (css) {
// Code to modify CSS
});
```
If you want to combine multiple processors (and parse CSS only once),
you can create empty processor and add several functions by `use(fn)` method:
```js
var all = postcss().
use(prefixer).
use(minifing);
```
Processor function can just change current CSS node tree:
```js
postcss(function (css) {
css.append( /* new rule */ )
});
```
or create totally new CSS root and return it:
```js
postcss(function (css) {
var newCSS = postcss.root()
// Add rules and declarations
return newCSS;
});
```
Processor will transform some CSS by `process(css, opts)` method:
```js
var doubler = postcss(function (css) {
// Clone each declaration
css.eachDecl(function (decl) {
decl.parent.prepend( decl.clone() );
});
});
var css = "a { color: black; }";
var result = processor.process(css);
result.css //=> "a { color: black; color: black; }"
```
You can set original CSS filename by `from` options and make syntax error
messages much more helpful:
```js
var wrong = "a {";
processor.process(wrong, { from: 'main.css' });
//=> Can't parse CSS: Unclosed block at line 1:1 in main.css
```
### Source Map
PostCSS will generate source map, if you set `map` option to `true`
in `process(css, opts)` method.
You must set input and output CSS files paths (by `from` and `to` options)
to generate correct map.
```js
var result = processor.process(css, {
map: true,
from: 'main.css',
to: 'main.out.css'
});
result.map //=> '{"version":3,"file":"main.out.css","sources":["main.css"],"names":[],"mappings":"AAAA,KAAI"}'
fs.writeFileSync('main.out.map', result.map);
```
PostCSS can also modify previous source map (for example, from Sass
compilation). So, if you compile: Sass to CSS and then minify CSS
by postprocessor, final source map will contain mapping from Sass code
to minified CSS.
Just set original source map content (as string or JS object)
to `map` option:
```js
var result = minifier.process(css, {
map: fs.readFileSync('main.sass.map'),
from: 'main.sass.css',
to: 'main.min.css'
});
result.map //=> Source map from main.sass to main.min.css
```
### Nodes
Processor function will receive `Root` node with CSS node tree inside.
```js
var processor = postcss(function (cssRoot) {
});
```
There are 3 types of child nodes: `AtRule`, `Rule` and `Declaration`.
All nodes contain `toString()` and `clone()` methods.
You can parse CSS and get `Root` node by `postcss.parse(css, opts)` method:
```js
var postcss = require('postcss');
var cssRoot = postcss.parse('a { }');
```
### Node Source
Every node stores it origin file (if you set `from` option to `process`
or `parse` method) and position at `source` property:
```
var root = postcss.parse(css, { from: 'main.css' });
var rule = root.rules[1];
rule.source.file //=> 'main.css'
rule.source.start //=> { line: 5, position: 1 }
rule.source.end //=> { line: 10, position: 5 }
```
### Whitespaces
All nodes (exclude `Root`) have `before` property with all earlier spaces and comments.
Nodes with children (`Root`, `AtRule` and `Rule`) contain also `after` property
with spaces after last child and before `}` or end of file.
```js
var root = postcss.parse("a {\n color: black;\n}\n");
root.after //=> "\n" from end of file
root.rules[0].after //=> "\n" before }
root.rules[0].decls[0].before //=> "\n " before color: black
```
So, the simplest way to minify CSS is to clean `before` and `after` properties:
```js
var minifier = postcss(function (css) {
css.eachDecl(function (decl) {
decl.before = '';
});
css.eachRule(function (rule) {
rule.before = '';
rule.after = '';
});
css.eachAtRule(function (atRule) {
atRule.before = '';
atRule.after = '';
});
});
var css = "a{\n color:black\n}\n";
minifier.process(css).css //=> "a{color:black}"
```
### Raw Properties
Some CSS values (like selectors, at-rule params and declaration values) can
contain comments. PostCSS will clean them for you:
```js
var root = postcss.parse("a /**/ b {}");
var ab = root.rules[0];
ab.selector //=> 'a b' trimmed and cleaned from comments
```
But PostCSS saves raw content to stringify it to CSS, if you don’t
set new value. As you can remember, PostCSS tries to save origin CSS
byte-to-byte, when it’s possible:
```js
ab.toString() //=> 'a /**/ b {}' with comment
ab.selector = '.link b';
ab.toString() //=> '.link b' you change value and magic was gone
```
### Containers
`Root`, `AtRule` and `Rule` nodes can contain children in `rules` or `decls`
property.
There are common method to work with children:
* `append(newChild)` to add child at the end of children list.
* `prepend(newChild)` to add child at the beginning of children list.
* `insertBefore(existsChild, newChild)` to insert new child before some
existent children.
* `insertAfter(existsChild, newChild)` to insert new child after some
existent children.
* `remove(child)` to remove child.
* `index(child)` to return child index.
* `some(fn)` to return true if `fn` return true on any child.
* `every(fn)` to return true if `fn` return true on all children.
Methods `insertBefore`, `insertAfter` and `remove` can receive child node
or child index number as existent child argument.
Have in mind that `index` works much faster.
### Children
`AtRule`, `Rule` and `Declaration` nodes should be wrapped in other nodes.
All children contain `parent` property with parent node:
```js
rule.decls[0].parent == rule;
```
All children has `removeSelf()` method:
```js
rule.decls[0].removeSelf();
```
But `remove(index)` in parent with child index is much faster:
```js
rule.each(function (decl, i) {
rule.remove(i);
});
```
### Iterators
All parent nodes have `each` method to iterate through children nodes:
```js
root = postcss.parse('a { color: black; display: none }');
root.each(function (rule, i) {
console.log(rule.selector, i); // Will log "a 0"
});
root.rules[0].each(function (decl, i) {
console.log(decl.prop, i); // Will log "color 0" and "display 1"
});
```
Instead of simple `for` or `Array#forEach()` this iterator is safe.
You can change children inside iteration and it will fix current index:
```js
rule.rules.forEach(function (decl, i) {
rule.prepend( decl.clone() );
// Will be infinity cycle, because on prepend current declaration become
// second and next index will go to current declaration again
});
rule.each(function (decl, i) {
rule.prepend( decl.clone() );
// Will work correct (once clone each declaration), because after prepend
// iterator index will be recalculated
});
```
Because CSS is nested structure, PostCSS contains recursive iterator
by node type:
```js
root.eachDecl(function (decl, i) {
// Each declaration inside root
});
root.eachRule(function (rule, i) {
// Each rule inside root and any nested at-rules
});
root.eachAtRule(function (atRule, i) {
// Each at-rule inside root and any nested at-rules
});
```
### Root Node
`Root` node contains all CSS tree. Its children can be only `AtRule` or `Rule`
nodes in `rules` property.
You can create new root by shortcut:
```js
var root = postcss.root();
```
Method `toString()` will stringify all current CSS:
```js
root = postcss.parse(css);
root.toString() == css;
```
### AtRule Node
```css
@charset 'utf-8';
@font-face {
font-family: 'Cool'
}
@media print {
img { display: none }
}
```
`AtRule` has two own properties: `name` and `params`.
As you see, some at-rules don’t contain any children (like `@charset`
or `@import`), some of at-rules can contain only declarations
(like `@font-face` or `@page`), but most of them can contain rules
and nested at-rules (like `@media`, `@keyframes` and others).
Parser select `AtRule` content type by its name. If you create `AtRule`
node manually, it will detect own content type with new child type on first
`append` or other add method call:
```js
var atRule = postcss.atRule({ name: '-x-animations' });
atRule.rules //=> undefined
atRule.decls //=> undefined
atRule.append( postcss.rule({ selector: 'from' }) );
atRule.rules.length //=> 1
atRule.decls //=> undefined
```
You can create new at-rule by shortcut:
```js
var atRule = postcss.atRule({ name: 'charset', params: 'utf-8' });
```
### Rule Node
```css
a {
color: black;
}
```
`Rule` node has `selector` property and contains `Declaration` children
in `decls` property.
You can miss `Declaration` constructor in `append` and other insert methods:
```js
rule.append({ prop: 'color', value: 'black' });
```
Property `semicolon` marks does last declaration in rule has semicolon or not:
```js
var root = postcss.parse('a { color: black }');
root.rules[0].semicolon //=> false
var root = postcss.parse('a { color: black; }');
root.rules[0].semicolon //=> true
```
You can create new rule by shortcut:
```js
var rule = postcss.rule({ selector: 'a' });
```
### Declaration Node
```css
color: black
```
`Declaration` node has `prop` and `value` properties.
You can create new declaration by shortcut:
```js
var decl = postcss.decl({ prop: 'color', value: 'black' });
```
Or use short form in `append()` and other add methods:
```js
rule.append({ prop: 'color', value: 'black' });
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc