@mailwoman/normalize 9.1.0 → 9.2.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/README.md CHANGED
@@ -61,7 +61,7 @@ Stage 1 in the [Staged Pipeline Contract](https://github.com/sister-software/mai
61
61
 
62
62
  - [`@mailwoman/query-shape`](../query-shape) — Stage 1.5, structural priors that consume the normalized output
63
63
  - [Staged Pipeline Contract](https://github.com/sister-software/mailwoman/blob/main/docs/engineering/reference/STAGES.mdx)
64
- - [Tokenization concepts](https://mailwoman.sister.software/articles/concepts/tokenization/)
64
+ - [Tokenization concepts](https://mailwoman.ai/articles/concepts/tokenization/)
65
65
 
66
66
  ## License
67
67
 
package/cjk.ts CHANGED
@@ -16,6 +16,9 @@
16
16
  * 1, a full-width `-` always a hyphen — keyboards and copy-paste produce these constantly.
17
17
  * Folding them to ASCII makes `104−0061` and `104-0061` the same input.
18
18
  * - **Fold the ideographic space (U+3000 → ' ').**
19
+ * - **Fold half-width katakana (U+FF61–U+FF9F).** This matches the JP corpus builder. A voiced
20
+ * pair such as `デ` contracts from two UTF-16 units to one `デ`; the output offset maps to the
21
+ * first raw unit in the pair.
19
22
  *
20
23
  * It deliberately does NOT convert **kanji numerals** (一二三…): place names carry numeral kanji as
21
24
  * ordinary characters (三田 _Mita_, 四谷 _Yotsuya_), so a blind 三→3 would corrupt them.
@@ -59,6 +62,13 @@ const IDEOGRAPHIC_SPACE = 0x30_00
59
62
  * 〒.
60
63
  */
61
64
  const POSTAL_MARK = 0x30_12
65
+ const HALFWIDTH_KATAKANA_START = 0xff_61
66
+ const HALFWIDTH_KATAKANA_END = 0xff_9f
67
+ const HALFWIDTH_VOICING_START = 0xff_9e
68
+
69
+ function isHalfwidthKatakana(code: number): boolean {
70
+ return code >= HALFWIDTH_KATAKANA_START && code <= HALFWIDTH_KATAKANA_END
71
+ }
62
72
 
63
73
  export function applyCjkNormalization(input: string): CjkResult {
64
74
  let folded = 0
@@ -93,6 +103,30 @@ export function applyCjkNormalization(input: string): CjkResult {
93
103
  continue
94
104
  }
95
105
 
106
+ if (isHalfwidthKatakana(code)) {
107
+ const next = input.charCodeAt(i + 1)
108
+
109
+ const consumesVoicingMark =
110
+ code < HALFWIDTH_VOICING_START && next >= HALFWIDTH_VOICING_START && next <= HALFWIDTH_KATAKANA_END
111
+
112
+ const width = consumesVoicingMark ? 2 : 1
113
+
114
+ const normalized = input
115
+ .slice(i, i + width)
116
+ .normalize("NFKC")
117
+ .normalize("NFC")
118
+
119
+ for (const unit of normalized) {
120
+ out.push(unit)
121
+ map.push(i)
122
+ }
123
+
124
+ folded += width
125
+ i += width - 1
126
+
127
+ continue
128
+ }
129
+
96
130
  out.push(input[i]!)
97
131
  map.push(i)
98
132
  }
package/out/cjk.d.ts CHANGED
@@ -16,6 +16,9 @@
16
16
  * 1, a full-width `-` always a hyphen — keyboards and copy-paste produce these constantly.
17
17
  * Folding them to ASCII makes `104−0061` and `104-0061` the same input.
18
18
  * - **Fold the ideographic space (U+3000 → ' ').**
19
+ * - **Fold half-width katakana (U+FF61–U+FF9F).** This matches the JP corpus builder. A voiced
20
+ * pair such as `デ` contracts from two UTF-16 units to one `デ`; the output offset maps to the
21
+ * first raw unit in the pair.
19
22
  *
20
23
  * It deliberately does NOT convert **kanji numerals** (一二三…): place names carry numeral kanji as
21
24
  * ordinary characters (三田 _Mita_, 四谷 _Yotsuya_), so a blind 三→3 would corrupt them.
package/out/cjk.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cjk.d.ts","sourceRoot":"","sources":["../cjk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,EAAE,CAAA;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;CAChB;AAoBD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CA0C9D"}
1
+ {"version":3,"file":"cjk.d.ts","sourceRoot":"","sources":["../cjk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,EAAE,CAAA;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;CAChB;AA2BD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAkE9D"}
package/out/cjk.js CHANGED
@@ -16,6 +16,9 @@
16
16
  * 1, a full-width `-` always a hyphen — keyboards and copy-paste produce these constantly.
17
17
  * Folding them to ASCII makes `104−0061` and `104-0061` the same input.
18
18
  * - **Fold the ideographic space (U+3000 → ' ').**
19
+ * - **Fold half-width katakana (U+FF61–U+FF9F).** This matches the JP corpus builder. A voiced
20
+ * pair such as `デ` contracts from two UTF-16 units to one `デ`; the output offset maps to the
21
+ * first raw unit in the pair.
19
22
  *
20
23
  * It deliberately does NOT convert **kanji numerals** (一二三…): place names carry numeral kanji as
21
24
  * ordinary characters (三田 _Mita_, 四谷 _Yotsuya_), so a blind 三→3 would corrupt them.
@@ -44,6 +47,12 @@ const IDEOGRAPHIC_SPACE = 0x30_00;
44
47
  * 〒.
45
48
  */
46
49
  const POSTAL_MARK = 0x30_12;
50
+ const HALFWIDTH_KATAKANA_START = 0xff_61;
51
+ const HALFWIDTH_KATAKANA_END = 0xff_9f;
52
+ const HALFWIDTH_VOICING_START = 0xff_9e;
53
+ function isHalfwidthKatakana(code) {
54
+ return code >= HALFWIDTH_KATAKANA_START && code <= HALFWIDTH_KATAKANA_END;
55
+ }
47
56
  export function applyCjkNormalization(input) {
48
57
  let folded = 0;
49
58
  let stripped = 0;
@@ -69,6 +78,22 @@ export function applyCjkNormalization(input) {
69
78
  folded += 1;
70
79
  continue;
71
80
  }
81
+ if (isHalfwidthKatakana(code)) {
82
+ const next = input.charCodeAt(i + 1);
83
+ const consumesVoicingMark = code < HALFWIDTH_VOICING_START && next >= HALFWIDTH_VOICING_START && next <= HALFWIDTH_KATAKANA_END;
84
+ const width = consumesVoicingMark ? 2 : 1;
85
+ const normalized = input
86
+ .slice(i, i + width)
87
+ .normalize("NFKC")
88
+ .normalize("NFC");
89
+ for (const unit of normalized) {
90
+ out.push(unit);
91
+ map.push(i);
92
+ }
93
+ folded += width;
94
+ i += width - 1;
95
+ continue;
96
+ }
72
97
  out.push(input[i]);
73
98
  map.push(i);
74
99
  }
package/out/cjk.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cjk.js","sourceRoot":"","sources":["../cjk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAe7C;;GAEG;AACH,MAAM,eAAe,GAAG,OAAO,CAAA;AAC/B;;GAEG;AACH,MAAM,aAAa,GAAG,OAAO,CAAA;AAC7B;;GAEG;AACH,MAAM,kBAAkB,GAAG,OAAO,CAAA;AAClC,MAAM,iBAAiB,GAAG,OAAO,CAAA;AACjC;;GAEG;AACH,MAAM,WAAW,GAAG,OAAO,CAAA;AAE3B,MAAM,UAAU,qBAAqB,CAAC,KAAa;IAClD,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,MAAM,GAAG,GAAa,EAAE,CAAA;IAExB,gGAAgG;IAChG,oFAAoF;IACpF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QAEhC,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAC1B,QAAQ,IAAI,CAAC,CAAA;YAEb,SAAQ,CAAC,yEAAyE;QACnF,CAAC;QAED,IAAI,IAAI,IAAI,eAAe,IAAI,IAAI,IAAI,aAAa,EAAE,CAAC;YACtD,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,GAAG,kBAAkB,CAAC,CAAC,CAAA;YACxD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACX,MAAM,IAAI,CAAC,CAAA;YAEX,SAAQ;QACT,CAAC;QAED,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAChC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACb,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACX,MAAM,IAAI,CAAC,CAAA;YAEX,SAAQ;QACT,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAA;QACnB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACZ,CAAC;IAED,IAAI,MAAM,KAAK,CAAC,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAA;IAC/E,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;AACrD,CAAC"}
1
+ {"version":3,"file":"cjk.js","sourceRoot":"","sources":["../cjk.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"punctuation.d.ts","sourceRoot":"","sources":["../punctuation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiBH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CA8BjE"}
1
+ {"version":3,"file":"punctuation.d.ts","sourceRoot":"","sources":["../punctuation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CA8BjE"}
@@ -14,8 +14,10 @@ const REPLACEMENTS = new Map([
14
14
  ["”", '"'], // ”
15
15
  ["–", "-"], // – en dash
16
16
  ["—", "-"], // — em dash
17
+ ["‐", "-"], // ‐ U+2010 hyphen
17
18
  ["−", "-"], // − U+2212 minus sign — Japanese IMEs emit this as the block separator (1−2−3)
18
19
  ["―", "-"], // ― U+2015 horizontal bar — another common JP block separator
20
+ ["﹣", "-"], // ﹣ U+FE63 small hyphen-minus
19
21
  ["…", "..."], // … expands; tracked specially
20
22
  [" ", " "], // non-breaking space
21
23
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"punctuation.js","sourceRoot":"","sources":["../punctuation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAiB;IAC5C,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;IACxB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;IACxB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,+EAA+E;IAC3F,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,8DAA8D;IAC1E,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,+BAA+B;IAC7C,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,qBAAqB;CACjC,CAAC,CAAA;AAQF,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC7C,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,MAAM,GAAG,GAAa,EAAE,CAAA;IAExB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAE,CAAA;QACpB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAEhC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACZ,CAAC;aAAM,CAAC;YACP,OAAO,GAAG,IAAI,CAAA;YACd,YAAY,IAAI,CAAC,CAAA;YAEjB,mGAAmG;YACnG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAA;gBACjB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACZ,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAA;IACxE,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAA;AACjD,CAAC"}
1
+ {"version":3,"file":"punctuation.js","sourceRoot":"","sources":["../punctuation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAiB;IAC5C,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI;IAChB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;IACxB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;IACxB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,kBAAkB;IAC9B,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,+EAA+E;IAC3F,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,8DAA8D;IAC1E,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,8BAA8B;IAC1C,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,+BAA+B;IAC7C,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,qBAAqB;CACjC,CAAC,CAAA;AAQF,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC7C,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,MAAM,GAAG,GAAa,EAAE,CAAA;IAExB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAE,CAAA;QACpB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAEhC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACZ,CAAC;aAAM,CAAC;YACP,OAAO,GAAG,IAAI,CAAA;YACd,YAAY,IAAI,CAAC,CAAA;YAEjB,mGAAmG;YACnG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAA;gBACjB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACZ,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAA;IACxE,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAA;AACjD,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@mailwoman/normalize",
3
- "version": "9.1.0",
3
+ "version": "9.2.0",
4
4
  "description": "Stage 1 of the runtime pipeline — deterministic input preprocessing (Unicode NFC, punctuation, whitespace, abbreviation). Pure functions, no ML.",
5
5
  "license": "AGPL-3.0-only OR LicenseRef-Commercial",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/sister-software/mailwoman.git",
9
- "directory": "normalize"
9
+ "directory": "packages/normalize"
10
10
  },
11
11
  "files": [
12
12
  "out/**/*.js",
@@ -20,7 +20,8 @@
20
20
  "!*.test.ts",
21
21
  "!*.test.tsx",
22
22
  "!**/*.test.ts",
23
- "!**/*.test.tsx"
23
+ "!**/*.test.tsx",
24
+ "!test/**"
24
25
  ],
25
26
  "type": "module",
26
27
  "exports": {
@@ -28,6 +29,34 @@
28
29
  ".": {
29
30
  "types": "./out/index.d.ts",
30
31
  "default": "./out/index.js"
32
+ },
33
+ "./abbreviations": {
34
+ "types": "./out/abbreviations.d.ts",
35
+ "default": "./out/abbreviations.js"
36
+ },
37
+ "./cjk": {
38
+ "types": "./out/cjk.d.ts",
39
+ "default": "./out/cjk.js"
40
+ },
41
+ "./compute": {
42
+ "types": "./out/compute.d.ts",
43
+ "default": "./out/compute.js"
44
+ },
45
+ "./nfc": {
46
+ "types": "./out/nfc.d.ts",
47
+ "default": "./out/nfc.js"
48
+ },
49
+ "./offset-map": {
50
+ "types": "./out/offset-map.d.ts",
51
+ "default": "./out/offset-map.js"
52
+ },
53
+ "./punctuation": {
54
+ "types": "./out/punctuation.d.ts",
55
+ "default": "./out/punctuation.js"
56
+ },
57
+ "./whitespace": {
58
+ "types": "./out/whitespace.d.ts",
59
+ "default": "./out/whitespace.js"
31
60
  }
32
61
  },
33
62
  "publishConfig": {
@@ -37,6 +66,34 @@
37
66
  ".": {
38
67
  "types": "./out/index.d.ts",
39
68
  "default": "./out/index.js"
69
+ },
70
+ "./abbreviations": {
71
+ "types": "./out/abbreviations.d.ts",
72
+ "default": "./out/abbreviations.js"
73
+ },
74
+ "./cjk": {
75
+ "types": "./out/cjk.d.ts",
76
+ "default": "./out/cjk.js"
77
+ },
78
+ "./compute": {
79
+ "types": "./out/compute.d.ts",
80
+ "default": "./out/compute.js"
81
+ },
82
+ "./nfc": {
83
+ "types": "./out/nfc.d.ts",
84
+ "default": "./out/nfc.js"
85
+ },
86
+ "./offset-map": {
87
+ "types": "./out/offset-map.d.ts",
88
+ "default": "./out/offset-map.js"
89
+ },
90
+ "./punctuation": {
91
+ "types": "./out/punctuation.d.ts",
92
+ "default": "./out/punctuation.js"
93
+ },
94
+ "./whitespace": {
95
+ "types": "./out/whitespace.d.ts",
96
+ "default": "./out/whitespace.js"
40
97
  }
41
98
  }
42
99
  }
package/punctuation.ts CHANGED
@@ -16,8 +16,10 @@ const REPLACEMENTS = new Map<string, string>([
16
16
  ["”", '"'], // ”
17
17
  ["–", "-"], // – en dash
18
18
  ["—", "-"], // — em dash
19
+ ["‐", "-"], // ‐ U+2010 hyphen
19
20
  ["−", "-"], // − U+2212 minus sign — Japanese IMEs emit this as the block separator (1−2−3)
20
21
  ["―", "-"], // ― U+2015 horizontal bar — another common JP block separator
22
+ ["﹣", "-"], // ﹣ U+FE63 small hyphen-minus
21
23
  ["…", "..."], // … expands; tracked specially
22
24
  [" ", " "], // non-breaking space
23
25
  ])