UNPKG

2.32 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * @typedef {import('./types').XastNode} XastNode
5 * @typedef {import('./types').XastChild} XastChild
6 * @typedef {import('./types').XastParent} XastParent
7 * @typedef {import('./types').Visitor} Visitor
8 */
9
10const { selectAll, selectOne, is } = require('css-select');
11const xastAdaptor = require('./svgo/css-select-adapter.js');
12
13const cssSelectOptions = {
14 xmlMode: true,
15 adapter: xastAdaptor,
16};
17
18/**
19 * @type {(node: XastNode, selector: string) => XastChild[]}
20 */
21const querySelectorAll = (node, selector) => {
22 return selectAll(selector, node, cssSelectOptions);
23};
24exports.querySelectorAll = querySelectorAll;
25
26/**
27 * @type {(node: XastNode, selector: string) => ?XastChild}
28 */
29const querySelector = (node, selector) => {
30 return selectOne(selector, node, cssSelectOptions);
31};
32exports.querySelector = querySelector;
33
34/**
35 * @type {(node: XastChild, selector: string) => boolean}
36 */
37const matches = (node, selector) => {
38 return is(node, selector, cssSelectOptions);
39};
40exports.matches = matches;
41
42const visitSkip = Symbol();
43exports.visitSkip = visitSkip;
44
45/**
46 * @type {(node: XastNode, visitor: Visitor, parentNode?: any) => void}
47 */
48const visit = (node, visitor, parentNode) => {
49 const callbacks = visitor[node.type];
50 if (callbacks && callbacks.enter) {
51 // @ts-ignore hard to infer
52 const symbol = callbacks.enter(node, parentNode);
53 if (symbol === visitSkip) {
54 return;
55 }
56 }
57 // visit root children
58 if (node.type === 'root') {
59 // copy children array to not loose cursor when children is spliced
60 for (const child of node.children) {
61 visit(child, visitor, node);
62 }
63 }
64 // visit element children if still attached to parent
65 if (node.type === 'element') {
66 if (parentNode.children.includes(node)) {
67 for (const child of node.children) {
68 visit(child, visitor, node);
69 }
70 }
71 }
72 if (callbacks && callbacks.exit) {
73 // @ts-ignore hard to infer
74 callbacks.exit(node, parentNode);
75 }
76};
77exports.visit = visit;
78
79/**
80 * @param {XastChild} node
81 * @param {XastParent} parentNode
82 */
83const detachNodeFromParent = (node, parentNode) => {
84 // avoid splice to not break for loops
85 parentNode.children = parentNode.children.filter((child) => child !== node);
86};
87exports.detachNodeFromParent = detachNodeFromParent;