@opencraw/studio 0.0.17 → 0.0.19
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/dist/browser-provisioning/ensure-browser-launch.use-case.d.ts +12 -0
- package/dist/browser-provisioning/index.d.ts +2 -0
- package/dist/browser-provisioning/install-chromium.use-case.d.ts +2 -0
- package/dist/browser-provisioning/missing-browser.policy.d.ts +3 -0
- package/dist/document-view/deck-view.mapper.d.ts +70 -0
- package/dist/document-view/index.d.ts +13 -0
- package/dist/document-view/pdf-view.mapper.d.ts +47 -0
- package/dist/document-view/region-preview.use-case.d.ts +30 -0
- package/dist/document-view/table-preview.use-case.d.ts +152 -0
- package/dist/document-view/tree-view.mapper.d.ts +47 -0
- package/dist/document-view/workbook-view.mapper.d.ts +51 -0
- package/dist/explain-why/index.d.ts +5 -0
- package/dist/explain-why/item-hint.algorithm.d.ts +13 -0
- package/dist/explain-why/why-sentence.mapper.d.ts +48 -0
- package/dist/explain-why/why.use-case.d.ts +26 -0
- package/dist/flow-recording/action-to-step.mapper.d.ts +16 -0
- package/dist/flow-recording/index.d.ts +13 -0
- package/dist/flow-recording/next-link.policy.d.ts +27 -0
- package/dist/flow-recording/recorded-action.contract.d.ts +114 -0
- package/dist/flow-recording/recorder-script.client.d.ts +48 -0
- package/dist/flow-recording/recorder-session.use-case.d.ts +67 -0
- package/dist/flow-recording/secret-field.policy.d.ts +33 -0
- package/dist/flow-recording/wait-insertion.policy.d.ts +26 -0
- package/dist/index.d.ts +14 -1
- package/dist/main.d.ts +18 -0
- package/dist/page-inspector/dom-tree.mapper.d.ts +32 -0
- package/dist/page-inspector/index.d.ts +7 -0
- package/dist/page-inspector/page-data.algorithm.d.ts +39 -0
- package/dist/page-inspector/responses-seen.use-case.d.ts +36 -0
- package/dist/page-snapshot/fetch-start-page.use-case.d.ts +20 -0
- package/dist/page-snapshot/hidden-marks.algorithm.d.ts +23 -0
- package/dist/page-snapshot/index.d.ts +13 -0
- package/dist/page-snapshot/invalidate-stale-snapshot.use-case.d.ts +12 -0
- package/dist/page-snapshot/pdf-bytes.use-case.d.ts +16 -0
- package/dist/page-snapshot/reread-csv.use-case.d.ts +22 -0
- package/dist/page-snapshot/rewrite-document.mapper.d.ts +27 -0
- package/dist/page-snapshot/snapshot.store.d.ts +14 -0
- package/dist/page-snapshot/start-point.policy.d.ts +12 -0
- package/dist/page-snapshot/take-snapshot.use-case.d.ts +60 -0
- package/dist/recipe-workspace/import-document.use-case.d.ts +22 -0
- package/dist/recipe-workspace/index.d.ts +5 -0
- package/dist/recipe-workspace/open-workspace.use-case.d.ts +15 -0
- package/dist/recipe-workspace/save-recipe.use-case.d.ts +21 -0
- package/dist/sample-run/index.d.ts +8 -0
- package/dist/sample-run/last-run.store.d.ts +17 -0
- package/dist/sample-run/load-recipe-pair.use-case.d.ts +18 -0
- package/dist/sample-run/run-sample.use-case.d.ts +40 -0
- package/dist/sample-run/sample-run-record.contract.d.ts +48 -0
- package/dist/scope-outline/card-sentence.mapper.d.ts +18 -0
- package/dist/scope-outline/index.d.ts +8 -0
- package/dist/scope-outline/outline-to-recipe.mapper.d.ts +17 -0
- package/dist/scope-outline/outline.model.d.ts +57 -0
- package/dist/scope-outline/recipe-to-outline.mapper.d.ts +14 -0
- package/dist/scope-outline/scope-at-path.algorithm.d.ts +19 -0
- package/dist/selector-inference/class-token.policy.d.ts +35 -0
- package/dist/selector-inference/dom-path.model.d.ts +73 -0
- package/dist/selector-inference/index.d.ts +12 -0
- package/dist/selector-inference/list-inference.algorithm.d.ts +43 -0
- package/dist/selector-inference/selector-candidates.algorithm.d.ts +22 -0
- package/dist/selector-inference/selector-ranking.policy.d.ts +27 -0
- package/dist/selector-inference/shadow-dom.error.d.ts +11 -0
- package/dist/selector-inference/take-kind.policy.d.ts +12 -0
- package/dist/studio-api/command.contract.d.ts +531 -0
- package/dist/studio-api/deck-preview-view.contract.d.ts +28 -0
- package/dist/studio-api/deck-view.contract.d.ts +127 -0
- package/dist/studio-api/document-tree-view.contract.d.ts +26 -0
- package/dist/studio-api/event.contract.d.ts +155 -0
- package/dist/studio-api/grid-preview-view.contract.d.ts +26 -0
- package/dist/studio-api/grid-view.contract.d.ts +75 -0
- package/dist/studio-api/import-document-view.contract.d.ts +8 -0
- package/dist/studio-api/index.d.ts +43 -0
- package/dist/studio-api/infer-selector-view.contract.d.ts +68 -0
- package/dist/studio-api/inspect-view.contract.d.ts +62 -0
- package/dist/studio-api/outline-view.contract.d.ts +37 -0
- package/dist/studio-api/pdf-view.contract.d.ts +66 -0
- package/dist/studio-api/region-preview-view.contract.d.ts +53 -0
- package/dist/studio-api/responses-seen-view.contract.d.ts +20 -0
- package/dist/studio-api/sample-run-view.contract.d.ts +28 -0
- package/dist/studio-api/snapshot-view.contract.d.ts +30 -0
- package/dist/studio-api/start-page-view.contract.d.ts +7 -0
- package/dist/studio-api/table-preview-view.contract.d.ts +65 -0
- package/dist/studio-api/verify-selector-view.contract.d.ts +18 -0
- package/dist/studio-api/why-view.contract.d.ts +16 -0
- package/dist/studio-api/workspace-view.contract.d.ts +67 -0
- package/dist/studio-server/access-token.policy.d.ts +26 -0
- package/dist/studio-server/deck-preview.handler.d.ts +17 -0
- package/dist/studio-server/deck-view.handler.d.ts +15 -0
- package/dist/studio-server/document-tree.handler.d.ts +14 -0
- package/dist/studio-server/explain-why.handler.d.ts +14 -0
- package/dist/studio-server/fetch-start-page.handler.d.ts +14 -0
- package/dist/studio-server/grid-preview.handler.d.ts +17 -0
- package/dist/studio-server/grid-view.handler.d.ts +20 -0
- package/dist/studio-server/import-document.handler.d.ts +14 -0
- package/dist/studio-server/index.d.ts +3 -0
- package/dist/studio-server/infer-selector.handler.d.ts +18 -0
- package/dist/studio-server/inspect-page.handler.d.ts +18 -0
- package/dist/studio-server/open-workspace.handler.d.ts +20 -0
- package/dist/studio-server/pdf-bytes.handler.d.ts +17 -0
- package/dist/studio-server/pdf-view.handler.d.ts +14 -0
- package/dist/studio-server/recording.handler.d.ts +36 -0
- package/dist/studio-server/region-preview.handler.d.ts +17 -0
- package/dist/studio-server/responses-seen.handler.d.ts +16 -0
- package/dist/studio-server/run-sample.handler.d.ts +28 -0
- package/dist/studio-server/save-outline.handler.d.ts +18 -0
- package/dist/studio-server/save-recipe.handler.d.ts +15 -0
- package/dist/studio-server/static-file.handler.d.ts +14 -0
- package/dist/studio-server/studio-http.use-case.d.ts +40 -0
- package/dist/studio-server/table-preview.handler.d.ts +16 -0
- package/dist/studio-server/take-snapshot.handler.d.ts +16 -0
- package/dist/studio-server/verify-selector.handler.d.ts +18 -0
- package/dist/studio-server/websocket.client.d.ts +22 -0
- package/dist/studio-server/workspace.store.d.ts +36 -0
- package/dist/trusted-plugins/index.d.ts +2 -0
- package/dist/trusted-plugins/trusted-plugins.contract.d.ts +14 -0
- package/package.json +3 -3
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { BodyKind, BrowserSessionConfig, HookMap, HttpBody, InputRecipe } from '@opencraw/core';
|
|
2
|
+
export interface SnapshotResult {
|
|
3
|
+
/** The rewritten document, ready for the content pane's sandboxed iframe. */
|
|
4
|
+
html: string;
|
|
5
|
+
/** How many elements carry a `data-oc-node` id. */
|
|
6
|
+
nodeCount: number;
|
|
7
|
+
/** The page's own URL, used to resolve every relative URL and as the `<base>`. */
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
/**
|
|
10
|
+
* The document as captured, before `rewriteDocument` strips every
|
|
11
|
+
* `<script>` for the sandboxed iframe — server-side only, never sent to the
|
|
12
|
+
* UI (`studio-api`'s `SnapshotView` does not carry it): `page-inspector`'s
|
|
13
|
+
* `page-data.algorithm.ts` (issue #93) needs the JSON-LD, inline state and
|
|
14
|
+
* `application/json` blocks a script tag can hold, which the display
|
|
15
|
+
* snapshot no longer has by the time it is cached.
|
|
16
|
+
*/
|
|
17
|
+
rawHtml: string;
|
|
18
|
+
/**
|
|
19
|
+
* The format `http.client.ts` read the body as (api mode only; `undefined`
|
|
20
|
+
* in web mode, whose document is always HTML) — what the content pane
|
|
21
|
+
* uses to pick a canvas: `document-view`'s tree/pdf/grid/deck for
|
|
22
|
+
* `json`/`yaml`/`xml`/`pdf`/`csv`/`xlsx`/`pptx`, the snapshot iframe for
|
|
23
|
+
* `html` (and `docx`/`markdown`, which `http.client.ts` already turns into
|
|
24
|
+
* HTML), studio plan §3.4, issue #94.
|
|
25
|
+
*/
|
|
26
|
+
format?: BodyKind;
|
|
27
|
+
/**
|
|
28
|
+
* The parsed body itself (api mode only), for `document-view`'s mappers to
|
|
29
|
+
* read — server-side only, never sent to the UI as-is (`studio-api`'s
|
|
30
|
+
* `SnapshotView` carries only `format`; a canvas asks for its own view
|
|
31
|
+
* model with a follow-up command, `inspect-page`'s own pattern).
|
|
32
|
+
*/
|
|
33
|
+
body?: HttpBody;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Captures the snapshot the content pane shows (studio plan §3.1, issue
|
|
37
|
+
* #91): runs the recipe up to `stepPath`, serialises the document, marks
|
|
38
|
+
* hidden elements in web mode, and hands it to `rewrite-document.mapper.ts`
|
|
39
|
+
* for display.
|
|
40
|
+
*
|
|
41
|
+
* `stepPath` is accepted (and cached against, by `snapshot.store.ts`) for
|
|
42
|
+
* the API the UI needs — one snapshot per selected step — but v1 only
|
|
43
|
+
* actually *captures* `"start"`: the first `start` point, before any step
|
|
44
|
+
* of the recipe has run, the same reach `fetch-start-page.use-case.ts` (phase
|
|
45
|
+
* 0) already had. Snapshotting mid-recipe (after an arbitrary later step)
|
|
46
|
+
* needs a "stop the crawl after step X and hand back the live page/document"
|
|
47
|
+
* hook in `crawl-execution` that does not exist yet; building one was out of
|
|
48
|
+
* this phase's budget (see this phase's final report for the tradeoff this
|
|
49
|
+
* was weighed against). Any other `stepPath` throws, clearly, rather than
|
|
50
|
+
* silently returning the start page under a misleading label.
|
|
51
|
+
*
|
|
52
|
+
* @param input - The input recipe; only `mode` and the first `start` point are used.
|
|
53
|
+
* @param stepPath - The step to snapshot after, e.g. `"start"` or `"steps.2"` (`scope-outline`'s path format).
|
|
54
|
+
* @param browser - Browser launch settings for web mode.
|
|
55
|
+
* @param hooks - The hooks a login bootstrap may call (the ones Studio was started with, issue #150).
|
|
56
|
+
* @returns The rewritten snapshot.
|
|
57
|
+
* @throws Error when the recipe has no start point, or `stepPath` is not `"start"`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function takeSnapshot(input: InputRecipe, stepPath: string, browser?: BrowserSessionConfig, hooks?: HookMap): Promise<SnapshotResult>;
|
|
60
|
+
//# sourceMappingURL=take-snapshot.use-case.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ImportedDocument {
|
|
2
|
+
/** The copy's path on disk, inside `folder`. */
|
|
3
|
+
path: string;
|
|
4
|
+
/** The copy as a `file:` URL: what the recipe's `start.url` becomes. */
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Copies a document into a workspace folder, so a recipe can read it with a
|
|
9
|
+
* `file:` URL the same way a run would read any downloaded file (core's
|
|
10
|
+
* `HttpClient` handles `file:` itself). The folder is created when missing,
|
|
11
|
+
* so dropping a file is also a way to start a workspace. A name already in
|
|
12
|
+
* the folder is never overwritten: the copy gets the next free numbered
|
|
13
|
+
* name (`report-2.pdf`), and the returned `path`/`url` say which.
|
|
14
|
+
*
|
|
15
|
+
* @param folder - The workspace folder; created (recursively) when it does not exist.
|
|
16
|
+
* @param name - The file's own name, no directories: the copy keeps it, extension included.
|
|
17
|
+
* @param bytes - The file's content.
|
|
18
|
+
* @returns Where the copy landed.
|
|
19
|
+
* @throws Error when `name` is not a plain file name, or the folder already holds too many same-named copies.
|
|
20
|
+
*/
|
|
21
|
+
export declare function importDocument(folder: string, name: string, bytes: Uint8Array): Promise<ImportedDocument>;
|
|
22
|
+
//# sourceMappingURL=import-document.use-case.d.ts.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { openWorkspace } from './open-workspace.use-case';
|
|
2
|
+
export { saveRecipe } from './save-recipe.use-case';
|
|
3
|
+
export { importDocument } from './import-document.use-case';
|
|
4
|
+
export type { ImportedDocument } from './import-document.use-case';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WorkspaceView } from '../studio-api';
|
|
2
|
+
/**
|
|
3
|
+
* Opens a recipe folder: every `.json`/`.jsonl` recipe directly inside it
|
|
4
|
+
* (core's own directory reading, so relative `file:` URLs resolve the same
|
|
5
|
+
* way a real run would), parsed and, for each output recipe found, bound to
|
|
6
|
+
* the input recipes that name it. Nothing throws for a bad recipe or a
|
|
7
|
+
* recipe that does not bind: every problem is reported on its file with the
|
|
8
|
+
* JSON path core already computes, exactly as `opencraw validate` prints it.
|
|
9
|
+
*
|
|
10
|
+
* @param folder - The workspace folder.
|
|
11
|
+
* @returns Every recipe file found, each with its validation and binding issues.
|
|
12
|
+
* @throws Error when the folder does not exist or cannot be read.
|
|
13
|
+
*/
|
|
14
|
+
export declare function openWorkspace(folder: string): Promise<WorkspaceView>;
|
|
15
|
+
//# sourceMappingURL=open-workspace.use-case.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes a recipe back to its file: pretty JSON, a 2-space indent, a
|
|
3
|
+
* trailing newline. Phase 0 takes the JSON tab's whole parsed object rather
|
|
4
|
+
* than a patch, so this is a full replacement, not a splice: loading a file
|
|
5
|
+
* the studio has not touched and saving it again keeps every key, value and
|
|
6
|
+
* key order (`JSON.parse` preserves insertion order, and `JSON.stringify`
|
|
7
|
+
* writes it back), but not necessarily the file's exact original formatting
|
|
8
|
+
* (alignment, how arrays wrap, a trailing comment). Byte-identical
|
|
9
|
+
* round-trip for a hand-formatted file is future work; see this file's test
|
|
10
|
+
* for what is guaranteed today.
|
|
11
|
+
*
|
|
12
|
+
* The text goes to a sibling temporary file that is then renamed over the
|
|
13
|
+
* recipe, so a reader (or a crash) never sees a half-written file. Windows
|
|
14
|
+
* refuses a rename over a file another process has open (`EPERM`, `EBUSY`),
|
|
15
|
+
* so the rename is retried briefly and then gives way to a plain write.
|
|
16
|
+
*
|
|
17
|
+
* @param path - The recipe file to write.
|
|
18
|
+
* @param recipe - The whole recipe object.
|
|
19
|
+
*/
|
|
20
|
+
export declare function saveRecipe(path: string, recipe: unknown): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=save-recipe.use-case.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { loadRecipePair } from './load-recipe-pair.use-case';
|
|
2
|
+
export type { RecipePair } from './load-recipe-pair.use-case';
|
|
3
|
+
export { runSample } from './run-sample.use-case';
|
|
4
|
+
export type { SampleRunCallbacks, SampleRunHandle } from './run-sample.use-case';
|
|
5
|
+
export type { SampleRunRecord, SampleRunRejected, SampleRunResult, SampleStepSummary, SampleStoppedBy } from './sample-run-record.contract';
|
|
6
|
+
export { createLastRunCache, lastRunOf, recordLastRun } from './last-run.store';
|
|
7
|
+
export type { LastRunCache, LastRunEntry } from './last-run.store';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SampleRunResult } from './sample-run-record.contract';
|
|
2
|
+
/** The last completed sample run of one input recipe: its records, rejections, mapping traces and step summary, kept for `explain-why` (issue #92) so a Why? click needs no second run. */
|
|
3
|
+
export interface LastRunEntry {
|
|
4
|
+
recipeId: string;
|
|
5
|
+
result: SampleRunResult;
|
|
6
|
+
}
|
|
7
|
+
/** One server's worth of last-run entries, by recipe id: a run replaces the previous one for the same recipe. */
|
|
8
|
+
export interface LastRunCache {
|
|
9
|
+
entries: Map<string, LastRunEntry>;
|
|
10
|
+
}
|
|
11
|
+
/** @returns A fresh, empty cache. */
|
|
12
|
+
export declare function createLastRunCache(): LastRunCache;
|
|
13
|
+
/** Records a finished sample run, replacing whatever this recipe's cache entry held before. */
|
|
14
|
+
export declare function recordLastRun(cache: LastRunCache, recipeId: string, result: SampleRunResult): void;
|
|
15
|
+
/** @returns The recipe's last completed sample run, or `undefined` when none has finished yet. */
|
|
16
|
+
export declare function lastRunOf(cache: LastRunCache, recipeId: string): LastRunEntry | undefined;
|
|
17
|
+
//# sourceMappingURL=last-run.store.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { InputRecipe, OutputRecipe } from '@opencraw/core';
|
|
2
|
+
/** An input recipe and the output recipe it names, both parsed. */
|
|
3
|
+
export interface RecipePair {
|
|
4
|
+
input: InputRecipe;
|
|
5
|
+
output: OutputRecipe;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Finds and parses one input recipe of a workspace folder, and the output
|
|
9
|
+
* recipe it names.
|
|
10
|
+
*
|
|
11
|
+
* @param folder - The workspace folder.
|
|
12
|
+
* @param recipeId - The input recipe's id.
|
|
13
|
+
* @returns The parsed pair.
|
|
14
|
+
* @throws RecipeValidationError when either recipe does not parse.
|
|
15
|
+
* @throws Error when the input or its output is not in the folder.
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadRecipePair(folder: string, recipeId: string): Promise<RecipePair>;
|
|
18
|
+
//# sourceMappingURL=load-recipe-pair.use-case.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { BrowserSessionConfig } from '@opencraw/core';
|
|
2
|
+
import type { SampleBudget } from '../studio-api';
|
|
3
|
+
import type { TrustedPlugins } from '../trusted-plugins';
|
|
4
|
+
import type { SampleRunRecord, SampleRunRejected, SampleRunResult } from './sample-run-record.contract';
|
|
5
|
+
/** Where trace lines and records go as a sample run proceeds. */
|
|
6
|
+
export interface SampleRunCallbacks {
|
|
7
|
+
onTraceLine: (line: string) => void;
|
|
8
|
+
onRecord: (record: SampleRunRecord) => void;
|
|
9
|
+
/** A record was rejected (a field's `skip-record` missing/coercion policy); optional, most callers only need the final `rejectedRecords` list. */
|
|
10
|
+
onRejected?: (rejected: SampleRunRejected) => void;
|
|
11
|
+
}
|
|
12
|
+
/** A sample run in progress. */
|
|
13
|
+
export interface SampleRunHandle {
|
|
14
|
+
/** Closes the crawler; the run's `result` still resolves, typically with an error from the interrupted request. */
|
|
15
|
+
stop: () => Promise<void>;
|
|
16
|
+
result: Promise<SampleRunResult>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Runs one input recipe of a workspace folder as a sample: `debug: true` (so
|
|
20
|
+
* each `record:emit` carries its scope snapshot and mapping trace, and each
|
|
21
|
+
* `record:reject` its scope), an in-memory sink, and `budget` as the
|
|
22
|
+
* crawler's `sample` (`@opencraw/core`'s `CrawlOptions.sample`, #89). Every
|
|
23
|
+
* engine event becomes a trace line with the same `traceLine` formatter the
|
|
24
|
+
* cli's `--trace` uses; every emitted record reaches `callbacks.onRecord` as
|
|
25
|
+
* it happens, not only in the final result. Step events (`step:start`,
|
|
26
|
+
* `step:skip`, `step:retry`) are aggregated by path into `result.steps`, so
|
|
27
|
+
* `explain-why` (#92) can later say whether the step that bound a mapping's
|
|
28
|
+
* source id ran, was skipped, or retried — without a second run.
|
|
29
|
+
*
|
|
30
|
+
* @param folder - The workspace folder the recipe lives in.
|
|
31
|
+
* @param recipeId - The input recipe to run.
|
|
32
|
+
* @param budget - The sample budget; unset runs the recipe to completion (still capped by its own `limits`).
|
|
33
|
+
* @param callbacks - Where trace lines and records go as the run proceeds.
|
|
34
|
+
* @param browser - Browser launch settings for a web-mode recipe (an executable path override, headless…); the server-wide setting `studio-http.use-case.ts`'s `StudioServerOptions.browser` carries in, e.g. `OPENCRAW_CHROMIUM` in a sandbox with no full Playwright install.
|
|
35
|
+
* @param plugins - Hooks, access plugins and captcha solvers the person started Studio with (`--hooks`, issue #150); none when it was started without.
|
|
36
|
+
* @returns A handle: `stop` closes the crawler cleanly, `result` resolves when the run ends.
|
|
37
|
+
* @throws RecipeValidationError, RecipeBindingError, Error when the recipe or its output cannot be loaded or bound.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runSample(folder: string, recipeId: string, budget: SampleBudget | undefined, callbacks: SampleRunCallbacks, browser?: BrowserSessionConfig, plugins?: TrustedPlugins): Promise<SampleRunHandle>;
|
|
40
|
+
//# sourceMappingURL=run-sample.use-case.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { MappingTrace } from '@opencraw/core';
|
|
2
|
+
/**
|
|
3
|
+
* One record streamed or kept from a sample run. `scope` (the snapshot it
|
|
4
|
+
* was mapped from) and `mapping` (each field's source value and its value
|
|
5
|
+
* after every transform, `@opencraw/core`'s `record:emit.mapping`, core
|
|
6
|
+
* since 0.1.12) are always present: `runSample` runs with `debug: true`.
|
|
7
|
+
* Kept per record (studio plan §4.2/§4.4, issue #92) so the Record tab can
|
|
8
|
+
* show a transform chain's real values and the Why? tab can explain a
|
|
9
|
+
* missing one, without a second run.
|
|
10
|
+
*/
|
|
11
|
+
export interface SampleRunRecord {
|
|
12
|
+
key: string | null;
|
|
13
|
+
data: Record<string, unknown>;
|
|
14
|
+
scope?: Record<string, unknown>;
|
|
15
|
+
mapping?: MappingTrace;
|
|
16
|
+
}
|
|
17
|
+
/** One record a sample run rejected (`RecordRejectedError`, a field's `skip-record` policy), kept for the Why? tab. */
|
|
18
|
+
export interface SampleRunRejected {
|
|
19
|
+
field: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
url: string;
|
|
22
|
+
scope?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/** A sample run's stopping reason: mirrors `@opencraw/core`'s `RecipeReport.stoppedBy`. */
|
|
25
|
+
export type SampleStoppedBy = 'sample-maxRecords' | 'sample-maxPages' | 'sample-maxMs';
|
|
26
|
+
/** One outcome of a step during a sample run, aggregated over every time its path ran: whether it ever ran cleanly, was skipped, or retried, kept for the Why? tab (issue #92) — which step bound a mapping's source id, and whether it found nothing. */
|
|
27
|
+
export interface SampleStepSummary {
|
|
28
|
+
path: string;
|
|
29
|
+
stepType: string;
|
|
30
|
+
stepId?: string;
|
|
31
|
+
as?: string;
|
|
32
|
+
outcome: 'ran' | 'skipped' | 'retried';
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
35
|
+
/** What a sample run finished with. */
|
|
36
|
+
export interface SampleRunResult {
|
|
37
|
+
recipeId: string;
|
|
38
|
+
emitted: number;
|
|
39
|
+
rejected: number;
|
|
40
|
+
duplicates: number;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
error?: string;
|
|
43
|
+
stoppedBy?: SampleStoppedBy;
|
|
44
|
+
records: SampleRunRecord[];
|
|
45
|
+
rejectedRecords: SampleRunRejected[];
|
|
46
|
+
steps: SampleStepSummary[];
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=sample-run-record.contract.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SentencePart } from './outline.model';
|
|
2
|
+
export interface StepSentence {
|
|
3
|
+
parts: SentencePart[];
|
|
4
|
+
/** `true` when this is a fallback (an unrecognised type, or one of `ALWAYS_CUSTOM`): the UI shows `step`'s raw JSON instead of trusting `parts` alone. */
|
|
5
|
+
custom: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Turns one step's raw JSON into its sentence parts (word/pill/code), the
|
|
9
|
+
* way the plan doc's examples read: *Go to…*, *Read… from…*, *For each… in…
|
|
10
|
+
* → one record*, and so on. Never throws: a step type this cannot read
|
|
11
|
+
* becomes a short, honest fallback with `custom: true`, so the outline never
|
|
12
|
+
* drops a step for looking unfamiliar.
|
|
13
|
+
*
|
|
14
|
+
* @param step - A step's raw JSON (its `type` and whatever fields it has).
|
|
15
|
+
* @returns The sentence parts, and whether they are a real reading or a fallback.
|
|
16
|
+
*/
|
|
17
|
+
export declare function cardSentence(step: Record<string, unknown>): StepSentence;
|
|
18
|
+
//# sourceMappingURL=card-sentence.mapper.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { BRACKET_STEP_TYPES, isBracket, isBracketStepType } from './outline.model';
|
|
2
|
+
export type { OutlineBracket, OutlineCard, OutlineNode, RecipeOutline, SentencePart, BracketStepType } from './outline.model';
|
|
3
|
+
export { cardSentence } from './card-sentence.mapper';
|
|
4
|
+
export type { StepSentence } from './card-sentence.mapper';
|
|
5
|
+
export { recipeToOutline } from './recipe-to-outline.mapper';
|
|
6
|
+
export { outlineToRecipe } from './outline-to-recipe.mapper';
|
|
7
|
+
export { scopeAtPath } from './scope-at-path.algorithm';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RecipeOutline } from './outline.model';
|
|
2
|
+
/**
|
|
3
|
+
* Rebuilds a recipe from its outline: `recipe`'s keys, in their original
|
|
4
|
+
* order, with `steps` (when the recipe had one) replaced by the outline's
|
|
5
|
+
* (possibly edited) step tree. A card's own raw `step` is used as-is; a
|
|
6
|
+
* bracket's `step` supplies every field but `steps`/`else`, which come from
|
|
7
|
+
* `children`/`elseChildren` instead, put back at the position `step` itself
|
|
8
|
+
* held that key at (or appended, for a bracket a `+` menu just added, whose
|
|
9
|
+
* `step` never had one) — this, together with `recipe-to-outline.mapper.ts`
|
|
10
|
+
* always keeping the step's whole original object, is what makes
|
|
11
|
+
* `recipe → outline → recipe` preserve every key and its order.
|
|
12
|
+
*
|
|
13
|
+
* @param outline - An outline, from `recipe-to-outline.mapper.ts` or edited by the UI.
|
|
14
|
+
* @returns The recipe's plain JSON, ready for `save-recipe`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function outlineToRecipe(outline: RecipeOutline): Record<string, unknown>;
|
|
17
|
+
//# sourceMappingURL=outline-to-recipe.mapper.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The outline model: an `InputRecipe`'s `steps` (and only `steps`; the rest
|
|
3
|
+
* of the recipe passes through untouched, see `recipe-to-outline.mapper.ts`)
|
|
4
|
+
* read as a tree of cards and brackets instead of raw JSON.
|
|
5
|
+
*
|
|
6
|
+
* A **card** is one step that reads as a sentence (`sentence`, built by
|
|
7
|
+
* `card-sentence.mapper.ts`). A **bracket** is a container step (`forEach`,
|
|
8
|
+
* `paginate`, `if`) whose body is itself a list of cards/brackets: the
|
|
9
|
+
* indentation the plan doc describes is this nesting, not a separate layout
|
|
10
|
+
* concept. Both kinds carry `step`, the step's own raw JSON exactly as
|
|
11
|
+
* parsed (every key, in its original order): `outline-to-recipe.mapper.ts`
|
|
12
|
+
* rebuilds the recipe from it, substituting only the (possibly edited)
|
|
13
|
+
* `children`/`elseChildren` for whatever `steps`/`else` value `step` itself
|
|
14
|
+
* holds, so an edit to one field never disturbs another's position or a
|
|
15
|
+
* step type this outline cannot make sense of.
|
|
16
|
+
*/
|
|
17
|
+
/** One piece of a card's sentence: plain wording, a bound id (a "pill"), or a literal (a selector, a template, a value) shown as code. */
|
|
18
|
+
export interface SentencePart {
|
|
19
|
+
kind: 'word' | 'pill' | 'code';
|
|
20
|
+
text: string;
|
|
21
|
+
}
|
|
22
|
+
/** The step types the outline renders as a bracket: their body is nested steps, not a single value. */
|
|
23
|
+
export declare const BRACKET_STEP_TYPES: readonly ['forEach', 'paginate', 'if'];
|
|
24
|
+
export type BracketStepType = typeof BRACKET_STEP_TYPES[number];
|
|
25
|
+
interface OutlineNodeBase {
|
|
26
|
+
/** The step's JSON path in the recipe, e.g. `steps.3.steps.1`. */
|
|
27
|
+
path: string;
|
|
28
|
+
/** The step's own `type`, or `'unknown'` when `step` has none. */
|
|
29
|
+
stepType: string;
|
|
30
|
+
sentence: SentencePart[];
|
|
31
|
+
/** The step's raw JSON, exactly as parsed: never dropped, always editable as JSON. */
|
|
32
|
+
step: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
/** One step the outline could not, or chose not to, read as a bracket: a leaf card. */
|
|
35
|
+
export interface OutlineCard extends OutlineNodeBase {
|
|
36
|
+
kind: 'card';
|
|
37
|
+
/** `true` when `card-sentence.mapper.ts` could not build a real sentence: the UI shows `step` as raw, editable JSON instead. */
|
|
38
|
+
custom: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** A container step (`forEach`, `paginate`, `if`): its body nested one level in. */
|
|
41
|
+
export interface OutlineBracket extends OutlineNodeBase {
|
|
42
|
+
kind: 'bracket';
|
|
43
|
+
stepType: BracketStepType;
|
|
44
|
+
children: OutlineNode[];
|
|
45
|
+
/** `if` only: the `else` branch, when the step has one. */
|
|
46
|
+
elseChildren?: OutlineNode[];
|
|
47
|
+
}
|
|
48
|
+
export type OutlineNode = OutlineCard | OutlineBracket;
|
|
49
|
+
/** A recipe read as an outline: `recipe` is everything but the derived view of `steps`, kept so the mapper back can restore it untouched. */
|
|
50
|
+
export interface RecipeOutline {
|
|
51
|
+
recipe: Record<string, unknown>;
|
|
52
|
+
steps: OutlineNode[];
|
|
53
|
+
}
|
|
54
|
+
export declare function isBracket(node: OutlineNode): node is OutlineBracket;
|
|
55
|
+
export declare function isBracketStepType(type: string): type is BracketStepType;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=outline.model.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RecipeOutline } from './outline.model';
|
|
2
|
+
/**
|
|
3
|
+
* Reads a recipe's `steps` as an outline. Works on whatever JSON parsed
|
|
4
|
+
* (not a validated `InputRecipe`): a recipe mid-edit in the JSON tab may be
|
|
5
|
+
* missing fields or have the wrong shape, and the outline still has to
|
|
6
|
+
* render something rather than crash the tab. Anything that is not a
|
|
7
|
+
* well-formed step becomes a custom card holding what was there; anything
|
|
8
|
+
* that is not an object at the top becomes an outline with no steps.
|
|
9
|
+
*
|
|
10
|
+
* @param content - The recipe's parsed JSON (the JSON tab's own `JSON.parse` of its text).
|
|
11
|
+
* @returns The outline: the untouched top-level record plus the step tree.
|
|
12
|
+
*/
|
|
13
|
+
export declare function recipeToOutline(content: unknown): RecipeOutline;
|
|
14
|
+
//# sourceMappingURL=recipe-to-outline.mapper.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ids visible at a step path: the built-ins (`page`, `start`, `vars`),
|
|
3
|
+
* every id bound above it on the same path, and the `as`/`next.as` name of
|
|
4
|
+
* every loop it sits inside. This is core's own binding rule
|
|
5
|
+
* (`bindingsAt`, `recipe-loading/recipe-binding.validator.ts`): the walk
|
|
6
|
+
* that decides what a `{{ }}` template, `from` or `over` can name is the one
|
|
7
|
+
* `opencraw validate` already runs, not a copy of it.
|
|
8
|
+
*
|
|
9
|
+
* `content` is the recipe's raw parsed JSON, the same loosely-typed value
|
|
10
|
+
* `recipe-to-outline.mapper.ts` reads: a recipe mid-edit may not parse as a
|
|
11
|
+
* valid `InputRecipe` (a missing `mode`, a step with the wrong shape), and
|
|
12
|
+
* this never throws for that — it falls back to just the built-ins.
|
|
13
|
+
*
|
|
14
|
+
* @param content - The recipe's parsed JSON.
|
|
15
|
+
* @param path - A step's JSON path, e.g. `steps.3.steps.1`.
|
|
16
|
+
* @returns The ids in scope at that path, `page`/`start`/`vars` first.
|
|
17
|
+
*/
|
|
18
|
+
export declare function scopeAtPath(content: unknown, path: string): string[];
|
|
19
|
+
//# sourceMappingURL=scope-at-path.algorithm.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which class tokens are worth building a selector on. A hand-authored class
|
|
3
|
+
* (`product_pod`, `price_color`) survives a rebuild; a generated one
|
|
4
|
+
* (a content hash, a CSS-module suffix, a styled-components token) does not,
|
|
5
|
+
* so a candidate built on it looks fine on the snapshot it was picked from
|
|
6
|
+
* and breaks on the very next deploy. This is the "generated/hashed class
|
|
7
|
+
* names" tradeoff issue #91 calls out explicitly: the heuristics below are a
|
|
8
|
+
* reasoned judgement call, not a guarantee — see the doc comments on each
|
|
9
|
+
* pattern for what real-world tool it targets.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Whether a class token looks hand-authored and safe to build a selector on.
|
|
13
|
+
*
|
|
14
|
+
* @param token - One class, no surrounding whitespace.
|
|
15
|
+
* @returns `false` for anything matching a known generated-class shape.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isStableClassToken(token: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* The subset of `tokens` worth ranking a selector candidate on, order kept.
|
|
20
|
+
*
|
|
21
|
+
* @param tokens - An element's class list.
|
|
22
|
+
* @returns Only the stable tokens.
|
|
23
|
+
*/
|
|
24
|
+
export declare function stableClasses(tokens: readonly string[]): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Whether two class lists describe "the same kind of element" for list
|
|
27
|
+
* inference: same stable classes, generated tokens (which often differ
|
|
28
|
+
* per-instance, e.g. a React `key`-derived class) ignored on both sides.
|
|
29
|
+
*
|
|
30
|
+
* @param a - One element's classes.
|
|
31
|
+
* @param b - Another element's classes.
|
|
32
|
+
* @returns Whether their stable class sets are equal, order ignored.
|
|
33
|
+
*/
|
|
34
|
+
export declare function sameClassSignature(a: readonly string[], b: readonly string[]): boolean;
|
|
35
|
+
//# sourceMappingURL=class-token.policy.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { AnyNode } from 'domhandler';
|
|
2
|
+
import type { Cheerio, CheerioAPI } from 'cheerio';
|
|
3
|
+
/**
|
|
4
|
+
* One level of a node's ancestry, root first: the element's own shape (tag,
|
|
5
|
+
* id, classes, attributes) plus where it sits among its same-tag siblings.
|
|
6
|
+
* Built over parsed HTML (cheerio), never a live DOM: the studio infers
|
|
7
|
+
* selectors from the snapshot the server captured, not from a browser
|
|
8
|
+
* window in the UI process (studio plan §3.1/§3.2, issue #91).
|
|
9
|
+
*/
|
|
10
|
+
export interface DomPathLevel {
|
|
11
|
+
tag: string;
|
|
12
|
+
id?: string;
|
|
13
|
+
classes: string[];
|
|
14
|
+
attrs: Record<string, string>;
|
|
15
|
+
/** 1-based position among same-tag siblings under the same parent (an `nth-of-type` index). */
|
|
16
|
+
index: number;
|
|
17
|
+
/** How many same-tag siblings share the parent, `index` included. */
|
|
18
|
+
siblingCount: number;
|
|
19
|
+
}
|
|
20
|
+
/** A node's whole ancestry, root first, the node itself last. */
|
|
21
|
+
export type DomPath = DomPathLevel[];
|
|
22
|
+
/**
|
|
23
|
+
* The path from the document root to `node`, one level per ancestor. Two
|
|
24
|
+
* elements that share an ancestor produce identical levels up to that
|
|
25
|
+
* ancestor and diverge exactly where their parents stop being the same node
|
|
26
|
+
* — `list-inference.algorithm.ts` leans on that to find the nearest pair of
|
|
27
|
+
* siblings two picks belong to, without ever touching cheerio again.
|
|
28
|
+
*
|
|
29
|
+
* @param $ - The parsed document.
|
|
30
|
+
* @param node - The element to describe.
|
|
31
|
+
* @returns The path, root first.
|
|
32
|
+
*/
|
|
33
|
+
export declare function domPathOf($: CheerioAPI, node: Cheerio<AnyNode>): DomPath;
|
|
34
|
+
/**
|
|
35
|
+
* Whether `id` looks handed by a framework (`react-`, a CSS-module or a
|
|
36
|
+
* `radix-`/`mui-` autogenerated one) rather than by the site's own markup —
|
|
37
|
+
* `class-token.policy.ts` has the equivalent check for class tokens, kept
|
|
38
|
+
* separate because ids and classes are ranked at different tiers.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isStableId(id: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Whether `path` failed to reach the real document root. `domPathOf` walks
|
|
43
|
+
* up through cheerio's own `.parent()`, which (matching real DOM semantics)
|
|
44
|
+
* never crosses from a `<template>`'s content into the light DOM outside
|
|
45
|
+
* it — a `<template shadowrootmode>` is exactly declarative shadow DOM, the
|
|
46
|
+
* only shadow-DOM shape that can show up in static, server-captured markup
|
|
47
|
+
* at all (imperative `attachShadow()` content never serialises into
|
|
48
|
+
* `page.content()`/a fetched response in the first place, so that case
|
|
49
|
+
* cannot reach this slice and needs no separate detection). A path whose
|
|
50
|
+
* first level is not `html` was cut short at exactly this kind of boundary:
|
|
51
|
+
* v1 does not pierce it, so callers report a clear "shadow DOM is not
|
|
52
|
+
* supported" error instead of building ancestor-based candidates over a
|
|
53
|
+
* chain that stops partway up.
|
|
54
|
+
*/
|
|
55
|
+
export declare function crossesShadowRoot(path: DomPath): boolean;
|
|
56
|
+
/** Parses `html` and returns cheerio's API, for callers that need more than one path from the same document. */
|
|
57
|
+
export declare function parseDocument(html: string): CheerioAPI;
|
|
58
|
+
/**
|
|
59
|
+
* The path to the element the snapshot stamped with `nodeId` (its
|
|
60
|
+
* `data-oc-node` attribute — `@opencraw/core`'s `NODE_ID_ATTRIBUTE`,
|
|
61
|
+
* `packages/studio/src/page-snapshot/rewrite-document.mapper.ts`). This is
|
|
62
|
+
* how a click in the content pane's iframe — which only ever needs to read
|
|
63
|
+
* that one attribute off the element the user clicked — turns into
|
|
64
|
+
* something `selector-inference`'s other algorithms can work with, without
|
|
65
|
+
* the browser-side picker script needing to know anything about ancestry,
|
|
66
|
+
* classes or candidate ranking itself.
|
|
67
|
+
*
|
|
68
|
+
* @param html - The snapshot document (already stamped with node ids).
|
|
69
|
+
* @param nodeId - The `data-oc-node` value to find.
|
|
70
|
+
* @returns The node's path, or `undefined` when no element carries that id.
|
|
71
|
+
*/
|
|
72
|
+
export declare function pathToNode(html: string, nodeId: string): DomPath | undefined;
|
|
73
|
+
//# sourceMappingURL=dom-path.model.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { domPathOf, isStableId, crossesShadowRoot, parseDocument, pathToNode } from './dom-path.model';
|
|
2
|
+
export type { DomPath, DomPathLevel } from './dom-path.model';
|
|
3
|
+
export { takeKindFor } from './take-kind.policy';
|
|
4
|
+
export { isStableClassToken, stableClasses, sameClassSignature } from './class-token.policy';
|
|
5
|
+
export { ShadowDomUnsupportedError } from './shadow-dom.error';
|
|
6
|
+
export { candidatesFor } from './selector-candidates.algorithm';
|
|
7
|
+
export type { SelectorCandidate, CandidateTier } from './selector-candidates.algorithm';
|
|
8
|
+
export { rankCandidates, bestCandidate } from './selector-ranking.policy';
|
|
9
|
+
export type { RankedCandidate } from './selector-ranking.policy';
|
|
10
|
+
export { inferList } from './list-inference.algorithm';
|
|
11
|
+
export type { ListInferenceResult } from './list-inference.algorithm';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { DomPath } from './dom-path.model';
|
|
2
|
+
export interface ListInferenceResult {
|
|
3
|
+
/**
|
|
4
|
+
* The item's shape, generalised across both picks (root first, item
|
|
5
|
+
* last): only the tag, the stable classes and the attributes the two
|
|
6
|
+
* picked items actually share survive the merge. An id or a `data-id`
|
|
7
|
+
* that differs per item (the ordinary case) is dropped here on purpose —
|
|
8
|
+
* built into a selector it would match one item and silently miss every
|
|
9
|
+
* other, which is a shifted-field-shaped bug in its own right even though
|
|
10
|
+
* it is not the one issue #91 names.
|
|
11
|
+
*/
|
|
12
|
+
itemPath: DomPath;
|
|
13
|
+
/** The field's shape from the item down to the click, generalised the same way as `itemPath`, for a selector that reads `from` the item and still works on every item, not just the one it was picked from. */
|
|
14
|
+
fieldPath: DomPath;
|
|
15
|
+
/** The concrete path of the first click, item-relative (index 0 = the item), kept for provenance (e.g. the value the pick actually read). */
|
|
16
|
+
fieldPathA: DomPath;
|
|
17
|
+
/** Same, for the second click. */
|
|
18
|
+
fieldPathB: DomPath;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Infers "these two picks are the same field on two items of a list" from
|
|
22
|
+
* two node paths, by walking up from both to the nearest ancestors that are
|
|
23
|
+
* real siblings (the same parent) with the same tag and stable-class
|
|
24
|
+
* signature — studio plan §3.2, issue #91. That ancestor is the item; the
|
|
25
|
+
* remainder of each path is the field, relative to it.
|
|
26
|
+
*
|
|
27
|
+
* Because a `DomPath` is built root-down (`dom-path.model.ts`), two paths
|
|
28
|
+
* from the same document are byte-for-byte identical up to their real
|
|
29
|
+
* common ancestor and diverge exactly at its differing children — so the
|
|
30
|
+
* *first* level where they differ is always the nearest-sibling test point;
|
|
31
|
+
* there is no need to look further down. This also makes the "wrapper trap"
|
|
32
|
+
* (an extra single-child element around each item) resolve itself: a
|
|
33
|
+
* wrapper's own instances are never one another's siblings, only the
|
|
34
|
+
* genuine repeating element is, so the walk naturally lands there instead of
|
|
35
|
+
* on the wrapper (see the wrapper-trap fixture in this slice's tests).
|
|
36
|
+
*
|
|
37
|
+
* @param pathA - The first click's path.
|
|
38
|
+
* @param pathB - The second click's path.
|
|
39
|
+
* @returns The item and field shapes (generalised) plus each pick's raw path, or `null` when the two picks are not on a coherent list (different branches entirely, the same node twice, or one path nested inside the other).
|
|
40
|
+
* @throws ShadowDomUnsupportedError when either path crosses a declarative shadow root.
|
|
41
|
+
*/
|
|
42
|
+
export declare function inferList(pathA: DomPath, pathB: DomPath): ListInferenceResult | null;
|
|
43
|
+
//# sourceMappingURL=list-inference.algorithm.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DomPath } from './dom-path.model';
|
|
2
|
+
/** The engine only ever runs `css` selectors from the studio (studio plan §3.2); xpath is a separate, text-only fallback the UI builds by hand. */
|
|
3
|
+
export type CandidateTier = 'id' | 'data-attr' | 'class' | 'structure' | 'position';
|
|
4
|
+
export interface SelectorCandidate {
|
|
5
|
+
selector: string;
|
|
6
|
+
tier: CandidateTier;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Every selector candidate worth trying for the last node of `path`, ranked
|
|
10
|
+
* best-first: `id` > stable `data-*`/`itemprop` attributes > stable class
|
|
11
|
+
* tokens > ancestor structure (`parent > tag`) > position (`nth-of-type`) as
|
|
12
|
+
* a last resort (issue #91's ranking, studio plan §3.2). Structure and
|
|
13
|
+
* position candidates only look as far up as `path` itself goes — pass a
|
|
14
|
+
* sub-path (e.g. from an item's root down) to keep a field's selector
|
|
15
|
+
* relative to its item instead of absolute to the document.
|
|
16
|
+
*
|
|
17
|
+
* @param path - The node's ancestry, root (or scope root) first, itself last.
|
|
18
|
+
* @param includePosition - `false` for an item selector: a position candidate would only ever match one of the items, which is never what an item selector should do.
|
|
19
|
+
* @returns Candidates, best tier first; ties keep this function's own order.
|
|
20
|
+
*/
|
|
21
|
+
export declare function candidatesFor(path: DomPath, includePosition?: boolean): SelectorCandidate[];
|
|
22
|
+
//# sourceMappingURL=selector-candidates.algorithm.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SelectorCandidate } from './selector-candidates.algorithm';
|
|
2
|
+
export interface RankedCandidate extends SelectorCandidate {
|
|
3
|
+
/** How many elements this candidate matches in the document it was verified against. */
|
|
4
|
+
matches: number;
|
|
5
|
+
/** Whether it matches `targetNodeId` (when one was given); a candidate that misses its own target is worse than useless. */
|
|
6
|
+
hitsTarget: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Verifies and orders selector candidates against real markup, by running
|
|
10
|
+
* each one through the engine's own CSS matching (`@opencraw/core`'s
|
|
11
|
+
* `countMatches`/`matchesOf`) rather than reimplementing it — issue #91's
|
|
12
|
+
* "every candidate is verified" requirement.
|
|
13
|
+
*
|
|
14
|
+
* Ordering: candidates that do not match `targetNodeId` (when given) sort
|
|
15
|
+
* last; among the rest, best tier first, and within a tier the fewest
|
|
16
|
+
* matches first (the most specific selector that still hits the target).
|
|
17
|
+
* A candidate matching nothing is dropped entirely: it is not a real option.
|
|
18
|
+
*
|
|
19
|
+
* @param html - The document to verify against (the snapshot, or the live page for the second, cross-check pass).
|
|
20
|
+
* @param candidates - Unranked candidates, e.g. from `candidatesFor`.
|
|
21
|
+
* @param targetNodeId - The `data-oc-node` id the pick landed on, when the document carries those stamps (the snapshot does; a live page fetched separately does not).
|
|
22
|
+
* @returns Every candidate that matched at least one element, ranked best first.
|
|
23
|
+
*/
|
|
24
|
+
export declare function rankCandidates(html: string, candidates: readonly SelectorCandidate[], targetNodeId?: string): RankedCandidate[];
|
|
25
|
+
/** The single best candidate, or `undefined` when none of them matched anything. */
|
|
26
|
+
export declare function bestCandidate(html: string, candidates: readonly SelectorCandidate[], targetNodeId?: string): RankedCandidate | undefined;
|
|
27
|
+
//# sourceMappingURL=selector-ranking.policy.d.ts.map
|