@h-ai/datapipe 1.0.0-beta.1 → 1.0.0-beta.3

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 CHANGED
@@ -10,6 +10,8 @@ A data processing pipeline module for text cleaning (`clean`), chunking (`chunk`
10
10
 
11
11
  ## Core features
12
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
+
13
15
  | Feature | Description |
14
16
  | -------------------- | ----------------------------------------------------------------------------------------------------- |
15
17
  | Text cleaning | Remove HTML tags, URLs, and emails; normalize whitespace; apply custom regex replacements |
package/README.ja.md CHANGED
@@ -10,6 +10,8 @@
10
10
 
11
11
  ## 主な機能
12
12
 
13
+ HTML 除去はテキスト抽出であり、安全な HTML 消毒ではありません。HTML として表示する際は UI の安全な描画機構を使用してください。組み込みのタグ・メール処理は長い不正入力での反復バックトラックを避けます。独自正規表現は信頼できる設定から与え、外部ユーザーの任意パターンを直接使用しないでください。
14
+
13
15
  | 機能 | 説明 |
14
16
  | ---------------------- | --------------------------------------------------------------------- |
15
17
  | テキストのクリーニング | HTML タグ・URL・Email の除去、空白の正規化、独自の正規表現による置換 |
package/README.md CHANGED
@@ -10,6 +10,8 @@
10
10
 
11
11
  ## 核心功能清单
12
12
 
13
+ HTML 清洗用于提取文本,不是安全消毒;结果用于 HTML 渲染时仍需使用 UI 的安全渲染机制。内置标签与邮箱清洗处理长异常输入时避免重复回溯;自定义正则来自可信配置,不直接接收外部用户提交的模式。
14
+
13
15
  | 功能 | 说明 |
14
16
  | -------- | ----------------------------------------------------------- |
15
17
  | 文本清洗 | 移除 HTML 标签、URL、Email,标准化空白,自定义正则替换 |
package/dist/index.js CHANGED
@@ -234,9 +234,24 @@ function chunkText(text, options) {
234
234
  return err(HaiDatapipeError.CHUNK_FAILED, datapipeM("datapipe_chunkFailed", { params: { error: String(cause) } }), cause);
235
235
  }
236
236
  }
237
- var HTML_TAG_REGEX = /<[^>]*>/g;
237
+ function stripHtmlTags(text) {
238
+ const parts = [];
239
+ let cursor = 0;
240
+ while (cursor < text.length) {
241
+ const start = text.indexOf("<", cursor);
242
+ if (start < 0)
243
+ break;
244
+ const end = text.indexOf(">", start + 1);
245
+ if (end < 0)
246
+ break;
247
+ parts.push(text.slice(cursor, start));
248
+ cursor = end + 1;
249
+ }
250
+ parts.push(text.slice(cursor));
251
+ return parts.join("");
252
+ }
238
253
  var URL_REGEX = /https?:\/\/[^\s<>"{}|\\^`[\]]+/g;
239
- var EMAIL_REGEX = /[\w.%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi;
254
+ var EMAIL_REGEX = /(?<![\w.%+-])[\w.%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi;
240
255
  var MULTI_NEWLINE_REGEX = /\n{3,}/g;
241
256
  var MULTI_SPACE_REGEX = /[ \t]{2,}/g;
242
257
  function cleanText(text, options) {
@@ -248,7 +263,7 @@ function cleanText(text, options) {
248
263
  let result = text;
249
264
  try {
250
265
  if (opts.removeHtml) {
251
- result = result.replace(HTML_TAG_REGEX, "");
266
+ result = stripHtmlTags(result);
252
267
  }
253
268
  if (opts.removeUrls) {
254
269
  result = result.replace(URL_REGEX, "");
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":";;;;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,CAAA,CAAE,MAAA,CAAO,CAAA,OAAA,KAAW,OAAA,CAAQ,OAAA,GAAU,OAAA,CAAQ,OAAA,EAAS,EAAE,IAAA,EAAM,CAAC,SAAS,CAAA,EAAG;;;ACnI7E,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,UAAU,SAAA,GAAY,KAAA;AAC9E;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,GAAS,QAAQ,UAAA,CAAW,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA;AAC1F,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,QAAQ,CAAC,GAAG,IAAA,CAAK,QAAA,CAAS,OAAO,CAAC,CAAA;AACxC,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,GAAI,CAAA,GAAI,KAAA,CAAM,KAAK,CAAA,CAAG,KAAA;AAC7C,IAAA,MAAM,EAAA,GAAK,QAAQ,KAAA,CAAM,MAAA,GAAS,KAAK,MAAA,GAAS,KAAA,CAAM,GAAG,CAAA,CAAG,KAAA;AAC5D,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,KAAK,EAAE,KAAA,EAAO,KAAK,KAAA,EAAO,SAAA,EAAW,KAAK,KAAA,GAAQ,IAAA,CAAK,CAAC,CAAA,CAAE,QAAQ,KAAA,EAAO,KAAA,EAAO,QAAQ,CAAC,CAAA,CAAG,QAAQ,CAAA;AAAA,IAC/G;AAAA,EACF;AACA,EAAA,IAAI,SAAS,MAAA,KAAW,CAAA;AACtB,IAAA,OAAO,CAAC,EAAE,KAAA,EAAO,CAAA,EAAG,SAAA,EAAW,CAAA,EAAG,GAAA,EAAK,IAAA,CAAK,MAAA,EAAQ,KAAA,EAAO,EAAA,EAAI,KAAA,EAAO,GAAG,CAAA;AAC3E,EAAA,MAAM,WAA8B,EAAC;AACrC,EAAA,IAAI,QAAA,CAAS,CAAC,CAAA,CAAG,KAAA,GAAQ,CAAA;AACvB,IAAA,QAAA,CAAS,IAAA,CAAK,EAAE,KAAA,EAAO,CAAA,EAAG,WAAW,CAAA,EAAG,GAAA,EAAK,QAAA,CAAS,CAAC,EAAG,KAAA,EAAO,KAAA,EAAO,EAAA,EAAI,KAAA,EAAO,GAAG,CAAA;AACxF,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,MAAA,CAAO,OAAA;AACV,IAAA,OAAO,IAAI,gBAAA,CAAiB,YAAA,EAAc,SAAA,CAAU,sBAAA,EAAwB,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,MAAA,CAAO,MAAM,OAAA,EAAQ,EAAG,CAAA,EAAG,OAAO,KAAK,CAAA;AACxI,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,IAAA,IAAQA,MAAAA;AACjB,UAAA,MAAA,CAAO,IAAA,CAAK,EAAE,KAAA,EAAO,MAAA,CAAO,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,QAAA,EAAU,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,KAAA,EAAO,QAAQ,KAAA,EAAO,GAAIA,MAAAA,CAAM,MAAA,GAAS,CAAA,GAAI,EAAE,QAAA,EAAU,IAAA,EAAK,GAAI,EAAC,EAAG,EAAG,CAAA;AAAA,MAClK;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,wBAAwB,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,OAAO,KAAK,CAAA,EAAE,EAAG,GAAG,KAAK,CAAA;AAAA,EAC1H;AACF;ACzKA,IAAM,cAAA,GAAiB,UAAA;AAKvB,IAAM,SAAA,GAAY,iCAAA;AAKlB,IAAM,WAAA,GAAc,oCAAA;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,IAAI,gBAAA,CAAiB,YAAA,EAAc,SAAA,CAAU,sBAAA,EAAwB,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,WAAA,CAAY,MAAM,OAAA,EAAQ,EAAG,CAAA,EAAG,YAAY,KAAK,CAAA;AAAA,EAClJ;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,MAAA,CAAO,OAAA,CAAQ,cAAA,EAAgB,EAAE,CAAA;AAAA,IAC5C;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,wBAAwB,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,OAAO,UAAU,CAAA,EAAE,EAAG,GAAG,UAAU,CAAA;AAAA,QACpI;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,wBAAwB,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,OAAO,KAAK,CAAA,EAAE,EAAG,GAAG,KAAK,CAAA;AAAA,EAC1H;AACF;ACvEO,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,4BAA4B,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,OAAO,KAAK,CAAA,EAAE,EAAG,GAAG,KAAK,CAAA;AAAA,QAClI;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,2BAA2B,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,OAAO,KAAK,CAAA,EAAE,EAAG,GAAG,KAAK,CAAA;AAAA,UAChI;AAAA,QACF;AACA,QAAA;AAAA,MACF;AAAA;AACF,EACF;AAEA,EAAA,OAAOC,EAAAA,CAAG,EAAE,IAAA,EAAM,WAAA,EAAa,QAAQ,CAAA;AACzC;;;AC9FO,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, { 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/**\n * HTML 标签正则\n */\nconst HTML_TAG_REGEX = /<[^>]*>/g\n\n/**\n * URL 正则(HTTP/HTTPS)\n */\nconst URL_REGEX = /https?:\\/\\/[^\\s<>\"{}|\\\\^`[\\]]+/g\n\n/**\n * Email 正则\n */\nconst EMAIL_REGEX = /[\\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 = result.replace(HTML_TAG_REGEX, '')\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":"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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"]}
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.1",
4
+ "version": "1.0.0-beta.3",
5
5
  "description": "Data processing pipeline module for hai-framework: clean, chunk, transform",
6
6
  "exports": {
7
7
  ".": {
@@ -21,7 +21,7 @@
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.1",
24
+ "@h-ai/core": "1.0.0-beta.3",
25
25
  "zod": "^4.6.5"
26
26
  },
27
27
  "devDependencies": {