From 6db3de6206b55bde6a803a81db10122d54d4c9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20B=C3=B6hm?= Date: Fri, 2 Oct 2020 09:48:13 -0700 Subject: [PATCH] feat(general): Add `cacheResults` option Allows users to manage cacheing behavior. --- src/general.ts | 5 ++++- src/types.ts | 12 ++++++++++-- test/api.ts | 24 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/general.ts b/src/general.ts index 587ac684..ac6a9a0f 100644 --- a/src/general.ts +++ b/src/general.ts @@ -51,7 +51,10 @@ export function compileGeneralSelector( // Traversal case "descendant": - if (typeof WeakSet === "undefined") { + if ( + options.cacheResults === false || + typeof WeakSet === "undefined" + ) { return function descendant(elem: ElementNode): boolean { let current: ElementNode | null = elem; diff --git a/src/types.ts b/src/types.ts index f926828c..c78032da 100644 --- a/src/types.ts +++ b/src/types.ts @@ -111,13 +111,21 @@ export interface Options { rootFunc?: (element: ElementNode) => boolean; /** * The adapter to use when interacting with the backing DOM structure. By - * default it uses domutils. + * default it uses the `domutils` module. */ adapter?: Adapter; /** - * The context of the current query. Used to + * The context of the current query. Used to limit the scope of searches. + * Can be matched directly using the `:scope` pseudo-selector. */ context?: ElementNode | ElementNode[]; + /** + * Allow css-select to cache results for some selectors, sometimes greatly + * improving querying performance. Disable this if your document can + * change in between queries with the same compiled selector. + * Defaults to `true`. + */ + cacheResults?: boolean; } // Internally, we want to ensure that no propterties are accessed on the passed objects diff --git a/test/api.ts b/test/api.ts index 03abd832..b9f774f9 100644 --- a/test/api.ts +++ b/test/api.ts @@ -173,5 +173,29 @@ describe("API", () => { CSSselect.selectAll("p", div, { context: div }) ).toStrictEqual(p); }); + + it("should cache results by default", () => { + const [dom] = parseDOM( + '

bar

' + ) as Element[]; + const query = CSSselect.compile("#bar p"); + + expect(CSSselect.selectAll(query, [dom])).toHaveLength(0); + dom.attribs.id = "bar"; + // The query should be cached and the changed attribute should be ignored. + expect(CSSselect.selectAll(query, [dom])).toHaveLength(0); + }); + + it("should skip cacheing results if asked to", () => { + const [dom] = parseDOM( + '

bar

' + ) as Element[]; + const query = CSSselect.compile("#bar p", { cacheResults: false }); + + expect(CSSselect.selectAll(query, [dom])).toHaveLength(0); + dom.attribs.id = "bar"; + // The query should not be cached, the changed attribute should be picked up. + expect(CSSselect.selectAll(query, [dom])).toHaveLength(1); + }); }); });