@nitpicker/core 0.24.0 → 0.25.1
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 +165 -35
- package/lib/assert-u32-id.d.ts +15 -0
- package/lib/assert-u32-id.js +22 -0
- package/lib/check-native-executor-config.d.ts +21 -0
- package/lib/check-native-executor-config.js +24 -0
- package/lib/compute-alias-keys.d.ts +28 -0
- package/lib/compute-alias-keys.js +30 -0
- package/lib/compute-body-hash.d.ts +22 -0
- package/lib/compute-body-hash.js +25 -0
- package/lib/compute-url-sort-ranks.d.ts +28 -0
- package/lib/compute-url-sort-ranks.js +49 -0
- package/lib/create-isolated-cluster-run.d.ts +35 -0
- package/lib/create-isolated-cluster-run.js +52 -0
- package/lib/create-template-classification-run.d.ts +49 -0
- package/lib/create-template-classification-run.js +386 -0
- package/lib/group-alias-candidates.d.ts +40 -0
- package/lib/group-alias-candidates.js +104 -0
- package/lib/load-native-binding.d.ts +26 -0
- package/lib/load-native-binding.js +152 -0
- package/lib/match-js-license-comment-signal.d.ts +19 -0
- package/lib/match-js-license-comment-signal.js +21 -0
- package/lib/match-selector-html.d.ts +41 -0
- package/lib/match-selector-html.js +42 -0
- package/lib/match-selector-snapshots.d.ts +40 -0
- package/lib/match-selector-snapshots.js +57 -0
- package/lib/match-structural-technology-signals.d.ts +23 -0
- package/lib/match-structural-technology-signals.js +25 -0
- package/lib/max-decoded-snapshot-bytes.d.ts +22 -0
- package/lib/max-decoded-snapshot-bytes.js +35 -0
- package/lib/native-binding.d.ts +9 -0
- package/lib/native-binding.js +9 -0
- package/lib/pack-stored-snapshots.d.ts +23 -0
- package/lib/pack-stored-snapshots.js +53 -0
- package/lib/run-with-signal.d.ts +27 -0
- package/lib/run-with-signal.js +54 -0
- package/lib/search-html-document.d.ts +32 -0
- package/lib/search-html-document.js +31 -0
- package/lib/search-html-snapshots.d.ts +46 -0
- package/lib/search-html-snapshots.js +54 -0
- package/lib/template-block-sample-size.d.ts +13 -0
- package/lib/template-block-sample-size.js +14 -0
- package/lib/template-exact-page-limit.d.ts +18 -0
- package/lib/template-exact-page-limit.js +19 -0
- package/lib/template-memory-budget.d.ts +16 -0
- package/lib/template-memory-budget.js +17 -0
- package/lib/to-native-selector-plan.d.ts +16 -0
- package/lib/to-native-selector-plan.js +40 -0
- package/lib/to-u32-ids.d.ts +14 -0
- package/lib/to-u32-ids.js +22 -0
- package/lib/types.d.ts +736 -248
- package/lib/validate-search-pattern.d.ts +25 -0
- package/lib/validate-search-pattern.js +27 -0
- package/package.json +83 -16
- package/lib/core.d.ts +0 -4
- package/lib/core.js +0 -4
- package/lib/discover-analyze-plugins.d.ts +0 -14
- package/lib/discover-analyze-plugins.js +0 -32
- package/lib/get-table-cache-root.d.ts +0 -18
- package/lib/get-table-cache-root.js +0 -22
- package/lib/hooks/define-plugin.d.ts +0 -68
- package/lib/hooks/define-plugin.js +0 -69
- package/lib/import-modules.d.ts +0 -24
- package/lib/import-modules.js +0 -38
- package/lib/load-plugin-settings.d.ts +0 -44
- package/lib/load-plugin-settings.js +0 -125
- package/lib/nitpicker.d.ts +0 -150
- package/lib/nitpicker.js +0 -437
- package/lib/page-analysis-worker.d.ts +0 -58
- package/lib/page-analysis-worker.js +0 -68
- package/lib/read-plugin-labels.d.ts +0 -15
- package/lib/read-plugin-labels.js +0 -30
- package/lib/table.d.ts +0 -75
- package/lib/table.js +0 -132
- package/lib/url-event-bus.d.ts +0 -33
- package/lib/url-event-bus.js +0 -21
- package/lib/worker/runner.d.ts +0 -25
- package/lib/worker/runner.js +0 -31
- package/lib/worker/types.d.ts +0 -23
- package/lib/worker/types.js +0 -1
- package/lib/worker/worker-pool.d.ts +0 -82
- package/lib/worker/worker-pool.js +0 -278
- package/lib/worker/worker.d.ts +0 -34
- package/lib/worker/worker.js +0 -108
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { nativeBinding } from './native-binding.js';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a native call rejected because its cancel token was raised.
|
|
4
|
+
* @param error - What the call rejected with.
|
|
5
|
+
*/
|
|
6
|
+
function isCancelled(error) {
|
|
7
|
+
return error instanceof Error && error.code === 'Cancelled';
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Runs one asynchronous native call so an `AbortSignal` can stop it.
|
|
11
|
+
*
|
|
12
|
+
* With no signal, `run` gets no token and nothing is allocated. With one, a
|
|
13
|
+
* fresh native token is raised when the signal fires, and the call stops at
|
|
14
|
+
* its next check (between snapshots, between mebibytes of a snapshot's
|
|
15
|
+
* decompression, or when it leaves the queue) and rejects
|
|
16
|
+
* with code `Cancelled`; that rejection, and only that one, is replaced by
|
|
17
|
+
* the signal's reason, so an abort reads as the caller's own abort. The
|
|
18
|
+
* addon reports a cancellation over a decode failure of the same batch (the
|
|
19
|
+
* caller asked to stop); a batch whose failure came before any snapshot saw
|
|
20
|
+
* the abort still rejects with that failure, which is passed on unchanged.
|
|
21
|
+
* A signal that is already aborted rejects with its reason without calling
|
|
22
|
+
* the addon.
|
|
23
|
+
* @param signal - The caller's signal, if any.
|
|
24
|
+
* @param run - Starts the native call, passing the token as its last argument.
|
|
25
|
+
* @returns What `run` resolved with.
|
|
26
|
+
* @throws {unknown} The signal's reason when the signal aborted before or during the call.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const flags = await runWithSignal(signal, (token) =>
|
|
30
|
+
* nativeBinding.matchSelectorSnapshots(plan, bodies, offsets, codecs, maxDecodedBytes, token),
|
|
31
|
+
* );
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export async function runWithSignal(signal, run) {
|
|
35
|
+
if (!signal) {
|
|
36
|
+
return run();
|
|
37
|
+
}
|
|
38
|
+
signal.throwIfAborted();
|
|
39
|
+
const token = new nativeBinding.NativeCancelToken();
|
|
40
|
+
const onAbort = () => token.cancel();
|
|
41
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
42
|
+
try {
|
|
43
|
+
return await run(token);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (signal.aborted && isCancelled(error)) {
|
|
47
|
+
throw signal.reason;
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
signal.removeEventListener('abort', onAbort);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { NativeSearchPattern, SnapshotSearchOutcome } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Counts the occurrences of a search pattern in one stored HTML document and
|
|
4
|
+
* cuts a snippet around the first.
|
|
5
|
+
*
|
|
6
|
+
* The document is read as UTF-8 (an invalid sequence becomes U+FFFD, as
|
|
7
|
+
* `Buffer#toString('utf8')` reads it). Positions and lengths are in Unicode
|
|
8
|
+
* scalar values, so `.` matches an emoji once. `matchCount` counts
|
|
9
|
+
* non-overlapping matches as Rust's `find_iter` walks them; the snippet is a
|
|
10
|
+
* window of `snippetLength` characters centred on the first match, with
|
|
11
|
+
* whitespace collapsed (JavaScript's `\s`) and the ends trimmed.
|
|
12
|
+
* @param options - The pattern and the document.
|
|
13
|
+
* @param options.pattern - The pattern and its flags.
|
|
14
|
+
* @param options.html - The stored markup, as a string or as UTF-8 bytes.
|
|
15
|
+
* @param options.snippetLength - Window size in characters.
|
|
16
|
+
* @returns The match count and the snippet (empty when nothing matched).
|
|
17
|
+
* @throws {Error} With code `InvalidArg` if the pattern cannot be compiled (see `validateSearchPattern`).
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const { matchCount, snippet } = searchHtmlDocument({
|
|
21
|
+
* pattern: { source: 'font-family', literal: true, ignoreCase: false, multiLine: false, dotAll: false },
|
|
22
|
+
* html: '<style>p { font-family: serif }</style>',
|
|
23
|
+
* snippetLength: 20,
|
|
24
|
+
* });
|
|
25
|
+
* matchCount; // 1
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function searchHtmlDocument(options: {
|
|
29
|
+
readonly pattern: NativeSearchPattern;
|
|
30
|
+
readonly html: string | Uint8Array;
|
|
31
|
+
readonly snippetLength: number;
|
|
32
|
+
}): SnapshotSearchOutcome;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { nativeBinding } from './native-binding.js';
|
|
2
|
+
/**
|
|
3
|
+
* Counts the occurrences of a search pattern in one stored HTML document and
|
|
4
|
+
* cuts a snippet around the first.
|
|
5
|
+
*
|
|
6
|
+
* The document is read as UTF-8 (an invalid sequence becomes U+FFFD, as
|
|
7
|
+
* `Buffer#toString('utf8')` reads it). Positions and lengths are in Unicode
|
|
8
|
+
* scalar values, so `.` matches an emoji once. `matchCount` counts
|
|
9
|
+
* non-overlapping matches as Rust's `find_iter` walks them; the snippet is a
|
|
10
|
+
* window of `snippetLength` characters centred on the first match, with
|
|
11
|
+
* whitespace collapsed (JavaScript's `\s`) and the ends trimmed.
|
|
12
|
+
* @param options - The pattern and the document.
|
|
13
|
+
* @param options.pattern - The pattern and its flags.
|
|
14
|
+
* @param options.html - The stored markup, as a string or as UTF-8 bytes.
|
|
15
|
+
* @param options.snippetLength - Window size in characters.
|
|
16
|
+
* @returns The match count and the snippet (empty when nothing matched).
|
|
17
|
+
* @throws {Error} With code `InvalidArg` if the pattern cannot be compiled (see `validateSearchPattern`).
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const { matchCount, snippet } = searchHtmlDocument({
|
|
21
|
+
* pattern: { source: 'font-family', literal: true, ignoreCase: false, multiLine: false, dotAll: false },
|
|
22
|
+
* html: '<style>p { font-family: serif }</style>',
|
|
23
|
+
* snippetLength: 20,
|
|
24
|
+
* });
|
|
25
|
+
* matchCount; // 1
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function searchHtmlDocument(options) {
|
|
29
|
+
const { pattern, html, snippetLength } = options;
|
|
30
|
+
return nativeBinding.searchHtmlDocument(pattern, typeof html === 'string' ? Buffer.from(html, 'utf8') : html, snippetLength);
|
|
31
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { NativeSearchPattern, SnapshotSearchOutcome, StoredHtmlSnapshot } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Searches a batch of stored HTML snapshots for a pattern.
|
|
4
|
+
*
|
|
5
|
+
* Each snapshot is decompressed, read as UTF-8 and searched as
|
|
6
|
+
* {@link import('./search-html-document.js').searchHtmlDocument} does, in
|
|
7
|
+
* parallel on the native thread pool, so no more decompressed documents are
|
|
8
|
+
* alive at once than there are threads. The pattern is compiled once, not per
|
|
9
|
+
* snapshot, and the addon reuses the last compiled pattern across batches. The
|
|
10
|
+
* call waits its turn behind any other asynchronous native call when
|
|
11
|
+
* `NITPICKER_NATIVE_CONCURRENCY` calls are already running (see
|
|
12
|
+
* `checkNativeExecutorConfig`). Only the
|
|
13
|
+
* batch's stored bytes cross the boundary, as one buffer and one offsets
|
|
14
|
+
* array.
|
|
15
|
+
*
|
|
16
|
+
* A snapshot that cannot be decompressed — its zstd data is corrupt, or it
|
|
17
|
+
* decompresses past `MAX_DECODED_SNAPSHOT_BYTES` — fails the whole call; it is
|
|
18
|
+
* never reported as "no match".
|
|
19
|
+
* @param options - The pattern, the snippet size and the batch.
|
|
20
|
+
* @param options.pattern - The pattern and its flags.
|
|
21
|
+
* @param options.snippetLength - Window size in characters.
|
|
22
|
+
* @param options.snapshots - The stored snapshots, in the order the results are returned.
|
|
23
|
+
* @param options.signal - Stops the call at its next snapshot, or within the next mebibyte of a decompression under way; a call still waiting for its turn stops when the turn comes.
|
|
24
|
+
* @returns One outcome per snapshot, in input order; `matchCount` is 0 where nothing matched.
|
|
25
|
+
* @throws {Error} If a codec is not `zstd` or `none`, or the batch takes more than 4 GiB.
|
|
26
|
+
* The returned promise rejects with code `InvalidArg` if the pattern cannot be
|
|
27
|
+
* compiled or the batch is malformed, and with a plain error naming the snapshot
|
|
28
|
+
* (`snapshot <n> could not be decoded`) if its zstd data is corrupt or
|
|
29
|
+
* decompresses past the limit, and with the signal's reason if `signal`
|
|
30
|
+
* aborted before the call finished.
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const outcomes = await searchHtmlSnapshots({
|
|
34
|
+
* pattern: { source: 'gtag(', literal: true, ignoreCase: false, multiLine: false, dotAll: false },
|
|
35
|
+
* snippetLength: 160,
|
|
36
|
+
* snapshots: rows.map((row) => ({ body: row.body, codec: row.codec })),
|
|
37
|
+
* });
|
|
38
|
+
* const hits = outcomes.filter((outcome) => outcome.matchCount > 0);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function searchHtmlSnapshots(options: {
|
|
42
|
+
readonly pattern: NativeSearchPattern;
|
|
43
|
+
readonly snippetLength: number;
|
|
44
|
+
readonly snapshots: readonly StoredHtmlSnapshot[];
|
|
45
|
+
readonly signal?: AbortSignal;
|
|
46
|
+
}): Promise<SnapshotSearchOutcome[]>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { MAX_DECODED_SNAPSHOT_BYTES } from './max-decoded-snapshot-bytes.js';
|
|
2
|
+
import { nativeBinding } from './native-binding.js';
|
|
3
|
+
import { packStoredSnapshots } from './pack-stored-snapshots.js';
|
|
4
|
+
import { runWithSignal } from './run-with-signal.js';
|
|
5
|
+
/**
|
|
6
|
+
* Searches a batch of stored HTML snapshots for a pattern.
|
|
7
|
+
*
|
|
8
|
+
* Each snapshot is decompressed, read as UTF-8 and searched as
|
|
9
|
+
* {@link import('./search-html-document.js').searchHtmlDocument} does, in
|
|
10
|
+
* parallel on the native thread pool, so no more decompressed documents are
|
|
11
|
+
* alive at once than there are threads. The pattern is compiled once, not per
|
|
12
|
+
* snapshot, and the addon reuses the last compiled pattern across batches. The
|
|
13
|
+
* call waits its turn behind any other asynchronous native call when
|
|
14
|
+
* `NITPICKER_NATIVE_CONCURRENCY` calls are already running (see
|
|
15
|
+
* `checkNativeExecutorConfig`). Only the
|
|
16
|
+
* batch's stored bytes cross the boundary, as one buffer and one offsets
|
|
17
|
+
* array.
|
|
18
|
+
*
|
|
19
|
+
* A snapshot that cannot be decompressed — its zstd data is corrupt, or it
|
|
20
|
+
* decompresses past `MAX_DECODED_SNAPSHOT_BYTES` — fails the whole call; it is
|
|
21
|
+
* never reported as "no match".
|
|
22
|
+
* @param options - The pattern, the snippet size and the batch.
|
|
23
|
+
* @param options.pattern - The pattern and its flags.
|
|
24
|
+
* @param options.snippetLength - Window size in characters.
|
|
25
|
+
* @param options.snapshots - The stored snapshots, in the order the results are returned.
|
|
26
|
+
* @param options.signal - Stops the call at its next snapshot, or within the next mebibyte of a decompression under way; a call still waiting for its turn stops when the turn comes.
|
|
27
|
+
* @returns One outcome per snapshot, in input order; `matchCount` is 0 where nothing matched.
|
|
28
|
+
* @throws {Error} If a codec is not `zstd` or `none`, or the batch takes more than 4 GiB.
|
|
29
|
+
* The returned promise rejects with code `InvalidArg` if the pattern cannot be
|
|
30
|
+
* compiled or the batch is malformed, and with a plain error naming the snapshot
|
|
31
|
+
* (`snapshot <n> could not be decoded`) if its zstd data is corrupt or
|
|
32
|
+
* decompresses past the limit, and with the signal's reason if `signal`
|
|
33
|
+
* aborted before the call finished.
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const outcomes = await searchHtmlSnapshots({
|
|
37
|
+
* pattern: { source: 'gtag(', literal: true, ignoreCase: false, multiLine: false, dotAll: false },
|
|
38
|
+
* snippetLength: 160,
|
|
39
|
+
* snapshots: rows.map((row) => ({ body: row.body, codec: row.codec })),
|
|
40
|
+
* });
|
|
41
|
+
* const hits = outcomes.filter((outcome) => outcome.matchCount > 0);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export async function searchHtmlSnapshots(options) {
|
|
45
|
+
const { pattern, snippetLength, snapshots, signal } = options;
|
|
46
|
+
// Before packing: a request that is already cancelled copies nothing.
|
|
47
|
+
signal?.throwIfAborted();
|
|
48
|
+
const { bodies, offsets, codecs } = packStoredSnapshots(snapshots);
|
|
49
|
+
const { matchCounts, snippets } = await runWithSignal(signal, (cancelToken) => nativeBinding.searchHtmlSnapshots(pattern, snippetLength, bodies, offsets, codecs, MAX_DECODED_SNAPSHOT_BYTES, cancelToken));
|
|
50
|
+
return matchCounts.map((matchCount, index) => ({
|
|
51
|
+
matchCount,
|
|
52
|
+
snippet: snippets[index],
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pages per sampled block a template classification run clusters (see
|
|
3
|
+
* `createTemplateClassificationRun`); every other page of the block is
|
|
4
|
+
* assigned to the nearest of those clusters, and the merge across blocks
|
|
5
|
+
* keeps at most this many members per cluster that holds one. Read from the addon,
|
|
6
|
+
* so a caller sizing its own work by the sample cannot drift from what the
|
|
7
|
+
* run actually keeps.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const sampledPages = Math.min(blockPageCount, TEMPLATE_BLOCK_SAMPLE_SIZE);
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare const TEMPLATE_BLOCK_SAMPLE_SIZE: number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { nativeBinding } from './native-binding.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pages per sampled block a template classification run clusters (see
|
|
4
|
+
* `createTemplateClassificationRun`); every other page of the block is
|
|
5
|
+
* assigned to the nearest of those clusters, and the merge across blocks
|
|
6
|
+
* keeps at most this many members per cluster that holds one. Read from the addon,
|
|
7
|
+
* so a caller sizing its own work by the sample cannot drift from what the
|
|
8
|
+
* run actually keeps.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const sampledPages = Math.min(blockPageCount, TEMPLATE_BLOCK_SAMPLE_SIZE);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export const TEMPLATE_BLOCK_SAMPLE_SIZE = nativeBinding.TEMPLATE_BLOCK_SAMPLE_SIZE;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pages of blocks clustered whole a template classification run (see
|
|
3
|
+
* `createTemplateClassificationRun`) holds at once, at most. Clustering a
|
|
4
|
+
* block needs every page's parsed markup until its block is done, about
|
|
5
|
+
* 60 KB a page, so this bounds that memory whatever the corpus size. When
|
|
6
|
+
* the blocks clustered whole would hold more, the largest blocks of more
|
|
7
|
+
* than `TEMPLATE_BLOCK_SAMPLE_SIZE` pages are clustered from a sample
|
|
8
|
+
* instead (most pages first) until the rest fits; a block of at most that
|
|
9
|
+
* many pages frees nothing by being sampled, so none is left out for this
|
|
10
|
+
* limit. Fixed, not a setting: which blocks are sampled decides their
|
|
11
|
+
* stored keys. Read from the addon, so a caller documenting or sizing by
|
|
12
|
+
* it cannot drift from what the run actually does.
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const heldPages = Math.min(wholeBlockPageCount, TEMPLATE_EXACT_PAGE_LIMIT);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const TEMPLATE_EXACT_PAGE_LIMIT: number;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { nativeBinding } from './native-binding.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pages of blocks clustered whole a template classification run (see
|
|
4
|
+
* `createTemplateClassificationRun`) holds at once, at most. Clustering a
|
|
5
|
+
* block needs every page's parsed markup until its block is done, about
|
|
6
|
+
* 60 KB a page, so this bounds that memory whatever the corpus size. When
|
|
7
|
+
* the blocks clustered whole would hold more, the largest blocks of more
|
|
8
|
+
* than `TEMPLATE_BLOCK_SAMPLE_SIZE` pages are clustered from a sample
|
|
9
|
+
* instead (most pages first) until the rest fits; a block of at most that
|
|
10
|
+
* many pages frees nothing by being sampled, so none is left out for this
|
|
11
|
+
* limit. Fixed, not a setting: which blocks are sampled decides their
|
|
12
|
+
* stored keys. Read from the addon, so a caller documenting or sizing by
|
|
13
|
+
* it cannot drift from what the run actually does.
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const heldPages = Math.min(wholeBlockPageCount, TEMPLATE_EXACT_PAGE_LIMIT);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export const TEMPLATE_EXACT_PAGE_LIMIT = nativeBinding.TEMPLATE_EXACT_PAGE_LIMIT;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytes a block's Stage A similarity table may take before a template
|
|
3
|
+
* classification run (see `createTemplateClassificationRun`) clusters the
|
|
4
|
+
* block from a sample instead of whole. The table is an upper triangle of
|
|
5
|
+
* `f64`, `n * (n - 1) / 2 * 8` bytes for `n` pages and the largest
|
|
6
|
+
* allocation of a run, so this bounds what clustering holds whatever the
|
|
7
|
+
* corpus size. Which blocks fall over it decides their stored keys. Read
|
|
8
|
+
* from the addon, so a caller sizing or documenting the budget cannot drift
|
|
9
|
+
* from what the run actually does.
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const pairBytes = (pages: number) => (pages * (pages - 1)) / 2 * 8;
|
|
13
|
+
* const sampled = pairBytes(blockPageCount) > TEMPLATE_MEMORY_BUDGET;
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const TEMPLATE_MEMORY_BUDGET: number;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { nativeBinding } from './native-binding.js';
|
|
2
|
+
/**
|
|
3
|
+
* Bytes a block's Stage A similarity table may take before a template
|
|
4
|
+
* classification run (see `createTemplateClassificationRun`) clusters the
|
|
5
|
+
* block from a sample instead of whole. The table is an upper triangle of
|
|
6
|
+
* `f64`, `n * (n - 1) / 2 * 8` bytes for `n` pages and the largest
|
|
7
|
+
* allocation of a run, so this bounds what clustering holds whatever the
|
|
8
|
+
* corpus size. Which blocks fall over it decides their stored keys. Read
|
|
9
|
+
* from the addon, so a caller sizing or documenting the budget cannot drift
|
|
10
|
+
* from what the run actually does.
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const pairBytes = (pages: number) => (pages * (pages - 1)) / 2 * 8;
|
|
14
|
+
* const sampled = pairBytes(blockPageCount) > TEMPLATE_MEMORY_BUDGET;
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export const TEMPLATE_MEMORY_BUDGET = nativeBinding.TEMPLATE_MEMORY_BUDGET;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NativeSelectorPlan, SelectorPlan } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Rewrites a selector plan into the shape the native conversion reads: the
|
|
4
|
+
* same plan, with every `null` tag and `null` literal list left out.
|
|
5
|
+
*
|
|
6
|
+
* The native object conversion reads an optional field only when it is
|
|
7
|
+
* absent (`undefined`), not when it is `null`: a `null` list fails with
|
|
8
|
+
* "Failed to get Array length". The plan states "none" as `null`.
|
|
9
|
+
* @param plan - The selector plan.
|
|
10
|
+
* @returns A plan the native functions accept.
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* toNativeSelectorPlan(plan).alternatives[0]!.prefilterLiterals; // undefined, not null
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function toNativeSelectorPlan(plan: SelectorPlan): NativeSelectorPlan;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The conditions of a compound, with a `null` tag left out.
|
|
3
|
+
* @param conditions - A compound, or the compound inside `:not(...)`.
|
|
4
|
+
* @returns The conditions in the shape the native conversion reads.
|
|
5
|
+
*/
|
|
6
|
+
function toNativeConditions(conditions) {
|
|
7
|
+
const { tag, attributes, nth } = conditions;
|
|
8
|
+
return tag === null ? { attributes, nth } : { tag, attributes, nth };
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Rewrites a selector plan into the shape the native conversion reads: the
|
|
12
|
+
* same plan, with every `null` tag and `null` literal list left out.
|
|
13
|
+
*
|
|
14
|
+
* The native object conversion reads an optional field only when it is
|
|
15
|
+
* absent (`undefined`), not when it is `null`: a `null` list fails with
|
|
16
|
+
* "Failed to get Array length". The plan states "none" as `null`.
|
|
17
|
+
* @param plan - The selector plan.
|
|
18
|
+
* @returns A plan the native functions accept.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* toNativeSelectorPlan(plan).alternatives[0]!.prefilterLiterals; // undefined, not null
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function toNativeSelectorPlan(plan) {
|
|
25
|
+
return {
|
|
26
|
+
alternatives: plan.alternatives.map((alternative) => ({
|
|
27
|
+
compounds: alternative.compounds.map((compound) => ({
|
|
28
|
+
...toNativeConditions(compound),
|
|
29
|
+
negations: compound.negations.map((negation) => toNativeConditions(negation)),
|
|
30
|
+
})),
|
|
31
|
+
combinators: alternative.combinators,
|
|
32
|
+
...(alternative.prefilterLiterals === null
|
|
33
|
+
? {}
|
|
34
|
+
: { prefilterLiterals: alternative.prefilterLiterals }),
|
|
35
|
+
direct: alternative.direct,
|
|
36
|
+
})),
|
|
37
|
+
needsChildIndex: plan.needsChildIndex,
|
|
38
|
+
needsTypeIndex: plan.needsTypeIndex,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copies row ids into the `u32` array the addon takes, refusing any value a
|
|
3
|
+
* `Uint32Array` would silently change (see `assertU32Id`).
|
|
4
|
+
* @param values - The ids (database row ids): an array or a typed array.
|
|
5
|
+
* @param what - What the ids are, for the error message.
|
|
6
|
+
* @returns The ids as a `Uint32Array`.
|
|
7
|
+
* @throws {RangeError} When a value is not an integer in `0..=4294967294`.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* toU32Ids([1, 2, 3], 'candidate ids'); // Uint32Array [1, 2, 3]
|
|
11
|
+
* toU32Ids([2 ** 32], 'candidate ids'); // throws RangeError
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function toU32Ids(values: ArrayLike<number>, what: string): Uint32Array;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { assertU32Id } from './assert-u32-id.js';
|
|
2
|
+
/**
|
|
3
|
+
* Copies row ids into the `u32` array the addon takes, refusing any value a
|
|
4
|
+
* `Uint32Array` would silently change (see `assertU32Id`).
|
|
5
|
+
* @param values - The ids (database row ids): an array or a typed array.
|
|
6
|
+
* @param what - What the ids are, for the error message.
|
|
7
|
+
* @returns The ids as a `Uint32Array`.
|
|
8
|
+
* @throws {RangeError} When a value is not an integer in `0..=4294967294`.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* toU32Ids([1, 2, 3], 'candidate ids'); // Uint32Array [1, 2, 3]
|
|
12
|
+
* toU32Ids([2 ** 32], 'candidate ids'); // throws RangeError
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function toU32Ids(values, what) {
|
|
16
|
+
const ids = new Uint32Array(values.length);
|
|
17
|
+
// `ArrayLike` has no iterator, so an index loop is the way to read it.
|
|
18
|
+
for (let index = 0; index < values.length; index++) {
|
|
19
|
+
ids[index] = assertU32Id(values[index], what);
|
|
20
|
+
}
|
|
21
|
+
return ids;
|
|
22
|
+
}
|