You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
2.5 KiB
JavaScript

'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;