formatferry 1.0.17 → 1.0.19

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.
Files changed (2) hide show
  1. package/dist/index.js +54 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -22126,6 +22126,30 @@ function escapeHtml(str) {
22126
22126
  function computeFontSize(transform) {
22127
22127
  return Math.sqrt(transform[2] ** 2 + transform[3] ** 2);
22128
22128
  }
22129
+ var CJK_REGEX2 = /[\u4E00-\u9FFF\u3400-\u4DBF\u3000-\u303F\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF\uF900-\uFAFF\uFF00-\uFF60\uFFE0-\uFFEF]/;
22130
+ function containsCJK(str) {
22131
+ return CJK_REGEX2.test(str);
22132
+ }
22133
+ function isCJKChar(ch) {
22134
+ const cp = ch.codePointAt(0);
22135
+ return cp >= 19968 && cp <= 40959 || // CJK Unified Ideographs
22136
+ cp >= 13312 && cp <= 19903 || // CJK Extension A
22137
+ cp >= 12288 && cp <= 12351 || // CJK Symbols and Punctuation
22138
+ cp >= 12352 && cp <= 12447 || // Hiragana
22139
+ cp >= 12448 && cp <= 12543 || // Katakana
22140
+ cp >= 44032 && cp <= 55215 || // Hangul Syllables
22141
+ cp >= 63744 && cp <= 64255 || // CJK Compatibility Ideographs
22142
+ // Fullwidth Forms — exclude halfwidth Katakana (FF61-FF9F) which are narrow
22143
+ cp >= 65280 && cp <= 65376 || // Fullwidth Latin + punctuation
22144
+ cp >= 65504 && cp <= 65519;
22145
+ }
22146
+ function visualCharCount(str) {
22147
+ let count = 0;
22148
+ for (const ch of str) {
22149
+ count += isCJKChar(ch) ? 2 : 1;
22150
+ }
22151
+ return count;
22152
+ }
22129
22153
  function normalizeLigatures(text) {
22130
22154
  return text.normalize("NFC").replace(/ff/g, "ff").replace(/fi/g, "fi").replace(/fl/g, "fl").replace(/ffi/g, "ffi").replace(/ffl/g, "ffl");
22131
22155
  }
@@ -22137,8 +22161,8 @@ function isSafeUrl(url) {
22137
22161
  }
22138
22162
  function detectFontStyle(fontName) {
22139
22163
  if (!fontName) return null;
22140
- const bold = /(Bold|Black|Heavy|Semibold|Demi)/i.test(fontName) && !/Blackletter/i.test(fontName);
22141
- const italic = /(Italic|Oblique|Slanted)/i.test(fontName);
22164
+ const bold = /(Bold|Black|Heavy|Semibold|Demi|太|中太)/i.test(fontName) && !/Blackletter/i.test(fontName);
22165
+ const italic = /(Italic|Oblique|Slanted|Kaiti|楷体|斜)/i.test(fontName);
22142
22166
  if (bold && italic) return "bold-italic";
22143
22167
  if (bold) return "bold";
22144
22168
  if (italic) return "italic";
@@ -22188,7 +22212,7 @@ function textItemToPositioned(item) {
22188
22212
  const ty = item.transform[5];
22189
22213
  const rawHeight = item.height ?? Math.abs(item.transform[3]) ?? 10;
22190
22214
  const height = rawHeight > 0 ? rawHeight : 10;
22191
- const width = item.width ?? item.str.length * (height * 0.5);
22215
+ const width = item.width ?? visualCharCount(item.str) * (height * 0.5);
22192
22216
  const descent = height * DESCENDER_BUDGET_FACTOR;
22193
22217
  const y = ty - descent;
22194
22218
  const paddedHeight = height + descent;
@@ -22276,7 +22300,10 @@ function itemsToLinearText(items) {
22276
22300
  rows.push([it]);
22277
22301
  }
22278
22302
  }
22279
- const widths = items.map((i) => i.str.length > 0 ? i.width / i.str.length : 0).filter((w) => w > 0);
22303
+ const widths = items.map((i) => {
22304
+ const vc = visualCharCount(i.str);
22305
+ return vc > 0 ? i.width / vc : 0;
22306
+ }).filter((w) => w > 0);
22280
22307
  const medianCharWidth = widths.length ? [...widths].sort((a, b) => a - b)[Math.floor(widths.length / 2)] || 1 : 1;
22281
22308
  const labelGap = medianCharWidth * FORM_LABEL_GAP_FACTOR;
22282
22309
  const NBSP2 = "\xA0\xA0";
@@ -22339,7 +22366,10 @@ function renderTextBlockEnhanced(items, medianPageFontSize, outlineTitles) {
22339
22366
  row.sort((a, b) => a.x - b.x);
22340
22367
  const fsSamples = row.map((it) => it.fontSize ?? 0).filter((f) => f > 0);
22341
22368
  const rowFs = fsSamples.length > 0 ? [...fsSamples].sort((a, b) => a - b)[Math.floor(fsSamples.length / 2)] : medianPageFontSize;
22342
- const rowWidths = row.map((it) => it.str.length > 0 ? it.width / it.str.length : 0).filter((w) => w > 0);
22369
+ const rowWidths = row.map((it) => {
22370
+ const vc = visualCharCount(it.str);
22371
+ return vc > 0 ? it.width / vc : 0;
22372
+ }).filter((w) => w > 0);
22343
22373
  const rowMedianCharWidth = rowWidths.length ? [...rowWidths].sort((a, b) => a - b)[Math.floor(rowWidths.length / 2)] || 1 : 1;
22344
22374
  const rowLabelGap = rowMedianCharWidth * FORM_LABEL_GAP_FACTOR;
22345
22375
  let plainText = "";
@@ -22422,8 +22452,14 @@ function repairRowHyphenation(rows) {
22422
22452
  const nextRow = rows[i + 1];
22423
22453
  const lastItem = [...row].sort((a, b) => b.right - a.right)[0];
22424
22454
  const firstNext = [...nextRow].sort((a, b) => a.x - b.x)[0];
22425
- if (lastItem && firstNext && /-$/.test(lastItem.str) && new RegExp("^\\p{Ll}", "u").test(firstNext.str)) {
22426
- const fixed = { ...lastItem, str: lastItem.str.slice(0, -1) };
22455
+ if (lastItem && firstNext && /-$/.test(lastItem.str) && !containsCJK(lastItem.str) && new RegExp("^\\p{Ll}", "u").test(firstNext.str)) {
22456
+ const hyphenWidth = lastItem.width / lastItem.str.length * 0.4;
22457
+ const fixed = {
22458
+ ...lastItem,
22459
+ str: lastItem.str.slice(0, -1),
22460
+ width: lastItem.width - hyphenWidth,
22461
+ right: lastItem.right - hyphenWidth
22462
+ };
22427
22463
  result.push([...row.map((it) => it === lastItem ? fixed : it), ...nextRow]);
22428
22464
  i += 2;
22429
22465
  continue;
@@ -22435,8 +22471,12 @@ function repairRowHyphenation(rows) {
22435
22471
  return result;
22436
22472
  }
22437
22473
  function detectListMarker(plainText) {
22474
+ const cjkBulletMatch = /^[・〇☆※]\s*(.+)/u.exec(plainText);
22475
+ if (cjkBulletMatch && cjkBulletMatch[1].length > 0) return { kind: "ul", bodyText: cjkBulletMatch[1] };
22438
22476
  const bulletMatch = /^[•◦◆▪▸–\-*·]\s+(.+)/u.exec(plainText);
22439
22477
  if (bulletMatch) return { kind: "ul", bodyText: bulletMatch[1] };
22478
+ const cjkNumberedMatch = /^[\u2460-\u24FF\u3248-\u325F\u3200-\u321E㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉]\s*(.+)/u.exec(plainText);
22479
+ if (cjkNumberedMatch) return { kind: "ol", bodyText: cjkNumberedMatch[1] };
22440
22480
  const numberedMatch = /^\d+[.)]\s+(.+)/.exec(plainText);
22441
22481
  if (numberedMatch) return { kind: "ol", bodyText: numberedMatch[1] };
22442
22482
  const letteredMatch = /^[a-z][.)]\s+(.+)/.exec(plainText);
@@ -24268,7 +24308,7 @@ function extractArticle(html, domProvider) {
24268
24308
  }
24269
24309
 
24270
24310
  // ../../src/shared/token-estimator.ts
24271
- var CJK_REGEX2 = /[\u4e00-\u9fff\u3400-\u4dbf\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g;
24311
+ var CJK_REGEX3 = /[\u4e00-\u9fff\u3400-\u4dbf\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g;
24272
24312
  var MAX_INPUT_LENGTH = 1e6;
24273
24313
  function estimateTokens(text) {
24274
24314
  if (!text || text.length === 0) {
@@ -24277,7 +24317,7 @@ function estimateTokens(text) {
24277
24317
  if (text.length > MAX_INPUT_LENGTH) {
24278
24318
  return Math.round(text.length / 4);
24279
24319
  }
24280
- const cjkMatches = text.match(CJK_REGEX2);
24320
+ const cjkMatches = text.match(CJK_REGEX3);
24281
24321
  const cjkCount = cjkMatches ? cjkMatches.length : 0;
24282
24322
  const otherCount = text.length - cjkCount;
24283
24323
  const cjkTokens = cjkCount / 1.5;
@@ -24637,6 +24677,9 @@ var ToonifyService = class {
24637
24677
  paragraphLines.push(line);
24638
24678
  endIndex++;
24639
24679
  }
24680
+ if (paragraphLines.length === 0) {
24681
+ return { block: null, endIndex: startIndex };
24682
+ }
24640
24683
  return {
24641
24684
  block: { p: paragraphLines.join(" ").trim() },
24642
24685
  endIndex: endIndex - 1
@@ -25315,8 +25358,8 @@ import { readFileSync as readFileSync4 } from "fs";
25315
25358
  import { resolve, dirname as dirname3 } from "path";
25316
25359
  import { fileURLToPath } from "url";
25317
25360
  var getVersion = () => {
25318
- if ("1.0.17") {
25319
- return "1.0.17";
25361
+ if ("1.0.19") {
25362
+ return "1.0.19";
25320
25363
  }
25321
25364
  try {
25322
25365
  const __dirname = dirname3(fileURLToPath(import.meta.url));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "formatferry",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "FormatFerry CLI — Convert HTML, DOCX, PDF, XLSX, CSV, JSON, XML, PPTX to Markdown",
5
5
  "keywords": [
6
6
  "markdown",