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