mirror of
https://github.com/10h30/odin-javascript-exercises.git
synced 2026-06-05 15:09:09 +09:00
remove timer and simon
This commit is contained in:
+26
@@ -0,0 +1,26 @@
|
||||
ESQuery is a library for querying the AST output by Esprima for patterns of syntax using a CSS style selector system. Check out the demo:
|
||||
|
||||
[demo](https://estools.github.io/esquery/)
|
||||
|
||||
The following selectors are supported:
|
||||
* AST node type: `ForStatement`
|
||||
* [wildcard](http://dev.w3.org/csswg/selectors4/#universal-selector): `*`
|
||||
* [attribute existence](http://dev.w3.org/csswg/selectors4/#attribute-selectors): `[attr]`
|
||||
* [attribute value](http://dev.w3.org/csswg/selectors4/#attribute-selectors): `[attr="foo"]` or `[attr=123]`
|
||||
* attribute regex: `[attr=/foo.*/]`
|
||||
* attribute conditons: `[attr!="foo"]`, `[attr>2]`, `[attr<3]`, `[attr>=2]`, or `[attr<=3]`
|
||||
* nested attribute: `[attr.level2="foo"]`
|
||||
* field: `FunctionDeclaration > Identifier.id`
|
||||
* [First](http://dev.w3.org/csswg/selectors4/#the-first-child-pseudo) or [last](http://dev.w3.org/csswg/selectors4/#the-last-child-pseudo) child: `:first-child` or `:last-child`
|
||||
* [nth-child](http://dev.w3.org/csswg/selectors4/#the-nth-child-pseudo) (no ax+b support): `:nth-child(2)`
|
||||
* [nth-last-child](http://dev.w3.org/csswg/selectors4/#the-nth-last-child-pseudo) (no ax+b support): `:nth-last-child(1)`
|
||||
* [descendant](http://dev.w3.org/csswg/selectors4/#descendant-combinators): `ancestor descendant`
|
||||
* [child](http://dev.w3.org/csswg/selectors4/#child-combinators): `parent > child`
|
||||
* [following sibling](http://dev.w3.org/csswg/selectors4/#general-sibling-combinators): `node ~ sibling`
|
||||
* [adjacent sibling](http://dev.w3.org/csswg/selectors4/#adjacent-sibling-combinators): `node + adjacent`
|
||||
* [negation](http://dev.w3.org/csswg/selectors4/#negation-pseudo): `:not(ForStatement)`
|
||||
* [matches-any](http://dev.w3.org/csswg/selectors4/#matches): `:matches([attr] > :first-child, :last-child)`
|
||||
* [subject indicator](http://dev.w3.org/csswg/selectors4/#subject): `!IfStatement > [name="foo"]`
|
||||
* class of AST node: `:statement`, `:expression`, `:declaration`, `:function`, or `:pattern`
|
||||
|
||||
[](https://travis-ci.org/estools/esquery)
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
/* vim: set sw=4 sts=4 : */
|
||||
(function () {
|
||||
|
||||
var estraverse = require('estraverse');
|
||||
var parser = require('./parser');
|
||||
|
||||
var isArray = Array.isArray || function isArray(array) {
|
||||
return {}.toString.call(array) === '[object Array]';
|
||||
};
|
||||
|
||||
var LEFT_SIDE = {};
|
||||
var RIGHT_SIDE = {};
|
||||
|
||||
function esqueryModule() {
|
||||
|
||||
/**
|
||||
* Get the value of a property which may be multiple levels down in the object.
|
||||
*/
|
||||
function getPath(obj, key) {
|
||||
var i, keys = key.split(".");
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
if (obj == null) { return obj; }
|
||||
obj = obj[keys[i]];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether `node` can be reached by following `path`, starting at `ancestor`.
|
||||
*/
|
||||
function inPath(node, ancestor, path) {
|
||||
var field, remainingPath, i;
|
||||
if (path.length === 0) { return node === ancestor; }
|
||||
if (ancestor == null) { return false; }
|
||||
field = ancestor[path[0]];
|
||||
remainingPath = path.slice(1);
|
||||
if (isArray(field)) {
|
||||
for (i = 0, l = field.length; i < l; ++i) {
|
||||
if (inPath(node, field[i], remainingPath)) { return true; }
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return inPath(node, field, remainingPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a `node` and its ancestors, determine if `node` is matched by `selector`.
|
||||
*/
|
||||
function matches(node, selector, ancestry) {
|
||||
var path, ancestor, i, l, p;
|
||||
if (!selector) { return true; }
|
||||
if (!node) { return false; }
|
||||
if (!ancestry) { ancestry = []; }
|
||||
|
||||
switch(selector.type) {
|
||||
case 'wildcard':
|
||||
return true;
|
||||
|
||||
case 'identifier':
|
||||
return selector.value.toLowerCase() === node.type.toLowerCase();
|
||||
|
||||
case 'field':
|
||||
path = selector.name.split('.');
|
||||
ancestor = ancestry[path.length - 1];
|
||||
return inPath(node, ancestor, path);
|
||||
|
||||
case 'matches':
|
||||
for (i = 0, l = selector.selectors.length; i < l; ++i) {
|
||||
if (matches(node, selector.selectors[i], ancestry)) { return true; }
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'compound':
|
||||
for (i = 0, l = selector.selectors.length; i < l; ++i) {
|
||||
if (!matches(node, selector.selectors[i], ancestry)) { return false; }
|
||||
}
|
||||
return true;
|
||||
|
||||
case 'not':
|
||||
for (i = 0, l = selector.selectors.length; i < l; ++i) {
|
||||
if (matches(node, selector.selectors[i], ancestry)) { return false; }
|
||||
}
|
||||
return true;
|
||||
|
||||
case 'child':
|
||||
if (matches(node, selector.right, ancestry)) {
|
||||
return matches(ancestry[0], selector.left, ancestry.slice(1));
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'descendant':
|
||||
if (matches(node, selector.right, ancestry)) {
|
||||
for (i = 0, l = ancestry.length; i < l; ++i) {
|
||||
if (matches(ancestry[i], selector.left, ancestry.slice(i + 1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'attribute':
|
||||
p = getPath(node, selector.name);
|
||||
switch (selector.operator) {
|
||||
case null:
|
||||
case void 0:
|
||||
return p != null;
|
||||
case '=':
|
||||
switch (selector.value.type) {
|
||||
case 'regexp': return selector.value.value.test(p);
|
||||
case 'literal': return '' + selector.value.value === '' + p;
|
||||
case 'type': return selector.value.value === typeof p;
|
||||
}
|
||||
case '!=':
|
||||
switch (selector.value.type) {
|
||||
case 'regexp': return !selector.value.value.test(p);
|
||||
case 'literal': return '' + selector.value.value !== '' + p;
|
||||
case 'type': return selector.value.value !== typeof p;
|
||||
}
|
||||
case '<=': return p <= selector.value.value;
|
||||
case '<': return p < selector.value.value;
|
||||
case '>': return p > selector.value.value;
|
||||
case '>=': return p >= selector.value.value;
|
||||
}
|
||||
|
||||
case 'sibling':
|
||||
return matches(node, selector.right, ancestry) &&
|
||||
sibling(node, selector.left, ancestry, LEFT_SIDE) ||
|
||||
selector.left.subject &&
|
||||
matches(node, selector.left, ancestry) &&
|
||||
sibling(node, selector.right, ancestry, RIGHT_SIDE);
|
||||
|
||||
case 'adjacent':
|
||||
return matches(node, selector.right, ancestry) &&
|
||||
adjacent(node, selector.left, ancestry, LEFT_SIDE) ||
|
||||
selector.right.subject &&
|
||||
matches(node, selector.left, ancestry) &&
|
||||
adjacent(node, selector.right, ancestry, RIGHT_SIDE);
|
||||
|
||||
case 'nth-child':
|
||||
return matches(node, selector.right, ancestry) &&
|
||||
nthChild(node, ancestry, function (length) {
|
||||
return selector.index.value - 1;
|
||||
});
|
||||
|
||||
case 'nth-last-child':
|
||||
return matches(node, selector.right, ancestry) &&
|
||||
nthChild(node, ancestry, function (length) {
|
||||
return length - selector.index.value;
|
||||
});
|
||||
|
||||
case 'class':
|
||||
if(!node.type) return false;
|
||||
switch(selector.name.toLowerCase()){
|
||||
case 'statement':
|
||||
if(node.type.slice(-9) === 'Statement') return true;
|
||||
// fallthrough: interface Declaration <: Statement { }
|
||||
case 'declaration':
|
||||
return node.type.slice(-11) === 'Declaration';
|
||||
case 'pattern':
|
||||
if(node.type.slice(-7) === 'Pattern') return true;
|
||||
// fallthrough: interface Expression <: Node, Pattern { }
|
||||
case 'expression':
|
||||
return node.type.slice(-10) === 'Expression' ||
|
||||
node.type === 'Literal' ||
|
||||
node.type === 'Identifier';
|
||||
case 'function':
|
||||
return node.type.slice(0, 8) === 'Function' ||
|
||||
node.type === 'ArrowFunctionExpression';
|
||||
}
|
||||
throw new Error('Unknown class name: ' + selector.name);
|
||||
}
|
||||
|
||||
throw new Error('Unknown selector type: ' + selector.type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the given node has a sibling that matches the given selector.
|
||||
*/
|
||||
function sibling(node, selector, ancestry, side) {
|
||||
var parent = ancestry[0], listProp, startIndex, keys, i, l, k, lowerBound, upperBound;
|
||||
if (!parent) { return false; }
|
||||
keys = estraverse.VisitorKeys[parent.type];
|
||||
for (i = 0, l = keys.length; i < l; ++i) {
|
||||
listProp = parent[keys[i]];
|
||||
if (isArray(listProp)) {
|
||||
startIndex = listProp.indexOf(node);
|
||||
if (startIndex < 0) { continue; }
|
||||
if (side === LEFT_SIDE) {
|
||||
lowerBound = 0;
|
||||
upperBound = startIndex;
|
||||
} else {
|
||||
lowerBound = startIndex + 1;
|
||||
upperBound = listProp.length;
|
||||
}
|
||||
for (k = lowerBound; k < upperBound; ++k) {
|
||||
if (matches(listProp[k], selector, ancestry)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the given node has an asjacent sibling that matches the given selector.
|
||||
*/
|
||||
function adjacent(node, selector, ancestry, side) {
|
||||
var parent = ancestry[0], listProp, keys, i, l, idx;
|
||||
if (!parent) { return false; }
|
||||
keys = estraverse.VisitorKeys[parent.type];
|
||||
for (i = 0, l = keys.length; i < l; ++i) {
|
||||
listProp = parent[keys[i]];
|
||||
if (isArray(listProp)) {
|
||||
idx = listProp.indexOf(node);
|
||||
if (idx < 0) { continue; }
|
||||
if (side === LEFT_SIDE && idx > 0 && matches(listProp[idx - 1], selector, ancestry)) {
|
||||
return true;
|
||||
}
|
||||
if (side === RIGHT_SIDE && idx < listProp.length - 1 && matches(listProp[idx + 1], selector, ancestry)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the given node is the nth child, determined by idxFn, which is given the containing list's length.
|
||||
*/
|
||||
function nthChild(node, ancestry, idxFn) {
|
||||
var parent = ancestry[0], listProp, keys, i, l, idx;
|
||||
if (!parent) { return false; }
|
||||
keys = estraverse.VisitorKeys[parent.type];
|
||||
for (i = 0, l = keys.length; i < l; ++i) {
|
||||
listProp = parent[keys[i]];
|
||||
if (isArray(listProp)) {
|
||||
idx = listProp.indexOf(node);
|
||||
if (idx >= 0 && idx === idxFn(listProp.length)) { return true; }
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each selector node marked as a subject, find the portion of the selector that the subject must match.
|
||||
*/
|
||||
function subjects(selector, ancestor) {
|
||||
var results, p;
|
||||
if (selector == null || typeof selector != 'object') { return []; }
|
||||
if (ancestor == null) { ancestor = selector; }
|
||||
results = selector.subject ? [ancestor] : [];
|
||||
for(p in selector) {
|
||||
if(!{}.hasOwnProperty.call(selector, p)) { continue; }
|
||||
[].push.apply(results, subjects(selector[p], p === 'left' ? selector[p] : ancestor));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* From a JS AST and a selector AST, collect all JS AST nodes that match the selector.
|
||||
*/
|
||||
function match(ast, selector) {
|
||||
var ancestry = [], results = [], altSubjects, i, l, k, m;
|
||||
if (!selector) { return results; }
|
||||
altSubjects = subjects(selector);
|
||||
estraverse.traverse(ast, {
|
||||
enter: function (node, parent) {
|
||||
if (parent != null) { ancestry.unshift(parent); }
|
||||
if (matches(node, selector, ancestry)) {
|
||||
if (altSubjects.length) {
|
||||
for (i = 0, l = altSubjects.length; i < l; ++i) {
|
||||
if (matches(node, altSubjects[i], ancestry)) { results.push(node); }
|
||||
for (k = 0, m = ancestry.length; k < m; ++k) {
|
||||
if (matches(ancestry[k], altSubjects[i], ancestry.slice(k + 1))) {
|
||||
results.push(ancestry[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results.push(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
leave: function () { ancestry.shift(); }
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a selector string and return its AST.
|
||||
*/
|
||||
function parse(selector) {
|
||||
return parser.parse(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the code AST using the selector string.
|
||||
*/
|
||||
function query(ast, selector) {
|
||||
return match(ast, parse(selector));
|
||||
}
|
||||
|
||||
query.parse = parse;
|
||||
query.match = match;
|
||||
query.matches = matches;
|
||||
return query.query = query;
|
||||
}
|
||||
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(esqueryModule);
|
||||
} else if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = esqueryModule();
|
||||
} else {
|
||||
this.esquery = esqueryModule();
|
||||
}
|
||||
|
||||
})();
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2013, Joel Feenstra
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the ESQuery nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL JOEL FEENSTRA BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"_from": "esquery@^1.0.0",
|
||||
"_id": "esquery@1.0.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=",
|
||||
"_location": "/esquery",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "esquery@^1.0.0",
|
||||
"name": "esquery",
|
||||
"escapedName": "esquery",
|
||||
"rawSpec": "^1.0.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "^1.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/eslint"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz",
|
||||
"_shasum": "cfba8b57d7fba93f17298a8a006a04cda13d80fa",
|
||||
"_spec": "esquery@^1.0.0",
|
||||
"_where": "/Users/cloyd/coderrr/odin/javascript-exercises/node_modules/eslint",
|
||||
"author": {
|
||||
"name": "Joel Feenstra",
|
||||
"email": "jrfeenst+esquery@gmail.com"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/jrfeenst/esquery/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"estraverse": "^4.0.0"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "A query library for ECMAScript AST using a CSS selector like query language.",
|
||||
"devDependencies": {
|
||||
"commonjs-everywhere": "~0.9.4",
|
||||
"esprima": "~1.1.1",
|
||||
"jstestr": ">=0.4",
|
||||
"pegjs": "~0.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"files": [
|
||||
"esquery.js",
|
||||
"parser.js",
|
||||
"license.txt",
|
||||
"README.md"
|
||||
],
|
||||
"homepage": "https://github.com/jrfeenst/esquery#readme",
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"javascript",
|
||||
"query"
|
||||
],
|
||||
"license": "BSD",
|
||||
"main": "esquery.js",
|
||||
"name": "esquery",
|
||||
"preferGlobal": false,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/jrfeenst/esquery.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/jstestr/bin/jstestr.js path=tests"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
+2595
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user