diff --git a/CHANGELOG.md b/CHANGELOG.md index f82321c..a341297 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ **Features** -- Added a non-standard _keys_ selector (`~`). The keys selector selects property names from an object or indexes from and array. It is only enabled when setting the `strict` option to `false` when constructing a `JSONPathEnvironment`. +- Added a non-standard _keys_ selector (`~`). The keys selector selects property names from an object or indexes from an array. It is only enabled when setting the `strict` option to `false` when constructing a `JSONPathEnvironment`. - Added a non-standard _current key_ identifier (`#`). `#` will be the key or index corresponding to `@` in a filter expression. The current key identifier is only enabled when setting the `strict` option to `false` when constructing a `JSONPathEnvironment`. ## Version 1.1.1 diff --git a/src/path/extra/selectors.ts b/src/path/extra/selectors.ts index bc46bf3..ce57b64 100644 --- a/src/path/extra/selectors.ts +++ b/src/path/extra/selectors.ts @@ -23,14 +23,16 @@ export class KeysSelector extends JSONPathSelector { if (isArray(node.value)) { for (let i = 0; i < node.value.length; i++) { rv.push( - new JSONPathNode(i, node.location.concat(`~${i}`), node.root), + new JSONPathNode(i, node.location.concat(`[~][${i}]`), node.root), ); } } else if (isObject(node.value)) { + let i = 0; for (const [key, _] of this.environment.entries(node.value)) { rv.push( - new JSONPathNode(key, node.location.concat(`~${key}`), node.root), + new JSONPathNode(key, node.location.concat(`[~][${i}]`), node.root), ); + i++; } } } @@ -42,15 +44,21 @@ export class KeysSelector extends JSONPathSelector { if (node.value instanceof String) continue; if (isArray(node.value)) { for (let i = 0; i < node.value.length; i++) { - yield new JSONPathNode(i, node.location.concat(`~${i}`), node.root); + yield new JSONPathNode( + i, + node.location.concat(`[~][${i}]`), + node.root, + ); } } else if (isObject(node.value)) { + let i = 0; for (const [key, _] of this.environment.entries(node.value)) { yield new JSONPathNode( key, - node.location.concat(`~${key}`), + node.location.concat(`[~][${i}]`), node.root, ); + i++; } } } diff --git a/tests/path/extra.test.ts b/tests/path/extra.test.ts index db36339..9d1611d 100644 --- a/tests/path/extra.test.ts +++ b/tests/path/extra.test.ts @@ -104,8 +104,33 @@ describe("extra features", () => { "$description", ({ path, data, want }: TestCase) => { expect(env.query(path, data).values()).toStrictEqual(want); + expect( + Array.from(env.lazyQuery(path, data)).map((n) => n.value), + ).toStrictEqual(want); }, ); + + test("keys from an array, location is valid", () => { + const path = "$.some[?# > 1]"; + const data = { some: ["other", "thing", "foo", "bar"] }; + const nodes = env.query(path, data); + expect(nodes.values()).toStrictEqual(["foo", "bar"]); + expect(env.query(nodes.nodes[0].path, data).values()).toStrictEqual([ + "foo", + ]); + expect(env.query(nodes.nodes[1].path, data).values()).toStrictEqual([ + "bar", + ]); + }); + + test("keys from an object, location is valid", () => { + const path = "$.some[?match(#, '^b.*')]"; + const data = { some: { foo: "a", bar: "b", baz: "c", qux: "d" } }; + const nodes = env.query(path, data); + expect(nodes.values()).toStrictEqual(["b", "c"]); + expect(env.query(nodes.nodes[0].path, data).values()).toStrictEqual(["b"]); + expect(env.query(nodes.nodes[1].path, data).values()).toStrictEqual(["c"]); + }); }); describe("extra errors", () => {