Skip to content

tonyganch/gonzales-pe

Repository files navigation

Gonzales PE @dev

NPM version Build Status AppVeyor Build Status

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

(1) To install command-line tool globally:

npm install -g git://github.com/tonyganch/gonzales-pe.git#dev

(2) To install parser as a project dependency:

npm install --save git://github.com/tonyganch/gonzales-pe.git#dev

(3) 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:

  1. parse css string and get a parse tree in return;
  2. modify tree nodes;
  3. remove tree nodes;
  4. add new nodes to the tree;
  5. 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
{Object} A new node.
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.
Returns
{Object} Parse tree.
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
{?Object} A node.
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
{?Object} A node.
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
{?Object} A node.
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
{Object} Removed node.
##### 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.