text-sanctifier 1.0.20 → 1.1.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/ADDITIONAL_TERMS.md +122 -122
- package/LICENSE +694 -694
- package/README.md +43 -2
- package/dist/text-sanctifier.min.js +12 -9
- package/dist/types/index.d.ts +2 -1
- package/dist/types/inspectText.d.ts +69 -0
- package/dist/types/sanctifyText.d.ts +2 -2
- package/package.json +69 -69
- package/robots.txt +79 -79
- package/src/index.d.ts +5 -4
- package/src/index.js +12 -12
- package/src/inspectText.js +339 -174
- package/src/sanctifyText.js +507 -507
package/README.md
CHANGED
|
@@ -5,12 +5,15 @@
|
|
|
5
5
|
[](https://bundlephobia.com/package/text-sanctifier)
|
|
6
6
|
[](https://github.com/iWhatty/text-sanctifier/blob/main/LICENSE)
|
|
7
7
|
[](https://github.com/iWhatty/text-sanctifier)
|
|
8
|
+
[](https://www.npmjs.com/package/text-sanctifier)
|
|
8
9
|
|
|
9
|
-
Brutal text normalizer and invisible Unicode scrubber for modern web projects. ~
|
|
10
|
+
Brutal text normalizer and invisible Unicode scrubber for modern web projects. ~2.17 KB gzipped.
|
|
10
11
|
|
|
11
12
|
## Features
|
|
12
13
|
|
|
13
14
|
- Purges zero-width Unicode garbage
|
|
15
|
+
- Purges bidi controls, including the isolates (U+2066–U+2069) and the Arabic letter mark (U+061C) used in Trojan Source attacks
|
|
16
|
+
- Locates invisible and control characters by offset, line and column (`inspectTextDetailed`)
|
|
14
17
|
- Normalizes line endings (CRLF, CR, LF) to LF
|
|
15
18
|
- Collapses unwanted spaces and paragraphs
|
|
16
19
|
- Nukes control characters (if enabled)
|
|
@@ -137,6 +140,42 @@ const report = inspectText(input);
|
|
|
137
140
|
|
|
138
141
|
Use `inspectText` to preflight text content before rendering, storing, or linting. It's a diagnostic tool to help inform sanitization needs. Pass the report to `getRecommendedSanctifierOptions(report)` to auto-generate config flags for `summonSanctifier()`.
|
|
139
142
|
|
|
143
|
+
### `inspectTextDetailed(text: string, options?: { maxFindings?: number }): DetailedTrashReport`
|
|
144
|
+
|
|
145
|
+
Returns each invisible or control character with its offset, line, column, code point and category, plus per-category counts and a `truncated` flag. Also exported from the browser build (`text-sanctifier/browser`). `inspectText`'s output is unchanged.
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
import { inspectTextDetailed } from 'text-sanctifier';
|
|
149
|
+
|
|
150
|
+
const { findings, counts, total, truncated } = inspectTextDetailed(input, { maxFindings: 100 });
|
|
151
|
+
|
|
152
|
+
/*
|
|
153
|
+
findings: [
|
|
154
|
+
{ offset: 0, line: 1, column: 1, codePoint: 0xFEFF, category: 'bom', atStart: true },
|
|
155
|
+
{ offset: 42, line: 3, column: 7, codePoint: 0x2067, category: 'bidi_control' },
|
|
156
|
+
]
|
|
157
|
+
counts: { bidi_control: 1, zero_width: 0, nonbreaking_space: 0, bom: 1, nul: 0, c0_control: 0, c1_control: 0 }
|
|
158
|
+
total: 2
|
|
159
|
+
truncated: false
|
|
160
|
+
*/
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
| Category | Code points |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| `bidi_control` | U+061C, U+200E, U+200F, U+202A–U+202E, U+2066–U+2069 |
|
|
166
|
+
| `zero_width` | U+200B–U+200D, U+2060 |
|
|
167
|
+
| `nonbreaking_space` | U+00A0, U+2000–U+200A, U+202F, U+3000 (non-breaking and typographic spaces) |
|
|
168
|
+
| `bom` | U+FEFF; `atStart` is true at offset 0, where a BOM is legitimate |
|
|
169
|
+
| `nul` | U+0000 |
|
|
170
|
+
| `c0_control` | U+0001–U+001F except tab, LF and CR; U+007F |
|
|
171
|
+
| `c1_control` | U+0080–U+009F |
|
|
172
|
+
|
|
173
|
+
`offset` is a 0-based UTF-16 index; `line` and `column` are 1-based, with columns in UTF-16 code units and lines ending at LF, CR or CRLF. Every occurrence is counted; only the first `maxFindings` (default 100, `Infinity` for all) are listed, and `truncated` says when some were not. The scan is one pass with no regex and no copy of the input.
|
|
174
|
+
|
|
175
|
+
`zero_width` also flags U+200D (zero width joiner) inside emoji ZWJ sequences such as 👨👩👧, so a finding there is not necessarily hidden text. Filter by neighbouring code points if you need to tell them apart. (`purgeInvisibleChars` removes those joiners too, splitting the emoji; `keyboardOnlyEmoji` keeps the sequences whole.)
|
|
176
|
+
|
|
177
|
+
The categories cover exactly what `nukeControls` and `purgeInvisibleChars` strip.
|
|
178
|
+
|
|
140
179
|
---
|
|
141
180
|
|
|
142
181
|
## Notes
|
|
@@ -145,12 +184,14 @@ Use `inspectText` to preflight text content before rendering, storing, or lintin
|
|
|
145
184
|
|
|
146
185
|
Requires a modern JavaScript runtime with ES2020+ support:
|
|
147
186
|
|
|
148
|
-
- Node.js
|
|
187
|
+
- Node.js 18+ (`engines.node >=18`)
|
|
149
188
|
- Modern evergreen browsers
|
|
150
189
|
|
|
151
190
|
### Package and build info
|
|
152
191
|
|
|
153
192
|
- **Source (`src/`):** ES2020+ ESM modules with JSDoc
|
|
193
|
+
- **ESM only:** no CommonJS build; `require('text-sanctifier')` works only on Node versions with `require(esm)` support (20.19+, 22.12+)
|
|
194
|
+
- **Types:** TypeScript declarations ship in `dist/types`
|
|
154
195
|
- **Browser build (`dist/`):** Minified ESM bundle for `<script type="module">`
|
|
155
196
|
- **Tree-shake friendly:** ships `sideEffects: false`
|
|
156
197
|
- **Zero transpilation:** no built-in polyfills or runtime overhead
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
var F=/[\u2018\u2019\u201A\u201B\u2032\u2035]/g,G=/[\u201C\u201D\u201E\u201F\u2033\u2036\u00AB\u00BB]/g,H=/[\u2012\u2013\u2014\u2015\u2212]/g,I=/\u2026/g,J=/[\u2022\u00B7]/g,K=/[\uFF01-\uFF5E]/g;function E(a){return a.replace(F,"'").replace(G,'"').replace(H,"-").replace(I,"...").replace(J,"*").replace(K,c=>String.fromCharCode(c.charCodeAt(0)-65248))}var
|
|
6
|
-
var x=/\r\n|\r|\n/g,y=/[ \t]*(\n+)[ \t]*/g,B=/\n{2,}/g,A=/\n{3,}/g,C=/ {2,}/g,v=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F\u0080-\u009F\u200E\u200F\u202A-\u202E]+/g;function L(a,c){a.lastIndex=0;return a.test(c)}
|
|
7
|
-
function M(a){if("string"!==typeof a)throw new TypeError("inspectText expects a string input.");const c=[],
|
|
8
|
-
var
|
|
9
|
-
|
|
1
|
+
function n(a={}){const c=!!a.purgeInvisibleChars,d=!!a.purgeEmojis,f=!!a.nukeControls,g=!!a.keyboardOnlyFilter,l=!!a.normalizeNewlines,h=!!a.trimSpacesAroundNewlines,b=!!a.collapseNewLines,e=!!a.preserveParagraphs,k=!!a.collapseSpaces,m=!!a.finalTrim,p=Number.isFinite(a.maxLength)&&0<=a.maxLength?a.maxLength:Infinity,q="truncate"===a.g||"noop"===a.g||"throw"===a.g?a.g:"throw";return z=>r(z,c,d,f,g,l,h,b,e,k,m,p,q)}n.strict=a=>r(a,!0,!0,!0,!1,!0,!0,!0,!1,!0,!0);
|
|
2
|
+
n.loose=a=>r(a,!1,!1,!1,!1,!0,!0,!0,!0,!0,!0);n.keyboardOnlyEmoji=a=>r(a,!1,!1,!1,!0,!0,!0,!1,!1,!1,!0);n.keyboardOnly=a=>r(a,!0,!0,!0,!0,!0,!0,!0,!1,!0,!0);
|
|
3
|
+
function r(a,c=!1,d=!1,f=!1,g=!1,l=!1,h=!1,b=!1,e=!1,k=!1,m=!1,p=Infinity,q="throw"){if("string"!==typeof a)throw new TypeError("sanctifyText expects a string input.");"truncate"!==q&&"noop"!==q&&"throw"!==q&&(q="throw");if(a.length>p)switch(q){case "truncate":a=a.slice(0,p);break;case "noop":return a;default:throw new RangeError(`sanctifyText input length ${a.length} exceeds maxLength ${p}.`);}c&&(a=a.replace(t,""));d&&(a=a.replace(u,""));f&&(a=a.replace(v,""));g&&(a=w(a,d));l&&(a=a.replace(x,"\n"));
|
|
4
|
+
h&&(a=a.replace(y,"$1"));b&&(c=a,a=e?c.replace(A,"\n\n"):c.replace(B,"\n"));k&&(a=a.replace(C," "));return m?a.trim():a}var t=/[\u00A0\u2000-\u200D\u202F\u2060\u3000\uFEFF\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]+/g,D=/[^\x20-\x7E\r\n]+/gu;function w(a,c=!1){a=E(a);return c?a.replace(D,""):a.replace(D,d=>{u.lastIndex=0;if(u.test(d)){u.lastIndex=0;var f="";for(const g of d.matchAll(u))f+=g[0];d=f}else d="";return d})}
|
|
5
|
+
var F=/[\u2018\u2019\u201A\u201B\u2032\u2035]/g,G=/[\u201C\u201D\u201E\u201F\u2033\u2036\u00AB\u00BB]/g,H=/[\u2012\u2013\u2014\u2015\u2212]/g,I=/\u2026/g,J=/[\u2022\u00B7]/g,K=/[\uFF01-\uFF5E]/g;function E(a){return a.replace(F,"'").replace(G,'"').replace(H,"-").replace(I,"...").replace(J,"*").replace(K,c=>String.fromCharCode(c.charCodeAt(0)-65248))}var u;try{u=RegExp("(?:\\p{Extended_Pictographic}(?:\\uFE0F|\\uFE0E)?(?:\\u200D(?:\\p{Extended_Pictographic}|\\w)+)*)","gu")}catch{u=/[\u{2700}-\u{27BF}\u{1F300}-\u{1FAFF}\u{1F3FB}-\u{1F3FF}\u200D\uFE0F\u{1F1E6}-\u{1F1FF}]/gu}
|
|
6
|
+
var x=/\r\n|\r|\n/g,y=/[ \t]*(\n+)[ \t]*/g,B=/\n{2,}/g,A=/\n{3,}/g,C=/ {2,}/g,v=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F\u0080-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]+/g;function L(a,c){a.lastIndex=0;return a.test(c)}
|
|
7
|
+
function M(a){if("string"!==typeof a)throw new TypeError("inspectText expects a string input.");const c=[],d={hasControlChars:!1,hasInvisibleChars:!1,hasMixedNewlines:!1,newlineStyle:null,hasEmojis:!1,hasNonKeyboardChars:!1,summary:c};L(v,a)&&(d.hasControlChars=!0,c.push("Control characters detected."));L(t,a)&&(d.hasInvisibleChars=!0,c.push("Invisible Unicode characters detected."));L(u,a)&&(d.hasEmojis=!0,c.push("Emojis detected."));if("string"!==typeof a)throw new TypeError("getNewlineStats expects a string input.");
|
|
8
|
+
var f=0,g=0;let l=0;for(let k=0,m=a.length;k<m;k++){const p=a.charCodeAt(k);13===p?10===a.charCodeAt(k+1)?(f++,k++):g++:10===p&&l++}f={i:f,h:g,j:l};g=[];0<f.i&&g.push("CRLF");0<f.h&&g.push("CR");0<f.j&&g.push("LF");const {l:h,types:b}={...f,types:g,l:1<g.length};d.hasMixedNewlines=h;d.newlineStyle=h?"Mixed":b[0]||null;d.newlineStyle&&c.push(h?"Mixed newline styles detected.":`Consistent newline style: ${d.newlineStyle}`);a:{a=E(a);if(L(D,a))for(e of a)if(!("\n"===e||"\r"===e||" "<=e&&"~">=e||L(u,
|
|
9
|
+
e))){var e=!0;break a}e=!1}e&&(d.hasNonKeyboardChars=!0,c.push("Non-keyboard characters detected."));return d}
|
|
10
|
+
function N(a,c={}){if("string"!==typeof a)throw new TypeError("inspectTextDetailed expects a string input.");c=c&&c.maxFindings;c=Infinity===c||Number.isInteger(c)&&0<=c?c:100;const d={bidi_control:0,zero_width:0,nonbreaking_space:0,bom:0,nul:0,c0_control:0,c1_control:0},f=[];let g=0,l=1,h=0;for(let e=0,k=a.length;e<k;e++){var b=a.charCodeAt(e);if(32<=b&&127>b)continue;if(10===b){l++;h=e+1;continue}if(13===b){10!==a.charCodeAt(e+1)&&(l++,h=e+1);continue}const m=128>b?0===b?"nul":32>b?9===b||10===
|
|
11
|
+
b||13===b?null:"c0_control":127===b?"c0_control":null:159>=b?"c1_control":160===b?"nonbreaking_space":1564===b?"bidi_control":8192>b?null:8202>=b?"nonbreaking_space":8205>=b?"zero_width":8207>=b||8234<=b&&8238>=b?"bidi_control":8239===b?"nonbreaking_space":8288===b?"zero_width":8294<=b&&8297>=b?"bidi_control":12288===b?"nonbreaking_space":65279===b?"bom":null;null!==m&&(d[m]++,g++,f.length<c&&(b={offset:e,line:l,column:e-h+1,codePoint:b,category:m},"bom"===m&&(b.atStart=0===e),f.push(b)))}return{findings:f,
|
|
12
|
+
counts:d,total:g,truncated:g>f.length}}function O(a){return{purgeInvisibleChars:a.hasInvisibleChars,purgeEmojis:a.hasEmojis,nukeControls:a.hasControlChars,keyboardOnlyFilter:a.hasNonKeyboardChars,normalizeNewlines:a.hasMixedNewlines||"CRLF"===a.newlineStyle||"CR"===a.newlineStyle}}export { n as summonSanctifier, M as inspectText, O as getRecommendedSanctifierOptions, N as inspectTextDetailed };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { inspectText } from './inspectText.js';
|
|
2
|
+
import { inspectTextDetailed } from './inspectText.js';
|
|
2
3
|
import { getRecommendedSanctifierOptions } from './inspectText.js';
|
|
3
4
|
import { summonSanctifier } from './sanctifyText.js';
|
|
4
|
-
export { inspectText, getRecommendedSanctifierOptions, summonSanctifier };
|
|
5
|
+
export { inspectText, inspectTextDetailed, getRecommendedSanctifierOptions, summonSanctifier };
|
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
* @param {string} text @returns {UnicodeTrashReport}
|
|
4
4
|
*/
|
|
5
5
|
export function inspectText(text: string): UnicodeTrashReport;
|
|
6
|
+
/**
|
|
7
|
+
* Locates invisible and control characters, one finding per character.
|
|
8
|
+
*
|
|
9
|
+
* Categories:
|
|
10
|
+
* - `bidi_control`: U+061C, U+200E, U+200F, U+202A–U+202E, U+2066–U+2069
|
|
11
|
+
* - `zero_width`: U+200B–U+200D, U+2060
|
|
12
|
+
* - `nonbreaking_space`: non-breaking and typographic spaces U+00A0, U+2000–U+200A, U+202F, U+3000
|
|
13
|
+
* - `bom`: U+FEFF (`atStart` says whether it sits at offset 0)
|
|
14
|
+
* - `nul`: U+0000
|
|
15
|
+
* - `c0_control`: U+0001–U+001F except tab, LF and CR; and U+007F
|
|
16
|
+
* - `c1_control`: U+0080–U+009F
|
|
17
|
+
*
|
|
18
|
+
* Every occurrence is counted; only the first `maxFindings` are listed.
|
|
19
|
+
* One pass over the string, no regex, no copy.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} text
|
|
22
|
+
* @param {InspectDetailedOptions} [options]
|
|
23
|
+
* @returns {DetailedTrashReport}
|
|
24
|
+
*/
|
|
25
|
+
export function inspectTextDetailed(text: string, options?: InspectDetailedOptions): DetailedTrashReport;
|
|
6
26
|
/**
|
|
7
27
|
* Counts the number of different newline types in a string.
|
|
8
28
|
* @param {string} text
|
|
@@ -36,3 +56,52 @@ export type UnicodeTrashReport = {
|
|
|
36
56
|
hasNonKeyboardChars: boolean;
|
|
37
57
|
summary: string[];
|
|
38
58
|
};
|
|
59
|
+
export type TrashCategory = "bidi_control" | "zero_width" | "nonbreaking_space" | "bom" | "nul" | "c0_control" | "c1_control";
|
|
60
|
+
/**
|
|
61
|
+
* One located character.
|
|
62
|
+
* - `offset`: 0-based UTF-16 index into the input (a JS string index).
|
|
63
|
+
* - `line`: 1-based; lines end at LF, CR, or CRLF (counted once).
|
|
64
|
+
* - `column`: 1-based, in UTF-16 code units from the start of the line.
|
|
65
|
+
* - `atStart`: present on `bom` findings only; true at offset 0, where a BOM is legitimate.
|
|
66
|
+
*/
|
|
67
|
+
export type TrashFinding = {
|
|
68
|
+
offset: number;
|
|
69
|
+
line: number;
|
|
70
|
+
column: number;
|
|
71
|
+
codePoint: number;
|
|
72
|
+
category: TrashCategory;
|
|
73
|
+
atStart?: boolean;
|
|
74
|
+
};
|
|
75
|
+
export type TrashCounts = {
|
|
76
|
+
bidi_control: number;
|
|
77
|
+
zero_width: number;
|
|
78
|
+
nonbreaking_space: number;
|
|
79
|
+
bom: number;
|
|
80
|
+
nul: number;
|
|
81
|
+
c0_control: number;
|
|
82
|
+
c1_control: number;
|
|
83
|
+
};
|
|
84
|
+
export type DetailedTrashReport = {
|
|
85
|
+
/**
|
|
86
|
+
* - In offset order, at most `maxFindings` long.
|
|
87
|
+
*/
|
|
88
|
+
findings: TrashFinding[];
|
|
89
|
+
/**
|
|
90
|
+
* - Every occurrence per category, listed or not.
|
|
91
|
+
*/
|
|
92
|
+
counts: TrashCounts;
|
|
93
|
+
/**
|
|
94
|
+
* - Sum of `counts`.
|
|
95
|
+
*/
|
|
96
|
+
total: number;
|
|
97
|
+
/**
|
|
98
|
+
* - True when `total` exceeds `findings.length`.
|
|
99
|
+
*/
|
|
100
|
+
truncated: boolean;
|
|
101
|
+
};
|
|
102
|
+
export type InspectDetailedOptions = {
|
|
103
|
+
/**
|
|
104
|
+
* - Cap on listed findings (non-negative integer or Infinity).
|
|
105
|
+
*/
|
|
106
|
+
maxFindings?: number;
|
|
107
|
+
};
|
|
@@ -123,7 +123,7 @@ export function normalizeTypographicJank(text: string): string;
|
|
|
123
123
|
* Targets:
|
|
124
124
|
* - Non-breaking spaces (\u00A0)
|
|
125
125
|
* - Zero-width spaces and miscellaneous Unicode spaces (\u2000–\u200D, \u202F, \u2060, \u3000, \uFEFF)
|
|
126
|
-
* -
|
|
126
|
+
* - Bidi controls: marks, embeddings/overrides and isolates (\u061C, \u200E, \u200F, \u202A–\u202E, \u2066–\u2069)
|
|
127
127
|
*
|
|
128
128
|
* @param {string} text
|
|
129
129
|
* @returns {string}
|
|
@@ -145,7 +145,7 @@ export let EMOJI_REGEX: RegExp;
|
|
|
145
145
|
* Control characters nuked:
|
|
146
146
|
* - ASCII control range (0x00-0x1F, 0x7F)
|
|
147
147
|
* - Unicode control range (0x80-0x9F)
|
|
148
|
-
* -
|
|
148
|
+
* - Bidi controls (U+061C, U+200E, U+200F, U+202A–U+202E, U+2066–U+2069)
|
|
149
149
|
*
|
|
150
150
|
* @param {string} text
|
|
151
151
|
* @returns {string}
|
package/package.json
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "text-sanctifier",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"type": "module",
|
|
5
|
-
"description": "A brutal text normalizer and invisible trash scrubber for modern web projects.",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": ">=18"
|
|
8
|
-
},
|
|
9
|
-
"main": "./src/index.js",
|
|
10
|
-
"module": "./src/index.js",
|
|
11
|
-
"browser": "./dist/text-sanctifier.min.js",
|
|
12
|
-
"files": [
|
|
13
|
-
"src",
|
|
14
|
-
"dist/text-sanctifier.min.js",
|
|
15
|
-
"dist/types",
|
|
16
|
-
"LICENSE",
|
|
17
|
-
"README.md",
|
|
18
|
-
"ADDITIONAL_TERMS.md",
|
|
19
|
-
"robots.txt"
|
|
20
|
-
],
|
|
21
|
-
"exports": {
|
|
22
|
-
".": {
|
|
23
|
-
"types": "./dist/types/index.d.ts",
|
|
24
|
-
"default": "./src/index.js"
|
|
25
|
-
},
|
|
26
|
-
"./browser": {
|
|
27
|
-
"types": "./dist/types/index.d.ts",
|
|
28
|
-
"default": "./dist/text-sanctifier.min.js"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"types": "./dist/types/index.d.ts",
|
|
32
|
-
"sideEffects": false,
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "node scripts/buildc.js",
|
|
35
|
-
"build:types": "tsc -p tsconfig.types.json",
|
|
36
|
-
"test": "node tests/sanctifyText.test.js",
|
|
37
|
-
"test-min": "node tests/sanctifyText.test.min.js",
|
|
38
|
-
"ci": "npm run test && npm run build && npm run build:types && npm run test-min"
|
|
39
|
-
},
|
|
40
|
-
"keywords": [
|
|
41
|
-
"text",
|
|
42
|
-
"sanitize",
|
|
43
|
-
"normalize",
|
|
44
|
-
"invisible",
|
|
45
|
-
"scrubber",
|
|
46
|
-
"unicode",
|
|
47
|
-
"clean",
|
|
48
|
-
"sanctify"
|
|
49
|
-
],
|
|
50
|
-
"author": "WATT3D <WATT3D@protonmail.com>",
|
|
51
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
52
|
-
"repository": {
|
|
53
|
-
"type": "git",
|
|
54
|
-
"url": "git+https://github.com/iWhatty/text-sanctifier.git"
|
|
55
|
-
},
|
|
56
|
-
"bugs": {
|
|
57
|
-
"url": "https://github.com/iWhatty/text-sanctifier/issues"
|
|
58
|
-
},
|
|
59
|
-
"homepage": "https://github.com/iWhatty/text-sanctifier#readme",
|
|
60
|
-
"directories": {
|
|
61
|
-
"test": "tests"
|
|
62
|
-
},
|
|
63
|
-
"devDependencies": {
|
|
64
|
-
"esbuild": "^0.25.3",
|
|
65
|
-
"google-closure-compiler": "^20240317.0.0",
|
|
66
|
-
"terser": "^5.39.0",
|
|
67
|
-
"typescript": "^5.9.3"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "text-sanctifier",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A brutal text normalizer and invisible trash scrubber for modern web projects.",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18"
|
|
8
|
+
},
|
|
9
|
+
"main": "./src/index.js",
|
|
10
|
+
"module": "./src/index.js",
|
|
11
|
+
"browser": "./dist/text-sanctifier.min.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"src",
|
|
14
|
+
"dist/text-sanctifier.min.js",
|
|
15
|
+
"dist/types",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"README.md",
|
|
18
|
+
"ADDITIONAL_TERMS.md",
|
|
19
|
+
"robots.txt"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/types/index.d.ts",
|
|
24
|
+
"default": "./src/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./browser": {
|
|
27
|
+
"types": "./dist/types/index.d.ts",
|
|
28
|
+
"default": "./dist/text-sanctifier.min.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"types": "./dist/types/index.d.ts",
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "node scripts/buildc.js",
|
|
35
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
36
|
+
"test": "node tests/sanctifyText.test.js && node tests/inspectTextDetailed.test.js",
|
|
37
|
+
"test-min": "node tests/sanctifyText.test.min.js",
|
|
38
|
+
"ci": "npm run test && npm run build && npm run build:types && npm run test-min"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"text",
|
|
42
|
+
"sanitize",
|
|
43
|
+
"normalize",
|
|
44
|
+
"invisible",
|
|
45
|
+
"scrubber",
|
|
46
|
+
"unicode",
|
|
47
|
+
"clean",
|
|
48
|
+
"sanctify"
|
|
49
|
+
],
|
|
50
|
+
"author": "WATT3D <WATT3D@protonmail.com>",
|
|
51
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/iWhatty/text-sanctifier.git"
|
|
55
|
+
},
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/iWhatty/text-sanctifier/issues"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/iWhatty/text-sanctifier#readme",
|
|
60
|
+
"directories": {
|
|
61
|
+
"test": "tests"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"esbuild": "^0.25.3",
|
|
65
|
+
"google-closure-compiler": "^20240317.0.0",
|
|
66
|
+
"terser": "^5.39.0",
|
|
67
|
+
"typescript": "^5.9.3"
|
|
68
|
+
}
|
|
69
|
+
}
|
package/robots.txt
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
# WATT3D — AI scraping policy
|
|
2
|
-
#
|
|
3
|
-
# This file enumerates known AI / LLM training and inference crawlers
|
|
4
|
-
# that the WATT3D AI Training Rider does not consent to. See
|
|
5
|
-
# ./ADDITIONAL_TERMS.md for the legal scope and definitions.
|
|
6
|
-
#
|
|
7
|
-
# Honoring robots.txt is voluntary. The rider applies whether or not
|
|
8
|
-
# a bot respects this file. The enumeration is non-exhaustive — bots
|
|
9
|
-
# not listed here are still bound by the rider if they perform
|
|
10
|
-
# Training Use as defined in ADDITIONAL_TERMS.md §1.
|
|
11
|
-
|
|
12
|
-
User-agent: GPTBot
|
|
13
|
-
Disallow: /
|
|
14
|
-
|
|
15
|
-
User-agent: ChatGPT-User
|
|
16
|
-
Disallow: /
|
|
17
|
-
|
|
18
|
-
User-agent: OAI-SearchBot
|
|
19
|
-
Disallow: /
|
|
20
|
-
|
|
21
|
-
User-agent: anthropic-ai
|
|
22
|
-
Disallow: /
|
|
23
|
-
|
|
24
|
-
User-agent: ClaudeBot
|
|
25
|
-
Disallow: /
|
|
26
|
-
|
|
27
|
-
User-agent: Claude-Web
|
|
28
|
-
Disallow: /
|
|
29
|
-
|
|
30
|
-
User-agent: Claude-SearchBot
|
|
31
|
-
Disallow: /
|
|
32
|
-
|
|
33
|
-
User-agent: Google-Extended
|
|
34
|
-
Disallow: /
|
|
35
|
-
|
|
36
|
-
User-agent: Applebot-Extended
|
|
37
|
-
Disallow: /
|
|
38
|
-
|
|
39
|
-
User-agent: Meta-ExternalAgent
|
|
40
|
-
Disallow: /
|
|
41
|
-
|
|
42
|
-
User-agent: Meta-ExternalFetcher
|
|
43
|
-
Disallow: /
|
|
44
|
-
|
|
45
|
-
User-agent: FacebookBot
|
|
46
|
-
Disallow: /
|
|
47
|
-
|
|
48
|
-
User-agent: CCBot
|
|
49
|
-
Disallow: /
|
|
50
|
-
|
|
51
|
-
User-agent: PerplexityBot
|
|
52
|
-
Disallow: /
|
|
53
|
-
|
|
54
|
-
User-agent: Perplexity-User
|
|
55
|
-
Disallow: /
|
|
56
|
-
|
|
57
|
-
User-agent: cohere-ai
|
|
58
|
-
Disallow: /
|
|
59
|
-
|
|
60
|
-
User-agent: Bytespider
|
|
61
|
-
Disallow: /
|
|
62
|
-
|
|
63
|
-
User-agent: Amazonbot
|
|
64
|
-
Disallow: /
|
|
65
|
-
|
|
66
|
-
User-agent: Omgilibot
|
|
67
|
-
Disallow: /
|
|
68
|
-
|
|
69
|
-
User-agent: AI2Bot
|
|
70
|
-
Disallow: /
|
|
71
|
-
|
|
72
|
-
User-agent: Diffbot
|
|
73
|
-
Disallow: /
|
|
74
|
-
|
|
75
|
-
# Everyone else: full access. Search engines and human-driven crawlers
|
|
76
|
-
# remain welcome.
|
|
77
|
-
|
|
78
|
-
User-agent: *
|
|
79
|
-
Allow: /
|
|
1
|
+
# WATT3D — AI scraping policy
|
|
2
|
+
#
|
|
3
|
+
# This file enumerates known AI / LLM training and inference crawlers
|
|
4
|
+
# that the WATT3D AI Training Rider does not consent to. See
|
|
5
|
+
# ./ADDITIONAL_TERMS.md for the legal scope and definitions.
|
|
6
|
+
#
|
|
7
|
+
# Honoring robots.txt is voluntary. The rider applies whether or not
|
|
8
|
+
# a bot respects this file. The enumeration is non-exhaustive — bots
|
|
9
|
+
# not listed here are still bound by the rider if they perform
|
|
10
|
+
# Training Use as defined in ADDITIONAL_TERMS.md §1.
|
|
11
|
+
|
|
12
|
+
User-agent: GPTBot
|
|
13
|
+
Disallow: /
|
|
14
|
+
|
|
15
|
+
User-agent: ChatGPT-User
|
|
16
|
+
Disallow: /
|
|
17
|
+
|
|
18
|
+
User-agent: OAI-SearchBot
|
|
19
|
+
Disallow: /
|
|
20
|
+
|
|
21
|
+
User-agent: anthropic-ai
|
|
22
|
+
Disallow: /
|
|
23
|
+
|
|
24
|
+
User-agent: ClaudeBot
|
|
25
|
+
Disallow: /
|
|
26
|
+
|
|
27
|
+
User-agent: Claude-Web
|
|
28
|
+
Disallow: /
|
|
29
|
+
|
|
30
|
+
User-agent: Claude-SearchBot
|
|
31
|
+
Disallow: /
|
|
32
|
+
|
|
33
|
+
User-agent: Google-Extended
|
|
34
|
+
Disallow: /
|
|
35
|
+
|
|
36
|
+
User-agent: Applebot-Extended
|
|
37
|
+
Disallow: /
|
|
38
|
+
|
|
39
|
+
User-agent: Meta-ExternalAgent
|
|
40
|
+
Disallow: /
|
|
41
|
+
|
|
42
|
+
User-agent: Meta-ExternalFetcher
|
|
43
|
+
Disallow: /
|
|
44
|
+
|
|
45
|
+
User-agent: FacebookBot
|
|
46
|
+
Disallow: /
|
|
47
|
+
|
|
48
|
+
User-agent: CCBot
|
|
49
|
+
Disallow: /
|
|
50
|
+
|
|
51
|
+
User-agent: PerplexityBot
|
|
52
|
+
Disallow: /
|
|
53
|
+
|
|
54
|
+
User-agent: Perplexity-User
|
|
55
|
+
Disallow: /
|
|
56
|
+
|
|
57
|
+
User-agent: cohere-ai
|
|
58
|
+
Disallow: /
|
|
59
|
+
|
|
60
|
+
User-agent: Bytespider
|
|
61
|
+
Disallow: /
|
|
62
|
+
|
|
63
|
+
User-agent: Amazonbot
|
|
64
|
+
Disallow: /
|
|
65
|
+
|
|
66
|
+
User-agent: Omgilibot
|
|
67
|
+
Disallow: /
|
|
68
|
+
|
|
69
|
+
User-agent: AI2Bot
|
|
70
|
+
Disallow: /
|
|
71
|
+
|
|
72
|
+
User-agent: Diffbot
|
|
73
|
+
Disallow: /
|
|
74
|
+
|
|
75
|
+
# Everyone else: full access. Search engines and human-driven crawlers
|
|
76
|
+
# remain welcome.
|
|
77
|
+
|
|
78
|
+
User-agent: *
|
|
79
|
+
Allow: /
|
package/src/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { inspectText } from './inspectText.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { inspectText } from './inspectText.js';
|
|
2
|
+
import { inspectTextDetailed } from './inspectText.js';
|
|
3
|
+
import { getRecommendedSanctifierOptions } from './inspectText.js';
|
|
4
|
+
import { summonSanctifier } from './sanctifyText.js';
|
|
5
|
+
export { inspectText, inspectTextDetailed, getRecommendedSanctifierOptions, summonSanctifier };
|
package/src/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// src/index.js
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { inspectText, getRecommendedSanctifierOptions } from './inspectText.js';
|
|
5
|
-
export { inspectText, getRecommendedSanctifierOptions };
|
|
6
|
-
|
|
7
|
-
import { summonSanctifier } from './sanctifyText.js';
|
|
8
|
-
export { summonSanctifier };
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// In Future: export helpers for power users
|
|
12
|
-
// export { purgeInvisibleTrash, purgeEmojisCharacters, normalizeNewlines, trimSpacesAroundNewlines, collapseParagraphs, collapseExtraSpaces, purgeControlCharacters } from './sanctifyText.js';
|
|
1
|
+
// src/index.js
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { inspectText, inspectTextDetailed, getRecommendedSanctifierOptions } from './inspectText.js';
|
|
5
|
+
export { inspectText, inspectTextDetailed, getRecommendedSanctifierOptions };
|
|
6
|
+
|
|
7
|
+
import { summonSanctifier } from './sanctifyText.js';
|
|
8
|
+
export { summonSanctifier };
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// In Future: export helpers for power users
|
|
12
|
+
// export { purgeInvisibleTrash, purgeEmojisCharacters, normalizeNewlines, trimSpacesAroundNewlines, collapseParagraphs, collapseExtraSpaces, purgeControlCharacters } from './sanctifyText.js';
|