@h-ai/datapipe 1.0.0-beta.2 → 1.0.0-beta.20
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.en.md +23 -19
- package/README.ja.md +22 -18
- package/README.md +24 -20
- package/dist/index.d.ts +2 -1
- package/dist/index.js +76 -17
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.en.md
CHANGED
|
@@ -4,25 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
[Framework home](../../README.en.md) · Related modules: [@h-ai/core](../core/README.en.md)
|
|
6
6
|
|
|
7
|
-
## Introduction
|
|
8
|
-
|
|
9
7
|
A data processing pipeline module for text cleaning (`clean`), chunking (`chunk`), and composable pipelines (`pipeline`). Pure functions; no initialization required.
|
|
10
8
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
HTML removal extracts text; it is not an HTML security sanitizer. Use the UI's safe rendering mechanism before rendering HTML. Built-in tag and email cleaning avoids repeated backtracking on long malformed input. Custom regular expressions must come from trusted configuration, not external user-supplied patterns.
|
|
14
|
-
|
|
15
|
-
| Feature | Description |
|
|
16
|
-
| -------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
17
|
-
| Text cleaning | Remove HTML tags, URLs, and emails; normalize whitespace; apply custom regex replacements |
|
|
18
|
-
| Text chunking | Sentences, paragraphs, Markdown headings, page breaks, word counts, characters, and custom separators |
|
|
19
|
-
| Pipeline composition | Chain cleaning → transformation → chunking → postprocessing in a single execution |
|
|
20
|
-
|
|
21
|
-
> Security: `customReplacements` and `separator` in `mode: 'custom'` are used as regular expressions. Only provide trusted, reviewed patterns; do not interpolate user input directly into regexes, to avoid ReDoS or unintended broad replacements.
|
|
22
|
-
|
|
23
|
-
## Getting started
|
|
24
|
-
|
|
25
|
-
### Quick start
|
|
9
|
+
## Quick Start
|
|
26
10
|
|
|
27
11
|
```ts
|
|
28
12
|
import { datapipe, HaiDatapipeError } from '@h-ai/datapipe'
|
|
@@ -51,6 +35,18 @@ if (!result.success)
|
|
|
51
35
|
throw new Error(result.error.message)
|
|
52
36
|
```
|
|
53
37
|
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
HTML removal extracts text; it is not an HTML security sanitizer. Use the UI's safe rendering mechanism before rendering HTML. Built-in tag and email cleaning avoids repeated backtracking on long malformed input. Custom regular expressions must come from trusted configuration, not external user-supplied patterns.
|
|
41
|
+
|
|
42
|
+
| Feature | Description |
|
|
43
|
+
| -------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| Text cleaning | Remove HTML tags, URLs, and emails; normalize whitespace; apply custom regex replacements |
|
|
45
|
+
| Text chunking | Sentences, paragraphs, Markdown headings, page breaks, word counts, characters, and custom separators |
|
|
46
|
+
| Pipeline composition | Chain cleaning → transformation → chunking → postprocessing in a single execution |
|
|
47
|
+
|
|
48
|
+
> Security: `customReplacements` and `separator` in `mode: 'custom'` are used as regular expressions. Only provide trusted, reviewed patterns; do not interpolate user input directly into regexes, to avoid ReDoS or unintended broad replacements.
|
|
49
|
+
|
|
54
50
|
### Chunking modes
|
|
55
51
|
|
|
56
52
|
| Mode | Description |
|
|
@@ -65,7 +61,15 @@ if (!result.success)
|
|
|
65
61
|
|
|
66
62
|
Chunk `maxSize` defaults to 1500; `overlap` defaults to 0 and must satisfy `0 <= overlap < maxSize`. Both use non-whitespace words in word mode (continuous Chinese can be one long word), and Unicode code points in every other mode, rather than UTF-16 length, bytes or model tokens. The limit includes overlap and separators. Natural sentence/paragraph/page/custom boundaries only guide split positions; oversized segments use a `maxSize-overlap` sliding window. Original whitespace, punctuation, page markers and custom separators are preserved, so removing overlap reconstructs the source. Chunks are not trimmed or joined with added newlines. Markdown overlaps only within each section, uses the same hard limit and ignores headings inside fenced code. Only `markdownKeepTitle=false` explicitly removes heading lines. Empty or entirely whitespace input returns no chunks. Custom regular expressions must come from trusted configuration; invalid expressions return CHUNK_FAILED.
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
This module has no init, global YAML or persistent connection. Pass clean/chunk options per call; pipeline options belong to that pipeline. Choose mode, maxSize and overlap for the source structure; custom regex patterns must come from trusted configuration.
|
|
67
|
+
|
|
68
|
+
[Per-option purpose, use cases and examples](../../docs/usage/configuration/ai.md).
|
|
69
|
+
|
|
70
|
+
## Error Handling
|
|
71
|
+
|
|
72
|
+
Check result.success for domain operations. Handle failures with the module error definitions and safe messages; retain codes, correlation IDs and sanitized causes in server logs. Synchronous tools, factories, stream iteration and lifecycle calls follow their own signatures. A completed Promise alone is not business success. See each feature for recovery limits.
|
|
69
73
|
|
|
70
74
|
All operations return `HaiResult<T>`; check `result.success` for success or failure. Error codes use the string format `hai:datapipe:NNN`.
|
|
71
75
|
|
|
@@ -86,7 +90,7 @@ if (!result.success) {
|
|
|
86
90
|
}
|
|
87
91
|
```
|
|
88
92
|
|
|
89
|
-
## Development
|
|
93
|
+
## Development
|
|
90
94
|
|
|
91
95
|
```bash
|
|
92
96
|
pnpm --filter @h-ai/datapipe test
|
package/README.ja.md
CHANGED
|
@@ -4,25 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
[フレームワークのホーム](../../README.ja.md) · 関連モジュール:[@h-ai/core](../core/README.ja.md)
|
|
6
6
|
|
|
7
|
-
## 概要
|
|
8
|
-
|
|
9
7
|
テキストのクリーニング(clean)、分割(chunk)、パイプラインの合成(pipeline)を提供するデータ処理モジュールです。純粋関数で構成され、初期化は不要です。
|
|
10
8
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
HTML 除去はテキスト抽出であり、安全な HTML 消毒ではありません。HTML として表示する際は UI の安全な描画機構を使用してください。組み込みのタグ・メール処理は長い不正入力での反復バックトラックを避けます。独自正規表現は信頼できる設定から与え、外部ユーザーの任意パターンを直接使用しないでください。
|
|
14
|
-
|
|
15
|
-
| 機能 | 説明 |
|
|
16
|
-
| ---------------------- | --------------------------------------------------------------------- |
|
|
17
|
-
| テキストのクリーニング | HTML タグ・URL・Email の除去、空白の正規化、独自の正規表現による置換 |
|
|
18
|
-
| テキストの分割 | 文、段落、Markdown 見出し、改ページ、単語数、文字数、独自の区切り文字 |
|
|
19
|
-
| パイプラインの合成 | クリーニング → 変換 → 分割 → 後処理を連結し、一度に実行 |
|
|
20
|
-
|
|
21
|
-
> セキュリティ:`customReplacements` と `mode: 'custom'` の `separator` は正規表現として使用されます。信頼できる検証済みのパターンのみを渡し、ReDoS や意図しない広範囲の置換を防ぐため、ユーザー入力を直接正規表現に組み込まないでください。
|
|
22
|
-
|
|
23
|
-
## 使い始める
|
|
24
|
-
|
|
25
|
-
### クイックスタート
|
|
9
|
+
## クイックスタート
|
|
26
10
|
|
|
27
11
|
```ts
|
|
28
12
|
import { datapipe, HaiDatapipeError } from '@h-ai/datapipe'
|
|
@@ -51,6 +35,18 @@ if (!result.success)
|
|
|
51
35
|
throw new Error(result.error.message)
|
|
52
36
|
```
|
|
53
37
|
|
|
38
|
+
## 機能
|
|
39
|
+
|
|
40
|
+
HTML 除去はテキスト抽出であり、安全な HTML 消毒ではありません。HTML として表示する際は UI の安全な描画機構を使用してください。組み込みのタグ・メール処理は長い不正入力での反復バックトラックを避けます。独自正規表現は信頼できる設定から与え、外部ユーザーの任意パターンを直接使用しないでください。
|
|
41
|
+
|
|
42
|
+
| 機能 | 説明 |
|
|
43
|
+
| ---------------------- | --------------------------------------------------------------------- |
|
|
44
|
+
| テキストのクリーニング | HTML タグ・URL・Email の除去、空白の正規化、独自の正規表現による置換 |
|
|
45
|
+
| テキストの分割 | 文、段落、Markdown 見出し、改ページ、単語数、文字数、独自の区切り文字 |
|
|
46
|
+
| パイプラインの合成 | クリーニング → 変換 → 分割 → 後処理を連結し、一度に実行 |
|
|
47
|
+
|
|
48
|
+
> セキュリティ:`customReplacements` と `mode: 'custom'` の `separator` は正規表現として使用されます。信頼できる検証済みのパターンのみを渡し、ReDoS や意図しない広範囲の置換を防ぐため、ユーザー入力を直接正規表現に組み込まないでください。
|
|
49
|
+
|
|
54
50
|
### 分割モード
|
|
55
51
|
|
|
56
52
|
| モード | 説明 |
|
|
@@ -65,7 +61,15 @@ if (!result.success)
|
|
|
65
61
|
|
|
66
62
|
分割の `maxSize` は既定1500、`overlap` は既定0で `0 <= overlap < maxSize` が必要です。word モードは非空白の語数(連続する中国語は1語になる場合があります)、その他は Unicode code point を単位とし、UTF-16 length・バイト・モデル token ではありません。重複と区切り文字も上限に含みます。自然な文・段落・ページ・独自境界は切点の優先度だけを決め、長い部分は `maxSize-overlap` で進みます。元の空白、句読点、改ページ、独自区切りを維持し、重複を除けば原文を復元できます。trim や改行の追加はしません。Markdown の重複は section 内だけで同じ上限を使い、コードフェンス内の見出しを本文として扱います。`markdownKeepTitle=false` の場合だけ見出し行を除きます。空または全空白の入力は空配列です。独自正規表現は信頼済み設定に限定し、不正な式は CHUNK_FAILED を返します。
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
## 設定
|
|
65
|
+
|
|
66
|
+
init・グローバル YAML・永続接続はありません。clean/chunk の指定は呼出しごと、pipeline の指定はそのパイプラインに属します。元文書の構造に応じ mode・maxSize・overlap を選び、独自正規表現は信頼する設定のみを使ってください。
|
|
67
|
+
|
|
68
|
+
[項目別の用途・適用場面・例](../../docs/usage/configuration/ai.md).
|
|
69
|
+
|
|
70
|
+
## エラー処理
|
|
71
|
+
|
|
72
|
+
領域操作は result.success を確認し、失敗時はモジュールのエラー定義と安全な説明を使います。コード・関連 ID・秘匿した原因をサーバーログに残します。同期ツール・ファクトリー・ストリーム反復・ライフサイクルは各署名に従い、Promise 完了だけで成功と判断しません。回復条件は各機能を参照してください。
|
|
69
73
|
|
|
70
74
|
すべての操作は `HaiResult<T>` を返します。`result.success` で成功・失敗を判定します。エラーコードは文字列形式 `hai:datapipe:NNN` です。
|
|
71
75
|
|
package/README.md
CHANGED
|
@@ -4,25 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
[框架首页](../../README.md) · 相关模块:[@h-ai/core](../core/README.md)
|
|
6
6
|
|
|
7
|
-
## 简介
|
|
8
|
-
|
|
9
7
|
数据处理管线模块,提供文本清洗(clean)、分块(chunk)和可组合管线(pipeline)功能。纯函数模块,无需初始化。
|
|
10
8
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
HTML 清洗用于提取文本,不是安全消毒;结果用于 HTML 渲染时仍需使用 UI 的安全渲染机制。内置标签与邮箱清洗处理长异常输入时避免重复回溯;自定义正则来自可信配置,不直接接收外部用户提交的模式。
|
|
14
|
-
|
|
15
|
-
| 功能 | 说明 |
|
|
16
|
-
| -------- | ----------------------------------------------------------- |
|
|
17
|
-
| 文本清洗 | 移除 HTML 标签、URL、Email,标准化空白,自定义正则替换 |
|
|
18
|
-
| 文本分块 | 句子、段落、Markdown 标题、分页符、字数、字符、自定义分隔符 |
|
|
19
|
-
| 管线组合 | 链式组合清洗 → 转换 → 分块 → 分块后处理,一次执行 |
|
|
20
|
-
|
|
21
|
-
> 安全提示:`customReplacements` 与 `mode: 'custom'` 的 `separator` 会作为正则使用。仅传入受信任、已审查的模式;不要把用户输入直接拼进正则,避免 ReDoS 或意外大范围替换。
|
|
22
|
-
|
|
23
|
-
## 使用入门
|
|
24
|
-
|
|
25
|
-
### 快速开始
|
|
9
|
+
## 快速开始
|
|
26
10
|
|
|
27
11
|
```ts
|
|
28
12
|
import { datapipe, HaiDatapipeError } from '@h-ai/datapipe'
|
|
@@ -51,6 +35,18 @@ if (!result.success)
|
|
|
51
35
|
throw new Error(result.error.message)
|
|
52
36
|
```
|
|
53
37
|
|
|
38
|
+
## 功能
|
|
39
|
+
|
|
40
|
+
HTML 清洗用于提取文本,不是安全消毒;结果用于 HTML 渲染时仍需使用 UI 的安全渲染机制。内置标签与邮箱清洗处理长异常输入时避免重复回溯;自定义正则来自可信配置,不直接接收外部用户提交的模式。
|
|
41
|
+
|
|
42
|
+
| 功能 | 说明 |
|
|
43
|
+
| -------- | ----------------------------------------------------------- |
|
|
44
|
+
| 文本清洗 | 移除 HTML 标签、URL、Email,标准化空白,自定义正则替换 |
|
|
45
|
+
| 文本分块 | 句子、段落、Markdown 标题、分页符、字数、字符、自定义分隔符 |
|
|
46
|
+
| 管线组合 | 链式组合清洗 → 转换 → 分块 → 分块后处理,一次执行 |
|
|
47
|
+
|
|
48
|
+
> 安全提示:`customReplacements` 与 `mode: 'custom'` 的 `separator` 会作为正则使用。仅传入受信任、已审查的模式;不要把用户输入直接拼进正则,避免 ReDoS 或意外大范围替换。
|
|
49
|
+
|
|
54
50
|
### 分块模式
|
|
55
51
|
|
|
56
52
|
| 模式 | 说明 |
|
|
@@ -63,9 +59,17 @@ if (!result.success)
|
|
|
63
59
|
| character | 按字符数分块 |
|
|
64
60
|
| custom | 自定义分隔符(需提供 separator) |
|
|
65
61
|
|
|
66
|
-
分块 `maxSize` 默认 1500,`overlap` 默认 0 且必须满足 `0 <= overlap < maxSize`。word 模式两者均按非空白词计量(连续中文可视为一个长词),其余模式均按 Unicode code point 计量,不是 UTF-16 length、字节或模型 token。上限包含重叠与分隔符;自然句/段/页/自定义边界只影响优先切点,超长段统一按 `maxSize-overlap`
|
|
62
|
+
分块 `maxSize` 默认 1500,`overlap` 默认 0 且必须满足 `0 <= overlap < maxSize`。word 模式两者均按非空白词计量(连续中文可视为一个长词),其余模式均按 Unicode code point 计量,不是 UTF-16 length、字节或模型 token。上限包含重叠与分隔符;自然句/段/页/自定义边界只影响优先切点,超长段统一按 `maxSize-overlap` 滑窗。保留原始空白、标点、分页符及自定义分隔符,移除重叠后可还原全文;分块保留原始文本,不做 split/join 或 trim。Markdown section 之间不重叠,section 内使用相同硬上限,代码围栏内的标题保留为正文;仅 `markdownKeepTitle=false` 明确移除标题行。空/全空白的整体输入返回空数组。自定义正则须由可信配置提供,非法表达式返回 CHUNK_FAILED。
|
|
63
|
+
|
|
64
|
+
## 配置
|
|
65
|
+
|
|
66
|
+
本模块没有 init、全局 YAML 或持久连接;clean/chunk 的选项按每次调用传入,pipeline 的步骤选项属于当前管线。按文本结构选择 mode、maxSize、overlap;自定义正则仅来自可信配置。
|
|
67
|
+
|
|
68
|
+
[逐项配置说明、适用场景和示例](../../docs/usage/configuration/ai.md).
|
|
69
|
+
|
|
70
|
+
## 错误处理
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
领域操作先判断 `result.success`,失败按本模块错误定义与安全提示处理,服务端保留错误码、关联编号和脱敏原因。同步工具、工厂、流迭代及生命周期按各自签名处理,不把 Promise 完成视为业务成功。具体失败与恢复边界见对应功能。
|
|
69
73
|
|
|
70
74
|
所有操作返回 `HaiResult<T>`,通过 `result.success` 判断成功或失败。错误码为字符串格式 `hai:datapipe:NNN`。
|
|
71
75
|
|
|
@@ -92,7 +96,7 @@ if (!result.success) {
|
|
|
92
96
|
pnpm --filter @h-ai/datapipe test
|
|
93
97
|
```
|
|
94
98
|
|
|
95
|
-
源码示例区分无需生命周期的纯函数、同步 HaiResult 与异步管线;类型检查方法见[模块 JSDoc 约定](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证)
|
|
99
|
+
源码示例区分无需生命周期的纯函数、同步 HaiResult 与异步管线;类型检查方法见[模块 JSDoc 约定](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证).
|
|
96
100
|
|
|
97
101
|
## 许可证
|
|
98
102
|
|
package/dist/index.d.ts
CHANGED
|
@@ -344,4 +344,5 @@ interface DatapipeFunctions {
|
|
|
344
344
|
*/
|
|
345
345
|
declare const datapipe: DatapipeFunctions;
|
|
346
346
|
|
|
347
|
-
export {
|
|
347
|
+
export { ChunkModeSchema, ChunkOptionsSchema, CleanOptionsSchema, HaiDatapipeError, datapipe };
|
|
348
|
+
export type { ChunkMode, ChunkOperations, ChunkOptions, ChunkOptionsInput, ChunkTransformFn, CleanOperations, CleanOptions, CleanOptionsInput, DataChunk, DatapipeFunctions, PipelineBuilder, PipelineResult, PipelineStep, TransformFn };
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,9 @@ var ChunkOptionsSchema = z.object({
|
|
|
51
51
|
markdownMinLevel: z.number().int().min(1).max(6).default(2),
|
|
52
52
|
/** 是否保留 Markdown 标题在分块内容中(默认 true) */
|
|
53
53
|
markdownKeepTitle: z.boolean().default(true)
|
|
54
|
-
}).refine((options) => options.overlap < options.maxSize, {
|
|
54
|
+
}).refine((options) => options.overlap < options.maxSize, {
|
|
55
|
+
path: ["overlap"]
|
|
56
|
+
});
|
|
55
57
|
|
|
56
58
|
// messages/en-US.json
|
|
57
59
|
var en_US_default = {
|
|
@@ -147,7 +149,9 @@ function splitCharacters(text, maxSize, overlap, expression) {
|
|
|
147
149
|
return chunks;
|
|
148
150
|
}
|
|
149
151
|
function splitWords(text, maxSize, overlap) {
|
|
150
|
-
const words = [
|
|
152
|
+
const words = [
|
|
153
|
+
...text.matchAll(/\S+/gu)
|
|
154
|
+
];
|
|
151
155
|
const chunks = [];
|
|
152
156
|
for (let start = 0; start < words.length; ) {
|
|
153
157
|
const end = Math.min(start + maxSize, words.length);
|
|
@@ -183,14 +187,35 @@ function markdownSections(text, minLevel) {
|
|
|
183
187
|
end--;
|
|
184
188
|
if (end < title.length && (title[end - 1] === " " || title[end - 1] === " "))
|
|
185
189
|
title = title.slice(0, end).trimEnd();
|
|
186
|
-
headings.push({
|
|
190
|
+
headings.push({
|
|
191
|
+
start: line.index,
|
|
192
|
+
bodyStart: line.index + line[0].length,
|
|
193
|
+
title,
|
|
194
|
+
level: heading[1].length
|
|
195
|
+
});
|
|
187
196
|
}
|
|
188
197
|
}
|
|
189
|
-
if (headings.length === 0)
|
|
190
|
-
return [
|
|
198
|
+
if (headings.length === 0) {
|
|
199
|
+
return [
|
|
200
|
+
{
|
|
201
|
+
start: 0,
|
|
202
|
+
bodyStart: 0,
|
|
203
|
+
end: text.length,
|
|
204
|
+
title: "",
|
|
205
|
+
level: 0
|
|
206
|
+
}
|
|
207
|
+
];
|
|
208
|
+
}
|
|
191
209
|
const sections = [];
|
|
192
|
-
if (headings[0].start > 0)
|
|
193
|
-
sections.push({
|
|
210
|
+
if (headings[0].start > 0) {
|
|
211
|
+
sections.push({
|
|
212
|
+
start: 0,
|
|
213
|
+
bodyStart: 0,
|
|
214
|
+
end: headings[0].start,
|
|
215
|
+
title: "",
|
|
216
|
+
level: 0
|
|
217
|
+
});
|
|
218
|
+
}
|
|
194
219
|
headings.forEach((heading, index) => sections.push({ ...heading, end: headings[index + 1]?.start ?? text.length }));
|
|
195
220
|
return sections;
|
|
196
221
|
}
|
|
@@ -210,8 +235,11 @@ function modeExpression(mode, separator) {
|
|
|
210
235
|
}
|
|
211
236
|
function chunkText(text, options) {
|
|
212
237
|
const parsed = ChunkOptionsSchema.safeParse(options);
|
|
213
|
-
if (!parsed.success)
|
|
214
|
-
return err(HaiDatapipeError.CONFIG_ERROR, datapipeM("datapipe_configError", {
|
|
238
|
+
if (!parsed.success) {
|
|
239
|
+
return err(HaiDatapipeError.CONFIG_ERROR, datapipeM("datapipe_configError", {
|
|
240
|
+
params: { error: parsed.error.message }
|
|
241
|
+
}), parsed.error);
|
|
242
|
+
}
|
|
215
243
|
const opts = parsed.data;
|
|
216
244
|
if (opts.mode === "custom" && !opts.separator)
|
|
217
245
|
return err(HaiDatapipeError.MISSING_SEPARATOR, datapipeM("datapipe_missingSeparator"));
|
|
@@ -223,15 +251,28 @@ function chunkText(text, options) {
|
|
|
223
251
|
for (const section of markdownSections(text, opts.markdownMinLevel)) {
|
|
224
252
|
const content = text.slice(opts.markdownKeepTitle ? section.start : section.bodyStart, section.end);
|
|
225
253
|
const parts2 = splitCharacters(content, opts.maxSize, opts.overlap, modeExpression("paragraph"));
|
|
226
|
-
for (const part of parts2)
|
|
227
|
-
chunks.push({
|
|
254
|
+
for (const part of parts2) {
|
|
255
|
+
chunks.push({
|
|
256
|
+
index: chunks.length,
|
|
257
|
+
content: part,
|
|
258
|
+
metadata: {
|
|
259
|
+
title: section.title,
|
|
260
|
+
level: section.level,
|
|
261
|
+
...parts2.length > 1 ? { subChunk: true } : {}
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
228
265
|
}
|
|
229
266
|
return ok(chunks);
|
|
230
267
|
}
|
|
231
268
|
const parts = opts.mode === "word" ? splitWords(text, opts.maxSize, opts.overlap) : splitCharacters(text, opts.maxSize, opts.overlap, modeExpression(opts.mode, opts.separator));
|
|
232
269
|
return ok(parts.map((content, index) => ({ index, content })));
|
|
233
270
|
} catch (cause) {
|
|
234
|
-
return err(HaiDatapipeError.CHUNK_FAILED, datapipeM("datapipe_chunkFailed", {
|
|
271
|
+
return err(HaiDatapipeError.CHUNK_FAILED, datapipeM("datapipe_chunkFailed", {
|
|
272
|
+
params: {
|
|
273
|
+
error: String(cause)
|
|
274
|
+
}
|
|
275
|
+
}), cause);
|
|
235
276
|
}
|
|
236
277
|
}
|
|
237
278
|
function stripHtmlTags(text) {
|
|
@@ -257,7 +298,9 @@ var MULTI_SPACE_REGEX = /[ \t]{2,}/g;
|
|
|
257
298
|
function cleanText(text, options) {
|
|
258
299
|
const parseResult = CleanOptionsSchema.safeParse(options ?? {});
|
|
259
300
|
if (!parseResult.success) {
|
|
260
|
-
return err(HaiDatapipeError.CONFIG_ERROR, datapipeM("datapipe_configError", {
|
|
301
|
+
return err(HaiDatapipeError.CONFIG_ERROR, datapipeM("datapipe_configError", {
|
|
302
|
+
params: { error: parseResult.error.message }
|
|
303
|
+
}), parseResult.error);
|
|
261
304
|
}
|
|
262
305
|
const opts = parseResult.data;
|
|
263
306
|
let result = text;
|
|
@@ -277,7 +320,11 @@ function cleanText(text, options) {
|
|
|
277
320
|
try {
|
|
278
321
|
regex = new RegExp(pattern, "g");
|
|
279
322
|
} catch (regexError) {
|
|
280
|
-
return err(HaiDatapipeError.CONFIG_ERROR, datapipeM("datapipe_configError", {
|
|
323
|
+
return err(HaiDatapipeError.CONFIG_ERROR, datapipeM("datapipe_configError", {
|
|
324
|
+
params: {
|
|
325
|
+
error: String(regexError)
|
|
326
|
+
}
|
|
327
|
+
}), regexError);
|
|
281
328
|
}
|
|
282
329
|
result = result.replace(regex, replacement);
|
|
283
330
|
}
|
|
@@ -291,7 +338,11 @@ function cleanText(text, options) {
|
|
|
291
338
|
}
|
|
292
339
|
return ok(result);
|
|
293
340
|
} catch (error) {
|
|
294
|
-
return err(HaiDatapipeError.CLEAN_FAILED, datapipeM("datapipe_cleanFailed", {
|
|
341
|
+
return err(HaiDatapipeError.CLEAN_FAILED, datapipeM("datapipe_cleanFailed", {
|
|
342
|
+
params: {
|
|
343
|
+
error: String(error)
|
|
344
|
+
}
|
|
345
|
+
}), error);
|
|
295
346
|
}
|
|
296
347
|
}
|
|
297
348
|
function createPipelineBuilder() {
|
|
@@ -340,7 +391,11 @@ async function runPipeline(steps, text) {
|
|
|
340
391
|
try {
|
|
341
392
|
currentText = await step.fn(currentText);
|
|
342
393
|
} catch (error) {
|
|
343
|
-
return err(HaiDatapipeError.TRANSFORM_FAILED, datapipeM("datapipe_transformFailed", {
|
|
394
|
+
return err(HaiDatapipeError.TRANSFORM_FAILED, datapipeM("datapipe_transformFailed", {
|
|
395
|
+
params: {
|
|
396
|
+
error: String(error)
|
|
397
|
+
}
|
|
398
|
+
}), error);
|
|
344
399
|
}
|
|
345
400
|
break;
|
|
346
401
|
}
|
|
@@ -349,7 +404,11 @@ async function runPipeline(steps, text) {
|
|
|
349
404
|
try {
|
|
350
405
|
chunks = await step.fn(chunks);
|
|
351
406
|
} catch (error) {
|
|
352
|
-
return err(HaiDatapipeError.PIPELINE_FAILED, datapipeM("datapipe_pipelineFailed", {
|
|
407
|
+
return err(HaiDatapipeError.PIPELINE_FAILED, datapipeM("datapipe_pipelineFailed", {
|
|
408
|
+
params: {
|
|
409
|
+
error: String(error)
|
|
410
|
+
}
|
|
411
|
+
}), error);
|
|
353
412
|
}
|
|
354
413
|
}
|
|
355
414
|
break;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/datapipe-config.ts","../messages/en-US.json","../messages/ja-JP.json","../messages/zh-CN.json","../src/datapipe-i18n.ts","../src/datapipe-types.ts","../src/datapipe-chunk.ts","../src/datapipe-clean.ts","../src/datapipe-pipeline.ts","../src/datapipe-main.ts"],"names":["core","parts","err","ok"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @h-ai/datapipe — 数据处理管线配置 Schema\n *\n * 本文件定义数据处理模块的错误码常量、Zod Schema 和配置类型。\n * 支持清洗(clean)、分块(chunk)、转换(transform)和管线(pipeline)。\n * @module datapipe-config\n */\n\nimport { z } from 'zod'\n\n// ─── 清洗配置 ───\n\n/**\n * 清洗选项 Schema\n *\n * 数据清洗规则配置,支持移除 HTML、URL、Email、标准化空白等。\n * @example\n * ```ts\n * import { CleanOptionsSchema } from '@h-ai/datapipe'\n * const options = CleanOptionsSchema.parse({ removeHtml: true, removeEmails: true })\n * ```\n */\nexport const CleanOptionsSchema = z.object({\n /** 移除 HTML 标签(默认 true) */\n removeHtml: z.boolean().default(true),\n /** 移除 URL(默认 false) */\n removeUrls: z.boolean().default(false),\n /** 移除 Email 地址(默认 false) */\n removeEmails: z.boolean().default(false),\n /** 标准化空白字符(多空格→单空格、去掉多余空行,默认 true) */\n normalizeWhitespace: z.boolean().default(true),\n /** 去除首尾空白(默认 true) */\n trim: z.boolean().default(true),\n /**\n * 自定义替换规则(正则→替换字符串)\n *\n * ❗ 安全提示:pattern 会通过 `new RegExp()` 构造,如果其值来源于用户输入,请在调用方先行校验以防止 ReDoS 攻击。\n */\n customReplacements: z.array(z.object({\n /** 正则表达式字符串 */\n pattern: z.string(),\n /** 替换文本 */\n replacement: z.string(),\n })).optional(),\n})\n\n/**\n * 清洗选项类型\n * @example\n * ```ts\n * import { CleanOptionsSchema, type CleanOptions } from '@h-ai/datapipe'\n * const options: CleanOptions = CleanOptionsSchema.parse({ removeHtml: true })\n * ```\n */\nexport type CleanOptions = z.infer<typeof CleanOptionsSchema>\n\n/**\n * 清洗选项输入类型\n * @example\n * ```ts\n * import type { CleanOptionsInput } from '@h-ai/datapipe'\n * const options: CleanOptionsInput = { removeHtml: true, removeUrls: true }\n * ```\n */\nexport type CleanOptionsInput = z.input<typeof CleanOptionsSchema>\n\n// ─── 分块配置 ───\n\n/**\n * 分块模式枚举\n *\n * - `sentence` — 按句子分块\n * - `paragraph` — 按段落分块\n * - `markdown` — 按 Markdown 标题分块(## / ### 等)\n * - `page` — 按分页符分块\n * - `word` — 按非空白词数分块,不截断单个词\n * - `character` — 按 Unicode code point 分块,不拆代理对\n * - `custom` — 自定义分隔符分块\n * @example\n * ```ts\n * import { ChunkModeSchema } from '@h-ai/datapipe'\n * const mode = ChunkModeSchema.parse('character')\n * ```\n */\nexport const ChunkModeSchema = z.enum([\n 'sentence',\n 'paragraph',\n 'markdown',\n 'page',\n 'word',\n 'character',\n 'custom',\n])\n\n/**\n * 分块模式类型\n * @example\n * ```ts\n * import type { ChunkMode } from '@h-ai/datapipe'\n * const options: ChunkMode = 'character'\n * ```\n */\nexport type ChunkMode = z.infer<typeof ChunkModeSchema>\n\n/**\n * 分块选项 Schema\n * datapipe 的默认 overlap 为 0;消费者可显式提供自己的默认值,例如 AI Knowledge 为 200。\n * @example\n * ```ts\n * import { ChunkOptionsSchema } from '@h-ai/datapipe'\n * const options = ChunkOptionsSchema.parse({ mode: 'markdown', maxSize: 500, overlap: 50 })\n * // maxSize 已包含重叠,overlap 必须小于 maxSize;自定义正则仅来自可信配置。\n * ```\n */\nexport const ChunkOptionsSchema = z.object({\n /** 分块模式 */\n mode: ChunkModeSchema,\n /** 每块上限包含 overlap/分隔符;word 按非空白词,其他按 Unicode code point,默认 1500。 */\n maxSize: z.number().int().positive().default(1500),\n /** 重叠使用与 maxSize 相同的单位,必须严格小于 maxSize。 */\n overlap: z.number().int().min(0).default(0),\n /**\n * 自定义分隔符正则(仅 mode='custom' 时使用)\n *\n * ❗ 安全提示:separator 会通过 `new RegExp()` 构造,如果其值来源于用户输入,请在调用方先行校验以防止 ReDoS 攻击。\n */\n separator: z.string().optional(),\n /** Markdown 标题分割深度(1-6,默认 2,即 # 和 ## 作为分块边界;设为 3 则 ### 也作为分块边界) */\n markdownMinLevel: z.number().int().min(1).max(6).default(2),\n /** 是否保留 Markdown 标题在分块内容中(默认 true) */\n markdownKeepTitle: z.boolean().default(true),\n}).refine(options => options.overlap < options.maxSize, { path: ['overlap'] })\n\n/**\n * 分块选项类型\n * @example\n * ```ts\n * import { ChunkOptionsSchema, type ChunkOptions } from '@h-ai/datapipe'\n * const options: ChunkOptions = ChunkOptionsSchema.parse({ mode: 'character', maxSize: 500 })\n * ```\n */\nexport type ChunkOptions = z.infer<typeof ChunkOptionsSchema>\n\n/**\n * 分块选项输入类型\n * @example\n * ```ts\n * import type { ChunkOptionsInput } from '@h-ai/datapipe'\n * const options: ChunkOptionsInput = { mode: 'character', maxSize: 500, overlap: 50 }\n * ```\n */\nexport type ChunkOptionsInput = z.input<typeof ChunkOptionsSchema>\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"datapipe_cleanFailed\": \"Failed to clean text: {error}\",\n \"datapipe_chunkFailed\": \"Failed to chunk text: {error}\",\n \"datapipe_transformFailed\": \"Failed to transform text: {error}\",\n \"datapipe_pipelineFailed\": \"Pipeline execution failed: {error}\",\n \"datapipe_configError\": \"Datapipe config validation failed: {error}\",\n \"datapipe_missingSeparator\": \"Custom chunk mode requires a separator parameter\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"datapipe_cleanFailed\": \"テキストのクリーニングに失敗しました: {error}\",\n \"datapipe_chunkFailed\": \"テキストの分割に失敗しました: {error}\",\n \"datapipe_transformFailed\": \"テキストの変換に失敗しました: {error}\",\n \"datapipe_pipelineFailed\": \"パイプラインの実行に失敗しました: {error}\",\n \"datapipe_configError\": \"データパイプ設定の検証に失敗しました: {error}\",\n \"datapipe_missingSeparator\": \"カスタム分割モードにはseparatorパラメーターが必要です\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"datapipe_cleanFailed\": \"清洗文本失败: {error}\",\n \"datapipe_chunkFailed\": \"分块文本失败: {error}\",\n \"datapipe_transformFailed\": \"转换文本失败: {error}\",\n \"datapipe_pipelineFailed\": \"管线执行失败: {error}\",\n \"datapipe_configError\": \"数据处理配置校验失败:{error}\",\n \"datapipe_missingSeparator\": \"自定义分块模式需要提供 separator 参数\"\n}\n","/**\n * @h-ai/datapipe — i18n\n *\n * 本文件提供数据处理模块的 i18n 文案访问入口。\n * @module datapipe-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesJaJP from '../messages/ja-JP.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n// ─── i18n ───\n\n/**\n * 数据处理模块文案 Key 类型\n * @example 模块内部上下文\n * ```ts\n * const key: DatapipeMessageKey = 'datapipe_cleanFailed'\n * const message = datapipeM(key)\n * ```\n */\ntype DatapipeMessageKey = keyof typeof messagesZhCN\n\n/**\n * 获取数据处理模块文案。\n * @param key - 文案 Key\n * @param options - 插值参数与格式化选项\n * @returns 本地化后的文案字符串\n * @example 模块内部上下文\n * ```ts\n * const message = datapipeM('datapipe_cleanFailed', { params: { error: 'invalid input' }, locale: 'en-US' })\n * ```\n */\nexport const datapipeM = core.i18n.createMessageGetter<DatapipeMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n 'ja-JP': messagesJaJP,\n})\n","/**\n * @h-ai/datapipe — 类型定义\n *\n * 本文件定义数据处理模块的核心接口和类型。\n * @module datapipe-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport type { ChunkOptionsInput, CleanOptionsInput } from './datapipe-config.js'\nimport { core } from '@h-ai/core'\n\n// ─── 错误定义(照 @h-ai/core 范式) ───\n\n/**\n * 数据处理错误信息映射(错误码:HTTP状态码)。\n *\n * 完整错误码将自动生成为:`hai:datapipe:NNN`\n */\nconst DatapipeErrorInfo = {\n CLEAN_FAILED: '001:500',\n CHUNK_FAILED: '002:500',\n TRANSFORM_FAILED: '003:500',\n PIPELINE_FAILED: '004:500',\n CONFIG_ERROR: '005:400',\n MISSING_SEPARATOR: '006:400',\n} as const satisfies ErrorInfo\n\n/**\n * Datapipe 模块标准错误定义对象。\n * @example\n * ```ts\n * import { HaiDatapipeError } from '@h-ai/datapipe'\n * import { err } from '@h-ai/core'\n * const result = err(HaiDatapipeError.CONFIG_ERROR, 'Invalid chunk configuration')\n * if (!result.success) result.error.httpStatus\n * ```\n */\nexport const HaiDatapipeError = core.error.buildHaiErrorsDef('datapipe', DatapipeErrorInfo)\n\n// ─── 数据块 ───\n\n/**\n * 数据块接口\n *\n * 表示经过分块处理后的单个文本片段。\n * @example\n * ```ts\n * import type { DataChunk } from '@h-ai/datapipe'\n * const options: DataChunk = { index: 0, content: '## Intro', metadata: { title: 'Intro', level: 2 } }\n * ```\n */\nexport interface DataChunk {\n /** 分块索引(从 0 开始) */\n index: number\n /** 原文切片;保留空白和分隔符。word 以词计量,其他模式以 Unicode code point 计量。 */\n content: string\n /** 分块元数据(可选) */\n metadata?: Record<string, unknown>\n}\n\n// ─── 转换函数 ───\n\n/**\n * 转换函数类型\n *\n * 自定义文本后处理函数,可以是同步或异步。\n * @example\n * ```ts\n * import type { TransformFn } from '@h-ai/datapipe'\n * const options: TransformFn = text => text.trim().toLowerCase()\n * ```\n */\nexport type TransformFn = (text: string) => string | Promise<string>\n\n/**\n * 分块转换函数类型\n *\n * 对分块列表进行后处理(如过滤、合并等)。\n * @example\n * ```ts\n * import type { ChunkTransformFn } from '@h-ai/datapipe'\n * const options: ChunkTransformFn = chunks => chunks.filter(chunk => chunk.content.trim().length > 0)\n * ```\n */\nexport type ChunkTransformFn = (chunks: DataChunk[]) => DataChunk[] | Promise<DataChunk[]>\n\n// ─── 管线步骤 ───\n\n/**\n * 管线步骤类型\n *\n * 管线由一系列步骤组成,支持清洗、分块和自定义转换。\n * @example\n * ```ts\n * import type { PipelineStep } from '@h-ai/datapipe'\n * const options: PipelineStep = { type: 'chunk', options: { mode: 'paragraph', maxSize: 500, overlap: 50 } }\n * ```\n */\nexport type PipelineStep\n = | { type: 'clean', options?: CleanOptionsInput }\n | { type: 'chunk', options: ChunkOptionsInput }\n | { type: 'transform', fn: TransformFn }\n | { type: 'chunkTransform', fn: ChunkTransformFn }\n\n// ─── 管线结果 ───\n\n/**\n * 管线执行结果\n * @example\n * ```ts\n * import type { PipelineResult } from '@h-ai/datapipe'\n * const options: PipelineResult = { text: 'One. Two.', chunks: [{ index: 0, content: 'One. Two.' }] }\n * ```\n */\nexport interface PipelineResult {\n /** 处理后的文本(分块前的最终文本) */\n text: string\n /** 分块列表(如果管线包含 chunk 步骤) */\n chunks: DataChunk[]\n}\n\n// ─── 操作接口 ───\n\n/**\n * 清洗操作接口\n *\n * 通过 `datapipe.clean()` 调用。\n * @example\n * ```ts\n * import { datapipe, type CleanOperations } from '@h-ai/datapipe'\n * const clean: CleanOperations = datapipe.clean\n * const result = clean('<p>Hello</p>')\n * if (result.success) result.data.trim()\n * ```\n */\nexport interface CleanOperations {\n /**\n * 清洗文本\n *\n * @param text - 原始文本\n * @param options - 清洗选项(可选,使用默认值)\n * @returns 清洗后的文本\n */\n (text: string, options?: CleanOptionsInput): HaiResult<string>\n}\n\n/**\n * 分块操作接口\n *\n * 通过 `datapipe.chunk()` 调用。\n * @example\n * ```ts\n * import { datapipe, type ChunkOperations } from '@h-ai/datapipe'\n * const chunk: ChunkOperations = datapipe.chunk\n * const result = chunk('One. Two.', { mode: 'sentence', maxSize: 10 })\n * if (result.success) result.data.map(item => item.index)\n * ```\n */\nexport interface ChunkOperations {\n /**\n * 对文本进行分块\n *\n * @param text - 输入文本\n * @param options - 分块选项\n * @returns 分块列表\n */\n (text: string, options: ChunkOptionsInput): HaiResult<DataChunk[]>\n}\n\n/**\n * 管线构建器接口\n *\n * 通过 `datapipe.pipeline()` 创建,链式添加步骤后执行。\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport interface PipelineBuilder {\n /** 添加清洗步骤 */\n clean: (options?: CleanOptionsInput) => PipelineBuilder\n /** 添加分块步骤 */\n chunk: (options: ChunkOptionsInput) => PipelineBuilder\n /** 添加文本转换步骤 */\n transform: (fn: TransformFn) => PipelineBuilder\n /** 添加分块后处理步骤 */\n chunkTransform: (fn: ChunkTransformFn) => PipelineBuilder\n /** 执行管线 */\n run: (text: string) => Promise<HaiResult<PipelineResult>>\n}\n\n/**\n * 数据处理管线服务接口\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport interface DatapipeFunctions {\n /** 清洗文本 */\n clean: CleanOperations\n /** 分块文本 */\n chunk: ChunkOperations\n /** 创建管线构建器 */\n pipeline: () => PipelineBuilder\n}\n","/**\n * @h-ai/datapipe — 保留源文本的有界分块。\n * word 按非空白词计数,其他模式按 Unicode code point 计数,均先计入 overlap。\n * @module datapipe-chunk\n */\nimport type { HaiResult } from '@h-ai/core'\nimport type { ChunkMode, ChunkOptionsInput } from './datapipe-config.js'\nimport type { DataChunk } from './datapipe-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { ChunkOptionsSchema } from './datapipe-config.js'\nimport { datapipeM } from './datapipe-i18n.js'\nimport { HaiDatapipeError } from './datapipe-types.js'\n\n/**\n * Markdown 源区间;标题移除仅影响显式 keepTitle=false 的内容起点。\n * @example 模块内部上下文\n * ```ts\n * const section: MarkdownSection = { start: 0, bodyStart: 8, end: 12, title: 'Title', level: 1 }\n * const bodyLength = section.end - section.bodyStart\n * ```\n */\ninterface MarkdownSection {\n start: number\n bodyStart: number\n end: number\n title: string\n level: number\n}\n\n/** 找出自然边界对应的 code point 下标;保留分隔符,不通过 split/join 改写正文。 */\nfunction findBoundaries(text: string, expression?: RegExp): number[] {\n if (!expression)\n return []\n const boundaries: number[] = []\n let previousOffset = 0\n let points = 0\n for (const match of text.matchAll(expression)) {\n const offset = match.index + match[0].length\n if (offset <= previousOffset)\n continue\n points += Array.from(text.slice(previousOffset, offset)).length\n boundaries.push(points)\n previousOffset = offset\n }\n return boundaries\n}\n\n/** 取不超过预算的最后自然边界;边界至少越过 overlap,保证下轮起点严格前进。 */\nfunction boundedEnd(boundaries: number[], start: number, limit: number, overlap: number): number {\n let lower = 0\n let upper = boundaries.length\n while (lower < upper) {\n const middle = Math.floor((lower + upper) / 2)\n if (boundaries[middle]! <= limit)\n lower = middle + 1\n else\n upper = middle\n }\n const candidate = boundaries[lower - 1]\n return candidate !== undefined && candidate > start + overlap ? candidate : limit\n}\n\n/**\n * 所有字符模式共用滑窗;原文切片已包含空白、标点和分隔符,不追加隐式换行。\n * @example splitCharacters('甲😀乙丙丁', 3, 1) // ['甲😀乙', '乙丙丁']\n */\nfunction splitCharacters(text: string, maxSize: number, overlap: number, expression?: RegExp): string[] {\n const points = Array.from(text)\n const boundaries = findBoundaries(text, expression)\n const chunks: string[] = []\n for (let start = 0; start < points.length;) {\n const limit = Math.min(start + maxSize, points.length)\n const end = limit === points.length ? limit : boundedEnd(boundaries, start, limit, overlap)\n chunks.push(points.slice(start, end).join(''))\n if (end === points.length)\n break\n start = end - overlap\n }\n return chunks\n}\n\n/** 按非空白词滑窗,切片仍使用原始字符串的 offset,保留词间全部空白。 */\nfunction splitWords(text: string, maxSize: number, overlap: number): string[] {\n const words = [...text.matchAll(/\\S+/gu)]\n const chunks: string[] = []\n for (let start = 0; start < words.length;) {\n const end = Math.min(start + maxSize, words.length)\n const from = start === 0 ? 0 : words[start]!.index\n const to = end === words.length ? text.length : words[end]!.index\n chunks.push(text.slice(from, to))\n if (end === words.length)\n break\n start = end - overlap\n }\n return chunks\n}\n\n/** 匹配 # 至配置级别的标题;fenced code 内的 # 是正文,不创建虚假 section。 */\nfunction markdownSections(text: string, minLevel: number): MarkdownSection[] {\n const headings: Array<Omit<MarkdownSection, 'end'>> = []\n let fence: { character: string, length: number } | undefined\n for (const line of text.matchAll(/[^\\n]*(?:\\n|$)/g)) {\n const content = line[0].replace(/\\r?\\n$/, '')\n if (fence) {\n if (new RegExp(`^ {0,3}${fence.character}{${fence.length},}[ \\\\t]*$`).test(content))\n fence = undefined\n continue\n }\n const opening = /^ {0,3}(`{3,}|~{3,})/.exec(content)\n if (opening) {\n fence = { character: opening[1]![0]!, length: opening[1]!.length }\n continue\n }\n const heading = /^ {0,3}(#{1,6})[ \\t]/.exec(content)\n if (heading && heading[1]!.length <= minLevel) {\n let title = content.slice(heading[0].length).trim()\n let end = title.length\n while (title[end - 1] === '#')\n end--\n // 只移除空白分隔的尾部 #,按线性扫描处理,避免可交换量词造成正则回溯。\n if (end < title.length && (title[end - 1] === ' ' || title[end - 1] === '\\t'))\n title = title.slice(0, end).trimEnd()\n headings.push({ start: line.index, bodyStart: line.index + line[0].length, title, level: heading[1]!.length })\n }\n }\n if (headings.length === 0)\n return [{ start: 0, bodyStart: 0, end: text.length, title: '', level: 0 }]\n const sections: MarkdownSection[] = []\n if (headings[0]!.start > 0)\n sections.push({ start: 0, bodyStart: 0, end: headings[0]!.start, title: '', level: 0 })\n headings.forEach((heading, index) => sections.push({ ...heading, end: headings[index + 1]?.start ?? text.length }))\n return sections\n}\n\n/** 自然边界只决定优先切点,不删除分隔符或改变预算单位。 */\nfunction modeExpression(mode: ChunkMode, separator?: string): RegExp | undefined {\n switch (mode) {\n case 'sentence': return /[。!?.!?]+\\s*/gu\n case 'paragraph': return /\\r?\\n(?:[ \\t]*\\r?\\n)+/gu\n case 'page': return /\\f/gu\n case 'custom': return new RegExp(separator!, 'gu')\n default: return undefined\n }\n}\n\n/**\n * 对文本分块;word 使用词数,其他模式使用 Unicode code point,非字节/token/UTF-16 长度。\n * maxSize 包含 overlap 和分隔符,0 <= overlap < maxSize;默认不重叠。\n * 原始空白与分隔符保留,Markdown 仅在显式 keepTitle=false 时移除标题行。\n * @param text - 源文本;空或全空白输入返回空数组。\n * @param options - 模式与预算;Markdown section 之间不重叠,section 内使用相同边界算法。\n * @returns 有界且顺序连续编号的分块;配置错误或非法正则返回错误结果。\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = datapipe.chunk('One. Two. Three.', { mode: 'sentence', maxSize: 12, overlap: 2 })\n * if (result.success) result.data.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport function chunkText(text: string, options: ChunkOptionsInput): HaiResult<DataChunk[]> {\n const parsed = ChunkOptionsSchema.safeParse(options)\n if (!parsed.success)\n return err(HaiDatapipeError.CONFIG_ERROR, datapipeM('datapipe_configError', { params: { error: parsed.error.message } }), parsed.error)\n const opts = parsed.data\n if (opts.mode === 'custom' && !opts.separator)\n return err(HaiDatapipeError.MISSING_SEPARATOR, datapipeM('datapipe_missingSeparator'))\n if (!text || text.trim().length === 0)\n return ok([])\n try {\n if (opts.mode === 'markdown') {\n const chunks: DataChunk[] = []\n for (const section of markdownSections(text, opts.markdownMinLevel)) {\n const content = text.slice(opts.markdownKeepTitle ? section.start : section.bodyStart, section.end)\n const parts = splitCharacters(content, opts.maxSize, opts.overlap, modeExpression('paragraph'))\n for (const part of parts)\n chunks.push({ index: chunks.length, content: part, metadata: { title: section.title, level: section.level, ...(parts.length > 1 ? { subChunk: true } : {}) } })\n }\n return ok(chunks)\n }\n const parts = opts.mode === 'word'\n ? splitWords(text, opts.maxSize, opts.overlap)\n : splitCharacters(text, opts.maxSize, opts.overlap, modeExpression(opts.mode, opts.separator))\n return ok(parts.map((content, index) => ({ index, content })))\n }\n catch (cause) {\n return err(HaiDatapipeError.CHUNK_FAILED, datapipeM('datapipe_chunkFailed', { params: { error: String(cause) } }), cause)\n }\n}\n","/**\n * @h-ai/datapipe — 文本清洗功能\n *\n * 提供文本清洗工具,支持移除 HTML、URL、Email、标准化空白等。\n * @module datapipe-clean\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { CleanOptionsInput } from './datapipe-config.js'\n\nimport { err, ok } from '@h-ai/core'\n\nimport { CleanOptionsSchema } from './datapipe-config.js'\nimport { datapipeM } from './datapipe-i18n.js'\nimport { HaiDatapipeError } from './datapipe-types.js'\n\n/** 按首个闭合符提取文本;仅用于清洗,不代替渲染 HTML 前的安全消毒。 */\nfunction stripHtmlTags(text: string): string {\n const parts: string[] = []\n let cursor = 0\n while (cursor < text.length) {\n const start = text.indexOf('<', cursor)\n if (start < 0)\n break\n const end = text.indexOf('>', start + 1)\n if (end < 0)\n break\n parts.push(text.slice(cursor, start))\n cursor = end + 1\n }\n parts.push(text.slice(cursor))\n return parts.join('')\n}\n\n/**\n * URL 正则(HTTP/HTTPS)\n */\nconst URL_REGEX = /https?:\\/\\/[^\\s<>\"{}|\\\\^`[\\]]+/g\n\n/**\n * Email 正则\n */\nconst EMAIL_REGEX = /(?<![\\w.%+-])[\\w.%+-]+@[a-z0-9.-]+\\.[a-z]{2,}/gi\n\n/**\n * 多空行正则(3行及以上空行 → 2行)\n */\nconst MULTI_NEWLINE_REGEX = /\\n{3,}/g\n\n/**\n * 多空格正则\n */\nconst MULTI_SPACE_REGEX = /[ \\t]{2,}/g\n\n/**\n * 清洗文本\n *\n * 根据配置选项对文本进行清洗处理。\n *\n * @param text - 原始文本\n * @param options - 清洗选项(可选)\n * @returns 清洗后的文本\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = datapipe.clean('<p>Hello</p>', { removeHtml: true })\n * if (result.success) result.data.toUpperCase()\n * else result.error.message\n * ```\n */\nexport function cleanText(text: string, options?: CleanOptionsInput): HaiResult<string> {\n const parseResult = CleanOptionsSchema.safeParse(options ?? {})\n if (!parseResult.success) {\n return err(HaiDatapipeError.CONFIG_ERROR, datapipeM('datapipe_configError', { params: { error: parseResult.error.message } }), parseResult.error)\n }\n\n const opts = parseResult.data\n let result = text\n\n try {\n // 移除 HTML 标签\n if (opts.removeHtml) {\n result = stripHtmlTags(result)\n }\n\n // 移除 URL\n if (opts.removeUrls) {\n result = result.replace(URL_REGEX, '')\n }\n\n // 移除 Email\n if (opts.removeEmails) {\n result = result.replace(EMAIL_REGEX, '')\n }\n\n // 自定义替换\n if (opts.customReplacements) {\n for (const { pattern, replacement } of opts.customReplacements) {\n let regex: RegExp\n try {\n regex = new RegExp(pattern, 'g')\n }\n catch (regexError) {\n return err(HaiDatapipeError.CONFIG_ERROR, datapipeM('datapipe_configError', { params: { error: String(regexError) } }), regexError)\n }\n result = result.replace(regex, replacement)\n }\n }\n\n // 标准化空白\n if (opts.normalizeWhitespace) {\n result = result.replace(MULTI_SPACE_REGEX, ' ')\n result = result.replace(MULTI_NEWLINE_REGEX, '\\n\\n')\n }\n\n // 去除首尾空白\n if (opts.trim) {\n result = result.trim()\n }\n\n return ok(result)\n }\n catch (error) {\n return err(HaiDatapipeError.CLEAN_FAILED, datapipeM('datapipe_cleanFailed', { params: { error: String(error) } }), error)\n }\n}\n","/**\n * @h-ai/datapipe — 管线构建器\n *\n * 提供可组合的管线构建器,支持链式添加清洗、分块、转换步骤后执行。\n * @module datapipe-pipeline\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ChunkOptionsInput, CleanOptionsInput } from './datapipe-config.js'\nimport type {\n ChunkTransformFn,\n DataChunk,\n PipelineBuilder,\n PipelineResult,\n PipelineStep,\n TransformFn,\n} from './datapipe-types.js'\n\nimport { err, ok } from '@h-ai/core'\n\nimport { chunkText } from './datapipe-chunk.js'\nimport { cleanText } from './datapipe-clean.js'\nimport { datapipeM } from './datapipe-i18n.js'\nimport { HaiDatapipeError } from './datapipe-types.js'\n\n/**\n * 创建管线构建器\n *\n * @returns PipelineBuilder 实例,支持链式添加步骤后执行\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport function createPipelineBuilder(): PipelineBuilder {\n const steps: PipelineStep[] = []\n\n const builder: PipelineBuilder = {\n clean(options?: CleanOptionsInput): PipelineBuilder {\n steps.push({ type: 'clean', options })\n return builder\n },\n\n chunk(options: ChunkOptionsInput): PipelineBuilder {\n steps.push({ type: 'chunk', options })\n return builder\n },\n\n transform(fn: TransformFn): PipelineBuilder {\n steps.push({ type: 'transform', fn })\n return builder\n },\n\n chunkTransform(fn: ChunkTransformFn): PipelineBuilder {\n steps.push({ type: 'chunkTransform', fn })\n return builder\n },\n\n run: (text: string) => runPipeline(steps, text),\n }\n\n return builder\n}\n\n// ─── 管线执行 ───\n\n/**\n * 执行管线步骤\n */\nasync function runPipeline(\n steps: PipelineStep[],\n text: string,\n): Promise<HaiResult<PipelineResult>> {\n let currentText = text\n let chunks: DataChunk[] = []\n\n for (const step of steps) {\n switch (step.type) {\n case 'clean': {\n const result = cleanText(currentText, step.options)\n if (!result.success)\n return result\n currentText = result.data\n break\n }\n\n case 'chunk': {\n const result = chunkText(currentText, step.options)\n if (!result.success)\n return result\n chunks = result.data\n break\n }\n\n case 'transform': {\n try {\n currentText = await step.fn(currentText)\n }\n catch (error) {\n return err(HaiDatapipeError.TRANSFORM_FAILED, datapipeM('datapipe_transformFailed', { params: { error: String(error) } }), error)\n }\n break\n }\n\n case 'chunkTransform': {\n if (chunks.length > 0) {\n try {\n chunks = await step.fn(chunks)\n }\n catch (error) {\n return err(HaiDatapipeError.PIPELINE_FAILED, datapipeM('datapipe_pipelineFailed', { params: { error: String(error) } }), error)\n }\n }\n break\n }\n }\n }\n\n return ok({ text: currentText, chunks })\n}\n","/**\n * @h-ai/datapipe — 数据处理管线主入口\n *\n * 提供统一的 `datapipe` 对象,聚合清洗、分块和管线功能。\n * datapipe 为纯函数模块,无需初始化即可使用。\n * @module datapipe-main\n */\n\nimport type { DatapipeFunctions } from './datapipe-types.js'\n\nimport { chunkText } from './datapipe-chunk.js'\nimport { cleanText } from './datapipe-clean.js'\nimport { createPipelineBuilder } from './datapipe-pipeline.js'\n\n// ─── 统一服务对象 ───\n\n/**\n * 数据处理管线服务对象\n *\n * 纯函数模块,无需初始化即可使用。\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport const datapipe: DatapipeFunctions = {\n clean: cleanText,\n chunk: chunkText,\n pipeline: createPipelineBuilder,\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/datapipe-config.ts","../messages/en-US.json","../messages/ja-JP.json","../messages/zh-CN.json","../src/datapipe-i18n.ts","../src/datapipe-types.ts","../src/datapipe-chunk.ts","../src/datapipe-clean.ts","../src/datapipe-pipeline.ts","../src/datapipe-main.ts"],"names":["core","parts","err","ok"],"mappings":";;;;AAsBO,IAAM,kBAAA,GAAqB,EAAE,MAAA,CAAO;AAAA;AAAA,EAEzC,UAAA,EAAY,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA;AAAA,EAEpC,UAAA,EAAY,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA;AAAA,EAErC,YAAA,EAAc,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA;AAAA,EAEvC,mBAAA,EAAqB,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA;AAAA,EAE7C,IAAA,EAAM,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9B,kBAAA,EAAoB,CAAA,CAAE,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO;AAAA;AAAA,IAEnC,OAAA,EAAS,EAAE,MAAA,EAAO;AAAA;AAAA,IAElB,WAAA,EAAa,EAAE,MAAA;AAAO,GACvB,CAAC,CAAA,CAAE,QAAA;AACN,CAAC;AAwCM,IAAM,eAAA,GAAkB,EAAE,IAAA,CAAK;AAAA,EACpC,UAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAC;AAsBM,IAAM,kBAAA,GAAqB,EAAE,MAAA,CAAO;AAAA;AAAA,EAEzC,IAAA,EAAM,eAAA;AAAA;AAAA,EAEN,OAAA,EAAS,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,IAAI,CAAA;AAAA;AAAA,EAEjD,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1C,SAAA,EAAW,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAE/B,gBAAA,EAAkB,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,QAAQ,CAAC,CAAA;AAAA;AAAA,EAE1D,iBAAA,EAAmB,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI;AAC7C,CAAC,EAAE,MAAA,CAAO,CAAA,OAAA,KAAW,OAAA,CAAQ,OAAA,GAAU,QAAQ,OAAA,EAAS;AAAA,EACtD,IAAA,EAAM,CAAC,SAAS;AAClB,CAAC;;;ACrID,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,oBAAA,EAAwB,+BAAA;AAAA,EACxB,oBAAA,EAAwB,+BAAA;AAAA,EACxB,wBAAA,EAA4B,mCAAA;AAAA,EAC5B,uBAAA,EAA2B,oCAAA;AAAA,EAC3B,oBAAA,EAAwB,4CAAA;AAAA,EACxB,yBAAA,EAA6B;AAC/B,CAAA;;;ACRA,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,oBAAA,EAAwB,uHAAA;AAAA,EACxB,oBAAA,EAAwB,+FAAA;AAAA,EACxB,wBAAA,EAA4B,+FAAA;AAAA,EAC5B,uBAAA,EAA2B,2GAAA;AAAA,EAC3B,oBAAA,EAAwB,uHAAA;AAAA,EACxB,yBAAA,EAA6B;AAC/B,CAAA;;;ACRA,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,oBAAA,EAAwB,+CAAA;AAAA,EACxB,oBAAA,EAAwB,+CAAA;AAAA,EACxB,wBAAA,EAA4B,+CAAA;AAAA,EAC5B,uBAAA,EAA2B,+CAAA;AAAA,EAC3B,oBAAA,EAAwB,2EAAA;AAAA,EACxB,yBAAA,EAA6B;AAC/B,CAAA;;;AC0BO,IAAM,SAAA,GAAY,IAAA,CAAK,IAAA,CAAK,mBAAA,CAAwC;AAAA,EACzE,OAAA,EAAS,aAAA;AAAA,EACT,OAAA,EAAS,aAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAC,CAAA;ACpBD,IAAM,iBAAA,GAAoB;AAAA,EACxB,YAAA,EAAc,SAAA;AAAA,EACd,YAAA,EAAc,SAAA;AAAA,EACd,gBAAA,EAAkB,SAAA;AAAA,EAClB,eAAA,EAAiB,SAAA;AAAA,EACjB,YAAA,EAAc,SAAA;AAAA,EACd,iBAAA,EAAmB;AACrB,CAAA;AAYO,IAAM,gBAAA,GAAmBA,IAAAA,CAAK,KAAA,CAAM,iBAAA,CAAkB,YAAY,iBAAiB;;;ACP1F,SAAS,cAAA,CAAe,MAAc,UAAA,EAA+B;AACnE,EAAA,IAAI,CAAC,UAAA;AACH,IAAA,OAAO,EAAC;AACV,EAAA,MAAM,aAAuB,EAAC;AAC9B,EAAA,IAAI,cAAA,GAAiB,CAAA;AACrB,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,QAAA,CAAS,UAAU,CAAA,EAAG;AAC7C,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,CAAE,MAAA;AACtC,IAAA,IAAI,MAAA,IAAU,cAAA;AACZ,MAAA;AACF,IAAA,MAAA,IAAU,MAAM,IAAA,CAAK,IAAA,CAAK,MAAM,cAAA,EAAgB,MAAM,CAAC,CAAA,CAAE,MAAA;AACzD,IAAA,UAAA,CAAW,KAAK,MAAM,CAAA;AACtB,IAAA,cAAA,GAAiB,MAAA;AAAA,EACnB;AACA,EAAA,OAAO,UAAA;AACT;AAGA,SAAS,UAAA,CAAW,UAAA,EAAsB,KAAA,EAAe,KAAA,EAAe,OAAA,EAAyB;AAC/F,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,QAAQ,UAAA,CAAW,MAAA;AACvB,EAAA,OAAO,QAAQ,KAAA,EAAO;AACpB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAA,CAAO,KAAA,GAAQ,SAAS,CAAC,CAAA;AAC7C,IAAA,IAAI,UAAA,CAAW,MAAM,CAAA,IAAM,KAAA;AACzB,MAAA,KAAA,GAAQ,MAAA,GAAS,CAAA;AAAA;AAEjB,MAAA,KAAA,GAAQ,MAAA;AAAA,EACZ;AACA,EAAA,MAAM,SAAA,GAAY,UAAA,CAAW,KAAA,GAAQ,CAAC,CAAA;AACtC,EAAA,OAAO,SAAA,KAAc,MAAA,IAAa,SAAA,GAAY,KAAA,GAAQ,UAClD,SAAA,GACA,KAAA;AACN;AAMA,SAAS,eAAA,CAAgB,IAAA,EAAc,OAAA,EAAiB,OAAA,EAAiB,UAAA,EAA+B;AACtG,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAC9B,EAAA,MAAM,UAAA,GAAa,cAAA,CAAe,IAAA,EAAM,UAAU,CAAA;AAClD,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,MAAA,IAAS;AAC1C,IAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,OAAA,EAAS,OAAO,MAAM,CAAA;AACrD,IAAA,MAAM,GAAA,GAAM,UAAU,MAAA,CAAO,MAAA,GACzB,QACA,UAAA,CAAW,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA;AAChD,IAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAA,CAAM,KAAA,EAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC,CAAA;AAC7C,IAAA,IAAI,QAAQ,MAAA,CAAO,MAAA;AACjB,MAAA;AACF,IAAA,KAAA,GAAQ,GAAA,GAAM,OAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,UAAA,CAAW,IAAA,EAAc,OAAA,EAAiB,OAAA,EAA2B;AAC5E,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,GAAG,IAAA,CAAK,QAAA,CAAS,OAAO;AAAA,GAC1B;AACA,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,KAAA,CAAM,MAAA,IAAS;AACzC,IAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,OAAA,EAAS,MAAM,MAAM,CAAA;AAClD,IAAA,MAAM,OAAO,KAAA,KAAU,CAAA,GACnB,CAAA,GACA,KAAA,CAAM,KAAK,CAAA,CAAG,KAAA;AAClB,IAAA,MAAM,EAAA,GAAK,QAAQ,KAAA,CAAM,MAAA,GACrB,KAAK,MAAA,GACL,KAAA,CAAM,GAAG,CAAA,CAAG,KAAA;AAChB,IAAA,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,IAAA,EAAM,EAAE,CAAC,CAAA;AAChC,IAAA,IAAI,QAAQ,KAAA,CAAM,MAAA;AAChB,MAAA;AACF,IAAA,KAAA,GAAQ,GAAA,GAAM,OAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,gBAAA,CAAiB,MAAc,QAAA,EAAqC;AAC3E,EAAA,MAAM,WAAgD,EAAC;AACvD,EAAA,IAAI,KAAA;AACJ,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,QAAA,CAAS,iBAAiB,CAAA,EAAG;AACnD,IAAA,MAAM,UAAU,IAAA,CAAK,CAAC,CAAA,CAAE,OAAA,CAAQ,UAAU,EAAE,CAAA;AAC5C,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,IAAI,IAAI,MAAA,CAAO,CAAA,OAAA,EAAU,KAAA,CAAM,SAAS,CAAA,CAAA,EAAI,KAAA,CAAM,MAAM,CAAA,UAAA,CAAY,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA;AAChF,QAAA,KAAA,GAAQ,MAAA;AACV,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAU,sBAAA,CAAuB,IAAA,CAAK,OAAO,CAAA;AACnD,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,KAAA,GAAQ,EAAE,SAAA,EAAW,OAAA,CAAQ,CAAC,CAAA,CAAG,CAAC,CAAA,EAAI,MAAA,EAAQ,OAAA,CAAQ,CAAC,CAAA,CAAG,MAAA,EAAO;AACjE,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAU,sBAAA,CAAuB,IAAA,CAAK,OAAO,CAAA;AACnD,IAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,CAAC,CAAA,CAAG,UAAU,QAAA,EAAU;AAC7C,MAAA,IAAI,KAAA,GAAQ,QAAQ,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,CAAE,MAAM,EAAE,IAAA,EAAK;AAClD,MAAA,IAAI,MAAM,KAAA,CAAM,MAAA;AAChB,MAAA,OAAO,KAAA,CAAM,GAAA,GAAM,CAAC,CAAA,KAAM,GAAA;AACxB,QAAA,GAAA,EAAA;AAEF,MAAA,IAAI,GAAA,GAAM,KAAA,CAAM,MAAA,KAAW,KAAA,CAAM,GAAA,GAAM,CAAC,CAAA,KAAM,GAAA,IAAO,KAAA,CAAM,GAAA,GAAM,CAAC,CAAA,KAAM,GAAA,CAAA;AACtE,QAAA,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,GAAG,EAAE,OAAA,EAAQ;AACtC,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,SAAA,EAAW,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,CAAC,CAAA,CAAE,MAAA;AAAA,QAChC,KAAA;AAAA,QACA,KAAA,EAAO,OAAA,CAAQ,CAAC,CAAA,CAAG;AAAA,OACpB,CAAA;AAAA,IACH;AAAA,EACF;AACA,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA,OAAO;AAAA,MACL;AAAA,QACE,KAAA,EAAO,CAAA;AAAA,QACP,SAAA,EAAW,CAAA;AAAA,QACX,KAAK,IAAA,CAAK,MAAA;AAAA,QACV,KAAA,EAAO,EAAA;AAAA,QACP,KAAA,EAAO;AAAA;AACT,KACF;AAAA,EACF;AACA,EAAA,MAAM,WAA8B,EAAC;AACrC,EAAA,IAAI,QAAA,CAAS,CAAC,CAAA,CAAG,KAAA,GAAQ,CAAA,EAAG;AAC1B,IAAA,QAAA,CAAS,IAAA,CAAK;AAAA,MACZ,KAAA,EAAO,CAAA;AAAA,MACP,SAAA,EAAW,CAAA;AAAA,MACX,GAAA,EAAK,QAAA,CAAS,CAAC,CAAA,CAAG,KAAA;AAAA,MAClB,KAAA,EAAO,EAAA;AAAA,MACP,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACA,EAAA,QAAA,CAAS,QAAQ,CAAC,OAAA,EAAS,UAAU,QAAA,CAAS,IAAA,CAAK,EAAE,GAAG,OAAA,EAAS,GAAA,EAAK,QAAA,CAAS,QAAQ,CAAC,CAAA,EAAG,SAAS,IAAA,CAAK,MAAA,EAAQ,CAAC,CAAA;AAClH,EAAA,OAAO,QAAA;AACT;AAGA,SAAS,cAAA,CAAe,MAAiB,SAAA,EAAwC;AAC/E,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,UAAA;AAAY,MAAA,OAAO,gBAAA;AAAA,IACxB,KAAK,WAAA;AAAa,MAAA,OAAO,yBAAA;AAAA,IACzB,KAAK,MAAA;AAAQ,MAAA,OAAO,MAAA;AAAA,IACpB,KAAK,QAAA;AAAU,MAAA,OAAO,IAAI,MAAA,CAAO,SAAA,EAAY,IAAI,CAAA;AAAA,IACjD;AAAS,MAAA,OAAO,MAAA;AAAA;AAEpB;AAiBO,SAAS,SAAA,CAAU,MAAc,OAAA,EAAoD;AAC1F,EAAA,MAAM,MAAA,GAAS,kBAAA,CAAmB,SAAA,CAAU,OAAO,CAAA;AACnD,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,OAAO,GAAA,CAAI,gBAAA,CAAiB,YAAA,EAAc,SAAA,CAAU,sBAAA,EAAwB;AAAA,MAC1E,MAAA,EAAQ,EAAE,KAAA,EAAO,MAAA,CAAO,MAAM,OAAA;AAAQ,KACvC,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA;AAAA,EAClB;AACA,EAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AACpB,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,QAAA,IAAY,CAAC,IAAA,CAAK,SAAA;AAClC,IAAA,OAAO,GAAA,CAAI,gBAAA,CAAiB,iBAAA,EAAmB,SAAA,CAAU,2BAA2B,CAAC,CAAA;AACvF,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,IAAA,GAAO,MAAA,KAAW,CAAA;AAClC,IAAA,OAAO,EAAA,CAAG,EAAE,CAAA;AACd,EAAA,IAAI;AACF,IAAA,IAAI,IAAA,CAAK,SAAS,UAAA,EAAY;AAC5B,MAAA,MAAM,SAAsB,EAAC;AAC7B,MAAA,KAAA,MAAW,OAAA,IAAW,gBAAA,CAAiB,IAAA,EAAM,IAAA,CAAK,gBAAgB,CAAA,EAAG;AACnE,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,iBAAA,GAAoB,QAAQ,KAAA,GAAQ,OAAA,CAAQ,SAAA,EAAW,OAAA,CAAQ,GAAG,CAAA;AAClG,QAAA,MAAMC,MAAAA,GAAQ,gBAAgB,OAAA,EAAS,IAAA,CAAK,SAAS,IAAA,CAAK,OAAA,EAAS,cAAA,CAAe,WAAW,CAAC,CAAA;AAC9F,QAAA,KAAA,MAAW,QAAQA,MAAAA,EAAO;AACxB,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,OAAO,MAAA,CAAO,MAAA;AAAA,YACd,OAAA,EAAS,IAAA;AAAA,YACT,QAAA,EAAU;AAAA,cACR,OAAO,OAAA,CAAQ,KAAA;AAAA,cACf,OAAO,OAAA,CAAQ,KAAA;AAAA,cACf,GAAIA,OAAM,MAAA,GAAS,CAAA,GACf,EAAE,QAAA,EAAU,IAAA,KACZ;AAAC;AACP,WACD,CAAA;AAAA,QACH;AAAA,MACF;AACA,MAAA,OAAO,GAAG,MAAM,CAAA;AAAA,IAClB;AACA,IAAA,MAAM,KAAA,GAAQ,KAAK,IAAA,KAAS,MAAA,GACxB,WAAW,IAAA,EAAM,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,OAAO,CAAA,GAC3C,gBAAgB,IAAA,EAAM,IAAA,CAAK,SAAS,IAAA,CAAK,OAAA,EAAS,eAAe,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,SAAS,CAAC,CAAA;AAC/F,IAAA,OAAO,EAAA,CAAG,KAAA,CAAM,GAAA,CAAI,CAAC,OAAA,EAAS,WAAW,EAAE,KAAA,EAAO,OAAA,EAAQ,CAAE,CAAC,CAAA;AAAA,EAC/D,SACO,KAAA,EAAO;AACZ,IAAA,OAAO,GAAA,CAAI,gBAAA,CAAiB,YAAA,EAAc,SAAA,CAAU,sBAAA,EAAwB;AAAA,MAC1E,MAAA,EAAQ;AAAA,QACN,KAAA,EAAO,OAAO,KAAK;AAAA;AACrB,KACD,GAAG,KAAK,CAAA;AAAA,EACX;AACF;AC5NA,SAAS,cAAc,IAAA,EAAsB;AAC3C,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,OAAO,MAAA,GAAS,KAAK,MAAA,EAAQ;AAC3B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,GAAA,EAAK,MAAM,CAAA;AACtC,IAAA,IAAI,KAAA,GAAQ,CAAA;AACV,MAAA;AACF,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,EAAK,QAAQ,CAAC,CAAA;AACvC,IAAA,IAAI,GAAA,GAAM,CAAA;AACR,MAAA;AACF,IAAA,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAC,CAAA;AACpC,IAAA,MAAA,GAAS,GAAA,GAAM,CAAA;AAAA,EACjB;AACA,EAAA,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAA;AAC7B,EAAA,OAAO,KAAA,CAAM,KAAK,EAAE,CAAA;AACtB;AAKA,IAAM,SAAA,GAAY,iCAAA;AAKlB,IAAM,WAAA,GAAc,iDAAA;AAKpB,IAAM,mBAAA,GAAsB,SAAA;AAK5B,IAAM,iBAAA,GAAoB,YAAA;AAkBnB,SAAS,SAAA,CAAU,MAAc,OAAA,EAAgD;AACtF,EAAA,MAAM,WAAA,GAAc,kBAAA,CAAmB,SAAA,CAAU,OAAA,IAAW,EAAE,CAAA;AAC9D,EAAA,IAAI,CAAC,YAAY,OAAA,EAAS;AACxB,IAAA,OAAOC,GAAAA,CAAI,gBAAA,CAAiB,YAAA,EAAc,SAAA,CAAU,sBAAA,EAAwB;AAAA,MAC1E,MAAA,EAAQ,EAAE,KAAA,EAAO,WAAA,CAAY,MAAM,OAAA;AAAQ,KAC5C,CAAA,EAAG,WAAA,CAAY,KAAK,CAAA;AAAA,EACvB;AAEA,EAAA,MAAM,OAAO,WAAA,CAAY,IAAA;AACzB,EAAA,IAAI,MAAA,GAAS,IAAA;AAEb,EAAA,IAAI;AAEF,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,MAAA,GAAS,cAAc,MAAM,CAAA;AAAA,IAC/B;AAGA,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA;AAAA,IACvC;AAGA,IAAA,IAAI,KAAK,YAAA,EAAc;AACrB,MAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,WAAA,EAAa,EAAE,CAAA;AAAA,IACzC;AAGA,IAAA,IAAI,KAAK,kBAAA,EAAoB;AAC3B,MAAA,KAAA,MAAW,EAAE,OAAA,EAAS,WAAA,EAAY,IAAK,KAAK,kBAAA,EAAoB;AAC9D,QAAA,IAAI,KAAA;AACJ,QAAA,IAAI;AACF,UAAA,KAAA,GAAQ,IAAI,MAAA,CAAO,OAAA,EAAS,GAAG,CAAA;AAAA,QACjC,SACO,UAAA,EAAY;AACjB,UAAA,OAAOA,GAAAA,CAAI,gBAAA,CAAiB,YAAA,EAAc,SAAA,CAAU,sBAAA,EAAwB;AAAA,YAC1E,MAAA,EAAQ;AAAA,cACN,KAAA,EAAO,OAAO,UAAU;AAAA;AAC1B,WACD,GAAG,UAAU,CAAA;AAAA,QAChB;AACA,QAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,WAAW,CAAA;AAAA,MAC5C;AAAA,IACF;AAGA,IAAA,IAAI,KAAK,mBAAA,EAAqB;AAC5B,MAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,iBAAA,EAAmB,GAAG,CAAA;AAC9C,MAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,mBAAA,EAAqB,MAAM,CAAA;AAAA,IACrD;AAGA,IAAA,IAAI,KAAK,IAAA,EAAM;AACb,MAAA,MAAA,GAAS,OAAO,IAAA,EAAK;AAAA,IACvB;AAEA,IAAA,OAAOC,GAAG,MAAM,CAAA;AAAA,EAClB,SACO,KAAA,EAAO;AACZ,IAAA,OAAOD,GAAAA,CAAI,gBAAA,CAAiB,YAAA,EAAc,SAAA,CAAU,sBAAA,EAAwB;AAAA,MAC1E,MAAA,EAAQ;AAAA,QACN,KAAA,EAAO,OAAO,KAAK;AAAA;AACrB,KACD,GAAG,KAAK,CAAA;AAAA,EACX;AACF;AC9FO,SAAS,qBAAA,GAAyC;AACvD,EAAA,MAAM,QAAwB,EAAC;AAE/B,EAAA,MAAM,OAAA,GAA2B;AAAA,IAC/B,MAAM,OAAA,EAA8C;AAClD,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,SAAS,CAAA;AACrC,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AAAA,IAEA,MAAM,OAAA,EAA6C;AACjD,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,SAAS,CAAA;AACrC,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AAAA,IAEA,UAAU,EAAA,EAAkC;AAC1C,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,WAAA,EAAa,IAAI,CAAA;AACpC,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AAAA,IAEA,eAAe,EAAA,EAAuC;AACpD,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,IAAI,CAAA;AACzC,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AAAA,IAEA,GAAA,EAAK,CAAC,IAAA,KAAiB,WAAA,CAAY,OAAO,IAAI;AAAA,GAChD;AAEA,EAAA,OAAO,OAAA;AACT;AAOA,eAAe,WAAA,CACb,OACA,IAAA,EACoC;AACpC,EAAA,IAAI,WAAA,GAAc,IAAA;AAClB,EAAA,IAAI,SAAsB,EAAC;AAE3B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,QAAQ,KAAK,IAAA;AAAM,MACjB,KAAK,OAAA,EAAS;AACZ,QAAA,MAAM,MAAA,GAAS,SAAA,CAAU,WAAA,EAAa,IAAA,CAAK,OAAO,CAAA;AAClD,QAAA,IAAI,CAAC,MAAA,CAAO,OAAA;AACV,UAAA,OAAO,MAAA;AACT,QAAA,WAAA,GAAc,MAAA,CAAO,IAAA;AACrB,QAAA;AAAA,MACF;AAAA,MAEA,KAAK,OAAA,EAAS;AACZ,QAAA,MAAM,MAAA,GAAS,SAAA,CAAU,WAAA,EAAa,IAAA,CAAK,OAAO,CAAA;AAClD,QAAA,IAAI,CAAC,MAAA,CAAO,OAAA;AACV,UAAA,OAAO,MAAA;AACT,QAAA,MAAA,GAAS,MAAA,CAAO,IAAA;AAChB,QAAA;AAAA,MACF;AAAA,MAEA,KAAK,WAAA,EAAa;AAChB,QAAA,IAAI;AACF,UAAA,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA,CAAG,WAAW,CAAA;AAAA,QACzC,SACO,KAAA,EAAO;AACZ,UAAA,OAAOA,GAAAA,CAAI,gBAAA,CAAiB,gBAAA,EAAkB,SAAA,CAAU,0BAAA,EAA4B;AAAA,YAClF,MAAA,EAAQ;AAAA,cACN,KAAA,EAAO,OAAO,KAAK;AAAA;AACrB,WACD,GAAG,KAAK,CAAA;AAAA,QACX;AACA,QAAA;AAAA,MACF;AAAA,MAEA,KAAK,gBAAA,EAAkB;AACrB,QAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,UAAA,IAAI;AACF,YAAA,MAAA,GAAS,MAAM,IAAA,CAAK,EAAA,CAAG,MAAM,CAAA;AAAA,UAC/B,SACO,KAAA,EAAO;AACZ,YAAA,OAAOA,GAAAA,CAAI,gBAAA,CAAiB,eAAA,EAAiB,SAAA,CAAU,yBAAA,EAA2B;AAAA,cAChF,MAAA,EAAQ;AAAA,gBACN,KAAA,EAAO,OAAO,KAAK;AAAA;AACrB,aACD,GAAG,KAAK,CAAA;AAAA,UACX;AAAA,QACF;AACA,QAAA;AAAA,MACF;AAAA;AACF,EACF;AAEA,EAAA,OAAOC,EAAAA,CAAG,EAAE,IAAA,EAAM,WAAA,EAAa,QAAQ,CAAA;AACzC;;;ACtGO,IAAM,QAAA,GAA8B;AAAA,EACzC,KAAA,EAAO,SAAA;AAAA,EACP,KAAA,EAAO,SAAA;AAAA,EACP,QAAA,EAAU;AACZ","file":"index.js","sourcesContent":["/**\n * @h-ai/datapipe — 数据处理管线配置 Schema\n *\n * 本文件定义数据处理模块的错误码常量、Zod Schema 和配置类型。\n * 支持清洗(clean)、分块(chunk)、转换(transform)和管线(pipeline)。\n * @module datapipe-config\n */\n\nimport { z } from 'zod'\n\n// ─── 清洗配置 ───\n\n/**\n * 清洗选项 Schema\n *\n * 数据清洗规则配置,支持移除 HTML、URL、Email、标准化空白等。\n * @example\n * ```ts\n * import { CleanOptionsSchema } from '@h-ai/datapipe'\n * const options = CleanOptionsSchema.parse({ removeHtml: true, removeEmails: true })\n * ```\n */\nexport const CleanOptionsSchema = z.object({\n /** 移除 HTML 标签(默认 true) */\n removeHtml: z.boolean().default(true),\n /** 移除 URL(默认 false) */\n removeUrls: z.boolean().default(false),\n /** 移除 Email 地址(默认 false) */\n removeEmails: z.boolean().default(false),\n /** 标准化空白字符(多空格→单空格、去掉多余空行,默认 true) */\n normalizeWhitespace: z.boolean().default(true),\n /** 去除首尾空白(默认 true) */\n trim: z.boolean().default(true),\n /**\n * 自定义替换规则(正则→替换字符串)\n *\n * ❗ 安全提示:pattern 会通过 `new RegExp()` 构造,如果其值来源于用户输入,请在调用方先行校验以防止 ReDoS 攻击。\n */\n customReplacements: z.array(z.object({\n /** 正则表达式字符串 */\n pattern: z.string(),\n /** 替换文本 */\n replacement: z.string(),\n })).optional(),\n})\n\n/**\n * 清洗选项类型\n * @example\n * ```ts\n * import { CleanOptionsSchema, type CleanOptions } from '@h-ai/datapipe'\n * const options: CleanOptions = CleanOptionsSchema.parse({ removeHtml: true })\n * ```\n */\nexport type CleanOptions = z.infer<typeof CleanOptionsSchema>\n\n/**\n * 清洗选项输入类型\n * @example\n * ```ts\n * import type { CleanOptionsInput } from '@h-ai/datapipe'\n * const options: CleanOptionsInput = { removeHtml: true, removeUrls: true }\n * ```\n */\nexport type CleanOptionsInput = z.input<typeof CleanOptionsSchema>\n\n// ─── 分块配置 ───\n\n/**\n * 分块模式枚举\n *\n * - `sentence` — 按句子分块\n * - `paragraph` — 按段落分块\n * - `markdown` — 按 Markdown 标题分块(## / ### 等)\n * - `page` — 按分页符分块\n * - `word` — 按非空白词数分块,不截断单个词\n * - `character` — 按 Unicode code point 分块,不拆代理对\n * - `custom` — 自定义分隔符分块\n * @example\n * ```ts\n * import { ChunkModeSchema } from '@h-ai/datapipe'\n * const mode = ChunkModeSchema.parse('character')\n * ```\n */\nexport const ChunkModeSchema = z.enum([\n 'sentence',\n 'paragraph',\n 'markdown',\n 'page',\n 'word',\n 'character',\n 'custom',\n])\n\n/**\n * 分块模式类型\n * @example\n * ```ts\n * import type { ChunkMode } from '@h-ai/datapipe'\n * const options: ChunkMode = 'character'\n * ```\n */\nexport type ChunkMode = z.infer<typeof ChunkModeSchema>\n\n/**\n * 分块选项 Schema\n * datapipe 的默认 overlap 为 0;消费者可显式提供自己的默认值,例如 AI Knowledge 为 200。\n * @example\n * ```ts\n * import { ChunkOptionsSchema } from '@h-ai/datapipe'\n * const options = ChunkOptionsSchema.parse({ mode: 'markdown', maxSize: 500, overlap: 50 })\n * // maxSize 已包含重叠,overlap 必须小于 maxSize;自定义正则仅来自可信配置。\n * ```\n */\nexport const ChunkOptionsSchema = z.object({\n /** 分块模式 */\n mode: ChunkModeSchema,\n /** 每块上限包含 overlap/分隔符;word 按非空白词,其他按 Unicode code point,默认 1500。 */\n maxSize: z.number().int().positive().default(1500),\n /** 重叠使用与 maxSize 相同的单位,必须严格小于 maxSize。 */\n overlap: z.number().int().min(0).default(0),\n /**\n * 自定义分隔符正则(仅 mode='custom' 时使用)\n *\n * ❗ 安全提示:separator 会通过 `new RegExp()` 构造,如果其值来源于用户输入,请在调用方先行校验以防止 ReDoS 攻击。\n */\n separator: z.string().optional(),\n /** Markdown 标题分割深度(1-6,默认 2,即 # 和 ## 作为分块边界;设为 3 则 ### 也作为分块边界) */\n markdownMinLevel: z.number().int().min(1).max(6).default(2),\n /** 是否保留 Markdown 标题在分块内容中(默认 true) */\n markdownKeepTitle: z.boolean().default(true),\n}).refine(options => options.overlap < options.maxSize, {\n path: ['overlap'],\n})\n\n/**\n * 分块选项类型\n * @example\n * ```ts\n * import { ChunkOptionsSchema, type ChunkOptions } from '@h-ai/datapipe'\n * const options: ChunkOptions = ChunkOptionsSchema.parse({ mode: 'character', maxSize: 500 })\n * ```\n */\nexport type ChunkOptions = z.infer<typeof ChunkOptionsSchema>\n\n/**\n * 分块选项输入类型\n * @example\n * ```ts\n * import type { ChunkOptionsInput } from '@h-ai/datapipe'\n * const options: ChunkOptionsInput = { mode: 'character', maxSize: 500, overlap: 50 }\n * ```\n */\nexport type ChunkOptionsInput = z.input<typeof ChunkOptionsSchema>\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"datapipe_cleanFailed\": \"Failed to clean text: {error}\",\n \"datapipe_chunkFailed\": \"Failed to chunk text: {error}\",\n \"datapipe_transformFailed\": \"Failed to transform text: {error}\",\n \"datapipe_pipelineFailed\": \"Pipeline execution failed: {error}\",\n \"datapipe_configError\": \"Datapipe config validation failed: {error}\",\n \"datapipe_missingSeparator\": \"Custom chunk mode requires a separator parameter\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"datapipe_cleanFailed\": \"テキストのクリーニングに失敗しました: {error}\",\n \"datapipe_chunkFailed\": \"テキストの分割に失敗しました: {error}\",\n \"datapipe_transformFailed\": \"テキストの変換に失敗しました: {error}\",\n \"datapipe_pipelineFailed\": \"パイプラインの実行に失敗しました: {error}\",\n \"datapipe_configError\": \"データパイプ設定の検証に失敗しました: {error}\",\n \"datapipe_missingSeparator\": \"カスタム分割モードにはseparatorパラメーターが必要です\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"datapipe_cleanFailed\": \"清洗文本失败: {error}\",\n \"datapipe_chunkFailed\": \"分块文本失败: {error}\",\n \"datapipe_transformFailed\": \"转换文本失败: {error}\",\n \"datapipe_pipelineFailed\": \"管线执行失败: {error}\",\n \"datapipe_configError\": \"数据处理配置校验失败:{error}\",\n \"datapipe_missingSeparator\": \"自定义分块模式需要提供 separator 参数\"\n}\n","/**\n * @h-ai/datapipe — i18n\n *\n * 本文件提供数据处理模块的 i18n 文案访问入口。\n * @module datapipe-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesJaJP from '../messages/ja-JP.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n// ─── i18n ───\n\n/**\n * 数据处理模块文案 Key 类型\n * @example 模块内部上下文\n * ```ts\n * const key: DatapipeMessageKey = 'datapipe_cleanFailed'\n * const message = datapipeM(key)\n * ```\n */\ntype DatapipeMessageKey = keyof typeof messagesZhCN\n\n/**\n * 获取数据处理模块文案。\n * @param key - 文案 Key\n * @param options - 插值参数与格式化选项\n * @returns 本地化后的文案字符串\n * @example 模块内部上下文\n * ```ts\n * const message = datapipeM('datapipe_cleanFailed', { params: { error: 'invalid input' }, locale: 'en-US' })\n * ```\n */\nexport const datapipeM = core.i18n.createMessageGetter<DatapipeMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n 'ja-JP': messagesJaJP,\n})\n","/**\n * @h-ai/datapipe — 类型定义\n *\n * 本文件定义数据处理模块的核心接口和类型。\n * @module datapipe-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport type { ChunkOptionsInput, CleanOptionsInput } from './datapipe-config.js'\nimport { core } from '@h-ai/core'\n\n// ─── 错误定义(照 @h-ai/core 范式) ───\n\n/**\n * 数据处理错误信息映射(错误码:HTTP状态码)。\n *\n * 完整错误码将自动生成为:`hai:datapipe:NNN`\n */\nconst DatapipeErrorInfo = {\n CLEAN_FAILED: '001:500',\n CHUNK_FAILED: '002:500',\n TRANSFORM_FAILED: '003:500',\n PIPELINE_FAILED: '004:500',\n CONFIG_ERROR: '005:400',\n MISSING_SEPARATOR: '006:400',\n} as const satisfies ErrorInfo\n\n/**\n * Datapipe 模块标准错误定义对象。\n * @example\n * ```ts\n * import { HaiDatapipeError } from '@h-ai/datapipe'\n * import { err } from '@h-ai/core'\n * const result = err(HaiDatapipeError.CONFIG_ERROR, 'Invalid chunk configuration')\n * if (!result.success) result.error.httpStatus\n * ```\n */\nexport const HaiDatapipeError = core.error.buildHaiErrorsDef('datapipe', DatapipeErrorInfo)\n\n// ─── 数据块 ───\n\n/**\n * 数据块接口\n *\n * 表示经过分块处理后的单个文本片段。\n * @example\n * ```ts\n * import type { DataChunk } from '@h-ai/datapipe'\n * const options: DataChunk = { index: 0, content: '## Intro', metadata: { title: 'Intro', level: 2 } }\n * ```\n */\nexport interface DataChunk {\n /** 分块索引(从 0 开始) */\n index: number\n /** 原文切片;保留空白和分隔符。word 以词计量,其他模式以 Unicode code point 计量。 */\n content: string\n /** 分块元数据(可选) */\n metadata?: Record<string, unknown>\n}\n\n// ─── 转换函数 ───\n\n/**\n * 转换函数类型\n *\n * 自定义文本后处理函数,可以是同步或异步。\n * @example\n * ```ts\n * import type { TransformFn } from '@h-ai/datapipe'\n * const options: TransformFn = text => text.trim().toLowerCase()\n * ```\n */\nexport type TransformFn = (text: string) => string | Promise<string>\n\n/**\n * 分块转换函数类型\n *\n * 对分块列表进行后处理(如过滤、合并等)。\n * @example\n * ```ts\n * import type { ChunkTransformFn } from '@h-ai/datapipe'\n * const options: ChunkTransformFn = chunks => chunks.filter(chunk => chunk.content.trim().length > 0)\n * ```\n */\nexport type ChunkTransformFn = (chunks: DataChunk[]) => DataChunk[] | Promise<DataChunk[]>\n\n// ─── 管线步骤 ───\n\n/**\n * 管线步骤类型\n *\n * 管线由一系列步骤组成,支持清洗、分块和自定义转换。\n * @example\n * ```ts\n * import type { PipelineStep } from '@h-ai/datapipe'\n * const options: PipelineStep = { type: 'chunk', options: { mode: 'paragraph', maxSize: 500, overlap: 50 } }\n * ```\n */\nexport type PipelineStep\n = | { type: 'clean', options?: CleanOptionsInput }\n | { type: 'chunk', options: ChunkOptionsInput }\n | { type: 'transform', fn: TransformFn }\n | { type: 'chunkTransform', fn: ChunkTransformFn }\n\n// ─── 管线结果 ───\n\n/**\n * 管线执行结果\n * @example\n * ```ts\n * import type { PipelineResult } from '@h-ai/datapipe'\n * const options: PipelineResult = { text: 'One. Two.', chunks: [{ index: 0, content: 'One. Two.' }] }\n * ```\n */\nexport interface PipelineResult {\n /** 处理后的文本(分块前的最终文本) */\n text: string\n /** 分块列表(如果管线包含 chunk 步骤) */\n chunks: DataChunk[]\n}\n\n// ─── 操作接口 ───\n\n/**\n * 清洗操作接口\n *\n * 通过 `datapipe.clean()` 调用。\n * @example\n * ```ts\n * import { datapipe, type CleanOperations } from '@h-ai/datapipe'\n * const clean: CleanOperations = datapipe.clean\n * const result = clean('<p>Hello</p>')\n * if (result.success) result.data.trim()\n * ```\n */\nexport interface CleanOperations {\n /**\n * 清洗文本\n *\n * @param text - 原始文本\n * @param options - 清洗选项(可选,使用默认值)\n * @returns 清洗后的文本\n */\n (text: string, options?: CleanOptionsInput): HaiResult<string>\n}\n\n/**\n * 分块操作接口\n *\n * 通过 `datapipe.chunk()` 调用。\n * @example\n * ```ts\n * import { datapipe, type ChunkOperations } from '@h-ai/datapipe'\n * const chunk: ChunkOperations = datapipe.chunk\n * const result = chunk('One. Two.', { mode: 'sentence', maxSize: 10 })\n * if (result.success) result.data.map(item => item.index)\n * ```\n */\nexport interface ChunkOperations {\n /**\n * 对文本进行分块\n *\n * @param text - 输入文本\n * @param options - 分块选项\n * @returns 分块列表\n */\n (text: string, options: ChunkOptionsInput): HaiResult<DataChunk[]>\n}\n\n/**\n * 管线构建器接口\n *\n * 通过 `datapipe.pipeline()` 创建,链式添加步骤后执行。\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport interface PipelineBuilder {\n /** 添加清洗步骤 */\n clean: (options?: CleanOptionsInput) => PipelineBuilder\n /** 添加分块步骤 */\n chunk: (options: ChunkOptionsInput) => PipelineBuilder\n /** 添加文本转换步骤 */\n transform: (fn: TransformFn) => PipelineBuilder\n /** 添加分块后处理步骤 */\n chunkTransform: (fn: ChunkTransformFn) => PipelineBuilder\n /** 执行管线 */\n run: (text: string) => Promise<HaiResult<PipelineResult>>\n}\n\n/**\n * 数据处理管线服务接口\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport interface DatapipeFunctions {\n /** 清洗文本 */\n clean: CleanOperations\n /** 分块文本 */\n chunk: ChunkOperations\n /** 创建管线构建器 */\n pipeline: () => PipelineBuilder\n}\n","/**\n * @h-ai/datapipe — 保留源文本的有界分块。\n * word 按非空白词计数,其他模式按 Unicode code point 计数,均先计入 overlap。\n * @module datapipe-chunk\n */\nimport type { HaiResult } from '@h-ai/core'\nimport type { ChunkMode, ChunkOptionsInput } from './datapipe-config.js'\nimport type { DataChunk } from './datapipe-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { ChunkOptionsSchema } from './datapipe-config.js'\nimport { datapipeM } from './datapipe-i18n.js'\nimport { HaiDatapipeError } from './datapipe-types.js'\n\n/**\n * Markdown 源区间;标题移除仅影响显式 keepTitle=false 的内容起点。\n * @example 模块内部上下文\n * ```ts\n * const section: MarkdownSection = { start: 0, bodyStart: 8, end: 12, title: 'Title', level: 1 }\n * const bodyLength = section.end - section.bodyStart\n * ```\n */\ninterface MarkdownSection {\n start: number\n bodyStart: number\n end: number\n title: string\n level: number\n}\n\n/** 找出自然边界对应的 code point 下标;保留分隔符,不通过 split/join 改写正文。 */\nfunction findBoundaries(text: string, expression?: RegExp): number[] {\n if (!expression)\n return []\n const boundaries: number[] = []\n let previousOffset = 0\n let points = 0\n for (const match of text.matchAll(expression)) {\n const offset = match.index + match[0].length\n if (offset <= previousOffset)\n continue\n points += Array.from(text.slice(previousOffset, offset)).length\n boundaries.push(points)\n previousOffset = offset\n }\n return boundaries\n}\n\n/** 取不超过预算的最后自然边界;边界至少越过 overlap,保证下轮起点严格前进。 */\nfunction boundedEnd(boundaries: number[], start: number, limit: number, overlap: number): number {\n let lower = 0\n let upper = boundaries.length\n while (lower < upper) {\n const middle = Math.floor((lower + upper) / 2)\n if (boundaries[middle]! <= limit)\n lower = middle + 1\n else\n upper = middle\n }\n const candidate = boundaries[lower - 1]\n return candidate !== undefined && candidate > start + overlap\n ? candidate\n : limit\n}\n\n/**\n * 所有字符模式共用滑窗;原文切片已包含空白、标点和分隔符,不追加隐式换行。\n * @example splitCharacters('甲😀乙丙丁', 3, 1) // ['甲😀乙', '乙丙丁']\n */\nfunction splitCharacters(text: string, maxSize: number, overlap: number, expression?: RegExp): string[] {\n const points = Array.from(text)\n const boundaries = findBoundaries(text, expression)\n const chunks: string[] = []\n for (let start = 0; start < points.length;) {\n const limit = Math.min(start + maxSize, points.length)\n const end = limit === points.length\n ? limit\n : boundedEnd(boundaries, start, limit, overlap)\n chunks.push(points.slice(start, end).join(''))\n if (end === points.length)\n break\n start = end - overlap\n }\n return chunks\n}\n\n/** 按非空白词滑窗,切片仍使用原始字符串的 offset,保留词间全部空白。 */\nfunction splitWords(text: string, maxSize: number, overlap: number): string[] {\n const words = [\n ...text.matchAll(/\\S+/gu),\n ]\n const chunks: string[] = []\n for (let start = 0; start < words.length;) {\n const end = Math.min(start + maxSize, words.length)\n const from = start === 0\n ? 0\n : words[start]!.index\n const to = end === words.length\n ? text.length\n : words[end]!.index\n chunks.push(text.slice(from, to))\n if (end === words.length)\n break\n start = end - overlap\n }\n return chunks\n}\n\n/** 匹配 # 至配置级别的标题;fenced code 内的 # 是正文,不创建虚假 section。 */\nfunction markdownSections(text: string, minLevel: number): MarkdownSection[] {\n const headings: Array<Omit<MarkdownSection, 'end'>> = []\n let fence: { character: string, length: number } | undefined\n for (const line of text.matchAll(/[^\\n]*(?:\\n|$)/g)) {\n const content = line[0].replace(/\\r?\\n$/, '')\n if (fence) {\n if (new RegExp(`^ {0,3}${fence.character}{${fence.length},}[ \\\\t]*$`).test(content))\n fence = undefined\n continue\n }\n const opening = /^ {0,3}(`{3,}|~{3,})/.exec(content)\n if (opening) {\n fence = { character: opening[1]![0]!, length: opening[1]!.length }\n continue\n }\n const heading = /^ {0,3}(#{1,6})[ \\t]/.exec(content)\n if (heading && heading[1]!.length <= minLevel) {\n let title = content.slice(heading[0].length).trim()\n let end = title.length\n while (title[end - 1] === '#')\n end--\n // 只移除空白分隔的尾部 #,按线性扫描处理,避免可交换量词造成正则回溯。\n if (end < title.length && (title[end - 1] === ' ' || title[end - 1] === '\\t'))\n title = title.slice(0, end).trimEnd()\n headings.push({\n start: line.index,\n bodyStart: line.index + line[0].length,\n title,\n level: heading[1]!.length,\n })\n }\n }\n if (headings.length === 0) {\n return [\n {\n start: 0,\n bodyStart: 0,\n end: text.length,\n title: '',\n level: 0,\n },\n ]\n }\n const sections: MarkdownSection[] = []\n if (headings[0]!.start > 0) {\n sections.push({\n start: 0,\n bodyStart: 0,\n end: headings[0]!.start,\n title: '',\n level: 0,\n })\n }\n headings.forEach((heading, index) => sections.push({ ...heading, end: headings[index + 1]?.start ?? text.length }))\n return sections\n}\n\n/** 自然边界只决定优先切点,不删除分隔符或改变预算单位。 */\nfunction modeExpression(mode: ChunkMode, separator?: string): RegExp | undefined {\n switch (mode) {\n case 'sentence': return /[。!?.!?]+\\s*/gu\n case 'paragraph': return /\\r?\\n(?:[ \\t]*\\r?\\n)+/gu\n case 'page': return /\\f/gu\n case 'custom': return new RegExp(separator!, 'gu')\n default: return undefined\n }\n}\n\n/**\n * 对文本分块;word 使用词数,其他模式使用 Unicode code point,非字节/token/UTF-16 长度。\n * maxSize 包含 overlap 和分隔符,0 <= overlap < maxSize;默认不重叠。\n * 原始空白与分隔符保留,Markdown 仅在显式 keepTitle=false 时移除标题行。\n * @param text - 源文本;空或全空白输入返回空数组。\n * @param options - 模式与预算;Markdown section 之间不重叠,section 内使用相同边界算法。\n * @returns 有界且顺序连续编号的分块;配置错误或非法正则返回错误结果。\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = datapipe.chunk('One. Two. Three.', { mode: 'sentence', maxSize: 12, overlap: 2 })\n * if (result.success) result.data.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport function chunkText(text: string, options: ChunkOptionsInput): HaiResult<DataChunk[]> {\n const parsed = ChunkOptionsSchema.safeParse(options)\n if (!parsed.success) {\n return err(HaiDatapipeError.CONFIG_ERROR, datapipeM('datapipe_configError', {\n params: { error: parsed.error.message },\n }), parsed.error)\n }\n const opts = parsed.data\n if (opts.mode === 'custom' && !opts.separator)\n return err(HaiDatapipeError.MISSING_SEPARATOR, datapipeM('datapipe_missingSeparator'))\n if (!text || text.trim().length === 0)\n return ok([])\n try {\n if (opts.mode === 'markdown') {\n const chunks: DataChunk[] = []\n for (const section of markdownSections(text, opts.markdownMinLevel)) {\n const content = text.slice(opts.markdownKeepTitle ? section.start : section.bodyStart, section.end)\n const parts = splitCharacters(content, opts.maxSize, opts.overlap, modeExpression('paragraph'))\n for (const part of parts) {\n chunks.push({\n index: chunks.length,\n content: part,\n metadata: {\n title: section.title,\n level: section.level,\n ...(parts.length > 1\n ? { subChunk: true }\n : {}),\n },\n })\n }\n }\n return ok(chunks)\n }\n const parts = opts.mode === 'word'\n ? splitWords(text, opts.maxSize, opts.overlap)\n : splitCharacters(text, opts.maxSize, opts.overlap, modeExpression(opts.mode, opts.separator))\n return ok(parts.map((content, index) => ({ index, content })))\n }\n catch (cause) {\n return err(HaiDatapipeError.CHUNK_FAILED, datapipeM('datapipe_chunkFailed', {\n params: {\n error: String(cause),\n },\n }), cause)\n }\n}\n","/**\n * @h-ai/datapipe — 文本清洗功能\n *\n * 提供文本清洗工具,支持移除 HTML、URL、Email、标准化空白等。\n * @module datapipe-clean\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { CleanOptionsInput } from './datapipe-config.js'\n\nimport { err, ok } from '@h-ai/core'\n\nimport { CleanOptionsSchema } from './datapipe-config.js'\nimport { datapipeM } from './datapipe-i18n.js'\nimport { HaiDatapipeError } from './datapipe-types.js'\n\n/** 按首个闭合符提取文本;仅用于清洗,不代替渲染 HTML 前的安全消毒。 */\nfunction stripHtmlTags(text: string): string {\n const parts: string[] = []\n let cursor = 0\n while (cursor < text.length) {\n const start = text.indexOf('<', cursor)\n if (start < 0)\n break\n const end = text.indexOf('>', start + 1)\n if (end < 0)\n break\n parts.push(text.slice(cursor, start))\n cursor = end + 1\n }\n parts.push(text.slice(cursor))\n return parts.join('')\n}\n\n/**\n * URL 正则(HTTP/HTTPS)\n */\nconst URL_REGEX = /https?:\\/\\/[^\\s<>\"{}|\\\\^`[\\]]+/g\n\n/**\n * Email 正则\n */\nconst EMAIL_REGEX = /(?<![\\w.%+-])[\\w.%+-]+@[a-z0-9.-]+\\.[a-z]{2,}/gi\n\n/**\n * 多空行正则(3行及以上空行 → 2行)\n */\nconst MULTI_NEWLINE_REGEX = /\\n{3,}/g\n\n/**\n * 多空格正则\n */\nconst MULTI_SPACE_REGEX = /[ \\t]{2,}/g\n\n/**\n * 清洗文本\n *\n * 根据配置选项对文本进行清洗处理。\n *\n * @param text - 原始文本\n * @param options - 清洗选项(可选)\n * @returns 清洗后的文本\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = datapipe.clean('<p>Hello</p>', { removeHtml: true })\n * if (result.success) result.data.toUpperCase()\n * else result.error.message\n * ```\n */\nexport function cleanText(text: string, options?: CleanOptionsInput): HaiResult<string> {\n const parseResult = CleanOptionsSchema.safeParse(options ?? {})\n if (!parseResult.success) {\n return err(HaiDatapipeError.CONFIG_ERROR, datapipeM('datapipe_configError', {\n params: { error: parseResult.error.message },\n }), parseResult.error)\n }\n\n const opts = parseResult.data\n let result = text\n\n try {\n // 移除 HTML 标签\n if (opts.removeHtml) {\n result = stripHtmlTags(result)\n }\n\n // 移除 URL\n if (opts.removeUrls) {\n result = result.replace(URL_REGEX, '')\n }\n\n // 移除 Email\n if (opts.removeEmails) {\n result = result.replace(EMAIL_REGEX, '')\n }\n\n // 自定义替换\n if (opts.customReplacements) {\n for (const { pattern, replacement } of opts.customReplacements) {\n let regex: RegExp\n try {\n regex = new RegExp(pattern, 'g')\n }\n catch (regexError) {\n return err(HaiDatapipeError.CONFIG_ERROR, datapipeM('datapipe_configError', {\n params: {\n error: String(regexError),\n },\n }), regexError)\n }\n result = result.replace(regex, replacement)\n }\n }\n\n // 标准化空白\n if (opts.normalizeWhitespace) {\n result = result.replace(MULTI_SPACE_REGEX, ' ')\n result = result.replace(MULTI_NEWLINE_REGEX, '\\n\\n')\n }\n\n // 去除首尾空白\n if (opts.trim) {\n result = result.trim()\n }\n\n return ok(result)\n }\n catch (error) {\n return err(HaiDatapipeError.CLEAN_FAILED, datapipeM('datapipe_cleanFailed', {\n params: {\n error: String(error),\n },\n }), error)\n }\n}\n","/**\n * @h-ai/datapipe — 管线构建器\n *\n * 提供可组合的管线构建器,支持链式添加清洗、分块、转换步骤后执行。\n * @module datapipe-pipeline\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ChunkOptionsInput, CleanOptionsInput } from './datapipe-config.js'\nimport type {\n ChunkTransformFn,\n DataChunk,\n PipelineBuilder,\n PipelineResult,\n PipelineStep,\n TransformFn,\n} from './datapipe-types.js'\n\nimport { err, ok } from '@h-ai/core'\n\nimport { chunkText } from './datapipe-chunk.js'\nimport { cleanText } from './datapipe-clean.js'\nimport { datapipeM } from './datapipe-i18n.js'\nimport { HaiDatapipeError } from './datapipe-types.js'\n\n/**\n * 创建管线构建器\n *\n * @returns PipelineBuilder 实例,支持链式添加步骤后执行\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport function createPipelineBuilder(): PipelineBuilder {\n const steps: PipelineStep[] = []\n\n const builder: PipelineBuilder = {\n clean(options?: CleanOptionsInput): PipelineBuilder {\n steps.push({ type: 'clean', options })\n return builder\n },\n\n chunk(options: ChunkOptionsInput): PipelineBuilder {\n steps.push({ type: 'chunk', options })\n return builder\n },\n\n transform(fn: TransformFn): PipelineBuilder {\n steps.push({ type: 'transform', fn })\n return builder\n },\n\n chunkTransform(fn: ChunkTransformFn): PipelineBuilder {\n steps.push({ type: 'chunkTransform', fn })\n return builder\n },\n\n run: (text: string) => runPipeline(steps, text),\n }\n\n return builder\n}\n\n// ─── 管线执行 ───\n\n/**\n * 执行管线步骤\n */\nasync function runPipeline(\n steps: PipelineStep[],\n text: string,\n): Promise<HaiResult<PipelineResult>> {\n let currentText = text\n let chunks: DataChunk[] = []\n\n for (const step of steps) {\n switch (step.type) {\n case 'clean': {\n const result = cleanText(currentText, step.options)\n if (!result.success)\n return result\n currentText = result.data\n break\n }\n\n case 'chunk': {\n const result = chunkText(currentText, step.options)\n if (!result.success)\n return result\n chunks = result.data\n break\n }\n\n case 'transform': {\n try {\n currentText = await step.fn(currentText)\n }\n catch (error) {\n return err(HaiDatapipeError.TRANSFORM_FAILED, datapipeM('datapipe_transformFailed', {\n params: {\n error: String(error),\n },\n }), error)\n }\n break\n }\n\n case 'chunkTransform': {\n if (chunks.length > 0) {\n try {\n chunks = await step.fn(chunks)\n }\n catch (error) {\n return err(HaiDatapipeError.PIPELINE_FAILED, datapipeM('datapipe_pipelineFailed', {\n params: {\n error: String(error),\n },\n }), error)\n }\n }\n break\n }\n }\n }\n\n return ok({ text: currentText, chunks })\n}\n","/**\n * @h-ai/datapipe — 数据处理管线主入口\n *\n * 提供统一的 `datapipe` 对象,聚合清洗、分块和管线功能。\n * datapipe 为纯函数模块,无需初始化即可使用。\n * @module datapipe-main\n */\n\nimport type { DatapipeFunctions } from './datapipe-types.js'\n\nimport { chunkText } from './datapipe-chunk.js'\nimport { cleanText } from './datapipe-clean.js'\nimport { createPipelineBuilder } from './datapipe-pipeline.js'\n\n// ─── 统一服务对象 ───\n\n/**\n * 数据处理管线服务对象\n *\n * 纯函数模块,无需初始化即可使用。\n * @example\n * ```ts\n * import { datapipe } from '@h-ai/datapipe'\n * const result = await datapipe.pipeline()\n * .clean({ removeHtml: true })\n * .transform(text => text.toLowerCase())\n * .chunk({ mode: 'character', maxSize: 500, overlap: 50 })\n * .run('<p>One. Two. Three.</p>')\n * if (result.success) result.data.chunks.map(chunk => chunk.content)\n * else result.error.message\n * ```\n */\nexport const datapipe: DatapipeFunctions = {\n clean: cleanText,\n chunk: chunkText,\n pipeline: createPipelineBuilder,\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/datapipe",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.20",
|
|
5
5
|
"description": "Data processing pipeline module for hai-framework: clean, chunk, transform",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"node": "^22.23.4 || ^24.22.1 || ^26.12.1"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@h-ai/core": "1.0.0-beta.
|
|
25
|
-
"zod": "^4.6.
|
|
24
|
+
"@h-ai/core": "1.0.0-beta.20",
|
|
25
|
+
"zod": "^4.6.7"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"tsup": "^
|
|
28
|
+
"tsup": "^9.0.0",
|
|
29
29
|
"typescript": "^6.0.3"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|