From 1fb91a00b659f28ba31a1f1e0f7e9cd50872b850 Mon Sep 17 00:00:00 2001 From: Dan Burzo Date: Mon, 20 Jul 2020 21:45:51 +0300 Subject: [PATCH] Add ^ prefix for qs() instead of qsa(), fixes #1 --- README.md | 20 ++++++++++++++++++++ index.js | 18 +++++++++++++----- test/index.test.js | 11 +++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 731939c..085c62e 100644 --- a/README.md +++ b/README.md @@ -173,3 +173,23 @@ qsx( ], ]; ``` + +### Pick first query result with `^` + +For more complex queries where there resulting JSON contains several nested arrays, but for which you want to select a single element, you can prefix a selector with `^` to select just the first matching element — like `querySelector()` rather than `querySelectorAll()`. + +```js +qsx(document, `li { ^a, @title }`); + +// => +[ + { + title: "item 1", + ".scoped": ['First link'], + }, + { + title: "item 2", + ".scoped": ['Second link'], + }, +]; +``` diff --git a/index.js b/index.js index 25a0172..5fd200d 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const T = { FUNC_START: "(", FUNC_END: ")", ATTR: "@", + ONCE: "^", }; const RE = new RegExp( @@ -46,7 +47,7 @@ function qsa(el, $node, tree) { let attrs = $node.attrs; let $children = tree.childrenToArray($node); - return elements.map((element) => { + let res = elements.map((element) => { let scoped_els; if ($children.length) { scoped_els = $children.map(($child) => qsa(element, $child, tree)); @@ -75,14 +76,18 @@ function qsa(el, $node, tree) { } return res; }); + + return $node.once ? res[0] : res; } module.exports = function qsx(el, selector) { const tree = new SymbolTree(); - const $root = { + const node = () => ({ ctx: "", attrs: [], - }; + once: false, + }); + const $root = node(); let $curr = $root; const tokens = selector @@ -108,7 +113,7 @@ module.exports = function qsx(el, selector) { break; case T.GROUP_START: ctx_depth++; - $curr = tree.appendChild($curr, { ctx: "", attrs: [] }); + $curr = tree.appendChild($curr, node()); break; case T.GROUP_END: if (ctx_depth <= 0) { @@ -123,7 +128,7 @@ module.exports = function qsx(el, selector) { break; case T.SEP: if (!fn_depth && ctx_depth) { - let $sibling = tree.insertAfter($curr, { ctx: "", attrs: [] }); + let $sibling = tree.insertAfter($curr, node()); if (!$curr.ctx) { tree.remove($curr); } @@ -139,6 +144,9 @@ module.exports = function qsx(el, selector) { } tree.parent($curr).attrs.push(attr.trim()); break; + case T.ONCE: + $curr.once = true; + break; default: $curr.ctx += token; } diff --git a/test/index.test.js b/test/index.test.js index 33c2fba..3e5b35f 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -97,6 +97,17 @@ tape("README examples", (t) => { }, ]); + t.deepEqual(qsx(links, `li { ^a, @title }`), [ + { + title: "item 1", + ".scoped": ['First link'], + }, + { + title: "item 2", + ".scoped": ['Second link'], + }, + ]); + let terms = document(`
First term