3 *Please use only this documented API when working with the parser. Methods
4 not documented here are subject to change at any point.*
8 This is the module's main entry point.
11 const parser = require('postcss-selector-parser');
14 ### `parser([transform], [options])`
16 Creates a new `processor` instance
19 const processor = parser();
21 // or, with optional transform function
22 const transform = selectors => {
23 selectors.walkUniversals(selector => {
28 const processor = parser(transform)
31 const result = processor.processSync('*.class');
35 [See processor documentation](#processor)
39 * `transform (function)`: Provide a function to work with the parsed AST.
40 * `options (object)`: Provide default options for all calls on the returned `Processor`.
42 ### `parser.attribute([props])`
44 Creates a new attribute selector.
47 parser.attribute({attribute: 'href'});
53 * `props (object)`: The new node's properties.
55 ### `parser.className([props])`
57 Creates a new class selector.
60 parser.className({value: 'button'});
66 * `props (object)`: The new node's properties.
68 ### `parser.combinator([props])`
70 Creates a new selector combinator.
73 parser.combinator({value: '+'});
79 * `props (object)`: The new node's properties.
81 ### `parser.comment([props])`
83 Creates a new comment.
86 parser.comment({value: '/* Affirmative, Dave. I read you. */'});
87 // => /* Affirmative, Dave. I read you. */
92 * `props (object)`: The new node's properties.
94 ### `parser.id([props])`
96 Creates a new id selector.
99 parser.id({value: 'search'});
105 * `props (object)`: The new node's properties.
107 ### `parser.nesting([props])`
109 Creates a new nesting selector.
118 * `props (object)`: The new node's properties.
120 ### `parser.pseudo([props])`
122 Creates a new pseudo selector.
125 parser.pseudo({value: '::before'});
131 * `props (object)`: The new node's properties.
133 ### `parser.root([props])`
135 Creates a new root node.
144 * `props (object)`: The new node's properties.
146 ### `parser.selector([props])`
148 Creates a new selector node.
157 * `props (object)`: The new node's properties.
159 ### `parser.string([props])`
161 Creates a new string node.
170 * `props (object)`: The new node's properties.
172 ### `parser.tag([props])`
174 Creates a new tag selector.
177 parser.tag({value: 'button'});
183 * `props (object)`: The new node's properties.
185 ### `parser.universal([props])`
187 Creates a new universal selector.
196 * `props (object)`: The new node's properties.
202 A string representation of the selector type. It can be one of the following;
203 `attribute`, `class`, `combinator`, `comment`, `id`, `nesting`, `pseudo`,
204 `root`, `selector`, `string`, `tag`, or `universal`. Note that for convenience,
205 these constants are exposed on the main `parser` as uppercased keys. So for
206 example you can get `id` by querying `parser.ID`.
209 parser.attribute({attribute: 'href'}).type;
215 Returns the parent node.
218 root.nodes[0].parent === root;
221 ### `node.toString()`, `String(node)`, or `'' + node`
223 Returns a string representation of the node.
226 const id = parser.id({value: 'search'});
227 console.log(String(id));
231 ### `node.next()` & `node.prev()`
233 Returns the next/previous child of the parent node.
236 const next = id.next();
237 if (next && next.type !== 'combinator') {
238 throw new Error('Qualified IDs are not allowed!');
242 ### `node.replaceWith(node)`
244 Replace a node with another.
247 const attr = selectors.first.first;
248 const className = parser.className({value: 'test'});
249 attr.replaceWith(className);
254 * `node`: The node to substitute the original with.
258 Removes the node from its parent node.
261 if (node.type === 'id') {
268 Returns a copy of a node, detached from any parent containers that the
269 original might have had.
272 const cloned = parser.id({value: 'search'});
280 Extra whitespaces around the node will be moved into `node.spaces.before` and
281 `node.spaces.after`. So for example, these spaces will be moved as they have
288 However, *combinating* spaces will form a `combinator` node:
294 A `combinator` node may only have the `spaces` property set if the combinator
295 value is a non-whitespace character, such as `+`, `~` or `>`. Otherwise, the
296 combinator value will contain all of the spaces between selectors.
300 An object describing the node's start/end, line/column source position.
302 Within the following CSS, the `.bar` class node ...
309 ... will contain the following `source` object.
324 ### `node.sourceIndex`
326 The zero-based index of the node within the original source string.
328 Within the following CSS, the `.baz` class node will have a `sourceIndex` of `12`.
336 The `root`, `selector`, and `pseudo` nodes have some helper methods for working
339 ### `container.nodes`
341 An array of the container's children.
345 selectors.at(0).nodes.length // => 3
346 selectors.at(0).nodes[0].value // => 'h1'
347 selectors.at(0).nodes[1].value // => ' '
350 ### `container.first` & `container.last`
352 The first/last child of the container.
355 selector.first === selector.nodes[0];
356 selector.last === selector.nodes[selector.nodes.length - 1];
359 ### `container.at(index)`
361 Returns the node at position `index`.
364 selector.at(0) === selector.first;
365 selector.at(0) === selector.nodes[0];
370 * `index`: The index of the node to return.
372 ### `container.index(node)`
374 Return the index of the node within its container.
377 selector.index(selector.nodes[2]) // => 2
382 * `node`: A node within the current container.
384 ### `container.length`
386 Proxy to the length of the container's nodes.
389 container.length === container.nodes.length
392 ### `container` Array iterators
394 The container class provides proxies to certain Array methods; these are:
396 * `container.map === container.nodes.map`
397 * `container.reduce === container.nodes.reduce`
398 * `container.every === container.nodes.every`
399 * `container.some === container.nodes.some`
400 * `container.filter === container.nodes.filter`
401 * `container.sort === container.nodes.sort`
403 Note that these methods only work on a container's immediate children; recursive
404 iteration is provided by `container.walk`.
406 ### `container.each(callback)`
408 Iterate the container's immediate children, calling `callback` for each child.
409 You may return `false` within the callback to break the iteration.
413 selectors.each((selector, index) => {
414 if (selector.type === 'class') {
415 className = selector.value;
421 Note that unlike `Array#forEach()`, this iterator is safe to use whilst adding
422 or removing nodes from the container.
426 * `callback (function)`: A function to call for each node, which receives `node`
427 and `index` arguments.
429 ### `container.walk(callback)`
431 Like `container#each`, but will also iterate child nodes as long as they are
435 selectors.walk((selector, index) => {
442 * `callback (function)`: A function to call for each node, which receives `node`
443 and `index` arguments.
445 This iterator is safe to use whilst mutating `container.nodes`,
446 like `container#each`.
448 ### `container.walk` proxies
450 The container class provides proxy methods for iterating over types of nodes,
451 so that it is easier to write modules that target specific selectors. Those
454 * `container.walkAttributes`
455 * `container.walkClasses`
456 * `container.walkCombinators`
457 * `container.walkComments`
458 * `container.walkIds`
459 * `container.walkNesting`
460 * `container.walkPseudos`
461 * `container.walkTags`
462 * `container.walkUniversals`
464 ### `container.split(callback)`
466 This method allows you to split a group of nodes by returning `true` from
467 a callback. It returns an array of arrays, where each inner array corresponds
468 to the groups that you created via the callback.
471 // (input) => h1 h2>>h3
472 const list = selectors.first.split(selector => {
473 return selector.type === 'combinator';
476 // (node values) => [['h1', ' '], ['h2', '>>'], ['h3']]
481 * `callback (function)`: A function to call for each node, which receives `node`
484 ### `container.prepend(node)` & `container.append(node)`
486 Add a node to the start/end of the container. Note that doing so will set
487 the parent property of the node to this container.
490 const id = parser.id({value: 'search'});
496 * `node`: The node to add.
498 ### `container.insertBefore(old, new)` & `container.insertAfter(old, new)`
500 Add a node before or after an existing node in a container:
503 selectors.walk(selector => {
504 if (selector.type !== 'class') {
505 const className = parser.className({value: 'theme-name'});
506 selector.parent.insertAfter(selector, className);
513 * `old`: The existing node in the container.
514 * `new`: The new node to add before/after the existing node.
516 ### `container.removeChild(node)`
518 Remove the node from the container. Note that you can also use
519 `node.remove()` if you would like to remove just a single node.
522 selector.length // => 2
524 selector.length // => 1;
525 id.parent // undefined
530 * `node`: The node to remove.
532 ### `container.removeAll()` or `container.empty()`
534 Remove all children from the container.
537 selector.removeAll();
538 selector.length // => 0
543 A root node represents a comma separated list of selectors. Indeed, all
544 a root's `toString()` method does is join its selector children with a ','.
545 Other than this, it has no special functionality and acts like a container.
547 ### `root.trailingComma`
549 This will be set to `true` if the input has a trailing comma, in order to
550 support parsing of legacy CSS hacks.
554 A selector node represents a single compound selector. For example, this
555 selector string `h1 h2 h3, [href] > p`, is represented as two selector nodes.
556 It has no special functionality of its own.
560 A pseudo selector extends a container node; if it has any parameters of its
561 own (such as `h1:not(h2, h3)`), they will be its children. Note that the pseudo
562 `value` will always contain the colons preceding the pseudo identifier. This
563 is so that both `:before` and `::before` are properly represented in the AST.
567 ### `attribute.quoted`
569 Returns `true` if the attribute's value is wrapped in quotation marks, false if it is not.
570 Remains `undefined` if there is no attribute value.
573 [href=foo] /* false */
574 [href='foo'] /* true */
575 [href="foo"] /* true */
576 [href] /* undefined */
579 ### `attribute.qualifiedAttribute`
581 Returns the attribute name qualified with the namespace if one is given.
583 ### `attribute.offsetOf(part)`
585 Returns the offset of the attribute part specified relative to the
586 start of the node of the output string. This is useful in raising
587 error messages about a specific part of the attribute, especially
588 in combination with `attribute.sourceIndex`.
590 Returns `-1` if the name is invalid or the value doesn't exist in this
593 The legal values for `part` are:
595 * `"ns"` - alias for "namespace"
596 * `"namespace"` - the namespace if it exists.
597 * `"attribute"` - the attribute name
598 * `"attributeNS"` - the start of the attribute or its namespace
599 * `"operator"` - the match operator of the attribute
600 * `"value"` - The value (string or identifier)
601 * `"insensitive"` - the case insensitivity flag
603 ### `attribute.raws.unquoted`
605 Returns the unquoted content of the attribute's value.
606 Remains `undefined` if there is no attribute value.
610 [href='foo'] /* foo */
611 [href="foo"] /* foo */
612 [href] /* undefined */
615 ### `attribute.spaces`
617 Like `node.spaces` with the `before` and `after` values containing the spaces
618 around the element, the parts of the attribute can also have spaces before
619 and after them. The for each of `attribute`, `operator`, `value` and
620 `insensitive` there is corresponding property of the same nam in
621 `node.spaces` that has an optional `before` or `after` string containing only
624 Note that corresponding values in `attributes.raws.spaces` contain values
625 including any comments. If set, these values will override the
626 `attribute.spaces` value. Take care to remove them if changing
631 The raws object stores comments and other information necessary to re-render
632 the node exactly as it was in the source.
634 If a comment is embedded within the identifiers for the `namespace`, `attribute`
635 or `value` then a property is placed in the raws for that value containing the full source of the propery including comments.
637 If a comment is embedded within the space between parts of the attribute
638 then the raw for that space is set accordingly.
640 Setting an attribute's property `raws` value to be deleted.
642 For now, changing the spaces required also updating or removing any of the
643 raws values that override them.
645 Example: `[ /*before*/ href /* after-attr */ = /* after-operator */ te/*inside-value*/st/* wow */ /*omg*/i/*bbq*/ /*whodoesthis*/]` would parse as:
655 attribute: { before: ' ', after: ' ' },
656 operator: { after: ' ' },
657 value: { after: ' ' },
658 insensitive: { after: ' ' }
662 attribute: { before: ' /*before*/ ', after: ' /* after-attr */ ' },
663 operator: { after: ' /* after-operator */ ' },
664 value: { after: '/* wow */ /*omg*/' },
665 insensitive: { after: '/*bbq*/ /*whodoesthis*/' }
668 value: 'te/*inside-value*/st'
675 ### `ProcessorOptions`
677 * `lossless` - When `true`, whitespace is preserved. Defaults to `true`.
678 * `updateSelector` - When `true`, if any processor methods are passed a postcss
679 `Rule` node instead of a string, then that Rule's selector is updated
680 with the results of the processing. Defaults to `true`.
682 ### `process|processSync(selectors, [options])`
684 Processes the `selectors`, returning a string from the result of processing.
686 Note: when the `updateSelector` option is set, the rule's selector
687 will be updated with the resulting string.
692 const parser = require("postcss-selector-parser");
693 const processor = parser();
695 let result = processor.processSync(' .class');
699 // Asynchronous operation
700 let promise = processor.process(' .class').then(result => {
705 // To have the parser normalize whitespace values, utilize the options
706 result = processor.processSync(' .class ', {lossless: false});
710 // For better syntax errors, pass a PostCSS Rule node.
711 const postcss = require('postcss');
712 rule = postcss.rule({selector: ' #foo > a, .class '});
713 processor.process(rule, {lossless: false, updateSelector: true}).then(result => {
716 console.log("rule:", rule.selector);
717 // => rule: #foo>a,.class
723 * `selectors (string|postcss.Rule)`: Either a selector string or a PostCSS Rule
725 * `[options] (object)`: Process options
728 ### `ast|astSync(selectors, [options])`
730 Like `process()` and `processSync()` but after
731 processing the `selectors` these methods return the `Root` node of the result
734 Note: when the `updateSelector` option is set, the rule's selector
735 will be updated with the resulting string.
737 ### `transform|transformSync(selectors, [options])`
739 Like `process()` and `processSync()` but after
740 processing the `selectors` these methods return the value returned by the
743 Note: when the `updateSelector` option is set, the rule's selector
744 will be updated with the resulting string.
746 ### Error Handling Within Selector Processors
748 The root node passed to the selector processor callback
749 has a method `error(message, options)` that returns an
750 error object. This method should always be used to raise
751 errors relating to the syntax of selectors. The options
752 to this method are passed to postcss's error constructor
753 ([documentation](http://api.postcss.org/Container.html#error)).
755 #### Async Error Example
758 let processor = (root) => {
759 return new Promise((resolve, reject) => {
760 root.walkClasses((classNode) => {
761 if (/^(.*)[-_]/.test(classNode.value)) {
762 let msg = "classes may not have underscores or dashes in them";
763 reject(root.error(msg, {
764 index: classNode.sourceIndex + RegExp.$1.length + 1,
765 word: classNode.value
773 const postcss = require("postcss");
774 const parser = require("postcss-selector-parser");
775 const selectorProcessor = parser(processor);
776 const plugin = postcss.plugin('classValidator', (options) => {
779 root.walkRules(rule => {
780 promises.push(selectorProcessor.process(rule));
782 return Promise.all(promises);
785 postcss(plugin()).process(`
789 `.trim(), {from: 'test.css'}).catch((e) => console.error(e.toString()));
791 // CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them
799 #### Synchronous Error Example
802 let processor = (root) => {
803 root.walkClasses((classNode) => {
804 if (/.*[-_]/.test(classNode.value)) {
805 let msg = "classes may not have underscores or dashes in them";
806 throw root.error(msg, {
807 index: classNode.sourceIndex,
808 word: classNode.value
814 const postcss = require("postcss");
815 const parser = require("postcss-selector-parser");
816 const selectorProcessor = parser(processor);
817 const plugin = postcss.plugin('classValidator', (options) => {
819 root.walkRules(rule => {
820 selectorProcessor.processSync(rule);
824 postcss(plugin()).process(`
828 `.trim(), {from: 'test.css'}).catch((e) => console.error(e.toString()));
830 // CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them