Gonzales PE @dev

Gonzales PE is a CSS parser which plays nicely with
preprocessors.
Currently those are supported: SCSS, Sass, LESS.
Try out Gonzales PE online: Gonzales PE Playground.
Install
- To install command-line tool globally:
npm install -g git://github.com/tonyganch/gonzales-pe.git#dev
- To install parser as a project dependency:
npm install --save git://github.com/tonyganch/gonzales-pe.git#dev
- If for some reason you want to build files yourself:
# Clone the repo.
git clone git@github.com:tonyganch/gonzales-pe.git
# Go to dev branch.
git checkout dev
# Install project dependencies.
npm install
# Install git hooks and build files.
npm run init
API
Basically there are a few things you can do:
- parse css string and get a parse tree in return;
- modify tree nodes;
- remove tree nodes;
- add new nodes to the tree;
- convert modified tree back to a string.
The different type of tree nodes can be found in docs/node-types.md.
In examples below I assume that gonzales
is a parser
module and parseTree
is some parsed css:
let gonzales = require('gonzales-pe');
let parseTree = gonzales.parse(css);
gonzales.createNode(options)
Description
Creates a new node. Useful when you need to add something to a
tree.
Parameters
{Object}
|
options
|
Options to pass to a Node constructor.
|
Returns
Examples
let css = 'a {color: tomato}';
let parseTree = gonzales.parse(css);
let node = gonzales.createNode({ type: 'animal', content: 'panda' });
parseTree.content.push(node);
gonzales.parse(css[, options])
Description
Parses a css string.
Parameters
{string}
|
css
|
A string to parse.
|
{Object=}
|
options
|
Optional. Additional options:
-
{string} syntax — any of the following: css ,
less , sass , scss . Default one is
css .
-
{string} context — root node’s type. For a list of
available values see “Node types”.
Default one is stylesheet .
-
{number} tabSize — size of a tab character in spaces.
Default one is 1.
</td>
|
Returns
Examples
let css = 'a {color: tomato}';
let parseTree = gonzales.parse(css);
let less = 'a {$color: tomato}';
let parseTree = gonzales.parse(less, {syntax: 'less'});
let less = '$color: tomato';
let parseTree = gonzales.parse(less, {syntax: 'less', rule: 'declaration'});
parseTree.contains(type)
Description
Checks whether there is a child node of given type.
Parameters
{string}
|
type
|
Node type we’re looking for. For a list of available values see
“Node types”.
|
Returns
{boolean}
|
true if a tree contains a child node of a given type,
false otherwise.
|
Examples
if (parseTree.contains('space')) {
doSomething();
}
parseTree.content
Returns
{string|Array}
|
Node’s content (child nodes or a string).
|
parseTree.eachFor([type,
]callback)
Description
Calls a function for every child node in tree. If type
parameter is passed, calls a function only for child nodes of a given
type. The main difference from parseTree.forEach()
is that
this method loops through node list from the end to beginning.
Parameters
{string=}
|
type
|
Optional. A node type by which to filter child nodes before applying a
callback function. For a list of available values see
“Node types”.
|
{Function}
|
callback
|
Function to call for every child node. Accepts following parameters:
-
{Object} — a child node;
-
{number} — index of the child node in node list;
-
{Object} — parent node (equals to parseTree ).
|
Examples
parseTree.eachFor(function(childNode) {
doSomething(childNode);
});
// Remove all child spaces.
parseTree.eachFor('space', function(spaceNode, i) {
parseTree.removeChild(i);
});
parseTree.end
Returns
{Object}
|
End position of the node. Contains following info:
-
{number} line — last symbol’s line number (1-based index);
-
{number} column — last symbol’s column number (1-based
index).
|
parseTree.first([type])
Description
Gets the first child node. If type
parameter is passed,
gets the first child node of a given type. If no node has been found,
returns null
.
Parameters
{string=}
|
type
|
Optional. Node type to look for. For a list of available values see
“Node types”.
|
Returns
Examples
let node = parseTree.first();
node.content = 'panda';
let node = parseTree.first('multilineComment');
node.content = 'panda';
parseTree.forEach([type,
]callback)
Description
Calls a function for every child node in tree. If type
parameter is passed, calls a function only for child nodes of a given
type. The main difference from parseTree.eachFor()
is that
this method loops through node list from the beginnig to end.
Parameters
{string=}
|
type
|
Optional. A node type by which to filter child nodes before applying a
callback function. For a list of available values see
“Node types”.
|
{Function}
|
callback
|
Function to call for every child node. Accepts following parameters:
-
{Object} — a child node;
-
{number} — index of the child node in node list;
-
{Object} — parent node (equals to parseTree ).
|
Examples
parseTree.forEach(function(childNode) {
doSomething();
});
parseTree.forEach('space', function(spaceNode) {
doSomething();
});
parseTree.get(index)
Description
Gets nth child of the parseTree
. If no node has
been found, returns null
.
Parameters
{number}
|
index
|
Index number of node which we’re looking for.
|
Returns
Examples
var node = parseTree.get(2);
doSomething(node);
parseTree.insert(index, node)
Description
Inserts a node to a given position in parseTree
.
Parameters
{number}
|
index
|
Index of position where to insert the node.
|
{Object}
|
node
|
A node to insert.
|
Examples
let node = gonzales.createNode({type: 'animal', content: 'panda'});
parseTree.insert(2, node);
parseTree.is(type)
Description
Checks whether the node is of given type.
Parameters
{string}
|
type
|
A node type against which to check type of parseTree . For a
list of available values see “Node
types”.
|
Returns
{boolean}
|
true if types are equal, false otherwise.
|
Examples
if (node.is('space')) {
node.content = '';
}
parseTree.last(type)
Gets the last child node. If type
parameter is passed,
gets the last child node of a given type. If no node has been found,
returns null
.
Parameters
{string=}
|
type
|
Optional. Node type to look for. For a list of available values see
“Node types”.
|
Returns
Examples
let node = parseTree.last();
node.content = 'panda';
let node = parseTree.last('multilineComment');
node.content = 'panda';
parseTree.length
Returns
{number}
|
Number of child nodes.
|
parseTree.removeChild(index)
Description
Removes a child node at a given position.
Parameters
{number}
|
index
|
Index of a child node we need to remove.
|
Returns
Examples
// Swap nodes.
var node = parseTree.removeChild(1);
parseTree.insert(0, node);
parseTree.start
Returns
{Object}
|
Start position of the node. Contains following info:
-
{number} line — first symbol’s line number (1-based index);
-
{number} column — first symbol’s column number (1-based
index).
|
parseTree.syntax
Returns
{string}
|
Syntax of original parsed string.
|
parseTree.toJson()
Description
Converts parse tree to JSON. Useful for printing.
Returns
{Object}
|
Parse tree in JSON
|
parseTree.toString()
Description
Converts parse tree back to string according to original syntax.
Returns
{string}
|
A compiled string.
|
Examples
let css = parseTree.toString();
parseTree.traverse(callback)
Description
Calls the function for every node in a tree including
parseTree
itself.
Parameters
{Function}
|
callback
|
Function to apply to every node. Accepts following parameters:
-
{Object} — a node to which we apply callback;
-
{number} — node’s index number inside its parent;
-
{Object} — a node’s parent;
-
{number} — node’s nesting level relative to its parent.
|
Examples
parseTree.traverse(function(node, index, parent) {
if (node.is('multilineComment')) {
parent.removeChild(index);
} else if (node.is('space')) {
node.content = ' ';
}
});
parseTree.traverseByType(type,
callback)
Description
This method should be called for a root node, because calling it for
a child will be more time consuming.
Calls the function for every node of a given type. This means not just
child nodes, but grandchilds and so on.
Parameters
{string}
|
type
|
Node type. For a list of available values please see
“Node types”.
|
{Function}
|
callback
|
Function to apply to every node of a given type. Accepts following
parameters:
-
{Object} — a node to which we apply callback;
-
{number} — node’s index number inside its parent;
-
{Object} — a node’s parent.
|
Examples
// Remove all comments.
parseTree.traverseByType('multilineComment', function(node, index, parent) {
parent.removeChild(index);
});
parseTree.traverseByTypes(types,
callback)
Description
This method should be called for a root node, because calling it for
a child will be more time consuming.
Calls the function for every node of given types. This means not just
child nodes, but grandchilds and so on.
Parameters
{Array.string}
|
types
|
List of node types. For a list of available values please see
“Node types”.
|
{Function}
|
callback
|
Function to apply to every node of given types. Accepts following
parameters:
-
{Object} — a node to which we apply callback;
-
{number} — node’s index number inside its parent;
-
{Object} — a node’s parent.
|
Examples
// Remove all comments and spaces.
let types = ['multilineComment', 'space'];
parseTree.traverseByTypes(types, function(node, index, parent) {
parent.removeChild(index);
});
parseTree.type
Returns
{string}
|
Node type. For a list of available values see
“Node types”.
|
Test
To run tests:
npm test
This command will build library files from sources and run tests on
all files in syntax directories.
Every test has 3 files: source stylesheet, expected parse tree and
expected string compiled back from parse tree to css.
If some tests fail, you can find information in test logs:
log/test.log
contains all information from stdout;
log/expected.txt
contains only expected text;
log/result.txt
contains only result text.
The last two are made for your convenience: you can use any diff app
to see the defference between them.
If you want to test one specific string or get a general idea of how
Gonzales works, you can use test/ast.js
file.
Simply change the first two strings (css
and
syntax
vars) and run:
node test/single-test.js
Report
If you find a bug or want to add a feature, welcome to Issues.
If you are shy but have a question, feel free to drop me a line.