Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
createTextPipeline,
lowerNfkc,
type AllocationAwareRangeScanner,
type ScanInput,
type TextCensor,
type TextRangeScanner,
} from "@textfilters/core";
Expand Down Expand Up @@ -77,6 +78,7 @@ const allocationAwareScanner: AllocationAwareRangeScanner = {

const prepared = createPreparedText("a.b");
const hasRange = allocationAwareScanner.check(prepared);
const sharedInput: ScanInput = prepared;
```

## API
Expand Down Expand Up @@ -106,6 +108,10 @@ const hasRange = allocationAwareScanner.check(prepared);
- `maskCodePointRanges(codePoints, ranges, maskChar)`
- `maskCodePointRangesPreservingLength(codePoints, ranges, maskChar)`
- `censorCodePointRanges(codePoints, ranges, maskChar)`
- `ScanInput`
- `ScanHints`
- `ScanResult`
- `TextRange`

### Public Input Normalization

Expand Down Expand Up @@ -165,6 +171,11 @@ registered scanners. They are intentionally generic; URL, email, phone,
profanity, spam, and future packages keep their own package-specific detection
logic.

`ScanInput`, `ScanHints`, and `ScanResult` are short shared aliases for the
allocation-aware prepared input, reusable text hints, and pipeline scan result
shape. The longer `PreparedText`, `TextHints`, and
`TextRangePipelineScanResult` names remain supported for existing callers.

`AllocationAwareRangeScanner` separates a cheap pre-scan `check()` gate from
sink-based `scan()`. A true `check()` result means the scanner is eligible to
scan the prepared input; it is not itself proof that a range exists.
Expand Down
4 changes: 4 additions & 0 deletions src/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ export interface TextRangePipelineScanResult {
readonly scanResults: readonly TextRangeScanResult[];
}

export type ScanHints = TextHints;
export type ScanInput = PreparedText;
export type ScanResult = TextRangePipelineScanResult;

export interface TextRangePipelineCensorResult {
readonly text: string;
readonly ranges: readonly TextCodePointRange[];
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export type {
PreparedText,
RangeMatch,
RangeMatchSink,
ScanHints,
ScanInput,
ScanResult,
TextCensor,
TextCodePointRange,
TextGuard,
Expand Down
50 changes: 49 additions & 1 deletion tests/contracts.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { describe, expect, it } from "vitest";
import type { TextCensor, TextGuard, TextGuardResult } from "../src/index.js";
import type {
ScanHints,
ScanInput,
ScanResult,
TextCensor,
TextGuard,
TextGuardResult,
TextRange,
} from "../src/index.js";

describe("textfilters core contracts", () => {
it("allows censors and guards to share stable shapes", () => {
Expand All @@ -19,4 +27,44 @@ describe("textfilters core contracts", () => {
expect(censor.censor("secret")).toBe("******");
expect(guard.check({ text: "value" })).toEqual(result);
});

it("exposes short scanner contract aliases for shared scanner work", () => {
const range: TextRange = [1, 3];
const hints: ScanHints = {
textLength: 3,
codePointLength: 3,
isEmpty: false,
hasAsciiOnly: true,
hasNonAscii: false,
hasDigit: false,
digitCount: 0,
hasAsciiLetter: true,
hasWhitespace: false,
hasPunctuation: false,
punctuationCount: 0,
hasAtSign: false,
hasDot: false,
hasSlash: false,
hasColon: false,
hasPlus: false,
};
const input: ScanInput = {
text: "abc",
codePoints: ["a", "b", "c"],
hints,
};
const result: ScanResult = {
text: input.text,
codePoints: input.codePoints,
ranges: [range],
scanResults: [{ ranges: [range] }],
};

expect(result).toEqual({
text: "abc",
codePoints: ["a", "b", "c"],
ranges: [[1, 3]],
scanResults: [{ ranges: [[1, 3]] }],
});
});
});