aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/css-tree/lib/walker/create.js
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
commit76cb9c2a39d477a64824a985ade40507e3bbade1 (patch)
tree41e997aa9c6f538d3a136af61dae9424db2005a9 /vanilla/node_modules/css-tree/lib/walker/create.js
parent819a39a21ac992b1393244a4c283bbb125208c69 (diff)
downloadneko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.gz
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.bz2
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.zip
feat(vanilla): add testing infrastructure and tests (NK-wjnczv)
Diffstat (limited to 'vanilla/node_modules/css-tree/lib/walker/create.js')
-rw-r--r--vanilla/node_modules/css-tree/lib/walker/create.js287
1 files changed, 287 insertions, 0 deletions
diff --git a/vanilla/node_modules/css-tree/lib/walker/create.js b/vanilla/node_modules/css-tree/lib/walker/create.js
new file mode 100644
index 0000000..ca76e03
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/walker/create.js
@@ -0,0 +1,287 @@
+const { hasOwnProperty } = Object.prototype;
+const noop = function() {};
+
+function ensureFunction(value) {
+ return typeof value === 'function' ? value : noop;
+}
+
+function invokeForType(fn, type) {
+ return function(node, item, list) {
+ if (node.type === type) {
+ fn.call(this, node, item, list);
+ }
+ };
+}
+
+function getWalkersFromStructure(name, nodeType) {
+ const structure = nodeType.structure;
+ const walkers = [];
+
+ for (const key in structure) {
+ if (hasOwnProperty.call(structure, key) === false) {
+ continue;
+ }
+
+ let fieldTypes = structure[key];
+ const walker = {
+ name: key,
+ type: false,
+ nullable: false
+ };
+
+ if (!Array.isArray(fieldTypes)) {
+ fieldTypes = [fieldTypes];
+ }
+
+ for (const fieldType of fieldTypes) {
+ if (fieldType === null) {
+ walker.nullable = true;
+ } else if (typeof fieldType === 'string') {
+ walker.type = 'node';
+ } else if (Array.isArray(fieldType)) {
+ walker.type = 'list';
+ }
+ }
+
+ if (walker.type) {
+ walkers.push(walker);
+ }
+ }
+
+ if (walkers.length) {
+ return {
+ context: nodeType.walkContext,
+ fields: walkers
+ };
+ }
+
+ return null;
+}
+
+function getTypesFromConfig(config) {
+ const types = {};
+
+ for (const name in config.node) {
+ if (hasOwnProperty.call(config.node, name)) {
+ const nodeType = config.node[name];
+
+ if (!nodeType.structure) {
+ throw new Error('Missed `structure` field in `' + name + '` node type definition');
+ }
+
+ types[name] = getWalkersFromStructure(name, nodeType);
+ }
+ }
+
+ return types;
+}
+
+function createTypeIterator(config, reverse) {
+ const fields = config.fields.slice();
+ const contextName = config.context;
+ const useContext = typeof contextName === 'string';
+
+ if (reverse) {
+ fields.reverse();
+ }
+
+ return function(node, context, walk, walkReducer) {
+ let prevContextValue;
+
+ if (useContext) {
+ prevContextValue = context[contextName];
+ context[contextName] = node;
+ }
+
+ for (const field of fields) {
+ const ref = node[field.name];
+
+ if (!field.nullable || ref) {
+ if (field.type === 'list') {
+ const breakWalk = reverse
+ ? ref.reduceRight(walkReducer, false)
+ : ref.reduce(walkReducer, false);
+
+ if (breakWalk) {
+ return true;
+ }
+ } else if (walk(ref)) {
+ return true;
+ }
+ }
+ }
+
+ if (useContext) {
+ context[contextName] = prevContextValue;
+ }
+ };
+}
+
+function createFastTraveralMap({
+ StyleSheet,
+ Atrule,
+ Rule,
+ Block,
+ DeclarationList
+}) {
+ return {
+ Atrule: {
+ StyleSheet,
+ Atrule,
+ Rule,
+ Block
+ },
+ Rule: {
+ StyleSheet,
+ Atrule,
+ Rule,
+ Block
+ },
+ Declaration: {
+ StyleSheet,
+ Atrule,
+ Rule,
+ Block,
+ DeclarationList
+ }
+ };
+}
+
+export function createWalker(config) {
+ const types = getTypesFromConfig(config);
+ const iteratorsNatural = {};
+ const iteratorsReverse = {};
+ const breakWalk = Symbol('break-walk');
+ const skipNode = Symbol('skip-node');
+
+ for (const name in types) {
+ if (hasOwnProperty.call(types, name) && types[name] !== null) {
+ iteratorsNatural[name] = createTypeIterator(types[name], false);
+ iteratorsReverse[name] = createTypeIterator(types[name], true);
+ }
+ }
+
+ const fastTraversalIteratorsNatural = createFastTraveralMap(iteratorsNatural);
+ const fastTraversalIteratorsReverse = createFastTraveralMap(iteratorsReverse);
+
+ const walk = function(root, options) {
+ function walkNode(node, item, list) {
+ const enterRet = enter.call(context, node, item, list);
+
+ if (enterRet === breakWalk) {
+ return true;
+ }
+
+ if (enterRet === skipNode) {
+ return false;
+ }
+
+ if (iterators.hasOwnProperty(node.type)) {
+ if (iterators[node.type](node, context, walkNode, walkReducer)) {
+ return true;
+ }
+ }
+
+ if (leave.call(context, node, item, list) === breakWalk) {
+ return true;
+ }
+
+ return false;
+ }
+
+ let enter = noop;
+ let leave = noop;
+ let iterators = iteratorsNatural;
+ let walkReducer = (ret, data, item, list) => ret || walkNode(data, item, list);
+ const context = {
+ break: breakWalk,
+ skip: skipNode,
+
+ root,
+ stylesheet: null,
+ atrule: null,
+ atrulePrelude: null,
+ rule: null,
+ selector: null,
+ block: null,
+ declaration: null,
+ function: null
+ };
+
+ if (typeof options === 'function') {
+ enter = options;
+ } else if (options) {
+ enter = ensureFunction(options.enter);
+ leave = ensureFunction(options.leave);
+
+ if (options.reverse) {
+ iterators = iteratorsReverse;
+ }
+
+ if (options.visit) {
+ if (fastTraversalIteratorsNatural.hasOwnProperty(options.visit)) {
+ iterators = options.reverse
+ ? fastTraversalIteratorsReverse[options.visit]
+ : fastTraversalIteratorsNatural[options.visit];
+ } else if (!types.hasOwnProperty(options.visit)) {
+ throw new Error('Bad value `' + options.visit + '` for `visit` option (should be: ' + Object.keys(types).sort().join(', ') + ')');
+ }
+
+ enter = invokeForType(enter, options.visit);
+ leave = invokeForType(leave, options.visit);
+ }
+ }
+
+ if (enter === noop && leave === noop) {
+ throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function');
+ }
+
+ walkNode(root);
+ };
+
+ walk.break = breakWalk;
+ walk.skip = skipNode;
+
+ walk.find = function(ast, fn) {
+ let found = null;
+
+ walk(ast, function(node, item, list) {
+ if (fn.call(this, node, item, list)) {
+ found = node;
+ return breakWalk;
+ }
+ });
+
+ return found;
+ };
+
+ walk.findLast = function(ast, fn) {
+ let found = null;
+
+ walk(ast, {
+ reverse: true,
+ enter(node, item, list) {
+ if (fn.call(this, node, item, list)) {
+ found = node;
+ return breakWalk;
+ }
+ }
+ });
+
+ return found;
+ };
+
+ walk.findAll = function(ast, fn) {
+ const found = [];
+
+ walk(ast, function(node, item, list) {
+ if (fn.call(this, node, item, list)) {
+ found.push(node);
+ }
+ });
+
+ return found;
+ };
+
+ return walk;
+};