Initial commit
parent
5b54082091
commit
349836fe2c
@ -0,0 +1,29 @@
|
|||||||
|
# packagename
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[WTFPL](http://www.wtfpl.net/txt/copying/) or [CC0](https://creativecommons.org/publicdomain/zero/1.0/), whichever you prefer. A donation and/or attribution are appreciated, but not required.
|
||||||
|
|
||||||
|
## Donate
|
||||||
|
|
||||||
|
My income consists largely of donations for my projects. If this module is useful to you, consider [making a donation](http://cryto.net/~joepie91/donate.html)!
|
||||||
|
|
||||||
|
You can donate using Bitcoin, PayPal, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you're editing the files in `src/`, not those in `lib/`.
|
||||||
|
|
||||||
|
Build tool of choice is `gulp`; simply run `gulp` while developing, and it will watch for changes.
|
||||||
|
|
||||||
|
Be aware that by making a pull request, you agree to release your modifications under the licenses stated above.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
TODO
|
@ -0,0 +1,38 @@
|
|||||||
|
var gulp = require('gulp');
|
||||||
|
|
||||||
|
var gutil = require('gulp-util');
|
||||||
|
var babel = require('gulp-babel');
|
||||||
|
var pegjs = require('gulp-peg');
|
||||||
|
var cache = require('gulp-cached');
|
||||||
|
var remember = require('gulp-remember');
|
||||||
|
var plumber = require('gulp-plumber');
|
||||||
|
|
||||||
|
var sources = {
|
||||||
|
babel: ["src/**/*.js"],
|
||||||
|
pegjs: ["src/**/*.pegjs"]
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('babel', function() {
|
||||||
|
return gulp.src(sources.babel)
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(cache("babel"))
|
||||||
|
.pipe(babel({presets: ["es2015"]}).on('error', gutil.log)).on('data', gutil.log)
|
||||||
|
.pipe(remember("babel"))
|
||||||
|
.pipe(gulp.dest("lib/"));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('pegjs', function() {
|
||||||
|
return gulp.src(sources.pegjs)
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(cache("pegjs"))
|
||||||
|
.pipe(pegjs().on('error', gutil.log)).on('data', gutil.log)
|
||||||
|
.pipe(remember("pegjs"))
|
||||||
|
.pipe(gulp.dest("lib/"));
|
||||||
|
})
|
||||||
|
|
||||||
|
gulp.task('watch', function () {
|
||||||
|
gulp.watch(sources.babel, ['babel']);
|
||||||
|
gulp.watch(sources.pegjs, ['pegjs']);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('default', ['pegjs', 'babel', 'watch']);
|
@ -0,0 +1,3 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = require("./lib");
|
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "riot-query",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Lets you traverse through a tree of Riot tags and underlying DOM elements",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "http://git.cryto.net/joepie91/riot-query.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"riot",
|
||||||
|
"query",
|
||||||
|
"jquery"
|
||||||
|
],
|
||||||
|
"author": "Sven Slootweg",
|
||||||
|
"license": "WTFPL",
|
||||||
|
"dependencies": {
|
||||||
|
"dedupe": "^2.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-preset-es2015": "^6.6.0",
|
||||||
|
"gulp": "^3.9.1",
|
||||||
|
"gulp-babel": "^6.1.2",
|
||||||
|
"gulp-cached": "^1.1.0",
|
||||||
|
"gulp-peg": "^0.2.0",
|
||||||
|
"gulp-plumber": "^1.1.0",
|
||||||
|
"gulp-remember": "^0.3.0",
|
||||||
|
"gulp-util": "^3.0.7"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
function flattenSegmentTree(stacks, segments) {
|
||||||
|
segments.forEach((segment) => {
|
||||||
|
stacks = flattenSegment(stacks, segment);
|
||||||
|
});
|
||||||
|
|
||||||
|
return stacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenSegment(stacks, segment) {
|
||||||
|
if (segment.type === "identifier" || segment.type === "wildcard") {
|
||||||
|
return stacks.map((stack) => {
|
||||||
|
return stack.concat([segment]);
|
||||||
|
});
|
||||||
|
} else if (segment.type === "group") {
|
||||||
|
let newStacks = [];
|
||||||
|
|
||||||
|
segment.items.forEach((groupItem) => {
|
||||||
|
newStacks = newStacks.concat(flattenSegmentTree(stacks, groupItem));
|
||||||
|
});
|
||||||
|
|
||||||
|
return newStacks;
|
||||||
|
} else if (segment.type === "empty") {
|
||||||
|
return stacks;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unknown segment type '${segment.type}'`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (queryTree) {
|
||||||
|
return flattenSegmentTree([[]], queryTree);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = function(query) {
|
||||||
|
return query.map((segment) => {
|
||||||
|
if (segment.type === "identifier") {
|
||||||
|
return segment.value;
|
||||||
|
} else if (segment.type === "wildcard") {
|
||||||
|
return "**";
|
||||||
|
} else {
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}).join("/");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
|||||||
|
'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 flattenedQueries = flatten(riotQuery);
|
||||||
|
tagQueries(flattenedQueries);
|
||||||
|
|
||||||
|
return function traverse(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let queryCache = {};
|
||||||
|
|
||||||
|
module.exports = function(tag, query) {
|
||||||
|
if (queryCache[query] == null) {
|
||||||
|
queryCache[query] = createQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: DOM traversal
|
||||||
|
|
||||||
|
return queryCache[query](tag);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
function concatRepeat(first, rest, restIndex) {
|
||||||
|
return [first].concat(rest.map(function(item) {
|
||||||
|
return item[restIndex];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function combineFinal(riotQuery, domQuery) {
|
||||||
|
var resultObject = {
|
||||||
|
riotQuery: riotQuery
|
||||||
|
};
|
||||||
|
|
||||||
|
if (domQuery != null) {
|
||||||
|
resultObject.domQuery = domQuery[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
= riotQuery:riotQuery domQuery:domQuerySuffix? { return combineFinal(riotQuery, domQuery) }
|
||||||
|
|
||||||
|
riotQuery
|
||||||
|
= segment:riotQuerySegment subSegments:("/" riotQuerySegment)* { return concatRepeat(segment, subSegments, 1); }
|
||||||
|
|
||||||
|
riotQuerySegment
|
||||||
|
= riotQuerySegmentSelector
|
||||||
|
/ riotQuerySegmentGroup
|
||||||
|
|
||||||
|
riotQuerySegmentGroup
|
||||||
|
= '{' items:riotQuerySegmentGroupItems '}' { return {type: "group", items: items}; }
|
||||||
|
|
||||||
|
riotQuerySegmentGroupItems
|
||||||
|
= item:riotQuerySegmentGroupItemsItem subItems:("," riotQuerySegmentGroupItemsItem)* { return concatRepeat(item, subItems, 1); }
|
||||||
|
|
||||||
|
riotQuerySegmentGroupItemsItem
|
||||||
|
= riotQuery
|
||||||
|
/ '' { return [{type: "empty"}]; }
|
||||||
|
|
||||||
|
riotQuerySegmentSelector
|
||||||
|
= riotQueryIdentifier
|
||||||
|
/ riotQueryWildcard
|
||||||
|
|
||||||
|
riotQueryIdentifier
|
||||||
|
= identifier:[a-z-]+ { return {type: "identifier", value: identifier.join("")}; }
|
||||||
|
|
||||||
|
riotQueryWildcard
|
||||||
|
= "**" { return {type: "wildcard"}; }
|
||||||
|
|
||||||
|
domQuery
|
||||||
|
= query:.+ { return query.join(""); }
|
||||||
|
|
||||||
|
domQuerySuffix
|
||||||
|
= '//' domQuery
|
@ -0,0 +1,23 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const format = require("./format-flattened-query");
|
||||||
|
|
||||||
|
module.exports = function tagQuerySegments(queries) {
|
||||||
|
let tagMap = {};
|
||||||
|
let currentTag = 0;
|
||||||
|
|
||||||
|
queries.forEach((query) => {
|
||||||
|
let stack = [];
|
||||||
|
|
||||||
|
query.forEach((segment) => {
|
||||||
|
stack.push(segment);
|
||||||
|
let formatted = format(stack);
|
||||||
|
|
||||||
|
if (tagMap[formatted] == null) {
|
||||||
|
tagMap[formatted] = currentTag++;
|
||||||
|
}
|
||||||
|
|
||||||
|
segment.tag = tagMap[formatted];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue