 85bf1341f3
			
		
	
	85bf1341f3
	
	
	
		
			
			Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			873 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			873 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # API Documentation
 | |
| 
 | |
| *Please use only this documented API when working with the parser. Methods
 | |
| not documented here are subject to change at any point.*
 | |
| 
 | |
| ## `parser` function
 | |
| 
 | |
| This is the module's main entry point.
 | |
| 
 | |
| ```js
 | |
| const parser = require('postcss-selector-parser');
 | |
| ```
 | |
| 
 | |
| ### `parser([transform], [options])`
 | |
| 
 | |
| Creates a new `processor` instance
 | |
| 
 | |
| ```js
 | |
| const processor = parser();
 | |
| ```
 | |
| 
 | |
| Or, with optional transform function
 | |
| 
 | |
| ```js
 | |
| const transform = selectors => {
 | |
|     selectors.walkUniversals(selector => {
 | |
|         selector.remove();
 | |
|     });
 | |
| };
 | |
| 
 | |
| const processor = parser(transform)
 | |
| 
 | |
| // Example
 | |
| const result = processor.processSync('*.class');
 | |
| // => .class
 | |
| ```
 | |
| 
 | |
| [See processor documentation](#processor)
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `transform (function)`: Provide a function to work with the parsed AST.
 | |
| * `options (object)`: Provide default options for all calls on the returned `Processor`.
 | |
| 
 | |
| ### `parser.attribute([props])`
 | |
| 
 | |
| Creates a new attribute selector.
 | |
| 
 | |
| ```js
 | |
| parser.attribute({attribute: 'href'});
 | |
| // => [href]
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.className([props])`
 | |
| 
 | |
| Creates a new class selector.
 | |
| 
 | |
| ```js
 | |
| parser.className({value: 'button'});
 | |
| // => .button
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.combinator([props])`
 | |
| 
 | |
| Creates a new selector combinator.
 | |
| 
 | |
| ```js
 | |
| parser.combinator({value: '+'});
 | |
| // => +
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| Notes:
 | |
| * **Descendant Combinators** The value of descendant combinators created by the
 | |
|   parser always just a single space (`" "`). For descendant selectors with no
 | |
|   comments, additional space is now stored in `node.spaces.before`. Depending
 | |
|   on the location of comments, additional spaces may be stored in
 | |
|   `node.raws.spaces.before`, `node.raws.spaces.after`, or `node.raws.value`.
 | |
| * **Named Combinators** Although, nonstandard and unlikely to ever become a standard,
 | |
|   named combinators like `/deep/` and `/for/` are parsed as combinators. The
 | |
|   `node.value` is name after being unescaped and normalized as lowercase. The
 | |
|   original value for the combinator name is stored in `node.raws.value`.
 | |
| 
 | |
| 
 | |
| ### `parser.comment([props])`
 | |
| 
 | |
| Creates a new comment.
 | |
| 
 | |
| ```js
 | |
| parser.comment({value: '/* Affirmative, Dave. I read you. */'});
 | |
| // => /* Affirmative, Dave. I read you. */
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.id([props])`
 | |
| 
 | |
| Creates a new id selector.
 | |
| 
 | |
| ```js
 | |
| parser.id({value: 'search'});
 | |
| // => #search
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.nesting([props])`
 | |
| 
 | |
| Creates a new nesting selector.
 | |
| 
 | |
| ```js
 | |
| parser.nesting();
 | |
| // => &
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.pseudo([props])`
 | |
| 
 | |
| Creates a new pseudo selector.
 | |
| 
 | |
| ```js
 | |
| parser.pseudo({value: '::before'});
 | |
| // => ::before
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.root([props])`
 | |
| 
 | |
| Creates a new root node.
 | |
| 
 | |
| ```js
 | |
| parser.root();
 | |
| // => (empty)
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.selector([props])`
 | |
| 
 | |
| Creates a new selector node.
 | |
| 
 | |
| ```js
 | |
| parser.selector();
 | |
| // => (empty)
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.string([props])`
 | |
| 
 | |
| Creates a new string node.
 | |
| 
 | |
| ```js
 | |
| parser.string();
 | |
| // => (empty)
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.tag([props])`
 | |
| 
 | |
| Creates a new tag selector.
 | |
| 
 | |
| ```js
 | |
| parser.tag({value: 'button'});
 | |
| // => button
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ### `parser.universal([props])`
 | |
| 
 | |
| Creates a new universal selector.
 | |
| 
 | |
| ```js
 | |
| parser.universal();
 | |
| // => *
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `props (object)`: The new node's properties.
 | |
| 
 | |
| ## Node types
 | |
| 
 | |
| ### `node.type`
 | |
| 
 | |
| A string representation of the selector type. It can be one of the following;
 | |
| `attribute`, `class`, `combinator`, `comment`, `id`, `nesting`, `pseudo`,
 | |
| `root`, `selector`, `string`, `tag`, or `universal`. Note that for convenience,
 | |
| these constants are exposed on the main `parser` as uppercased keys. So for
 | |
| example you can get `id` by querying `parser.ID`.
 | |
| 
 | |
| ```js
 | |
| parser.attribute({attribute: 'href'}).type;
 | |
| // => 'attribute'
 | |
| ```
 | |
| 
 | |
| ### `node.parent`
 | |
| 
 | |
| Returns the parent node.
 | |
| 
 | |
| ```js
 | |
| root.nodes[0].parent === root;
 | |
| ```
 | |
| 
 | |
| ### `node.toString()`, `String(node)`, or `'' + node`
 | |
| 
 | |
| Returns a string representation of the node.
 | |
| 
 | |
| ```js
 | |
| const id = parser.id({value: 'search'});
 | |
| console.log(String(id));
 | |
| // => #search
 | |
| ```
 | |
| 
 | |
| ### `node.next()` & `node.prev()`
 | |
| 
 | |
| Returns the next/previous child of the parent node.
 | |
| 
 | |
| ```js
 | |
| const next = id.next();
 | |
| if (next && next.type !== 'combinator') {
 | |
|     throw new Error('Qualified IDs are not allowed!');
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### `node.replaceWith(node)`
 | |
| 
 | |
| Replace a node with another.
 | |
| 
 | |
| ```js
 | |
| const attr = selectors.first.first;
 | |
| const className = parser.className({value: 'test'});
 | |
| attr.replaceWith(className);
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `node`: The node to substitute the original with.
 | |
| 
 | |
| ### `node.remove()`
 | |
| 
 | |
| Removes the node from its parent node.
 | |
| 
 | |
| ```js
 | |
| if (node.type === 'id') {
 | |
|     node.remove();
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### `node.clone([opts])`
 | |
| 
 | |
| Returns a copy of a node, detached from any parent containers that the
 | |
| original might have had.
 | |
| 
 | |
| ```js
 | |
| const cloned = node.clone();
 | |
| ```
 | |
| 
 | |
| ### `node.isAtPosition(line, column)`
 | |
| 
 | |
| Return a `boolean` indicating whether this node includes the character at the
 | |
| position of the given line and column. Returns `undefined` if the nodes lack
 | |
| sufficient source metadata to determine the position.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `line`: 1-index based line number relative to the start of the selector.
 | |
| * `column`: 1-index based column number relative to the start of the selector.
 | |
| 
 | |
| ### `node.spaces`
 | |
| 
 | |
| Extra whitespaces around the node will be moved into `node.spaces.before` and
 | |
| `node.spaces.after`. So for example, these spaces will be moved as they have
 | |
| no semantic meaning:
 | |
| 
 | |
| ```css
 | |
|       h1     ,     h2   {}
 | |
| ```
 | |
| 
 | |
| For descendent selectors, the value is always a single space.
 | |
| 
 | |
| ```css
 | |
| h1        h2 {}
 | |
| ```
 | |
| 
 | |
| Additional whitespace is found in either the `node.spaces.before` and `node.spaces.after` depending on the presence of comments or other whitespace characters. If the actual whitespace does not start or end with a single space, the node's raw value is set to the actual space(s) found in the source.
 | |
| 
 | |
| ### `node.source`
 | |
| 
 | |
| An object describing the node's start/end, line/column source position.
 | |
| 
 | |
| Within the following CSS, the `.bar` class node ...
 | |
| 
 | |
| ```css
 | |
| .foo,
 | |
|   .bar {}
 | |
| ```
 | |
| 
 | |
| ... will contain the following `source` object.
 | |
| 
 | |
| ```js
 | |
| source: {
 | |
|     start: {
 | |
|         line: 2,
 | |
|         column: 3
 | |
|     },
 | |
|     end: {
 | |
|         line: 2,
 | |
|         column: 6
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### `node.sourceIndex`
 | |
| 
 | |
| The zero-based index of the node within the original source string.
 | |
| 
 | |
| Within the following CSS, the `.baz` class node will have a `sourceIndex` of `12`.
 | |
| 
 | |
| ```css
 | |
| .foo, .bar, .baz {}
 | |
| ```
 | |
| 
 | |
| ## Container types
 | |
| 
 | |
| The `root`, `selector`, and `pseudo` nodes have some helper methods for working
 | |
| with their children.
 | |
| 
 | |
| ### `container.nodes`
 | |
| 
 | |
| An array of the container's children.
 | |
| 
 | |
| ```js
 | |
| // Input: h1 h2
 | |
| selectors.at(0).nodes.length   // => 3
 | |
| selectors.at(0).nodes[0].value // => 'h1'
 | |
| selectors.at(0).nodes[1].value // => ' '
 | |
| ```
 | |
| 
 | |
| ### `container.first` & `container.last`
 | |
| 
 | |
| The first/last child of the container.
 | |
| 
 | |
| ```js
 | |
| selector.first === selector.nodes[0];
 | |
| selector.last === selector.nodes[selector.nodes.length - 1];
 | |
| ```
 | |
| 
 | |
| ### `container.at(index)`
 | |
| 
 | |
| Returns the node at position `index`.
 | |
| 
 | |
| ```js
 | |
| selector.at(0) === selector.first;
 | |
| selector.at(0) === selector.nodes[0];
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `index`: The index of the node to return.
 | |
| 
 | |
| ### `container.atPosition(line, column)`
 | |
| 
 | |
| Returns the node at the source position `line` and `column`.
 | |
| 
 | |
| ```js
 | |
| // Input: :not(.foo),\n#foo > :matches(ol, ul)
 | |
| selector.atPosition(1, 1); // => :not(.foo)
 | |
| selector.atPosition(2, 1); // => \n#foo
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `line`: The line number of the node to return.
 | |
| * `column`: The column number of the node to return.
 | |
| 
 | |
| ### `container.index(node)`
 | |
| 
 | |
| Return the index of the node within its container.
 | |
| 
 | |
| ```js
 | |
| selector.index(selector.nodes[2]) // => 2
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `node`: A node within the current container.
 | |
| 
 | |
| ### `container.length`
 | |
| 
 | |
| Proxy to the length of the container's nodes.
 | |
| 
 | |
| ```js
 | |
| container.length === container.nodes.length
 | |
| ```
 | |
| 
 | |
| ### `container` Array iterators
 | |
| 
 | |
| The container class provides proxies to certain Array methods; these are:
 | |
| 
 | |
| * `container.map === container.nodes.map`
 | |
| * `container.reduce === container.nodes.reduce`
 | |
| * `container.every === container.nodes.every`
 | |
| * `container.some === container.nodes.some`
 | |
| * `container.filter === container.nodes.filter`
 | |
| * `container.sort === container.nodes.sort`
 | |
| 
 | |
| Note that these methods only work on a container's immediate children; recursive
 | |
| iteration is provided by `container.walk`.
 | |
| 
 | |
| ### `container.each(callback)`
 | |
| 
 | |
| Iterate the container's immediate children, calling `callback` for each child.
 | |
| You may return `false` within the callback to break the iteration.
 | |
| 
 | |
| ```js
 | |
| let className;
 | |
| selectors.each((selector, index) => {
 | |
|     if (selector.type === 'class') {
 | |
|         className = selector.value;
 | |
|         return false;
 | |
|     }
 | |
| });
 | |
| ```
 | |
| 
 | |
| Note that unlike `Array#forEach()`, this iterator is safe to use whilst adding
 | |
| or removing nodes from the container.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `callback (function)`: A function to call for each node, which receives `node`
 | |
|   and `index` arguments.
 | |
| 
 | |
| ### `container.walk(callback)`
 | |
| 
 | |
| Like `container#each`, but will also iterate child nodes as long as they are
 | |
| `container` types.
 | |
| 
 | |
| ```js
 | |
| selectors.walk((selector, index) => {
 | |
|     // all nodes
 | |
| });
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `callback (function)`: A function to call for each node, which receives `node`
 | |
|   and `index` arguments.
 | |
| 
 | |
| This iterator is safe to use whilst mutating `container.nodes`,
 | |
| like `container#each`.
 | |
| 
 | |
| ### `container.walk` proxies
 | |
| 
 | |
| The container class provides proxy methods for iterating over types of nodes,
 | |
| so that it is easier to write modules that target specific selectors. Those
 | |
| methods are:
 | |
| 
 | |
| * `container.walkAttributes`
 | |
| * `container.walkClasses`
 | |
| * `container.walkCombinators`
 | |
| * `container.walkComments`
 | |
| * `container.walkIds`
 | |
| * `container.walkNesting`
 | |
| * `container.walkPseudos`
 | |
| * `container.walkTags`
 | |
| * `container.walkUniversals`
 | |
| 
 | |
| ### `container.split(callback)`
 | |
| 
 | |
| This method allows you to split a group of nodes by returning `true` from
 | |
| a callback. It returns an array of arrays, where each inner array corresponds
 | |
| to the groups that you created via the callback.
 | |
| 
 | |
| ```js
 | |
| // (input) => h1 h2>>h3
 | |
| const list = selectors.first.split(selector => {
 | |
|     return selector.type === 'combinator';
 | |
| });
 | |
| 
 | |
| // (node values) => [['h1', ' '], ['h2', '>>'], ['h3']]
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `callback (function)`: A function to call for each node, which receives `node`
 | |
|   as an argument.
 | |
| 
 | |
| ### `container.prepend(node)` & `container.append(node)`
 | |
| 
 | |
| Add a node to the start/end of the container. Note that doing so will set
 | |
| the parent property of the node to this container.
 | |
| 
 | |
| ```js
 | |
| const id = parser.id({value: 'search'});
 | |
| selector.append(id);
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `node`: The node to add.
 | |
| 
 | |
| ### `container.insertBefore(old, new)` & `container.insertAfter(old, new)`
 | |
| 
 | |
| Add a node before or after an existing node in a container:
 | |
| 
 | |
| ```js
 | |
| selectors.walk(selector => {
 | |
|     if (selector.type !== 'class') {
 | |
|         const className = parser.className({value: 'theme-name'});
 | |
|         selector.parent.insertAfter(selector, className);
 | |
|     }
 | |
| });
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `old`: The existing node in the container.
 | |
| * `new`: The new node to add before/after the existing node.
 | |
| 
 | |
| ### `container.removeChild(node)`
 | |
| 
 | |
| Remove the node from the container. Note that you can also use
 | |
| `node.remove()` if you would like to remove just a single node.
 | |
| 
 | |
| ```js
 | |
| selector.length // => 2
 | |
| selector.remove(id)
 | |
| selector.length // => 1;
 | |
| id.parent       // undefined
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `node`: The node to remove.
 | |
| 
 | |
| ### `container.removeAll()` or `container.empty()`
 | |
| 
 | |
| Remove all children from the container.
 | |
| 
 | |
| ```js
 | |
| selector.removeAll();
 | |
| selector.length // => 0
 | |
| ```
 | |
| 
 | |
| ## Root nodes
 | |
| 
 | |
| A root node represents a comma separated list of selectors. Indeed, all
 | |
| a root's `toString()` method does is join its selector children with a ','.
 | |
| Other than this, it has no special functionality and acts like a container.
 | |
| 
 | |
| ### `root.trailingComma`
 | |
| 
 | |
| This will be set to `true` if the input has a trailing comma, in order to
 | |
| support parsing of legacy CSS hacks.
 | |
| 
 | |
| ## Selector nodes
 | |
| 
 | |
| A selector node represents a single complex selector. For example, this
 | |
| selector string `h1 h2 h3, [href] > p`, is represented as two selector nodes.
 | |
| It has no special functionality of its own.
 | |
| 
 | |
| ## Pseudo nodes
 | |
| 
 | |
| A pseudo selector extends a container node; if it has any parameters of its
 | |
| own (such as `h1:not(h2, h3)`), they will be its children. Note that the pseudo
 | |
| `value` will always contain the colons preceding the pseudo identifier. This
 | |
| is so that both `:before` and `::before` are properly represented in the AST.
 | |
| 
 | |
| ## Attribute nodes
 | |
| 
 | |
| ### `attribute.quoted`
 | |
| 
 | |
| Returns `true` if the attribute's value is wrapped in quotation marks, false if it is not.
 | |
| Remains `undefined` if there is no attribute value.
 | |
| 
 | |
| ```css
 | |
| [href=foo] /* false */
 | |
| [href='foo'] /* true */
 | |
| [href="foo"] /* true */
 | |
| [href] /* undefined */
 | |
| ```
 | |
| 
 | |
| ### `attribute.qualifiedAttribute`
 | |
| 
 | |
| Returns the attribute name qualified with the namespace if one is given.
 | |
| 
 | |
| ### `attribute.offsetOf(part)`
 | |
| 
 | |
|  Returns the offset of the attribute part specified relative to the
 | |
|  start of the node of the output string. This is useful in raising
 | |
|  error messages about a specific part of the attribute, especially
 | |
|  in combination with `attribute.sourceIndex`.
 | |
| 
 | |
|  Returns `-1` if the name is invalid or the value doesn't exist in this
 | |
|  attribute.
 | |
| 
 | |
|  The legal values for `part` are:
 | |
| 
 | |
|  * `"ns"` - alias for "namespace"
 | |
|  * `"namespace"` - the namespace if it exists.
 | |
|  * `"attribute"` - the attribute name
 | |
|  * `"attributeNS"` - the start of the attribute or its namespace
 | |
|  * `"operator"` - the match operator of the attribute
 | |
|  * `"value"` - The value (string or identifier)
 | |
|  * `"insensitive"` - the case insensitivity flag
 | |
| 
 | |
| ### `attribute.raws.unquoted`
 | |
| 
 | |
| Returns the unquoted content of the attribute's value.
 | |
| Remains `undefined` if there is no attribute value.
 | |
| 
 | |
| ```css
 | |
| [href=foo] /* foo */
 | |
| [href='foo'] /* foo */
 | |
| [href="foo"] /* foo */
 | |
| [href] /* undefined */
 | |
| ```
 | |
| 
 | |
| ### `attribute.spaces`
 | |
| 
 | |
| Like `node.spaces` with the `before` and `after` values containing the spaces
 | |
| around the element, the parts of the attribute can also have spaces before
 | |
| and after them. The for each of `attribute`, `operator`, `value` and
 | |
| `insensitive` there is corresponding property of the same nam in
 | |
| `node.spaces` that has an optional `before` or `after` string containing only
 | |
| whitespace.
 | |
| 
 | |
| Note that corresponding values in `attributes.raws.spaces` contain values
 | |
| including any comments. If set, these values will override the
 | |
| `attribute.spaces` value. Take care to remove them if changing
 | |
| `attribute.spaces`.
 | |
| 
 | |
| ### `attribute.raws`
 | |
| 
 | |
| The raws object stores comments and other information necessary to re-render
 | |
| the node exactly as it was in the source.
 | |
| 
 | |
| If a comment is embedded within the identifiers for the `namespace`, `attribute`
 | |
| or `value` then a property is placed in the raws for that value containing the full source of the propery including comments.
 | |
| 
 | |
| If a comment is embedded within the space between parts of the attribute
 | |
| then the raw for that space is set accordingly.
 | |
| 
 | |
| Setting an attribute's property `raws` value to be deleted.
 | |
| 
 | |
| For now, changing the spaces required also updating or removing any of the
 | |
| raws values that override them.
 | |
| 
 | |
| Example: `[ /*before*/ href /* after-attr */ = /* after-operator */ te/*inside-value*/st/* wow */ /*omg*/i/*bbq*/ /*whodoesthis*/]` would parse as:
 | |
| 
 | |
| ```js
 | |
| {
 | |
|   attribute: "href",
 | |
|   operator: "=",
 | |
|   value: "test",
 | |
|   spaces: {
 | |
|     before: '',
 | |
|     after: '',
 | |
|     attribute: { before: '  ', after: '  ' },
 | |
|     operator: { after: '  ' },
 | |
|     value: { after: ' ' },
 | |
|     insensitive: { after: ' ' }
 | |
|   },
 | |
|   raws: {
 | |
|     spaces: {
 | |
|       attribute: { before: ' /*before*/ ', after: ' /* after-attr */ ' },
 | |
|       operator: { after: ' /* after-operator */ ' },
 | |
|       value: { after: '/* wow */ /*omg*/' },
 | |
|       insensitive: { after: '/*bbq*/ /*whodoesthis*/' }
 | |
|     },
 | |
|     unquoted: 'test',
 | |
|     value: 'te/*inside-value*/st'
 | |
|   }
 | |
| }
 | |
| ```
 | |
| 
 | |
| ## `Processor`
 | |
| 
 | |
| ### `ProcessorOptions`
 | |
| 
 | |
| * `lossless` - When `true`, whitespace is preserved. Defaults to `true`.
 | |
| * `updateSelector` - When `true`, if any processor methods are passed a postcss
 | |
|   `Rule` node instead of a string, then that Rule's selector is updated
 | |
|   with the results of the processing. Defaults to `true`.
 | |
| 
 | |
| ### `process|processSync(selectors, [options])`
 | |
| 
 | |
| Processes the `selectors`, returning a string from the result of processing.
 | |
| 
 | |
| Note: when the `updateSelector` option is set, the rule's selector
 | |
| will be updated with the resulting string.
 | |
| 
 | |
| **Example:**
 | |
| 
 | |
| ```js
 | |
| const parser = require("postcss-selector-parser");
 | |
| const processor = parser();
 | |
| 
 | |
| let result = processor.processSync(' .class');
 | |
| console.log(result);
 | |
| // =>  .class
 | |
| 
 | |
| // Asynchronous operation
 | |
| let promise = processor.process(' .class').then(result => {
 | |
|     console.log(result)
 | |
|     // => .class
 | |
| });
 | |
| 
 | |
| // To have the parser normalize whitespace values, utilize the options
 | |
| result = processor.processSync('  .class  ', {lossless: false});
 | |
| console.log(result);
 | |
| // => .class
 | |
| 
 | |
| // For better syntax errors, pass a PostCSS Rule node.
 | |
| const postcss = require('postcss');
 | |
| rule = postcss.rule({selector: ' #foo    > a,  .class  '});
 | |
| processor.process(rule, {lossless: false, updateSelector: true}).then(result => {
 | |
|     console.log(result);
 | |
|     // => #foo>a,.class
 | |
|     console.log("rule:", rule.selector);
 | |
|     // => rule: #foo>a,.class
 | |
| })
 | |
| ```
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| * `selectors (string|postcss.Rule)`: Either a selector string or a PostCSS Rule
 | |
|   node.
 | |
| * `[options] (object)`: Process options
 | |
| 
 | |
| 
 | |
| ### `ast|astSync(selectors, [options])`
 | |
| 
 | |
| Like `process()` and `processSync()` but after
 | |
| processing the `selectors` these methods return the `Root` node of the result
 | |
| instead of a string.
 | |
| 
 | |
| Note: when the `updateSelector` option is set, the rule's selector
 | |
| will be updated with the resulting string.
 | |
| 
 | |
| ### `transform|transformSync(selectors, [options])`
 | |
| 
 | |
| Like `process()` and `processSync()` but after
 | |
| processing the `selectors` these methods return the value returned by the
 | |
| processor callback.
 | |
| 
 | |
| Note: when the `updateSelector` option is set, the rule's selector
 | |
| will be updated with the resulting string.
 | |
| 
 | |
| ### Error Handling Within Selector Processors
 | |
| 
 | |
| The root node passed to the selector processor callback
 | |
| has a method `error(message, options)` that returns an
 | |
| error object. This method should always be used to raise
 | |
| errors relating to the syntax of selectors. The options
 | |
| to this method are passed to postcss's error constructor
 | |
| ([documentation](http://postcss.org/api/#container-error)).
 | |
| 
 | |
| #### Async Error Example
 | |
| 
 | |
| ```js
 | |
| let processor = (root) => {
 | |
|     return new Promise((resolve, reject) => {
 | |
|         root.walkClasses((classNode) => {
 | |
|             if (/^(.*)[-_]/.test(classNode.value)) {
 | |
|                 let msg = "classes may not have underscores or dashes in them";
 | |
|                 reject(root.error(msg, {
 | |
|                     index: classNode.sourceIndex + RegExp.$1.length + 1,
 | |
|                     word: classNode.value
 | |
|                 }));
 | |
|             }
 | |
|         });
 | |
|         resolve();
 | |
|     });
 | |
| };
 | |
| 
 | |
| const postcss = require("postcss");
 | |
| const parser = require("postcss-selector-parser");
 | |
| const selectorProcessor = parser(processor);
 | |
| const plugin = postcss.plugin('classValidator', (options) => {
 | |
|     return (root) => {
 | |
|         let promises = [];
 | |
|         root.walkRules(rule => {
 | |
|             promises.push(selectorProcessor.process(rule));
 | |
|         });
 | |
|         return Promise.all(promises);
 | |
|     };
 | |
| });
 | |
| postcss(plugin()).process(`
 | |
| .foo-bar {
 | |
|   color: red;
 | |
| }
 | |
| `.trim(), {from: 'test.css'}).catch((e) => console.error(e.toString()));
 | |
| 
 | |
| // CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them
 | |
| //
 | |
| // > 1 | .foo-bar {
 | |
| //     |     ^
 | |
| //   2 |   color: red;
 | |
| //   3 | }
 | |
| ```
 | |
| 
 | |
| #### Synchronous Error Example
 | |
| 
 | |
| ```js
 | |
| let processor = (root) => {
 | |
|     root.walkClasses((classNode) => {
 | |
|         if (/.*[-_]/.test(classNode.value)) {
 | |
|             let msg = "classes may not have underscores or dashes in them";
 | |
|             throw root.error(msg, {
 | |
|                 index: classNode.sourceIndex,
 | |
|                 word: classNode.value
 | |
|             });
 | |
|         }
 | |
|     });
 | |
| };
 | |
| 
 | |
| const postcss = require("postcss");
 | |
| const parser = require("postcss-selector-parser");
 | |
| const selectorProcessor = parser(processor);
 | |
| const plugin = postcss.plugin('classValidator', (options) => {
 | |
|     return (root) => {
 | |
|         root.walkRules(rule => {
 | |
|             selectorProcessor.processSync(rule);
 | |
|         });
 | |
|     };
 | |
| });
 | |
| postcss(plugin()).process(`
 | |
| .foo-bar {
 | |
|   color: red;
 | |
| }
 | |
| `.trim(), {from: 'test.css'}).catch((e) => console.error(e.toString()));
 | |
| 
 | |
| // CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them
 | |
| //
 | |
| // > 1 | .foo-bar {
 | |
| //     |     ^
 | |
| //   2 |   color: red;
 | |
| //   3 | }
 | |
| ```
 |