diff --git a/src/common.js b/src/common.js deleted file mode 100644 index 9224297..0000000 --- a/src/common.js +++ /dev/null @@ -1,66 +0,0 @@ -import { - isDomElement, isCompositeElement - , isReactInstance, isDOMComponent, isCompositeComponent } from './utils'; - -function anyParent(test, element, node){ - do { - node = node.parentNode - } while(node && !test(node.element, node)) - - return !!node -} - -function directParent(test, _, node) { - node = node.parentNode - return !!(node && test(node.element, node)) -} - -function anySibling(test, _, node) { - do { - node = node.prevSibling - } while(node && !test(node.element, node)) - - return !!node -} - -function directSibling(test, _, node) { - node = node.prevSibling - return !!(node && test(node.element, node)) -} - -export default function(compiler) { - compiler.registerPseudo('dom', ()=> isDomElement) - compiler.registerPseudo('composite', ()=> isCompositeElement) - - compiler.registerPseudo('not', function(compiledSelector) { - return (element, node) => { - let matches = compiledSelector(element, node) - return !matches - } - }) - - compiler.registerPseudo('first-child', () => - (element, node) => { - let parent = node.parentNode; - return parent && parent.children.indexOf(node.instance || element) === 0 - }) - - compiler.registerPseudo('last-child', () => - (element, node) => { - let parent = node.parentNode; - let children = parent && parent.children - return parent && children.indexOf(node.instance || element) === (children.length - 1) - }) - - compiler.registerNesting('any', test => - (element, node) => anyParent(test, element, node)) - - compiler.registerNesting('>', test => - (element, node) => directParent(test, element, node)) - - compiler.registerNesting('~', test => - (element, node) => anySibling(test, element, node)) - - compiler.registerNesting('+', test => - (element, node) => directSibling(test, element, node)) -} diff --git a/src/compiler.js b/src/compiler.js index 8b395b2..4f2e8e6 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -2,12 +2,15 @@ import React from 'react'; import transform from 'lodash/object/transform'; import has from 'lodash/object/has'; import uid from 'lodash/utility/uniqueId'; +import { createNode, NODE_TYPES } from './node'; import { isTextElement, legacySelector } from './utils'; import { CssSelectorParser } from 'css-selector-parser'; import fnName from 'fn-name'; let parser = new CssSelectorParser(); -let name = type => type.displayName || fnName(type) || '' + +let name = type => typeof type === 'string' + ? type : type.displayName || fnName(type) || '' let prim = value => { let typ = typeof value; @@ -15,7 +18,7 @@ let prim = value => { } function failText(fn){ - return (...args) => isTextElement(args[0]) ? false : fn(...args) + return (...args) => args[0].nodeType === NODE_TYPES.TEXT ? false : fn(...args) } export function parse(selector){ @@ -88,9 +91,7 @@ export function create(options = {}) { let rule = rules.shift(); if (rule.tagName) - fns.push( - failText(getTagComparer(rule, values)) - ) + fns.push(getTagComparer(rule, values)) if (rule.attrs) fns.push( @@ -99,7 +100,7 @@ export function create(options = {}) { if (rule.classNames) fns.push( - failText(({ props }) => { + failText(({ element: { props } }) => { let className = props && props.className return rule.classNames.every(clsName => className && className.indexOf(clsName) !== -1) @@ -131,9 +132,11 @@ export function create(options = {}) { fns.push(NESTING[operator](nestedCompiled)) } - return fns.reduce((current, next = ()=> true)=> { + let compiledRule = fns.reduce((current, next = ()=> true)=> { return (...args)=> current(...args) && next(...args) }) + + return (element, ...args)=> compiledRule(createNode(element), ...args) } function selector(strings, ...values){ @@ -161,24 +164,27 @@ export function create(options = {}) { } function getTagComparer(rule, values) { - let isStr = t => typeof t === 'string' - let tagName = values[rule.tagName] || rule.tagName; + let tagName = values[rule.tagName] || rule.tagName + , test; if (rule.tagName === '*') - return ()=> true + test = ()=> true + + else { + if (typeof tagName !== 'string') + test = root => root.element.type === tagName + else { + test = root => name(root.element.type).toUpperCase() === tagName.toUpperCase(); + } - if (isStr(tagName)){ - tagName = tagName.toUpperCase(); - return root => isStr(root.type) - ? root.type.toUpperCase() === tagName - : name(root.type).toUpperCase() === tagName; + test = failText(test) } - return root => root.type === tagName + return test } function getPropComparer(rule, values) { - return ({ props }) => rule.attrs.every(attr => { + return ({ element: { props } }) => rule.attrs.every(attr => { if (!has(attr, 'value')) return !!props[attr.name] diff --git a/src/element-selector.js b/src/element-selector.js deleted file mode 100644 index 006ed87..0000000 --- a/src/element-selector.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import transform from 'lodash/object/transform'; -import has from 'lodash/object/has'; -import { create as createCompiler, parse } from './compiler'; -import common from './common'; -import { createNode, eachChild } from './node'; -import { anyParent, directParent, isDomElement, isCompositeElement } from './utils'; - -export let compiler = createCompiler() - -common(compiler); - -compiler.registerPseudo('has', function(compiledSelector) { - return root => { - let matches = findAll(root, compiledSelector) - return !!matches.length - } -}) - -export function match(selector, tree, includeSelf = true){ - return findAll(tree, compiler.compile(selector), includeSelf) -} - -export function findAll(element, test, includeSelf, parent) { - let found = [], children = []; - - if (element == null || element === false) - return found; - - var node = createNode(element, parent); - - if (includeSelf && test(element, node)) - found.push(element); - - - if (React.isValidElement(element)) - eachChild(element, child => { - found = found.concat(findAll(child, test, true, node)) - }) - - return found -} diff --git a/src/index.js b/src/index.js index ef3ca32..078b651 100644 --- a/src/index.js +++ b/src/index.js @@ -1,15 +1,25 @@ import { isValidElement } from 'react'; -import * as elements from './element-selector'; -import * as instance from './instance-selector'; +import { NODE_TYPE } from './node'; +import { findAll, createNode } from './node'; +import { create as createCompiler, parse } from './compiler'; +import selectors from './selectors'; -function match(selector, element){ - if (isValidElement(element)) - return elements.match(selector, element) +let compiler = createCompiler() - return instance.match(selector, element) +selectors(compiler); + +function match(selector, tree, includeSelf = true) { + return createNode(tree).findAll(compiler.compile(selector), includeSelf) +} + +function matchKind(selector, element, includeSelf) { + return match(selector, element, includeSelf) + .map(node => node.instance || node.element) } module.exports = { match, - selector: elements.compiler.selector + matchKind, + findAll, + isNode: el => el && el.$$typeof === NODE_TYPE, } diff --git a/src/instance-selector.js b/src/instance-selector.js deleted file mode 100644 index edc4fee..0000000 --- a/src/instance-selector.js +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; -import ReactInstanceMap from 'react/lib/ReactInstanceMap'; -import isPlainObject from 'lodash/lang/isPlainObject'; -import { create as createCompiler, parse } from './compiler'; -import common from './common'; -import { createNode, eachChild } from './node'; -import { - anyParent, directParent - , isDomElement, isCompositeElement - , isReactInstance, isDOMComponent, isCompositeComponent } from './utils'; - -export let compiler = createCompiler() - -common(compiler); - -compiler.registerPseudo('has', function(compiledSelector) { - return (_, node) => { - let matches = findAll(node.instance, compiledSelector) - return !!matches.length - } -}) - -export function findAll(inst, test, includeSelf, parent) { - let found = [], publicInst; - - if (!inst) - return found; - - if (inst.getPublicInstance) - publicInst = inst.getPublicInstance() - - var node = createNode(inst, parent); - - // ReactEmptyComponents (return null render