Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
1# API Documentation
2
3*Please use only this documented API when working with the parser. Methods
4not documented here are subject to change at any point.*
5
6## `parser` function
7
8This is the module's main entry point.
9
10```js
11const parser = require('postcss-selector-parser');
12```
13
14### `parser([transform], [options])`
15
16Creates a new `processor` instance
17
18```js
19const processor = parser();
20```
21
22Or, with optional transform function
23
24```js
25const transform = selectors => {
26    selectors.walkUniversals(selector => {
27        selector.remove();
28    });
29};
30
31const processor = parser(transform)
32
33// Example
34const result = processor.processSync('*.class');
35// => .class
36```
37
38[See processor documentation](#processor)
39
40Arguments:
41
42* `transform (function)`: Provide a function to work with the parsed AST.
43* `options (object)`: Provide default options for all calls on the returned `Processor`.
44
45### `parser.attribute([props])`
46
47Creates a new attribute selector.
48
49```js
50parser.attribute({attribute: 'href'});
51// => [href]
52```
53
54Arguments:
55
56* `props (object)`: The new node's properties.
57
58### `parser.className([props])`
59
60Creates a new class selector.
61
62```js
63parser.className({value: 'button'});
64// => .button
65```
66
67Arguments:
68
69* `props (object)`: The new node's properties.
70
71### `parser.combinator([props])`
72
73Creates a new selector combinator.
74
75```js
76parser.combinator({value: '+'});
77// => +
78```
79
80Arguments:
81
82* `props (object)`: The new node's properties.
83
84Notes:
85* **Descendant Combinators** The value of descendant combinators created by the
86  parser always just a single space (`" "`). For descendant selectors with no
87  comments, additional space is now stored in `node.spaces.before`. Depending
88  on the location of comments, additional spaces may be stored in
89  `node.raws.spaces.before`, `node.raws.spaces.after`, or `node.raws.value`.
90* **Named Combinators** Although, nonstandard and unlikely to ever become a standard,
91  named combinators like `/deep/` and `/for/` are parsed as combinators. The
92  `node.value` is name after being unescaped and normalized as lowercase. The
93  original value for the combinator name is stored in `node.raws.value`.
94
95
96### `parser.comment([props])`
97
98Creates a new comment.
99
100```js
101parser.comment({value: '/* Affirmative, Dave. I read you. */'});
102// => /* Affirmative, Dave. I read you. */
103```
104
105Arguments:
106
107* `props (object)`: The new node's properties.
108
109### `parser.id([props])`
110
111Creates a new id selector.
112
113```js
114parser.id({value: 'search'});
115// => #search
116```
117
118Arguments:
119
120* `props (object)`: The new node's properties.
121
122### `parser.nesting([props])`
123
124Creates a new nesting selector.
125
126```js
127parser.nesting();
128// => &
129```
130
131Arguments:
132
133* `props (object)`: The new node's properties.
134
135### `parser.pseudo([props])`
136
137Creates a new pseudo selector.
138
139```js
140parser.pseudo({value: '::before'});
141// => ::before
142```
143
144Arguments:
145
146* `props (object)`: The new node's properties.
147
148### `parser.root([props])`
149
150Creates a new root node.
151
152```js
153parser.root();
154// => (empty)
155```
156
157Arguments:
158
159* `props (object)`: The new node's properties.
160
161### `parser.selector([props])`
162
163Creates a new selector node.
164
165```js
166parser.selector();
167// => (empty)
168```
169
170Arguments:
171
172* `props (object)`: The new node's properties.
173
174### `parser.string([props])`
175
176Creates a new string node.
177
178```js
179parser.string();
180// => (empty)
181```
182
183Arguments:
184
185* `props (object)`: The new node's properties.
186
187### `parser.tag([props])`
188
189Creates a new tag selector.
190
191```js
192parser.tag({value: 'button'});
193// => button
194```
195
196Arguments:
197
198* `props (object)`: The new node's properties.
199
200### `parser.universal([props])`
201
202Creates a new universal selector.
203
204```js
205parser.universal();
206// => *
207```
208
209Arguments:
210
211* `props (object)`: The new node's properties.
212
213## Node types
214
215### `node.type`
216
217A string representation of the selector type. It can be one of the following;
218`attribute`, `class`, `combinator`, `comment`, `id`, `nesting`, `pseudo`,
219`root`, `selector`, `string`, `tag`, or `universal`. Note that for convenience,
220these constants are exposed on the main `parser` as uppercased keys. So for
221example you can get `id` by querying `parser.ID`.
222
223```js
224parser.attribute({attribute: 'href'}).type;
225// => 'attribute'
226```
227
228### `node.parent`
229
230Returns the parent node.
231
232```js
233root.nodes[0].parent === root;
234```
235
236### `node.toString()`, `String(node)`, or `'' + node`
237
238Returns a string representation of the node.
239
240```js
241const id = parser.id({value: 'search'});
242console.log(String(id));
243// => #search
244```
245
246### `node.next()` & `node.prev()`
247
248Returns the next/previous child of the parent node.
249
250```js
251const next = id.next();
252if (next && next.type !== 'combinator') {
253    throw new Error('Qualified IDs are not allowed!');
254}
255```
256
257### `node.replaceWith(node[,...nodeN])`
258
259Replace a node with another.
260
261```js
262const attr = selectors.first.first;
263const className = parser.className({value: 'test'});
264attr.replaceWith(className);
265```
266
267Arguments:
268
269* `node`: The node to substitute the original with.
270...
271* `nodeN`: The node to substitute the original with.
272
273### `node.remove()`
274
275Removes the node from its parent node.
276
277```js
278if (node.type === 'id') {
279    node.remove();
280}
281```
282
283### `node.clone([opts])`
284
285Returns a copy of a node, detached from any parent containers that the
286original might have had.
287
288```js
289const cloned = node.clone();
290```
291
292### `node.isAtPosition(line, column)`
293
294Return a `boolean` indicating whether this node includes the character at the
295position of the given line and column. Returns `undefined` if the nodes lack
296sufficient source metadata to determine the position.
297
298Arguments:
299
300* `line`: 1-index based line number relative to the start of the selector.
301* `column`: 1-index based column number relative to the start of the selector.
302
303### `node.spaces`
304
305Extra whitespaces around the node will be moved into `node.spaces.before` and
306`node.spaces.after`. So for example, these spaces will be moved as they have
307no semantic meaning:
308
309```css
310      h1     ,     h2   {}
311```
312
313For descendent selectors, the value is always a single space.
314
315```css
316h1        h2 {}
317```
318
319Additional 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.
320
321### `node.source`
322
323An object describing the node's start/end, line/column source position.
324
325Within the following CSS, the `.bar` class node ...
326
327```css
328.foo,
329  .bar {}
330```
331
332... will contain the following `source` object.
333
334```js
335source: {
336    start: {
337        line: 2,
338        column: 3
339    },
340    end: {
341        line: 2,
342        column: 6
343    }
344}
345```
346
347### `node.sourceIndex`
348
349The zero-based index of the node within the original source string.
350
351Within the following CSS, the `.baz` class node will have a `sourceIndex` of `12`.
352
353```css
354.foo, .bar, .baz {}
355```
356
357## Container types
358
359The `root`, `selector`, and `pseudo` nodes have some helper methods for working
360with their children.
361
362### `container.nodes`
363
364An array of the container's children.
365
366```js
367// Input: h1 h2
368selectors.at(0).nodes.length   // => 3
369selectors.at(0).nodes[0].value // => 'h1'
370selectors.at(0).nodes[1].value // => ' '
371```
372
373### `container.first` & `container.last`
374
375The first/last child of the container.
376
377```js
378selector.first === selector.nodes[0];
379selector.last === selector.nodes[selector.nodes.length - 1];
380```
381
382### `container.at(index)`
383
384Returns the node at position `index`.
385
386```js
387selector.at(0) === selector.first;
388selector.at(0) === selector.nodes[0];
389```
390
391Arguments:
392
393* `index`: The index of the node to return.
394
395### `container.atPosition(line, column)`
396
397Returns the node at the source position `line` and `column`.
398
399```js
400// Input: :not(.foo),\n#foo > :matches(ol, ul)
401selector.atPosition(1, 1); // => :not(.foo)
402selector.atPosition(2, 1); // => \n#foo
403```
404
405Arguments:
406
407* `line`: The line number of the node to return.
408* `column`: The column number of the node to return.
409
410### `container.index(node)`
411
412Return the index of the node within its container.
413
414```js
415selector.index(selector.nodes[2]) // => 2
416```
417
418Arguments:
419
420* `node`: A node within the current container.
421
422### `container.length`
423
424Proxy to the length of the container's nodes.
425
426```js
427container.length === container.nodes.length
428```
429
430### `container` Array iterators
431
432The container class provides proxies to certain Array methods; these are:
433
434* `container.map === container.nodes.map`
435* `container.reduce === container.nodes.reduce`
436* `container.every === container.nodes.every`
437* `container.some === container.nodes.some`
438* `container.filter === container.nodes.filter`
439* `container.sort === container.nodes.sort`
440
441Note that these methods only work on a container's immediate children; recursive
442iteration is provided by `container.walk`.
443
444### `container.each(callback)`
445
446Iterate the container's immediate children, calling `callback` for each child.
447You may return `false` within the callback to break the iteration.
448
449```js
450let className;
451selectors.each((selector, index) => {
452    if (selector.type === 'class') {
453        className = selector.value;
454        return false;
455    }
456});
457```
458
459Note that unlike `Array#forEach()`, this iterator is safe to use whilst adding
460or removing nodes from the container.
461
462Arguments:
463
464* `callback (function)`: A function to call for each node, which receives `node`
465  and `index` arguments.
466
467### `container.walk(callback)`
468
469Like `container#each`, but will also iterate child nodes as long as they are
470`container` types.
471
472```js
473selectors.walk((selector, index) => {
474    // all nodes
475});
476```
477
478Arguments:
479
480* `callback (function)`: A function to call for each node, which receives `node`
481  and `index` arguments.
482
483This iterator is safe to use whilst mutating `container.nodes`,
484like `container#each`.
485
486### `container.walk` proxies
487
488The container class provides proxy methods for iterating over types of nodes,
489so that it is easier to write modules that target specific selectors. Those
490methods are:
491
492* `container.walkAttributes`
493* `container.walkClasses`
494* `container.walkCombinators`
495* `container.walkComments`
496* `container.walkIds`
497* `container.walkNesting`
498* `container.walkPseudos`
499* `container.walkTags`
500* `container.walkUniversals`
501
502### `container.split(callback)`
503
504This method allows you to split a group of nodes by returning `true` from
505a callback. It returns an array of arrays, where each inner array corresponds
506to the groups that you created via the callback.
507
508```js
509// (input) => h1 h2>>h3
510const list = selectors.first.split(selector => {
511    return selector.type === 'combinator';
512});
513
514// (node values) => [['h1', ' '], ['h2', '>>'], ['h3']]
515```
516
517Arguments:
518
519* `callback (function)`: A function to call for each node, which receives `node`
520  as an argument.
521
522### `container.prepend(node)` & `container.append(node)`
523
524Add a node to the start/end of the container. Note that doing so will set
525the parent property of the node to this container.
526
527```js
528const id = parser.id({value: 'search'});
529selector.append(id);
530```
531
532Arguments:
533
534* `node`: The node to add.
535
536### `container.insertBefore(old, new[, ...newNodes])` & `container.insertAfter(old, new[, ...newNodes])`
537
538Add a node before or after an existing node in a container:
539
540```js
541selectors.walk(selector => {
542    if (selector.type !== 'class') {
543        const className = parser.className({value: 'theme-name'});
544        selector.parent.insertAfter(selector, className);
545    }
546});
547```
548
549Arguments:
550
551* `old`: The existing node in the container.
552* `new`: The new node to add before/after the existing node.
553
554### `container.removeChild(node)`
555
556Remove the node from the container. Note that you can also use
557`node.remove()` if you would like to remove just a single node.
558
559```js
560selector.length // => 2
561selector.remove(id)
562selector.length // => 1;
563id.parent       // undefined
564```
565
566Arguments:
567
568* `node`: The node to remove.
569
570### `container.removeAll()` or `container.empty()`
571
572Remove all children from the container.
573
574```js
575selector.removeAll();
576selector.length // => 0
577```
578
579## Root nodes
580
581A root node represents a comma separated list of selectors. Indeed, all
582a root's `toString()` method does is join its selector children with a ','.
583Other than this, it has no special functionality and acts like a container.
584
585### `root.trailingComma`
586
587This will be set to `true` if the input has a trailing comma, in order to
588support parsing of legacy CSS hacks.
589
590## Selector nodes
591
592A selector node represents a single complex selector. For example, this
593selector string `h1 h2 h3, [href] > p`, is represented as two selector nodes.
594It has no special functionality of its own.
595
596## Pseudo nodes
597
598A pseudo selector extends a container node; if it has any parameters of its
599own (such as `h1:not(h2, h3)`), they will be its children. Note that the pseudo
600`value` will always contain the colons preceding the pseudo identifier. This
601is so that both `:before` and `::before` are properly represented in the AST.
602
603## Attribute nodes
604
605### `attribute.quoted`
606
607Returns `true` if the attribute's value is wrapped in quotation marks, false if it is not.
608Remains `undefined` if there is no attribute value.
609
610```css
611[href=foo] /* false */
612[href='foo'] /* true */
613[href="foo"] /* true */
614[href] /* undefined */
615```
616
617### `attribute.qualifiedAttribute`
618
619Returns the attribute name qualified with the namespace if one is given.
620
621### `attribute.offsetOf(part)`
622
623 Returns the offset of the attribute part specified relative to the
624 start of the node of the output string. This is useful in raising
625 error messages about a specific part of the attribute, especially
626 in combination with `attribute.sourceIndex`.
627
628 Returns `-1` if the name is invalid or the value doesn't exist in this
629 attribute.
630
631 The legal values for `part` are:
632
633 * `"ns"` - alias for "namespace"
634 * `"namespace"` - the namespace if it exists.
635 * `"attribute"` - the attribute name
636 * `"attributeNS"` - the start of the attribute or its namespace
637 * `"operator"` - the match operator of the attribute
638 * `"value"` - The value (string or identifier)
639 * `"insensitive"` - the case insensitivity flag
640
641### `attribute.raws.unquoted`
642
643Returns the unquoted content of the attribute's value.
644Remains `undefined` if there is no attribute value.
645
646```css
647[href=foo] /* foo */
648[href='foo'] /* foo */
649[href="foo"] /* foo */
650[href] /* undefined */
651```
652
653### `attribute.spaces`
654
655Like `node.spaces` with the `before` and `after` values containing the spaces
656around the element, the parts of the attribute can also have spaces before
657and after them. The for each of `attribute`, `operator`, `value` and
658`insensitive` there is corresponding property of the same nam in
659`node.spaces` that has an optional `before` or `after` string containing only
660whitespace.
661
662Note that corresponding values in `attributes.raws.spaces` contain values
663including any comments. If set, these values will override the
664`attribute.spaces` value. Take care to remove them if changing
665`attribute.spaces`.
666
667### `attribute.raws`
668
669The raws object stores comments and other information necessary to re-render
670the node exactly as it was in the source.
671
672If a comment is embedded within the identifiers for the `namespace`, `attribute`
673or `value` then a property is placed in the raws for that value containing the full source of the propery including comments.
674
675If a comment is embedded within the space between parts of the attribute
676then the raw for that space is set accordingly.
677
678Setting an attribute's property `raws` value to be deleted.
679
680For now, changing the spaces required also updating or removing any of the
681raws values that override them.
682
683Example: `[ /*before*/ href /* after-attr */ = /* after-operator */ te/*inside-value*/st/* wow */ /*omg*/i/*bbq*/ /*whodoesthis*/]` would parse as:
684
685```js
686{
687  attribute: "href",
688  operator: "=",
689  value: "test",
690  spaces: {
691    before: '',
692    after: '',
693    attribute: { before: '  ', after: '  ' },
694    operator: { after: '  ' },
695    value: { after: ' ' },
696    insensitive: { after: ' ' }
697  },
698  raws: {
699    spaces: {
700      attribute: { before: ' /*before*/ ', after: ' /* after-attr */ ' },
701      operator: { after: ' /* after-operator */ ' },
702      value: { after: '/* wow */ /*omg*/' },
703      insensitive: { after: '/*bbq*/ /*whodoesthis*/' }
704    },
705    unquoted: 'test',
706    value: 'te/*inside-value*/st'
707  }
708}
709```
710
711## `Processor`
712
713### `ProcessorOptions`
714
715* `lossless` - When `true`, whitespace is preserved. Defaults to `true`.
716* `updateSelector` - When `true`, if any processor methods are passed a postcss
717  `Rule` node instead of a string, then that Rule's selector is updated
718  with the results of the processing. Defaults to `true`.
719
720### `process|processSync(selectors, [options])`
721
722Processes the `selectors`, returning a string from the result of processing.
723
724Note: when the `updateSelector` option is set, the rule's selector
725will be updated with the resulting string.
726
727**Example:**
728
729```js
730const parser = require("postcss-selector-parser");
731const processor = parser();
732
733let result = processor.processSync(' .class');
734console.log(result);
735// =>  .class
736
737// Asynchronous operation
738let promise = processor.process(' .class').then(result => {
739    console.log(result)
740    // => .class
741});
742
743// To have the parser normalize whitespace values, utilize the options
744result = processor.processSync('  .class  ', {lossless: false});
745console.log(result);
746// => .class
747
748// For better syntax errors, pass a PostCSS Rule node.
749const postcss = require('postcss');
750rule = postcss.rule({selector: ' #foo    > a,  .class  '});
751processor.process(rule, {lossless: false, updateSelector: true}).then(result => {
752    console.log(result);
753    // => #foo>a,.class
754    console.log("rule:", rule.selector);
755    // => rule: #foo>a,.class
756})
757```
758
759Arguments:
760
761* `selectors (string|postcss.Rule)`: Either a selector string or a PostCSS Rule
762  node.
763* `[options] (object)`: Process options
764
765
766### `ast|astSync(selectors, [options])`
767
768Like `process()` and `processSync()` but after
769processing the `selectors` these methods return the `Root` node of the result
770instead of a string.
771
772Note: when the `updateSelector` option is set, the rule's selector
773will be updated with the resulting string.
774
775### `transform|transformSync(selectors, [options])`
776
777Like `process()` and `processSync()` but after
778processing the `selectors` these methods return the value returned by the
779processor callback.
780
781Note: when the `updateSelector` option is set, the rule's selector
782will be updated with the resulting string.
783
784### Error Handling Within Selector Processors
785
786The root node passed to the selector processor callback
787has a method `error(message, options)` that returns an
788error object. This method should always be used to raise
789errors relating to the syntax of selectors. The options
790to this method are passed to postcss's error constructor
791([documentation](http://postcss.org/api/#container-error)).
792
793#### Async Error Example
794
795```js
796let processor = (root) => {
797    return new Promise((resolve, reject) => {
798        root.walkClasses((classNode) => {
799            if (/^(.*)[-_]/.test(classNode.value)) {
800                let msg = "classes may not have underscores or dashes in them";
801                reject(root.error(msg, {
802                    index: classNode.sourceIndex + RegExp.$1.length + 1,
803                    word: classNode.value
804                }));
805            }
806        });
807        resolve();
808    });
809};
810
811const postcss = require("postcss");
812const parser = require("postcss-selector-parser");
813const selectorProcessor = parser(processor);
814const plugin = postcss.plugin('classValidator', (options) => {
815    return (root) => {
816        let promises = [];
817        root.walkRules(rule => {
818            promises.push(selectorProcessor.process(rule));
819        });
820        return Promise.all(promises);
821    };
822});
823postcss(plugin()).process(`
824.foo-bar {
825  color: red;
826}
827`.trim(), {from: 'test.css'}).catch((e) => console.error(e.toString()));
828
829// CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them
830//
831// > 1 | .foo-bar {
832//     |     ^
833//   2 |   color: red;
834//   3 | }
835```
836
837#### Synchronous Error Example
838
839```js
840let processor = (root) => {
841    root.walkClasses((classNode) => {
842        if (/.*[-_]/.test(classNode.value)) {
843            let msg = "classes may not have underscores or dashes in them";
844            throw root.error(msg, {
845                index: classNode.sourceIndex,
846                word: classNode.value
847            });
848        }
849    });
850};
851
852const postcss = require("postcss");
853const parser = require("postcss-selector-parser");
854const selectorProcessor = parser(processor);
855const plugin = postcss.plugin('classValidator', (options) => {
856    return (root) => {
857        root.walkRules(rule => {
858            selectorProcessor.processSync(rule);
859        });
860    };
861});
862postcss(plugin()).process(`
863.foo-bar {
864  color: red;
865}
866`.trim(), {from: 'test.css'}).catch((e) => console.error(e.toString()));
867
868// CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them
869//
870// > 1 | .foo-bar {
871//     |     ^
872//   2 |   color: red;
873//   3 | }
874```
875 
codekingpro/portable-devtools · Team Ai