Initial commit

master
Sven Slootweg 8 years ago
parent 5b54082091
commit 349836fe2c

3
.gitignore vendored

@ -2,4 +2,5 @@
# https://help.github.com/articles/ignoring-files
# Example .gitignore files: https://github.com/github/gitignore
/bower_components/
/node_modules/
/node_modules/
/lib/

@ -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];
});
});
}

@ -0,0 +1,8 @@
'use strict';
const util = require("util");
const parse = require("./lib");
let testQuery = "foo/bar/**/{baz,qux/quz,something/{hai,bai},}/{duck,swan}//.domFoo .domBar";
// TODO
Loading…
Cancel
Save