'use strict'; const dedupe = require("dedupe"); const queryParser = require("./query"); const flatten = require("./flatten-query"); const tagQueries = require("./tag-queries"); function ensureArray(item) { if (Array.isArray(item)) { return item; } else if (item == null) { return []; } else { return [item]; } } function recurseTags(tag) { let allTags = [tag]; Object.keys(tag.tags).forEach((tagType) => { ensureArray(tag.tags[tagType]).forEach((subTag) => { allTags = allTags.concat(recurseTags(subTag)); }); }); return allTags; } function createQuery(query) { let {riotQuery, domQuery} = queryParser.parse(query); let tagObtainer; if (riotQuery != null) { let flattenedQueries = flatten(riotQuery); tagQueries(flattenedQueries); tagObtainer = function(tag) { let results = []; flattenedQueries.forEach((subQuery) => { let lastFound = [tag]; subQuery.forEach((segment) => { let nextLastFound = []; lastFound.forEach((subTag) => { //console.log("subtag", subQuery, segment, subTag); let found; if (segment.type === "identifier") { found = ensureArray(subTag.tags[segment.value]); } else if (segment.type === "wildcard") { found = recurseTags(subTag); } if (found.length > 0) { nextLastFound = nextLastFound.concat(found) } }); lastFound = nextLastFound; }); results = results.concat(lastFound); }); return dedupe(results, result => result._riot_id); } } else { tagObtainer = function(tag) { return [tag]; } } return function traverse(tag) { let riotResults = tagObtainer(tag); if (domQuery == null) { return riotResults; } else { let domElements = []; riotResults.forEach((foundTag) => { domElements = domElements.concat(Array.from(foundTag.root.querySelectorAll(domQuery))); }); return domElements; } } } let queryCache = {}; function query(tag, queryString) { if (queryCache[queryString] == null) { queryCache[queryString] = createQuery(queryString); } return queryCache[queryString](tag); } query.one = function queryOne(tag, queryString) { let results = query(tag, queryString); if (results.length === 0) { throw new Error(`No matches found for query ${queryString}`); } else { return results[0]; } } /* For use with `riot.mixin(query.mixin)`: */ query.mixin = { init: function() { this.query = query.bind(null, this); this.queryOne = query.one.bind(null, this); } } module.exports = query;