portadom 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -0
- package/dist/cjs/dom/dom.d.ts +19 -0
- package/dist/cjs/dom/dom.js +813 -0
- package/dist/cjs/dom/dom.js.map +1 -0
- package/dist/cjs/dom/domUtils.d.ts +42 -0
- package/dist/cjs/dom/domUtils.js +126 -0
- package/dist/cjs/dom/domUtils.js.map +1 -0
- package/dist/cjs/dom/types.d.ts +371 -0
- package/dist/cjs/dom/types.js +216 -0
- package/dist/cjs/dom/types.js.map +1 -0
- package/dist/cjs/index.d.ts +6 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/page/page.d.ts +12 -0
- package/dist/cjs/page/page.js +105 -0
- package/dist/cjs/page/page.js.map +1 -0
- package/dist/cjs/page/pageUtils.d.ts +16 -0
- package/dist/cjs/page/pageUtils.js +116 -0
- package/dist/cjs/page/pageUtils.js.map +1 -0
- package/dist/cjs/page/types.d.ts +61 -0
- package/dist/cjs/page/types.js +3 -0
- package/dist/cjs/page/types.js.map +1 -0
- package/dist/cjs/utils/async.d.ts +19 -0
- package/dist/cjs/utils/async.js +74 -0
- package/dist/cjs/utils/async.js.map +1 -0
- package/dist/cjs/utils/error.d.ts +1 -0
- package/dist/cjs/utils/error.js +10 -0
- package/dist/cjs/utils/error.js.map +1 -0
- package/dist/cjs/utils/format.d.ts +9 -0
- package/dist/cjs/utils/format.js +19 -0
- package/dist/cjs/utils/format.js.map +1 -0
- package/dist/cjs/utils/types.d.ts +6 -0
- package/dist/cjs/utils/types.js +9 -0
- package/dist/cjs/utils/types.js.map +1 -0
- package/dist/cjs/utils/url.d.ts +9 -0
- package/dist/cjs/utils/url.js +32 -0
- package/dist/cjs/utils/url.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/dom/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StrAsNumOptions } from '../utils/format';\nimport type { FormatUrlOptions } from '../utils/url';\nimport type { MaybeArray, MaybePromise } from '../utils/types';\n\n/**\n * Common interface for working with DOM despite different environments.\n *\n * Consider these environments:\n * 1) Browser (via Playwright & Chromium) - uses Browser API to work with DOM\n * 2) Cheerio - uses own API to work with DOM\n *\n * This common interfaces makes the scraping code more portable between the two.\n */\nexport interface Portadom<El extends BaseEl, BaseEl> {\n node: El | null;\n\n ///////////////////////\n // SCALAR OPERATIONS\n ///////////////////////\n\n /** Get element's text (trimmed) */\n text: (options?: { allowEmpty?: boolean }) => MaybePromise<string | null>;\n /** Get element's text as uppercase (trimmed) */\n textAsUpper: (options?: { allowEmpty?: boolean }) => MaybePromise<string | null>;\n /** Get element's text as lowercase (trimmed) */\n textAsLower: (options?: { allowEmpty?: boolean }) => MaybePromise<string | null>;\n /** Get element's text and convert it to number */\n textAsNumber: (options?: StrAsNumOptions) => MaybePromise<number | null>;\n /** Get element's attribute */\n attr: (attrName: string, options?: { allowEmpty?: boolean }) => MaybePromise<string | null>;\n /** Get element's attributes */\n attrs: <T extends string>(\n attrNames: T[],\n options?: { allowEmpty?: boolean }\n ) => MaybePromise<Record<T, string | null>>;\n /** Get element's property */\n prop: <R = unknown>(\n /** Single or nested prop path */\n propName: MaybeArray<string>,\n options?: { allowEmpty?: boolean }\n ) => MaybePromise<R>;\n /** Get element's properties */\n props: <R extends any[]>(\n /** List of single or nested prop paths */\n propName: MaybeArray<string>[],\n options?: { allowEmpty?: boolean }\n ) => MaybePromise<R>;\n /** Get element's href */\n href: (options?: { allowEmpty?: boolean } & FormatUrlOptions) => MaybePromise<string | null>;\n /** Get element's src */\n src: (options?: { allowEmpty?: boolean } & FormatUrlOptions) => MaybePromise<string | null>;\n /** Get element's nodeName */\n nodeName: () => MaybePromise<string | null>;\n /** Get URL of website associated with the DOM */\n url: () => MaybePromise<string | null>;\n /** Freely modify the underlying DOM node */\n map: <TVal>(map: (node: El | null) => TVal) => MaybePromise<TVal>;\n\n ///////////////////////\n // NODE OPERATIONS\n ///////////////////////\n\n /** Get a single descendant matching the selector */\n findOne: <TNewEl extends BaseEl = El>(selector: string) => PortadomPromise<TNewEl, BaseEl>; // prettier-ignore\n /** Get all descendants matching the selector */\n findMany: <TNewEl extends BaseEl = El>(selector: string) => PortadomArrayPromise<TNewEl, BaseEl>; // prettier-ignore\n /** Get a single ancestor (or itself) matching the selector */\n closest: <TNewEl extends BaseEl = El>(selector: string) => PortadomPromise<TNewEl, BaseEl>; // prettier-ignore\n /** Get element's parent */\n parent: <TNewEl extends BaseEl = El>() => PortadomPromise<TNewEl, BaseEl>;\n /** Get element's children */\n children: <TNewEl extends BaseEl = El>() => PortadomArrayPromise<TNewEl, BaseEl>;\n /** Remove the element */\n remove: () => MaybePromise<void>;\n /** Get root element */\n root: <TNewEl extends BaseEl = El>() => PortadomPromise<TNewEl, BaseEl>;\n\n /**\n * Given two elements, return closest ancestor element that encompases them both,\n * or `null` if none such found.\n */\n getCommonAncestor: <TNewEl extends BaseEl = El>(otherEl: El) => PortadomPromise<TNewEl, BaseEl>;\n /**\n * Given a selector, find all DOM elements that match the selector,\n * and return closest ancestor element that encompases them all,\n * or `null` if none such found.\n */\n getCommonAncestorFromSelector: <TNewEl extends BaseEl = El>(\n selector: string\n ) => PortadomPromise<TNewEl, BaseEl>;\n}\n\n/**\n * Wrapper for a {@link Promise} that resolves to a {@link Portadom} instance. This allows us to chain\n * Portadom methods before the Promise is resolved.\n *\n * Example:\n *\n * ```js\n * const dom = Promise.resolve(browserPortadom({}));\n * ```\n *\n * Instead of:\n * ```js\n * const resA = await (await dom).findOne('..');\n * const resB = await (await dom).text();\n * ```\n *\n * You can call:\n * ```js\n * const domP = createPortadomPromise(dom);\n * const resA = await domP.findOne('..');\n * const resB = await domP.text();\n * ```\n */\nexport interface PortadomPromise<El extends BaseEl, BaseEl> {\n promise: Promise<Portadom<El, BaseEl> | null>;\n node: Promise<NonNullable<El> | null>;\n\n ///////////////////////\n // SCALAR OPERATIONS\n ///////////////////////\n\n /** Get element's text (trimmed) */\n text: (\n ...args: Parameters<Portadom<El, BaseEl>['text']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['text']>>>;\n /** Get element's text as uppercase (trimmed) */\n textAsUpper: (\n ...args: Parameters<Portadom<El, BaseEl>['textAsUpper']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['textAsUpper']>>>;\n /** Get element's text as lowercase (trimmed) */\n textAsLower: (\n ...args: Parameters<Portadom<El, BaseEl>['textAsLower']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['textAsLower']>>>;\n /** Get element's text and convert it to number */\n textAsNumber: (\n ...args: Parameters<Portadom<El, BaseEl>['textAsNumber']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['textAsNumber']>>>;\n /** Get element's attribute */\n attr: (\n ...args: Parameters<Portadom<El, BaseEl>['attr']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['attr']>>>;\n /** Get element's attributes */\n attrs: <Attrs extends string>(\n ...args: [attrNames: Attrs[], options?: { allowEmpty?: boolean }]\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['attrs']> | null>>;\n /** Get element's property */\n prop: <R = unknown>(...args: Parameters<Portadom<El, BaseEl>['prop']>) => Promise<R | null>;\n /** Get element's properties */\n props: <R extends any[]>(...args: Parameters<Portadom<El, BaseEl>['props']>) => Promise<R | null>;\n /** Get element's href */\n href: (\n ...args: Parameters<Portadom<El, BaseEl>['href']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['href']>>>;\n /** Get element's src */\n src: (\n ...args: Parameters<Portadom<El, BaseEl>['src']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['src']>>>;\n /** Get element's nodeName */\n nodeName: (\n ...args: Parameters<Portadom<El, BaseEl>['nodeName']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['nodeName']>>>;\n /** Get URL of website associated with the DOM */\n url: (\n ...args: Parameters<Portadom<El, BaseEl>['url']>\n ) => Promise<Awaited<ReturnType<Portadom<El, BaseEl>['url']>>>;\n /** Freely modify the underlying DOM node */\n map: <TVal>(...args: [map: (node: El | null) => TVal]) => Promise<TVal | null>;\n\n ///////////////////////\n // NODE OPERATIONS\n ///////////////////////\n\n /** Get a single descendant matching the selector */\n findOne: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['findOne']>\n ) => PortadomPromise<TNewEl, BaseEl>;\n /** Get all descendants matching the selector */\n findMany: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['findMany']>\n ) => PortadomArrayPromise<TNewEl, BaseEl>;\n /** Get a single ancestor (or itself) matching the selector */\n closest: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['closest']>\n ) => PortadomPromise<TNewEl, BaseEl>;\n /** Get element's parent */\n parent: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['parent']>\n ) => PortadomPromise<TNewEl, BaseEl>;\n /** Get element's children */\n children: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['children']>\n ) => PortadomArrayPromise<TNewEl, BaseEl>;\n /** Remove the element */\n remove: (...args: Parameters<Portadom<El, BaseEl>['remove']>) => MaybePromise<void>;\n /** Get root element */\n root: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['root']>\n ) => PortadomPromise<TNewEl, BaseEl>;\n\n /**\n * Given two elements, return closest ancestor element that encompases them both,\n * or `null` if none such found.\n */\n getCommonAncestor: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['getCommonAncestor']>\n ) => PortadomPromise<TNewEl, BaseEl>;\n /**\n * Given a selector, find all DOM elements that match the selector,\n * and return closest ancestor element that encompases them all,\n * or `null` if none such found.\n */\n getCommonAncestorFromSelector: <TNewEl extends BaseEl = El>(\n ...args: Parameters<Portadom<El, BaseEl>['getCommonAncestorFromSelector']>\n ) => PortadomPromise<TNewEl, BaseEl>;\n}\n\n/**\n * Wrapper for a {@link Promise} that resolves to a {@link Portadom} instance. This allows us to chain\n * Portadom methods before the Promise is resolved.\n *\n * Example:\n *\n * ```js\n * const dom = Promise.resolve(browserPortadom({}));\n * ```\n *\n * Instead of:\n * ```js\n * const resA = await (await dom).findOne('..');\n * const resB = await (await dom).text();\n * ```\n *\n * You can call:\n * ```js\n * const domP = createPortadomPromise(dom);\n * const resA = await domP.findOne('..');\n * const resB = await domP.text();\n * ```\n */\nexport const createPortadomPromise = <El extends BaseEl, BaseEl>(\n promiseDom: MaybePromise<Portadom<El, BaseEl> | null>\n): PortadomPromise<El, BaseEl> => {\n type T = Portadom<El, BaseEl>;\n\n const promise = Promise.resolve(promiseDom);\n return {\n promise,\n get node() {\n return promise.then((d) => d?.node ?? null);\n },\n\n ///////////////////////\n // SCALAR OPERATIONS\n ///////////////////////\n\n /** Get element's text (trimmed) */\n text: (...args: Parameters<T['text']>) => promise.then((d) => d?.text(...args) ?? null),\n /** Get element's text as uppercase (trimmed) */\n textAsUpper: (...args: Parameters<T['textAsUpper']>) => promise.then((d) => d?.textAsUpper(...args) ?? null),\n /** Get element's text as lowercase (trimmed) */\n textAsLower: (...args: Parameters<T['textAsLower']>) => promise.then((d) => d?.textAsLower(...args) ?? null),\n /** Get element's text and convert it to number */\n textAsNumber: (...args: Parameters<T['textAsNumber']>) => promise.then((d) => d?.textAsNumber(...args) ?? null),\n /** Get element's attribute */\n attr: (...args: Parameters<T['attr']>) => promise.then((d) => d?.attr(...args) ?? null),\n /** Get element's attributes */\n attrs: <Attrs extends string>(...args: [\n attrNames: Attrs[],\n options?: { allowEmpty?: boolean }\n ]) => promise.then((d) => d?.attrs<Attrs>(...args) ?? null),\n /** Get element's property */\n prop: <R = unknown>(...args: Parameters<T['prop']>) => promise.then<R | null>((d) => d?.prop<R>(...args) ?? null),\n /** Get element's properties */\n props: <R extends any[]>(...args: Parameters<T['props']>) => promise.then<R | null>((d) => d?.props<R>(...args) ?? null),\n /** Get element's href */\n href: (...args: Parameters<T['href']>) => promise.then((d) => d?.href(...args) ?? null),\n /** Get element's src */\n src: (...args: Parameters<T['src']>) => promise.then((d) => d?.src(...args) ?? null),\n /** Get element's nodeName */\n nodeName: (...args: Parameters<T['nodeName']>) => promise.then((d) => d?.nodeName(...args) ?? null),\n /** Get URL of website associated with the DOM */\n url: (...args: Parameters<T['url']>) => promise.then((d) => d?.url(...args) ?? null),\n /** Freely modify the underlying DOM node */\n map: <TVal>(...args: [\n map: (node: El | null) => TVal\n ]) => promise.then<TVal | null>((d) => d?.map<TVal>(...args) ?? null),\n\n ///////////////////////\n // NODE OPERATIONS\n ///////////////////////\n\n /** Get a single descendant matching the selector */\n findOne: <TNewEl extends BaseEl = El>(...args: Parameters<T['findOne']>) => {\n return createPortadomPromise(\n promise.then<Portadom<TNewEl, BaseEl> | null>(async (d) => {\n const res = await d?.findOne<TNewEl>(...args).promise ?? null;\n return res;\n })\n );\n },\n /** Get all descendants matching the selector */\n findMany: <TNewEl extends BaseEl = El>(...args: Parameters<T['findMany']>) => {\n return createPortadomArrayPromise(\n promise.then<Portadom<TNewEl, BaseEl>[]>((d) => d ? d.findMany<TNewEl>(...args).promise : [])\n );\n },\n /** Get a single ancestor (or itself) matching the selector */\n closest: <TNewEl extends BaseEl = El>(...args: Parameters<T['closest']>) => {\n return createPortadomPromise(\n promise.then<Portadom<TNewEl, BaseEl> | null>(async (d) => {\n const res = await d?.closest<TNewEl>(...args).promise ?? null;\n return res;\n })\n );\n },\n /** Get element's parent */\n parent: <TNewEl extends BaseEl = El>(...args: Parameters<T['parent']>) => {\n return createPortadomPromise(\n promise.then<Portadom<TNewEl, BaseEl> | null>(async (d) => {\n const res = await d?.parent<TNewEl>(...args).promise ?? null;\n return res;\n }),\n );\n },\n /** Get element's children */\n children: <TNewEl extends BaseEl = El>(...args: Parameters<T['children']>) => {\n return createPortadomArrayPromise(\n promise.then<Portadom<TNewEl, BaseEl>[]>((d) => d ? d.children<TNewEl>(...args).promise : [])\n );\n },\n /** Get remove the element */\n remove: (...args: Parameters<T['remove']>) => promise.then((d) => d?.remove(...args)),\n /** Get root element */\n root: <TNewEl extends BaseEl = El>(...args: Parameters<T['root']>) => {\n return createPortadomPromise(\n promise.then<Portadom<TNewEl, BaseEl> | null>(async (d) => {\n const res = await d?.root<TNewEl>(...args).promise ?? null;\n return res;\n })\n );\n },\n /**\n * Given two elements, return closest ancestor element that encompases them both,\n * or `null` if none such found.\n */\n getCommonAncestor: <TNewEl extends BaseEl = El>(...args: [\n otherEl: El\n ]) => {\n return createPortadomPromise(\n promise.then<Portadom<TNewEl, BaseEl> | null>(async (d) => {\n const res = await d?.getCommonAncestor<TNewEl>(...args).promise ?? null;\n return res;\n }),\n );\n },\n /**\n * Given a selector, find all DOM elements that match the selector,\n * and return closest ancestor element that encompases them all,\n * or `null` if none such found.\n */\n getCommonAncestorFromSelector: <TNewEl extends BaseEl = El>(...args: [\n selector: string\n ]) => {\n return createPortadomPromise(\n promise.then<Portadom<TNewEl, BaseEl> | null>(async (d) => {\n const res = await d?.getCommonAncestorFromSelector<TNewEl>(...args).promise ?? null;\n return res;\n }),\n );\n },\n } satisfies PortadomPromise<El, BaseEl>; // prettier-ignore\n};\n\n/**\n * Wrapper for a {@link Promise} that resolves to a n Array of {@link Portadom} instances. This allows us to chain\n * Portadom methods before the Promise is resolved.\n *\n * Example:\n *\n * ```js\n * const dom = Promise.resolve(browserPortadom({}));\n * ```\n *\n * Instead of:\n * ```js\n * const resA = await (await dom).findOne('..');\n * const resB = await (await dom).text();\n * ```\n *\n * You can call:\n * ```js\n * const domP = createPortadomArrayPromise(dom);\n * const resA = await domP.findOne('..');\n * const resB = await domP.text();\n * ```\n */\nexport interface PortadomArrayPromise<El extends BaseEl, BaseEl> {\n /** Wrapped Promise of an array of {@link Portadom} instances */\n promise: Promise<Portadom<El, BaseEl>[]>;\n /** Wrapper for {@link Array.at} that returns the resulting item as {@link PortadomPromise}. */\n at: (...args: Parameters<Portadom<El, BaseEl>[]['at']>) => PortadomPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.concat} that returns the resulting array wrapped in {@link PortadomArrayPromise}.\n *\n * NOTE: The concat values are expected to be {@link Portadom} instances\n */\n concat: (\n ...args: Parameters<Portadom<El, BaseEl>[]['concat']>\n ) => PortadomArrayPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.copyWithin} that returns the resulting array wrapped in {@link PortadomArrayPromise}.\n *\n * NOTE: The concat values are expected to be {@link Portadom} instances\n */\n copyWithin: (\n ...args: Parameters<Portadom<El, BaseEl>[]['copyWithin']>\n ) => PortadomArrayPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.entries}.\n *\n * NOTE: Does NOT return an instance of {@link PortadomArrayPromise}\n */\n entries: (\n ...args: Parameters<Portadom<El, BaseEl>[]['entries']>\n ) => Promise<IterableIterator<[number, Portadom<El, BaseEl>]>>;\n /** Wrapper for {@link Array.every}. */\n every: (...args: Parameters<Portadom<El, BaseEl>[]['every']>) => Promise<boolean>;\n /**\n * Wrapper for {@link Array.fill}.\n *\n * NOTE: Fill values can be anything, so result is NOT wrapped in an instance of {@link PortadomArrayPromise}.\n *\n * NOTE2: Unlike {@link Array.fill}, this option doesn't allow to specify `start` and `end`.\n */\n fill: <U>(...args: [value: U]) => Promise<U[]>;\n /**\n * Wrapper for {@link Array.filter} that returns the resulting array wrapped in {@link PortadomArrayPromise}.\n */\n filter: (\n ...args: Parameters<Portadom<El, BaseEl>[]['filter']>\n ) => PortadomArrayPromise<El, BaseEl>;\n /** Wrapper for {@link Array.find} that returns the resulting item as {@link PortadomPromise}. */\n find: (...args: Parameters<Portadom<El, BaseEl>[]['find']>) => PortadomPromise<El, BaseEl>;\n /** Wrapper for {@link Array.findIndex}. */\n findIndex: (...args: Parameters<Portadom<El, BaseEl>[]['findIndex']>) => Promise<number>;\n /** Wrapper for {@link Array.flat} that returns the resulting array wrapped in {@link PortadomArrayPromise}. */\n flat: (...args: Parameters<Portadom<El, BaseEl>[]['flat']>) => PortadomArrayPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.entries}.\n *\n * NOTE: Mapped values can be anything, so result is NOT wrapped in an instance of {@link PortadomArrayPromise}\n */\n flatMap: <U, This>(...args: [\n callback: (this: This, value: Portadom<El, BaseEl>, index: number, array: Portadom<El, BaseEl>[]) => U | readonly U[],\n thisArg?: This | undefined\n ]) => Promise<U[]>; // prettier-ignore\n /** Wrapper for {@link Array.forEach}. */\n forEach: (...args: Parameters<Portadom<El, BaseEl>[]['forEach']>) => Promise<void>;\n /** Wrapper for {@link Array.includes}. */\n includes: (...args: Parameters<Portadom<El, BaseEl>[]['includes']>) => Promise<boolean>;\n /** Wrapper for {@link Array.indexOf}. */\n indexOf: (...args: Parameters<Portadom<El, BaseEl>[]['indexOf']>) => Promise<number>;\n /** Wrapper for {@link Array.join}. */\n join: (...args: Parameters<Portadom<El, BaseEl>[]['join']>) => Promise<string>;\n /** Wrapper for {@link Array.keys}. */\n keys: (...args: Parameters<Portadom<El, BaseEl>[]['keys']>) => Promise<IterableIterator<number>>;\n /** Wrapper for {@link Array.lastIndexOf}. */\n lastIndexOf: (...args: Parameters<Portadom<El, BaseEl>[]['lastIndexOf']>) => Promise<number>;\n /** Wrapper for {@link Array.length}. */\n length: Promise<number>;\n /**\n * Wrapper for {@link Array.map}.\n *\n * NOTE: Mapped values can be anything, so result is NOT wrapped in an instance of {@link PortadomArrayPromise}\n */\n map: <U>(...args: [\n callbackfn: (value: Portadom<El, BaseEl>, index: number, array: Portadom<El, BaseEl>[]) => U,\n thisArg?: any\n ]) => Promise<U[]>; // prettier-ignore\n /** Wrapper for {@link Array.pop} that returns the resulting item as {@link PortadomPromise}. */\n pop: (...args: Parameters<Portadom<El, BaseEl>[]['pop']>) => PortadomPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.push}.\n *\n * NOTE: The pushed values are expected to be {@link Portadom} instances.\n */\n push: (...args: Parameters<Portadom<El, BaseEl>[]['push']>) => Promise<number>;\n /**\n * Wrapper for {@link Array.reduce}.\n *\n * NOTE: The reduce value can be anything, so result is NOT wrapped in an instance of {@link PortadomArrayPromise}\n */\n reduce: {\n (callbackfn: (previousValue: Portadom<El, BaseEl>, currentValue: Portadom<El, BaseEl>, currentIndex: number, array: Portadom<El, BaseEl>[]) => Portadom<El, BaseEl>): Promise<Portadom<El, BaseEl>>;\n (callbackfn: (previousValue: Portadom<El, BaseEl>, currentValue: Portadom<El, BaseEl>, currentIndex: number, array: Portadom<El, BaseEl>[]) => Portadom<El, BaseEl>, initialValue: Portadom<El, BaseEl>): Promise<Portadom<El, BaseEl>>;\n <U>(callbackfn: (previousValue: U, currentValue: Portadom<El, BaseEl>, currentIndex: number, array: Portadom<El, BaseEl>[]) => U, initialValue: U): Promise<U>;\n }; // prettier-ignore\n /**\n * Wrapper for {@link Array.reduceRight}.\n *\n * NOTE: The reduce value can be anything, so result is NOT wrapped in an instance of {@link PortadomArrayPromise}\n */\n reduceRight: {\n reduceRight(callbackfn: (previousValue: Portadom<El, BaseEl>, currentValue: Portadom<El, BaseEl>, currentIndex: number, array: Portadom<El, BaseEl>[]) => Portadom<El, BaseEl>): Promise<Portadom<El, BaseEl>>;\n reduceRight(callbackfn: (previousValue: Portadom<El, BaseEl>, currentValue: Portadom<El, BaseEl>, currentIndex: number, array: Portadom<El, BaseEl>[]) => Portadom<El, BaseEl>, initialValue: Portadom<El, BaseEl>): Promise<Portadom<El, BaseEl>>;\n reduceRight<U>(callbackfn: (previousValue: U, currentValue: Portadom<El, BaseEl>, currentIndex: number, array: Portadom<El, BaseEl>[]) => U, initialValue: U): Promise<U>;\n }; // prettier-ignore\n /**\n * Wrapper for {@link Array.reverse} that returns the resulting array wrapped in {@link PortadomArrayPromise}.\n */\n reverse: (\n ...args: Parameters<Portadom<El, BaseEl>[]['reverse']>\n ) => PortadomArrayPromise<El, BaseEl>;\n /** Wrapper for {@link Array.shift} that returns the resulting item as {@link PortadomPromise}. */\n shift: (...args: Parameters<Portadom<El, BaseEl>[]['shift']>) => PortadomPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.slice} that returns the resulting array wrapped in {@link PortadomArrayPromise}.\n */\n slice: (...args: Parameters<Portadom<El, BaseEl>[]['slice']>) => PortadomArrayPromise<El, BaseEl>;\n /** Wrapper for {@link Array.some}. */\n some: (...args: Parameters<Portadom<El, BaseEl>[]['some']>) => Promise<boolean>;\n /**\n * Wrapper for {@link Array.sort} that returns the resulting array wrapped in {@link PortadomArrayPromise}.\n */\n sort: (...args: Parameters<Portadom<El, BaseEl>[]['sort']>) => PortadomArrayPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.splice} that returns the resulting array wrapped in {@link PortadomArrayPromise}.\n */\n splice: (\n ...args: Parameters<Portadom<El, BaseEl>[]['splice']>\n ) => PortadomArrayPromise<El, BaseEl>;\n /**\n * Wrapper for {@link Array.unshift}.\n *\n * NOTE: The added values are expected to be {@link Portadom} instances.\n */\n unshift: (...args: Parameters<Portadom<El, BaseEl>[]['unshift']>) => Promise<number>;\n /** NOTE: Does NOT return an instance of PortadomArrayPromise */\n values: (\n ...args: Parameters<Portadom<El, BaseEl>[]['values']>\n ) => Promise<IterableIterator<Portadom<El, BaseEl>>>;\n}\n\n/**\n * Wrapper for a {@link Promise} that resolves to a n Array of {@link Portadom} instances. This allows us to chain\n * Portadom methods before the Promise is resolved.\n *\n * Example:\n *\n * ```js\n * const dom = Promise.resolve(browserPortadom({}));\n * ```\n *\n * Instead of:\n * ```js\n * const resA = await (await dom).findOne('..');\n * const resB = await (await dom).text();\n * ```\n *\n * You can call:\n * ```js\n * const domP = createPortadomArrayPromise(dom);\n * const resA = await domP.findOne('..');\n * const resB = await domP.text();\n * ```\n */\nexport const createPortadomArrayPromise = <El extends BaseEl, BaseEl>(\n promiseDom: MaybePromise<Portadom<El, BaseEl>[]>\n): PortadomArrayPromise<El, BaseEl> => {\n type T = Portadom<El, BaseEl>;\n\n const promise = Promise.resolve(promiseDom);\n return {\n promise,\n at: (...args: Parameters<T[]['at']>) => createPortadomPromise(\n promise.then((d) => d.at(...args) ?? null)\n ),\n /** NOTE: The concat values are expected to be Portadom instances */\n concat: (...args: Parameters<T[]['concat']>) => createPortadomArrayPromise(\n promise.then((d) => d.concat(...args))\n ),\n copyWithin: (...args: Parameters<T[]['copyWithin']>) => createPortadomArrayPromise(\n promise.then((d) => d.copyWithin(...args))\n ),\n /** NOTE: Does NOT return an instance of PortadomArrayPromise */\n entries: (...args: Parameters<T[]['entries']>) => promise.then((d) => d.entries(...args)),\n every: (...args: Parameters<T[]['every']>) => promise.then((d) => d.every(...args)),\n /** NOTE: The fill value is expected to be a Portadom instance */\n fill: <U>(...args: [value: U]) => promise.then((d) => d.fill(...(args as [any])) as U[]),\n filter: (...args: Parameters<T[]['filter']>) => createPortadomArrayPromise(\n promise.then((d) => d.filter(...args))\n ),\n find: (...args: Parameters<T[]['find']>) => createPortadomPromise(\n promise.then((d) => d.find(...args) ?? null)\n ),\n findIndex: (...args: Parameters<T[]['findIndex']>) => promise.then((d) => d.findIndex(...args)),\n flat: (...args: Parameters<T[]['flat']>) => createPortadomArrayPromise(\n promise.then((d) => d.flat(...args))\n ),\n /** NOTE: Items are expected to be mapped to Portadom instances */\n flatMap: <U, This>(...args: [\n callback: (this: This, value: T, index: number, array: T[]) => U | readonly U[],\n thisArg?: This | undefined\n ]) => promise.then<U[]>((d) => d.flatMap<U, This>(...args)),\n forEach: (...args: Parameters<T[]['forEach']>) => promise.then((d) => d.forEach(...args)),\n includes: (...args: Parameters<T[]['includes']>) => promise.then((d) => d.includes(...args)),\n indexOf: (...args: Parameters<T[]['indexOf']>) => promise.then((d) => d.indexOf(...args)),\n join: (...args: Parameters<T[]['join']>) => promise.then((d) => d.join(...args)),\n keys: (...args: Parameters<T[]['keys']>) => promise.then((d) => d.keys(...args)),\n lastIndexOf: (...args: Parameters<T[]['lastIndexOf']>) => promise.then((d) => d.lastIndexOf(...args)),\n get length () {\n return promise.then((d) => d.length);\n },\n /** NOTE: Does NOT return an instance of PortadomArrayPromise */\n map: <U>(...args: [\n callbackfn: (value: Portadom<El, BaseEl>, index: number, array: Portadom<El, BaseEl>[]) => U,\n thisArg?: any\n ]) => promise.then<U[]>((d) => d.map(...args)),\n pop: (...args: Parameters<T[]['pop']>) => createPortadomPromise(\n promise.then((d) => d.pop(...args) ?? null)\n ),\n push: (...args: Parameters<T[]['push']>) => promise.then((d) => d.push(...args)),\n /** NOTE: Does NOT return an instance of PortadomArrayPromise */\n // NOTE: reduce has a complex type, so let the type definition handle that\n reduce: (...args: any[]) => promise.then((d) => d.reduce(...args as [any])),\n /** NOTE: Does NOT return an instance of PortadomArrayPromise */\n // NOTE: reduceRight has a complex type, so let the type definition handle that\n reduceRight: ((...args: any[]) => promise.then<any>((d) => d.reduceRight(...args as [any]))) as any as PortadomArrayPromise<El, BaseEl>['reduceRight'],\n reverse: (...args: Parameters<T[]['reverse']>) => createPortadomArrayPromise(\n promise.then((d) => d.reverse(...args))\n ),\n shift: (...args: Parameters<T[]['shift']>) => createPortadomPromise(\n promise.then((d) => d.shift(...args) ?? null)\n ),\n slice: (...args: Parameters<T[]['slice']>) => createPortadomArrayPromise(\n promise.then((d) => d.slice(...args))\n ),\n some: (...args: Parameters<T[]['some']>) => promise.then((d) => d.some(...args)),\n sort: (...args: Parameters<T[]['sort']>) => createPortadomArrayPromise(\n promise.then((d) => d.sort(...args))\n ),\n splice: (...args: Parameters<T[]['splice']>) => createPortadomArrayPromise(\n promise.then((d) => d.splice(...args))\n ),\n unshift: (...args: Parameters<T[]['unshift']>) => promise.then((d) => d.unshift(...args)),\n /** NOTE: Does NOT return an instance of PortadomArrayPromise */\n values: (...args: Parameters<T[]['values']>) => promise.then((d) => d.values(...args)),\n } satisfies PortadomArrayPromise<El, BaseEl>; // prettier-ignore\n};\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./dom/dom"), exports);
|
|
18
|
+
__exportStar(require("./dom/domUtils"), exports);
|
|
19
|
+
__exportStar(require("./dom/types"), exports);
|
|
20
|
+
__exportStar(require("./page/page"), exports);
|
|
21
|
+
__exportStar(require("./page/pageUtils"), exports);
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,iDAA+B;AAC/B,8CAA4B;AAC5B,8CAA4B;AAC5B,mDAAiC","sourcesContent":["export * from './dom/dom';\nexport * from './dom/domUtils';\nexport * from './dom/types';\nexport * from './page/page';\nexport * from './page/pageUtils';\nexport { Portapage, InfiniteScrollLoaderOptions } from './page/types';\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Page, Locator, ElementHandle, JSHandle } from 'playwright';
|
|
2
|
+
import type { Portapage, _InfiScrollTypes } from './types';
|
|
3
|
+
type PlaywrightInfiScrollTypes = _InfiScrollTypes<Locator | ElementHandle<Element>, JSHandle<Element | null>, JSHandle<Element[]>, JSHandle<(Element | null)[]>>;
|
|
4
|
+
type PWIST = PlaywrightInfiScrollTypes;
|
|
5
|
+
/** Implementation of Portapage in Playwright */
|
|
6
|
+
export type PlaywrightPortapage<T extends Page = Page> = Portapage<T, PWIST, {
|
|
7
|
+
container: PWIST['container'];
|
|
8
|
+
page: T;
|
|
9
|
+
}>;
|
|
10
|
+
/** Implementation of Portapage in Playwright */
|
|
11
|
+
export declare const playwrightPortapage: <T extends Page>(page: T) => Promise<PlaywrightPortapage<T>>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.playwrightPortapage = void 0;
|
|
13
|
+
const error_1 = require("../utils/error");
|
|
14
|
+
const domUtils_1 = require("../dom/domUtils");
|
|
15
|
+
const pageUtils_1 = require("./pageUtils");
|
|
16
|
+
/** Implementation of Portapage in Playwright */
|
|
17
|
+
const playwrightPortapage = (page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
+
const { serializeEls, resolveId, resolveIds } = yield (0, pageUtils_1.createPlaywrightElementSerializer)(page);
|
|
19
|
+
const infiniteScroll = (container, onNewChildren, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
var _a, _b, _c, _d, _e;
|
|
21
|
+
const childrenCounter = (_a = options === null || options === void 0 ? void 0 : options.childrenCounter) !== null && _a !== void 0 ? _a : ((h) => h.evaluate((el) => el ? el.childElementCount : 0).catch(error_1.logAndRethrow)); // prettier-ignore
|
|
22
|
+
const childrenGetter = (_b = options === null || options === void 0 ? void 0 : options.childrenGetter) !== null && _b !== void 0 ? _b : ((h) => h.evaluateHandle((el) => el ? el.children : []).catch(error_1.logAndRethrow)); // prettier-ignore
|
|
23
|
+
const scrollIntoView = (_c = options === null || options === void 0 ? void 0 : options.scrollIntoView) !== null && _c !== void 0 ? _c : ((h) => h.evaluate((el) => { el && el.scrollIntoView(); }).catch(error_1.logAndRethrow)); // prettier-ignore
|
|
24
|
+
const waitAfterScroll = (_d = options === null || options === void 0 ? void 0 : options.waitAfterScroll) !== null && _d !== void 0 ? _d : (() => page.waitForLoadState('networkidle')); // prettier-ignore
|
|
25
|
+
const handleOrLocator = typeof container === 'string' ? page.locator(container) : container;
|
|
26
|
+
if ((0, domUtils_1.handleIsLocator)(handleOrLocator) && handleOrLocator.page() !== page) {
|
|
27
|
+
throw Error('Locator does not belong to given Page.');
|
|
28
|
+
}
|
|
29
|
+
yield _infiniteScrollLoader(handleOrLocator, (childIds, ctx, stopFn) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
// Resolve child IDs to handle of child elements on the page
|
|
31
|
+
const elsHandle = yield resolveIds(childIds);
|
|
32
|
+
// Then pass them to user
|
|
33
|
+
yield (onNewChildren === null || onNewChildren === void 0 ? void 0 : onNewChildren(elsHandle, Object.assign(Object.assign({}, ctx), { page }), stopFn));
|
|
34
|
+
}), {
|
|
35
|
+
retries: (_e = options === null || options === void 0 ? void 0 : options.retries) !== null && _e !== void 0 ? _e : 3,
|
|
36
|
+
childrenCounter: (el, ctx) => childrenCounter(el, Object.assign(Object.assign({}, ctx), { page })),
|
|
37
|
+
childrenGetter: (handle, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
|
+
// First let user tell us how to collect the child elements
|
|
39
|
+
const childElsHandle = yield childrenGetter(handle, Object.assign(Object.assign({}, ctx), { page }));
|
|
40
|
+
// Then convert them to serializable IDs that we can return to user
|
|
41
|
+
const childIds = yield serializeEls(childElsHandle);
|
|
42
|
+
return childIds;
|
|
43
|
+
}),
|
|
44
|
+
scrollIntoView: (childId, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
// First resolve serializable ID to an element on the page
|
|
46
|
+
const childElHandle = yield resolveId(childId);
|
|
47
|
+
// Then let user tell us how to scroll into view
|
|
48
|
+
yield scrollIntoView(childElHandle, Object.assign(Object.assign({}, ctx), { page }));
|
|
49
|
+
}),
|
|
50
|
+
waitAfterScroll: (childId, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
51
|
+
// First resolve serializable ID to an element on the page
|
|
52
|
+
const childElHandle = yield resolveId(childId);
|
|
53
|
+
// Then let user tell us how to wait after scroll
|
|
54
|
+
yield waitAfterScroll(childElHandle, Object.assign(Object.assign({}, ctx), { page }));
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
page,
|
|
60
|
+
infiniteScroll,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
exports.playwrightPortapage = playwrightPortapage;
|
|
64
|
+
/** Load entries via infinite scroll and process them as you go. */
|
|
65
|
+
const _infiniteScrollLoader = (container, onNewChildren, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
66
|
+
const containerElGetter = (typeof container === 'function' ? container : () => container);
|
|
67
|
+
const processedChildren = new Set();
|
|
68
|
+
let userAskedToStop = false;
|
|
69
|
+
const stopFn = () => {
|
|
70
|
+
userAskedToStop = true;
|
|
71
|
+
};
|
|
72
|
+
const processChildren = (childrenEl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
const newChildren = yield childrenEl.filter((el) => !processedChildren.has(el));
|
|
74
|
+
const container = yield containerElGetter();
|
|
75
|
+
yield (onNewChildren === null || onNewChildren === void 0 ? void 0 : onNewChildren(newChildren, { container }, stopFn));
|
|
76
|
+
newChildren.forEach((el) => processedChildren.add(el));
|
|
77
|
+
});
|
|
78
|
+
const initContainer = yield containerElGetter();
|
|
79
|
+
let currChildrenCount = yield options.childrenCounter(initContainer, { container: initContainer }); // prettier-ignore
|
|
80
|
+
let currRetries = 0;
|
|
81
|
+
while (!userAskedToStop) {
|
|
82
|
+
// Process currently-loaded children
|
|
83
|
+
const containerEl = yield containerElGetter();
|
|
84
|
+
const currChildren = [...(yield options.childrenGetter(containerEl, { container: containerEl }))]; // prettier-ignore
|
|
85
|
+
yield processChildren(currChildren);
|
|
86
|
+
if (userAskedToStop)
|
|
87
|
+
break;
|
|
88
|
+
// Load next batch
|
|
89
|
+
const lastChildEl = currChildren.slice(-1)[0];
|
|
90
|
+
yield options.scrollIntoView(lastChildEl, { container: containerEl });
|
|
91
|
+
yield options.waitAfterScroll(lastChildEl, { container: containerEl });
|
|
92
|
+
const newChildrenCount = yield options.childrenCounter(containerEl, { container: containerEl }); // prettier-ignore
|
|
93
|
+
if (newChildrenCount <= currChildrenCount) {
|
|
94
|
+
if (currRetries >= options.retries)
|
|
95
|
+
break;
|
|
96
|
+
else
|
|
97
|
+
currRetries++;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
currRetries = 0;
|
|
101
|
+
}
|
|
102
|
+
currChildrenCount = newChildrenCount;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/page/page.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Page, Locator, ElementHandle, JSHandle } from 'playwright';\n\nimport type { MaybePromise } from '../utils/types';\nimport { logAndRethrow } from '../utils/error';\nimport { handleIsLocator } from '../dom/domUtils';\nimport type {\n InfiniteScrollLoaderOptions,\n Portapage,\n _AnyInfiScrollTypes,\n _InfiScrollTypes,\n} from './types';\nimport { createPlaywrightElementSerializer } from './pageUtils';\n\ntype PlaywrightInfiScrollTypes = _InfiScrollTypes<\n Locator | ElementHandle<Element>,\n JSHandle<Element | null>,\n JSHandle<Element[]>,\n JSHandle<(Element | null)[]>\n>;\ntype PWIST = PlaywrightInfiScrollTypes; // For brevity\n\n/** Implementation of Portapage in Playwright */\nexport type PlaywrightPortapage<T extends Page = Page> = Portapage<\n T,\n PWIST,\n { container: PWIST['container']; page: T }\n>;\n\n/** Implementation of Portapage in Playwright */\nexport const playwrightPortapage = async <T extends Page>(\n page: T\n): Promise<PlaywrightPortapage<T>> => {\n const { serializeEls, resolveId, resolveIds } = await createPlaywrightElementSerializer(page);\n\n const infiniteScroll: PlaywrightPortapage<T>['infiniteScroll'] = async (\n container,\n onNewChildren,\n options\n ) => {\n const childrenCounter = options?.childrenCounter ?? ((h) => (h as ElementHandle).evaluate((el) => el ? (el as Element).childElementCount : 0).catch(logAndRethrow)); // prettier-ignore\n const childrenGetter = options?.childrenGetter ?? ((h) => h.evaluateHandle((el) => el ? (el as Element).children : []).catch(logAndRethrow)); // prettier-ignore\n const scrollIntoView = options?.scrollIntoView ?? ((h) => h.evaluate((el) => { el && el.scrollIntoView() }).catch(logAndRethrow)); // prettier-ignore\n const waitAfterScroll = options?.waitAfterScroll ?? (() => page.waitForLoadState('networkidle')); // prettier-ignore\n\n const handleOrLocator = typeof container === 'string' ? page.locator(container) : container;\n if (handleIsLocator(handleOrLocator) && handleOrLocator.page() !== page) {\n throw Error('Locator does not belong to given Page.');\n }\n\n await _infiniteScrollLoader<_InfiScrollTypes<PWIST['container'], string, string[], string[]>>(\n handleOrLocator,\n async (childIds, ctx, stopFn) => {\n // Resolve child IDs to handle of child elements on the page\n const elsHandle = await resolveIds(childIds);\n // Then pass them to user\n await onNewChildren?.(elsHandle, { ...ctx, page }, stopFn);\n },\n {\n retries: options?.retries ?? 3,\n childrenCounter: (el, ctx) => childrenCounter(el, { ...ctx, page }),\n childrenGetter: async (handle, ctx) => {\n // First let user tell us how to collect the child elements\n const childElsHandle = await childrenGetter(handle, { ...ctx, page });\n // Then convert them to serializable IDs that we can return to user\n const childIds = await serializeEls(childElsHandle);\n return childIds;\n },\n scrollIntoView: async (childId, ctx) => {\n // First resolve serializable ID to an element on the page\n const childElHandle = await resolveId(childId);\n // Then let user tell us how to scroll into view\n await scrollIntoView(childElHandle, { ...ctx, page });\n },\n waitAfterScroll: async (childId, ctx) => {\n // First resolve serializable ID to an element on the page\n const childElHandle = await resolveId(childId);\n // Then let user tell us how to wait after scroll\n await waitAfterScroll(childElHandle, { ...ctx, page });\n },\n }\n );\n };\n\n return {\n page,\n\n infiniteScroll,\n } satisfies PlaywrightPortapage<T>;\n};\n\n/** Load entries via infinite scroll and process them as you go. */\nconst _infiniteScrollLoader = async <T extends _AnyInfiScrollTypes>(\n container: T['container'] | (() => MaybePromise<T['container']>),\n onNewChildren: (\n childEls: T['callbackArg'],\n ctx: { container: T['container'] },\n stop: () => void\n ) => MaybePromise<void>,\n options: Required<InfiniteScrollLoaderOptions<T>>\n) => {\n const containerElGetter = (\n typeof container === 'function' ? container : () => container\n ) as () => MaybePromise<T['container']>;\n\n const processedChildren = new Set();\n let userAskedToStop = false;\n\n const stopFn = () => {\n userAskedToStop = true;\n };\n\n const processChildren = async (childrenEl: T['child'][]) => {\n const newChildren = await childrenEl.filter((el) => !processedChildren.has(el));\n const container = await containerElGetter();\n await onNewChildren?.(newChildren, { container }, stopFn);\n newChildren.forEach((el) => processedChildren.add(el));\n };\n\n const initContainer = await containerElGetter();\n let currChildrenCount = await options.childrenCounter(initContainer, { container: initContainer }); // prettier-ignore\n let currRetries = 0;\n\n while (!userAskedToStop) {\n // Process currently-loaded children\n const containerEl = await containerElGetter();\n const currChildren = [...(await options.childrenGetter(containerEl, { container: containerEl }))]; // prettier-ignore\n await processChildren(currChildren);\n\n if (userAskedToStop) break;\n\n // Load next batch\n const lastChildEl = currChildren.slice(-1)[0];\n await options.scrollIntoView(lastChildEl, { container: containerEl });\n await options.waitAfterScroll(lastChildEl, { container: containerEl });\n const newChildrenCount = await options.childrenCounter(containerEl, { container: containerEl }); // prettier-ignore\n\n if (newChildrenCount <= currChildrenCount) {\n if (currRetries >= options.retries) break;\n else currRetries++;\n } else {\n currRetries = 0;\n }\n\n currChildrenCount = newChildrenCount;\n }\n};\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { JSHandle, Page } from 'playwright';
|
|
2
|
+
/**
|
|
3
|
+
* Helper methods that allow to represent HTML Elements on the Page as string IDs
|
|
4
|
+
*
|
|
5
|
+
* We use this so we can identify which elements have already been processed, and which have not.
|
|
6
|
+
* Normally, the elements are represented via Playwright JSHandle/ElementHandle. However, if two
|
|
7
|
+
* Handles are pointing to the same Element, we're unable to count them as one, because it's two
|
|
8
|
+
* instances that don't have any IDs of the Elemenets. On the other hand, using the string IDs,
|
|
9
|
+
* two different JSHandles will return the same string if they point to the same Element, so we
|
|
10
|
+
* cache the IDs outside of Playwright in Sets or Maps.
|
|
11
|
+
*/
|
|
12
|
+
export declare const createPlaywrightElementSerializer: <T extends Page>(page: T) => Promise<{
|
|
13
|
+
serializeEls: (elsHandle: JSHandle<Element[]>) => Promise<string[]>;
|
|
14
|
+
resolveIds: (ids: string[]) => Promise<JSHandle<(Element | null)[]>>;
|
|
15
|
+
resolveId: (id: string) => Promise<JSHandle<null> | import("playwright-core").ElementHandle<Element>>;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createPlaywrightElementSerializer = void 0;
|
|
13
|
+
const error_1 = require("../utils/error");
|
|
14
|
+
/**
|
|
15
|
+
* Helper methods that allow to represent HTML Elements on the Page as string IDs
|
|
16
|
+
*
|
|
17
|
+
* We use this so we can identify which elements have already been processed, and which have not.
|
|
18
|
+
* Normally, the elements are represented via Playwright JSHandle/ElementHandle. However, if two
|
|
19
|
+
* Handles are pointing to the same Element, we're unable to count them as one, because it's two
|
|
20
|
+
* instances that don't have any IDs of the Elemenets. On the other hand, using the string IDs,
|
|
21
|
+
* two different JSHandles will return the same string if they point to the same Element, so we
|
|
22
|
+
* cache the IDs outside of Playwright in Sets or Maps.
|
|
23
|
+
*/
|
|
24
|
+
const createPlaywrightElementSerializer = (page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
const prefix = '__portadom_infiniteScrollLoader__';
|
|
26
|
+
const helperKey = `${prefix}helpers_elIdMap`;
|
|
27
|
+
// There may be multiple instances of this cache on the Page, so we distinguish
|
|
28
|
+
// them with operationId.
|
|
29
|
+
const operationId = Math.floor(Math.random() * Math.pow(10, 9)).toString().padStart(9, '0'); // prettier-ignore
|
|
30
|
+
const mapKey = `${prefix}${operationId}`;
|
|
31
|
+
// Prepare a function in-page that creates the cache to store and retrieve the elements.
|
|
32
|
+
yield page
|
|
33
|
+
.evaluate(({ mapKey, helperKey }) => {
|
|
34
|
+
// Create mapping between IDs and HTMLElements, so we can pass the IDs as a serializable
|
|
35
|
+
// reference to the in-page DOM elements
|
|
36
|
+
globalThis[helperKey] = () => {
|
|
37
|
+
const elMap = (globalThis[mapKey] = globalThis[mapKey] || new Map());
|
|
38
|
+
const elMapRev = (globalThis[`${mapKey}_rev`] = globalThis[`${mapKey}_rev`] || new Map());
|
|
39
|
+
return { elMap, elMapRev };
|
|
40
|
+
};
|
|
41
|
+
}, { mapKey, helperKey })
|
|
42
|
+
.catch(error_1.logAndRethrow);
|
|
43
|
+
/**
|
|
44
|
+
* Given a Playwright JSHandle holding an array of Elements, cache the Elements
|
|
45
|
+
* in the Page and generate serializable IDs that can be used to refer to these
|
|
46
|
+
* elements outside of Playwright.
|
|
47
|
+
*
|
|
48
|
+
* This is the opposite of `_resolveIds`.
|
|
49
|
+
*
|
|
50
|
+
* We use this so we can identify which elements have already been processed, and which have not.
|
|
51
|
+
* Normally, the elements are represented via Playwright JSHandle/ElementHandle. However, if two
|
|
52
|
+
* Handles are pointing to the same Element, we're unable to count them as one, because it's two
|
|
53
|
+
* instances that don't have any IDs of the Elemenets. On the other hand, using the string IDs,
|
|
54
|
+
* two different JSHandles will return the same string if they point to the same Element, so we
|
|
55
|
+
* cache the IDs outside of Playwright in Sets or Maps.
|
|
56
|
+
*/
|
|
57
|
+
const serializeEls = (elsHandle) => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
|
+
const ids = yield page
|
|
59
|
+
.evaluate(({ els, helperKey }) => {
|
|
60
|
+
if (!els)
|
|
61
|
+
return [];
|
|
62
|
+
const { elMap, elMapRev } = globalThis[helperKey](); // prettier-ignore
|
|
63
|
+
const innerIds = [...els].map((el) => {
|
|
64
|
+
if (!elMap.has(el)) {
|
|
65
|
+
const elId = Math.floor(Math.random() * Math.pow(10, 9))
|
|
66
|
+
.toString()
|
|
67
|
+
.padStart(9, '0');
|
|
68
|
+
elMap.set(el, elId);
|
|
69
|
+
elMapRev.set(elId, el);
|
|
70
|
+
return elId;
|
|
71
|
+
}
|
|
72
|
+
return elMap.get(el);
|
|
73
|
+
});
|
|
74
|
+
return innerIds;
|
|
75
|
+
}, { els: elsHandle, helperKey })
|
|
76
|
+
.catch(error_1.logAndRethrow);
|
|
77
|
+
return ids;
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* Given an array of IDs, resolve them to a Playwright JSHandle holding an array of corresponding
|
|
81
|
+
* Elements cached in Page's global context.
|
|
82
|
+
*
|
|
83
|
+
* This is the opposite of `_serializeEls`.
|
|
84
|
+
*
|
|
85
|
+
* We use this so we can identify which elements have already been processed, and which have not.
|
|
86
|
+
* Normally, the elements are represented via Playwright JSHandle/ElementHandle. However, if two
|
|
87
|
+
* Handles are pointing to the same Element, we're unable to count them as one, because it's two
|
|
88
|
+
* instances that don't have any IDs of the Elemenets. On the other hand, using the string IDs,
|
|
89
|
+
* two different JSHandles will return the same string if they point to the same Element, so we
|
|
90
|
+
* cache the IDs outside of Playwright in Sets or Maps.
|
|
91
|
+
*/
|
|
92
|
+
const resolveIds = (ids) => __awaiter(void 0, void 0, void 0, function* () {
|
|
93
|
+
// Resolve serializable IDs to an element on the page
|
|
94
|
+
const elsHandle = yield page
|
|
95
|
+
.evaluateHandle(({ ids, helperKey }) => {
|
|
96
|
+
const { elMapRev } = globalThis[helperKey](); // prettier-ignore
|
|
97
|
+
const els = ids.map((id) => elMapRev.get(id) || null);
|
|
98
|
+
return els;
|
|
99
|
+
}, { ids, helperKey })
|
|
100
|
+
.catch(error_1.logAndRethrow);
|
|
101
|
+
return elsHandle;
|
|
102
|
+
});
|
|
103
|
+
/** See {@link resolveIds}. */
|
|
104
|
+
const resolveId = (id) => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
|
+
const elsHandle = yield resolveIds([id]);
|
|
106
|
+
const handle = yield elsHandle.evaluateHandle((ids) => ids[0]).catch(error_1.logAndRethrow);
|
|
107
|
+
return handle;
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
serializeEls,
|
|
111
|
+
resolveIds,
|
|
112
|
+
resolveId,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
exports.createPlaywrightElementSerializer = createPlaywrightElementSerializer;
|
|
116
|
+
//# sourceMappingURL=pageUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageUtils.js","sourceRoot":"","sources":["../../../src/page/pageUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JSHandle, Page } from 'playwright';\n\nimport { logAndRethrow } from '../utils/error';\n\ninterface PlaywrightElementSerializerHelperResult {\n elMap: Map<Element, string>;\n elMapRev: Map<string, Element>;\n}\n\n/**\n * Helper methods that allow to represent HTML Elements on the Page as string IDs\n *\n * We use this so we can identify which elements have already been processed, and which have not.\n * Normally, the elements are represented via Playwright JSHandle/ElementHandle. However, if two\n * Handles are pointing to the same Element, we're unable to count them as one, because it's two\n * instances that don't have any IDs of the Elemenets. On the other hand, using the string IDs,\n * two different JSHandles will return the same string if they point to the same Element, so we\n * cache the IDs outside of Playwright in Sets or Maps.\n */\nexport const createPlaywrightElementSerializer = async <T extends Page>(page: T) => {\n const prefix = '__portadom_infiniteScrollLoader__';\n const helperKey = `${prefix}helpers_elIdMap`;\n // There may be multiple instances of this cache on the Page, so we distinguish\n // them with operationId.\n const operationId = Math.floor(Math.random() * 10 ** 9).toString().padStart(9, '0'); // prettier-ignore\n const mapKey = `${prefix}${operationId}`;\n\n // Prepare a function in-page that creates the cache to store and retrieve the elements.\n await page\n .evaluate(\n ({ mapKey, helperKey }) => {\n // Create mapping between IDs and HTMLElements, so we can pass the IDs as a serializable\n // reference to the in-page DOM elements\n globalThis[helperKey] = () => {\n const elMap = (globalThis[mapKey] = globalThis[mapKey] || new Map());\n const elMapRev = (globalThis[`${mapKey}_rev`] = globalThis[`${mapKey}_rev`] || new Map());\n return { elMap, elMapRev } satisfies PlaywrightElementSerializerHelperResult;\n };\n },\n { mapKey, helperKey }\n )\n .catch(logAndRethrow);\n\n /**\n * Given a Playwright JSHandle holding an array of Elements, cache the Elements\n * in the Page and generate serializable IDs that can be used to refer to these\n * elements outside of Playwright.\n *\n * This is the opposite of `_resolveIds`.\n *\n * We use this so we can identify which elements have already been processed, and which have not.\n * Normally, the elements are represented via Playwright JSHandle/ElementHandle. However, if two\n * Handles are pointing to the same Element, we're unable to count them as one, because it's two\n * instances that don't have any IDs of the Elemenets. On the other hand, using the string IDs,\n * two different JSHandles will return the same string if they point to the same Element, so we\n * cache the IDs outside of Playwright in Sets or Maps.\n */\n const serializeEls = async (elsHandle: JSHandle<Element[]>) => {\n const ids = await page\n .evaluate(\n ({ els, helperKey }) => {\n if (!els) return [] as string[];\n\n const { elMap, elMapRev } = globalThis[helperKey]() as PlaywrightElementSerializerHelperResult; // prettier-ignore\n\n const innerIds = [...els].map((el) => {\n if (!elMap.has(el)) {\n const elId = Math.floor(Math.random() * 10 ** 9)\n .toString()\n .padStart(9, '0');\n elMap.set(el, elId);\n elMapRev.set(elId, el);\n return elId;\n }\n return elMap.get(el)!;\n });\n return innerIds;\n },\n { els: elsHandle, helperKey }\n )\n .catch(logAndRethrow);\n\n return ids;\n };\n\n /**\n * Given an array of IDs, resolve them to a Playwright JSHandle holding an array of corresponding\n * Elements cached in Page's global context.\n *\n * This is the opposite of `_serializeEls`.\n *\n * We use this so we can identify which elements have already been processed, and which have not.\n * Normally, the elements are represented via Playwright JSHandle/ElementHandle. However, if two\n * Handles are pointing to the same Element, we're unable to count them as one, because it's two\n * instances that don't have any IDs of the Elemenets. On the other hand, using the string IDs,\n * two different JSHandles will return the same string if they point to the same Element, so we\n * cache the IDs outside of Playwright in Sets or Maps.\n */\n const resolveIds = async (ids: string[]) => {\n // Resolve serializable IDs to an element on the page\n const elsHandle = await page\n .evaluateHandle(\n ({ ids, helperKey }) => {\n const { elMapRev } = globalThis[helperKey]() as PlaywrightElementSerializerHelperResult; // prettier-ignore\n\n const els = ids.map((id) => elMapRev.get(id) || null);\n return els;\n },\n { ids, helperKey }\n )\n .catch(logAndRethrow);\n return elsHandle;\n };\n\n /** See {@link resolveIds}. */\n const resolveId = async (id: string) => {\n const elsHandle = await resolveIds([id]);\n const handle = await elsHandle.evaluateHandle((ids) => ids[0]).catch(logAndRethrow);\n return handle;\n };\n\n return {\n serializeEls,\n resolveIds,\n resolveId,\n };\n};\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { MaybePromise } from '../utils/types';
|
|
2
|
+
export type _InfiScrollTypes<TContainer, TChild, TChildren, TCB> = {
|
|
3
|
+
container: TContainer;
|
|
4
|
+
child: TChild;
|
|
5
|
+
children: TChildren;
|
|
6
|
+
callbackArg: TCB;
|
|
7
|
+
};
|
|
8
|
+
export type _AnyInfiScrollTypes = _InfiScrollTypes<any, any, any, any>;
|
|
9
|
+
/**
|
|
10
|
+
* Common interface for working with browser page despite different environments
|
|
11
|
+
* (e.g. Browser API, Playwright, Puppeteer, Selenium).
|
|
12
|
+
*
|
|
13
|
+
* This common interfaces makes the scraping code more portable between them.
|
|
14
|
+
*
|
|
15
|
+
* WARNING: Portapage is experimental.
|
|
16
|
+
*/
|
|
17
|
+
export interface Portapage<TPage, TScroll extends _AnyInfiScrollTypes, TCtx extends {
|
|
18
|
+
container: TScroll['container'];
|
|
19
|
+
}> {
|
|
20
|
+
page: TPage;
|
|
21
|
+
/** Load entries via infinite scroll and process them as you go. */
|
|
22
|
+
infiniteScroll: (
|
|
23
|
+
/** A container, or selector for it, that includes the dynamically loaded items. */
|
|
24
|
+
container: string | TScroll['container'],
|
|
25
|
+
/**
|
|
26
|
+
* Callback that receives a handle to the new child elements in the DOM
|
|
27
|
+
*
|
|
28
|
+
* Example:
|
|
29
|
+
* ```js
|
|
30
|
+
* // Get text from all new child elements of the infinite-scroller container
|
|
31
|
+
* async (elementsHandle) => {
|
|
32
|
+
* const result = await page.evaluate((els) => els.map((el) => el.textContent), elementsHandle);
|
|
33
|
+
* return result;
|
|
34
|
+
* };
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
onNewChildren?: (
|
|
38
|
+
/** New elements that were added */
|
|
39
|
+
elsHandle: TScroll['callbackArg'], ctx: {
|
|
40
|
+
page: TPage;
|
|
41
|
+
container: TScroll['container'];
|
|
42
|
+
},
|
|
43
|
+
/** Function that, if called, stops the infinite scrolling */
|
|
44
|
+
stop: () => void) => MaybePromise<void>, options?: InfiniteScrollLoaderOptions<TScroll, TCtx>) => MaybePromise<void>;
|
|
45
|
+
}
|
|
46
|
+
export interface InfiniteScrollLoaderOptions<T extends _AnyInfiScrollTypes, TCtx extends {
|
|
47
|
+
container: T['container'];
|
|
48
|
+
} = {
|
|
49
|
+
container: T['container'];
|
|
50
|
+
}> {
|
|
51
|
+
/** How many times to retry the infinite scroll if new items aren't loading */
|
|
52
|
+
retries?: number;
|
|
53
|
+
/** Override how container children are counted. Default uses `el.childElementCount` */
|
|
54
|
+
childrenCounter?: (containerEl: T['container'], ctx: TCtx) => MaybePromise<number>;
|
|
55
|
+
/** Override how container children are extraced. Default uses `el.children` */
|
|
56
|
+
childrenGetter?: (containerEl: T['container'], ctx: TCtx) => MaybePromise<T['children']>;
|
|
57
|
+
/** Override how container children are scrolled into view. Default uses `el.scrollIntoView` */
|
|
58
|
+
scrollIntoView?: (childEl: T['child'], ctx: TCtx) => MaybePromise<void>;
|
|
59
|
+
/** Override whether and how to wait after scrolling into view */
|
|
60
|
+
waitAfterScroll?: (childEl: T['child'], ctx: TCtx) => MaybePromise<void>;
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/page/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MaybePromise } from '../utils/types';\n\nexport type _InfiScrollTypes<TContainer, TChild, TChildren, TCB> = {\n container: TContainer;\n child: TChild;\n children: TChildren;\n callbackArg: TCB;\n};\n\nexport type _AnyInfiScrollTypes = _InfiScrollTypes<any, any, any, any>;\n\n/**\n * Common interface for working with browser page despite different environments\n * (e.g. Browser API, Playwright, Puppeteer, Selenium).\n *\n * This common interfaces makes the scraping code more portable between them.\n *\n * WARNING: Portapage is experimental.\n */\nexport interface Portapage<\n TPage,\n TScroll extends _AnyInfiScrollTypes,\n TCtx extends { container: TScroll['container'] }\n> {\n page: TPage;\n\n /** Load entries via infinite scroll and process them as you go. */\n infiniteScroll: (\n /** A container, or selector for it, that includes the dynamically loaded items. */\n container: string | TScroll['container'],\n /**\n * Callback that receives a handle to the new child elements in the DOM\n *\n * Example:\n * ```js\n * // Get text from all new child elements of the infinite-scroller container\n * async (elementsHandle) => {\n * const result = await page.evaluate((els) => els.map((el) => el.textContent), elementsHandle);\n * return result;\n * };\n * ```\n */\n onNewChildren?: (\n /** New elements that were added */\n elsHandle: TScroll['callbackArg'],\n ctx: { page: TPage; container: TScroll['container'] },\n /** Function that, if called, stops the infinite scrolling */\n stop: () => void\n ) => MaybePromise<void>,\n options?: InfiniteScrollLoaderOptions<TScroll, TCtx>\n ) => MaybePromise<void>;\n}\n\nexport interface InfiniteScrollLoaderOptions<\n T extends _AnyInfiScrollTypes,\n TCtx extends { container: T['container'] } = { container: T['container'] }\n> {\n /** How many times to retry the infinite scroll if new items aren't loading */\n retries?: number;\n /** Override how container children are counted. Default uses `el.childElementCount` */\n childrenCounter?: (containerEl: T['container'], ctx: TCtx) => MaybePromise<number>;\n /** Override how container children are extraced. Default uses `el.children` */\n childrenGetter?: (containerEl: T['container'], ctx: TCtx) => MaybePromise<T['children']>;\n /** Override how container children are scrolled into view. Default uses `el.scrollIntoView` */\n scrollIntoView?: (childEl: T['child'], ctx: TCtx) => MaybePromise<void>;\n /** Override whether and how to wait after scrolling into view */\n waitAfterScroll?: (childEl: T['child'], ctx: TCtx) => MaybePromise<void>;\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MaybePromise } from '../utils/types';
|
|
2
|
+
export declare const serialAsyncMap: <T, R>(inputArr: T[], fn: (item: T, index: number) => MaybePromise<R>) => Promise<R[]>;
|
|
3
|
+
export declare const serialAsyncFilter: <T>(inputArr: T[], fn: (item: T, index: number) => MaybePromise<any>) => Promise<T[]>;
|
|
4
|
+
export declare const serialAsyncFind: <T>(inputArr: T[], fn: (item: T, index: number) => MaybePromise<any>) => Promise<T | undefined>;
|
|
5
|
+
export interface RetryAsyncOptions {
|
|
6
|
+
/** Number of retries after the function call fails */
|
|
7
|
+
maxRetries?: number;
|
|
8
|
+
/** Delay between retries in milliseconds */
|
|
9
|
+
delay?: number;
|
|
10
|
+
/** Callback called with error if the function call errors */
|
|
11
|
+
onError?: (error: unknown, retryIndex: number) => MaybePromise<void>;
|
|
12
|
+
}
|
|
13
|
+
/** @param {number} ms Number of ms to wait */
|
|
14
|
+
export declare const wait: (ms?: number) => Promise<unknown>;
|
|
15
|
+
/** Call async function, and retry to call it `maxRetries` times if it fails. */
|
|
16
|
+
export declare const retryAsync: <T>(fn: (retries: number) => Promise<T>, { maxRetries, delay, onError }?: RetryAsyncOptions) => Promise<{
|
|
17
|
+
result: T | null;
|
|
18
|
+
errors: unknown[];
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.retryAsync = exports.wait = exports.serialAsyncFind = exports.serialAsyncFilter = exports.serialAsyncMap = void 0;
|
|
13
|
+
const serialAsyncMap = (inputArr, fn) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
const results = yield inputArr.reduce((aggResultPromise, input, index) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
const agg = yield aggResultPromise;
|
|
16
|
+
const result = yield fn(input, index);
|
|
17
|
+
agg.push(result);
|
|
18
|
+
return agg;
|
|
19
|
+
}), Promise.resolve([]));
|
|
20
|
+
return results;
|
|
21
|
+
});
|
|
22
|
+
exports.serialAsyncMap = serialAsyncMap;
|
|
23
|
+
const serialAsyncFilter = (inputArr, fn) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
const results = yield inputArr.reduce((aggResultPromise, input, index) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
const agg = yield aggResultPromise;
|
|
26
|
+
const result = yield fn(input, index);
|
|
27
|
+
if (result)
|
|
28
|
+
agg.push(input);
|
|
29
|
+
return agg;
|
|
30
|
+
}), Promise.resolve([]));
|
|
31
|
+
return results;
|
|
32
|
+
});
|
|
33
|
+
exports.serialAsyncFilter = serialAsyncFilter;
|
|
34
|
+
const serialAsyncFind = (inputArr, fn) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
let index = 0;
|
|
36
|
+
for (const input of inputArr) {
|
|
37
|
+
const result = yield fn(input, index);
|
|
38
|
+
if (result)
|
|
39
|
+
return input;
|
|
40
|
+
index++;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
exports.serialAsyncFind = serialAsyncFind;
|
|
44
|
+
/** @param {number} ms Number of ms to wait */
|
|
45
|
+
const wait = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
46
|
+
exports.wait = wait;
|
|
47
|
+
/** Call async function, and retry to call it `maxRetries` times if it fails. */
|
|
48
|
+
const retryAsync = (fn, { maxRetries = 1, delay = 0, onError = () => { } } = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
49
|
+
if (typeof maxRetries !== 'number' || maxRetries < 0) {
|
|
50
|
+
throw Error(`Invalid input for maxRetries in retryAsync(fn, maxRetries). maxRetries must be a non-negative number. Got ${maxRetries}`);
|
|
51
|
+
}
|
|
52
|
+
let result = null;
|
|
53
|
+
const errors = [];
|
|
54
|
+
let retries = 0;
|
|
55
|
+
while (retries <= maxRetries) {
|
|
56
|
+
try {
|
|
57
|
+
result = yield fn(retries);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
errors.push(err);
|
|
61
|
+
yield onError(err, retries);
|
|
62
|
+
yield (0, exports.wait)(delay);
|
|
63
|
+
retries++;
|
|
64
|
+
continue; // Retry if failed
|
|
65
|
+
}
|
|
66
|
+
break; // Exit loop and continue flow if success
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
result,
|
|
70
|
+
errors,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
exports.retryAsync = retryAsync;
|
|
74
|
+
//# sourceMappingURL=async.js.map
|