/** * A `SerialScraper` allows for the application of a `Scraper` to a sequence of * sibling nodes. This allows for use cases like targeting the sibling of a node, * or extracting a sequence of sibling nodes (e.g. paragraphs (`

`) under a * header (`

`)). * * Conceptually, serial scrapers operate on a sequence of tags that correspond * to the immediate children of the currently focused node. For example, given * the following HTML: * * ```html *
*

title

*

Section 1

*

Paragraph 1.1

*

Paragraph 1.2

*

Section 2

*

Paragraph 2.1

*

Paragraph 2.2

*
* ``` * * Each `SerialScraper` primitive follows the pattern of first moving the focus * backward or forward, and then extracting the content from the new focus. * Attempting to extract content from beyond the end of the sequence causes the * scraper to fail. * * To complete the above example, a serial scraper that visits and extracts the * content of the header and paragraph nodes can be executed with the following... * * ```typescript * import { pipe } from 'fp-ts/function' * import * as Scrape from 'scalpel-ts/Scraper' * import * as Select from 'scalpel-ts/Select' * import * as Serial from 'scalpel-ts/SerialScraper' * * pipe( * Serial.seekNext(Scrape.text(Select.tag('h1'))), * Serial.bindTo('title'), * Serial.bind('sections', () => * pipe( * Serial.seekNext(Scrape.text(Select.tag('h2'))), * Serial.bindTo('section'), * Serial.bind('ps', () => * pipe( * Serial.seekNext(Scrape.text(Select.tag('p'))), * Serial.repeat, * Serial.untilNext(Scrape.matches(Select.tag('h2'))) * ) * ), * Serial.repeat * ) * ), * Serial.inSerial, * Scrape.chroot(Select.tag('article')) * ) * ``` * * ...which will evaluate to: * * ```sh * { * _tag: 'Some', * value: { * title: 'title', * sections: [ * { * section: 'Section 1', * ps: [ 'Paragraph 1.1', 'Paragraph 1.2' ] * }, * { * section: 'Section 2', * ps: [ 'Paragraph 2.1', 'Paragraph 2.2' ] * } * ] * } * ``` * * @since 0.0.1 */ import type { Option } from 'fp-ts/Option' import * as RNEA from 'fp-ts/ReadonlyNonEmptyArray' import * as Z from 'fp-ts-contrib/Zipper' import type { StateOption } from './Internal/StateOption' import type { Scraper } from './Scraper' import { TagSpec } from './Internal/Tag/TagSpec' export * from './Internal/StateOption' /** * Serial scrapers operate on a zipper of `TagSpec`s that correspond to the root * nodes and siblings in a document. * * Access to the ziper is always performed in a move-then-read manner. For this reason, * it is valid for the current focus of the zipper to be just off either end of the list * such that moving forward or backward would result in reading the first or last node. * * These valid focuses are expressed as `None` values at either end of the zipper, * since they are valid positions for the focus to pass over but not valid positions * for the focus to read. * * @category model * @since 0.0.1 */ export declare type SpecZipper = Z.Zipper> /** * Represents a `Scraper` that is able to be applied to a sequence of sibling nodes. * * @category model * @since 0.0.1 */ export declare type SerialScraper = StateOption /** * Executes a `SerialScraper` in the context of a `Scraper`. The immediate children * of the currently focused node are visted serially. * * @category destructors * @since 0.0.1 */ export declare const inSerial: (serialScraper: SerialScraper) => Scraper export declare const repeat: (serialScraper: SerialScraper) => SerialScraper export declare const repeat1: ( serialScraper: SerialScraper ) => SerialScraper> /** * Moves the cursor of the `SerialScraper` back one node and execute the specified * `scraper` on the newly focused node. * * @category combinators * @since 0.0.1 */ export declare const stepBack: (scraper: Scraper) => SerialScraper /** * Moves the cursor of the `SerialScraper` forward one node and execute the specified * `scraper` on the newly focused node. * * @category combinators * @since 0.0.1 */ export declare const stepNext: (scraper: Scraper) => SerialScraper /** * Moves the cursor of the `SerialScraper` backward until the specified `scraper` * is successfully able to execute on the focused node. If the scraper is never * successful, then the `SerialScraper` will fail. * * @category combinators * @since 0.0.1 */ export declare const seekBack: (scraper: Scraper) => SerialScraper /** * Moves the cursor of the `SerialScraper` forward until the specified `scraper` * is successfully able to execute on the focused node. If the scraper is never * successful, then the `SerialScraper` will fail. * * @category combinators * @since 0.0.1 */ export declare const seekNext: (scraper: Scraper) => SerialScraper /** * Creates a new serial context by moving the focus of the `SerialScraper` * backward and collecting nodes until the specified `scraper` matches the * focused node. The `SerialScraper` is then executed on the collected nodes. * * @category combinators * @since 0.0.1 */ export declare const untilBack: ( until: Scraper ) => (scraper: SerialScraper) => SerialScraper /** * Creates a new serial context by moving the focus of the `SerialScraper` * forward and collecting nodes until the specified `scraper` matches the * focused node. The `SerialScraper` is then executed on the collected nodes. * * The specified `scraper` is unable to see nodes outside the new restricted * context. * * @category combinators * @since 0.0.1 */ export declare const untilNext: ( until: Scraper ) => (scraper: SerialScraper) => SerialScraper