@dragon708/docmind-markdown 1.2.9 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -0
- package/dist/index.js +128 -103
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# `@dragon708/docmind-markdown`
|
|
2
|
+
|
|
3
|
+
Convierte **`StructuredDocumentResult`** (modelo compartido de DocMind) en **Markdown** (GFM), **texto orientado a LLM** y **secciones/chunks** con Markdown opcional por trozo. Expone **`extractMarkdown`**: un router unificado sobre **estructurado**, **bytes** o **ruta** (Node) que delega en **DOCX** (Mammoth → Turndown), **PDF** y formatos **HTML / CSV / Excel** mediante el **motor de conversión a Markdown integrado** (solo en Node), con **fallback** a serialización estructurada cuando la ruta especializada no aplica o falla.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Instalación
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @dragon708/docmind-markdown
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Dependencias destacadas: `@dragon708/docmind-shared`, cadena de conversión a Markdown empaquetada con el paquete, `mammoth`, `turndown`, `turndown-plugin-gfm`. La lógica es **Node-first**; en navegador puro las rutas binarias pesadas y parte de DOCX bytes no están disponibles (ver mensajes `unsupported-runtime` / warnings).
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Módulos conceptuales
|
|
18
|
+
|
|
19
|
+
| Área | Entradas principales | Salida |
|
|
20
|
+
|------|----------------------|--------|
|
|
21
|
+
| Structured → MD | `StructuredDocumentResult` | `convertStructuredToMarkdown` / `renderMarkdown` |
|
|
22
|
+
| Structured → LLM text | Mismo envelope | `convertStructuredToLlmText` / `renderLlmText` / alias `extractLlmContent` |
|
|
23
|
+
| Chunks | Structured + opciones | `splitStructuredIntoChunks` / `renderMarkdownSections` / `extractStructuredChunks` |
|
|
24
|
+
| DOCX bytes → MD | Buffer/path | `convertDocxToMarkdown` (Mammoth + Turndown + GFM) |
|
|
25
|
+
| PDF bytes → MD | Buffer/path | `convertPdfToMarkdown` (motor integrado en Node) |
|
|
26
|
+
| HTML / CSV / XLSX | Bytes/path/text | `convertHtmlToMarkdown`, `convertCsvToMarkdown`, `convertSpreadsheetToMarkdown` |
|
|
27
|
+
| Router único | structured \| bytes \| path | `extractMarkdown` |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Uso rápido
|
|
32
|
+
|
|
33
|
+
### Desde documento estructurado
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { convertStructuredToMarkdown, renderMarkdown } from "@dragon708/docmind-markdown";
|
|
37
|
+
|
|
38
|
+
const md = convertStructuredToMarkdown(structured, {
|
|
39
|
+
appendUnreferencedTables: true,
|
|
40
|
+
pageTransitionMarkers: true,
|
|
41
|
+
});
|
|
42
|
+
// renderMarkdown es alias del mismo símbolo
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Texto para LLM (no es Markdown)
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { renderLlmText } from "@dragon708/docmind-markdown";
|
|
49
|
+
|
|
50
|
+
const plain = renderLlmText(structured, { compact: true });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Trozos con Markdown por sección
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { renderMarkdownSections } from "@dragon708/docmind-markdown";
|
|
57
|
+
|
|
58
|
+
const sections = await renderMarkdownSections(structured, {
|
|
59
|
+
maxChars: 4000,
|
|
60
|
+
chunks: { includeMarkdown: true, preserveTables: true },
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `extractMarkdown` unificado (Node con bytes)
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { extractMarkdown } from "@dragon708/docmind-markdown";
|
|
68
|
+
|
|
69
|
+
const result = await extractMarkdown(
|
|
70
|
+
{ data: buffer, filename: "informe.pdf" },
|
|
71
|
+
{
|
|
72
|
+
structuredFallback: structured,
|
|
73
|
+
pdf: { /* opciones del conversor PDF → Markdown */ },
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
console.log(result.markdown);
|
|
78
|
+
console.log(result.strategy, result.warnings, result.routing);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Opciones frecuentes (ver tipos `ExtractMarkdownOptions`):
|
|
82
|
+
|
|
83
|
+
- **`structuredFallback`**: envelope si la ruta especializada falla o está vacía.
|
|
84
|
+
- **`markdown`**: opciones de `convertStructuredToMarkdown` en fallback.
|
|
85
|
+
- **`docx` / `pdf` / `html` / `csv` / `spreadsheet`**: knobs por formato binario (p. ej. `markdownSpreadsheet.maxRowsPerSheet`, `includeSheetNames`, `compactMode`).
|
|
86
|
+
- Post-proceso Excel: las tablas GFM “atascadas” en una sola línea se **normalizan** en el paquete (filas separadas por `\n`) antes de devolver el string.
|
|
87
|
+
|
|
88
|
+
### Conversores directos por formato
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import {
|
|
92
|
+
convertDocxToMarkdown,
|
|
93
|
+
convertPdfToMarkdown,
|
|
94
|
+
convertHtmlToMarkdown,
|
|
95
|
+
convertCsvToMarkdown,
|
|
96
|
+
convertSpreadsheetToMarkdown,
|
|
97
|
+
} from "@dragon708/docmind-markdown";
|
|
98
|
+
|
|
99
|
+
// Cada uno devuelve markdown, warnings y origen (p. ej. ruta especializada vs fallback estructurado)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Detección de binario
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { detectBinaryFormat } from "@dragon708/docmind-markdown";
|
|
106
|
+
|
|
107
|
+
const fmt = detectBinaryFormat(bytes, "archivo.bin", mimeType);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### HTML: cadena vs ruta
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { looksLikeHtmlString } from "@dragon708/docmind-markdown";
|
|
114
|
+
|
|
115
|
+
if (looksLikeHtmlString(input)) {
|
|
116
|
+
// Tratar como markup, no como path
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Estrategias y routing (`extractMarkdown`)
|
|
123
|
+
|
|
124
|
+
El resultado puede incluir:
|
|
125
|
+
|
|
126
|
+
- **`strategy`**: qué ruta tomó el router (identificadores tipo `pdf-*-specialized`, `spreadsheet-structured-fallback`, etc.; ver tipos exportados).
|
|
127
|
+
- **`warnings`**: trazas legibles (`[docmind-markdown:extractMarkdown]`, etc.).
|
|
128
|
+
- **`routing`**: resumen opcional (`routingSummary`, `detectedFormat`, `specializedPipeline`, `usedStructuredFallback`, `mediaHint`).
|
|
129
|
+
|
|
130
|
+
Útil para telemetría y UI de depuración (p. ej. playground).
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## CSV y hojas de cálculo
|
|
135
|
+
|
|
136
|
+
- **Preparación de CSV** (módulo tabular): cabecera sintética, `maxRows`, etc., antes de la conversión.
|
|
137
|
+
- **`convertSpreadsheetToMarkdown`**: tras la conversión desde hoja de cálculo, opciones `includeSheetNames`, `compactMode`, `maxRowsPerSheet` vía `limitSpreadsheetMarkdownRowsPerSheet`.
|
|
138
|
+
- **`splitJammedSpreadsheetPipeTableLines`**: corrige tablas GFM en una sola línea antes de devolver el Markdown.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Empaquetado y `prepack`
|
|
143
|
+
|
|
144
|
+
El `package.json` define scripts **`prepack`** que validan y copian dependencias **vendoradas** del runtime de conversión para que el tarball npm sea autocontenido. Si desarrollas en el monorepo, ejecuta `npm run build` antes de `npm pack` / publicar.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Seguridad
|
|
149
|
+
|
|
150
|
+
- El Markdown y el HTML intermedio (DOCX) pueden contener contenido hostil. **Sanitiza** antes de `dangerouslySetInnerHTML` o equivalentes.
|
|
151
|
+
- No confíes en documentos arbitrarios para conversión sin cuarentena en servidor.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Paquetes relacionados
|
|
156
|
+
|
|
157
|
+
| Paquete | Rol |
|
|
158
|
+
|---------|-----|
|
|
159
|
+
| `@dragon708/docmind-node` | Cliente que llama a `extractMarkdown` con `structuredFallback` cableado |
|
|
160
|
+
| `@dragon708/docmind-browser` | Mismas firmas; sin conversión binaria pesada en el cliente |
|
|
161
|
+
| `@dragon708/docmind-shared` | `StructuredDocumentResult` |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Licencia
|
|
166
|
+
|
|
167
|
+
MIT (monorepo DocMind).
|
package/dist/index.js
CHANGED
|
@@ -1197,6 +1197,131 @@ async function convertPdfBufferToMarkdown(input, options) {
|
|
|
1197
1197
|
return { markdown: r.markdown };
|
|
1198
1198
|
}
|
|
1199
1199
|
|
|
1200
|
+
// src/tabular-markdown-postprocess.ts
|
|
1201
|
+
function compactMarkdownOutput(markdown) {
|
|
1202
|
+
return markdown.replace(/\n{3,}/g, "\n\n").split("\n").map((l) => l.trimEnd()).join("\n").trim();
|
|
1203
|
+
}
|
|
1204
|
+
function countCsvColumns(firstLine) {
|
|
1205
|
+
let n = 1;
|
|
1206
|
+
let inQuotes = false;
|
|
1207
|
+
for (let i = 0; i < firstLine.length; i++) {
|
|
1208
|
+
const c = firstLine[i];
|
|
1209
|
+
if (c === '"') {
|
|
1210
|
+
inQuotes = !inQuotes;
|
|
1211
|
+
} else if (c === "," && !inQuotes) {
|
|
1212
|
+
n++;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return n;
|
|
1216
|
+
}
|
|
1217
|
+
function prepareCsvTextForCognipeer(text, options) {
|
|
1218
|
+
const warnings = [];
|
|
1219
|
+
const includeHeader = options?.includeHeader !== false;
|
|
1220
|
+
const maxRows = options?.maxRows;
|
|
1221
|
+
let lines = text.split(/\r?\n/).filter((l) => l.length > 0);
|
|
1222
|
+
if (lines.length === 0) {
|
|
1223
|
+
return { text, warnings };
|
|
1224
|
+
}
|
|
1225
|
+
if (!includeHeader) {
|
|
1226
|
+
const colCount = Math.max(1, countCsvColumns(lines[0]));
|
|
1227
|
+
const synth = Array.from({ length: colCount }, (_, i) => `Column ${i + 1}`).join(",");
|
|
1228
|
+
lines = [synth, ...lines];
|
|
1229
|
+
warnings.push(
|
|
1230
|
+
"[docmind-markdown:csv] includeHeader:false: prepended synthetic header row so the first CSV row appears as table data."
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
if (maxRows != null && maxRows >= 0) {
|
|
1234
|
+
const header = lines[0];
|
|
1235
|
+
const rest = lines.slice(1);
|
|
1236
|
+
const data = rest.slice(0, maxRows);
|
|
1237
|
+
if (rest.length > maxRows) {
|
|
1238
|
+
warnings.push(
|
|
1239
|
+
`[docmind-markdown:csv] maxRows:${maxRows}: truncated data rows before conversion (line-based; quoted newlines inside fields may skew counts).`
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
lines = [header, ...data];
|
|
1243
|
+
}
|
|
1244
|
+
return { text: lines.join("\n"), warnings };
|
|
1245
|
+
}
|
|
1246
|
+
function lineHasGfmPipeSeparatorFragment(line) {
|
|
1247
|
+
return /\|(?:\s*:?-+\s*\|){2,}/.test(line);
|
|
1248
|
+
}
|
|
1249
|
+
function newlineBeforePipeTableAfterSheetHeading(markdown) {
|
|
1250
|
+
return markdown.replace(/^##([^\n|]+)\|/gm, "##$1\n|");
|
|
1251
|
+
}
|
|
1252
|
+
function splitJammedSpreadsheetPipeTableLines(markdown) {
|
|
1253
|
+
const md = newlineBeforePipeTableAfterSheetHeading(markdown.replace(/^\uFEFF/, ""));
|
|
1254
|
+
const lines = md.split(/\r?\n/);
|
|
1255
|
+
const out = [];
|
|
1256
|
+
for (const line of lines) {
|
|
1257
|
+
const trimmedStart = line.trimStart();
|
|
1258
|
+
if (!trimmedStart.startsWith("|") || !lineHasGfmPipeSeparatorFragment(line)) {
|
|
1259
|
+
out.push(line);
|
|
1260
|
+
continue;
|
|
1261
|
+
}
|
|
1262
|
+
let split = line.replace(/\|\|(?=\s*:?-{2,})/g, "|\n|");
|
|
1263
|
+
split = split.replace(/\|\s+(?=\|)/g, "|\n");
|
|
1264
|
+
out.push(...split.split("\n"));
|
|
1265
|
+
}
|
|
1266
|
+
return out.join("\n");
|
|
1267
|
+
}
|
|
1268
|
+
function stripSpreadsheetSheetHeadings(markdown) {
|
|
1269
|
+
return markdown.replace(/^##[^\n]+\n+/gm, "");
|
|
1270
|
+
}
|
|
1271
|
+
function limitSpreadsheetMarkdownRowsPerSheet(markdown, maxRowsPerSheet) {
|
|
1272
|
+
const warnings = [];
|
|
1273
|
+
if (maxRowsPerSheet < 0) return { markdown, warnings };
|
|
1274
|
+
const lines = markdown.split("\n");
|
|
1275
|
+
const out = [];
|
|
1276
|
+
let i = 0;
|
|
1277
|
+
let truncatedAny = false;
|
|
1278
|
+
const emitLimitedTable = (tableLines) => {
|
|
1279
|
+
if (tableLines.length >= 3) {
|
|
1280
|
+
const header = tableLines[0];
|
|
1281
|
+
const sep = tableLines[1];
|
|
1282
|
+
const body = tableLines.slice(2, 2 + maxRowsPerSheet);
|
|
1283
|
+
if (tableLines.length - 2 > maxRowsPerSheet) truncatedAny = true;
|
|
1284
|
+
out.push(header, sep, ...body);
|
|
1285
|
+
} else {
|
|
1286
|
+
out.push(...tableLines);
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
while (i < lines.length) {
|
|
1290
|
+
const line = lines[i];
|
|
1291
|
+
const isSheetTitle = /^##\s+.+$/.test(line);
|
|
1292
|
+
if (isSheetTitle) {
|
|
1293
|
+
out.push(line);
|
|
1294
|
+
i++;
|
|
1295
|
+
while (i < lines.length && lines[i].trim() === "") {
|
|
1296
|
+
out.push(lines[i]);
|
|
1297
|
+
i++;
|
|
1298
|
+
}
|
|
1299
|
+
const tableStart = i;
|
|
1300
|
+
while (i < lines.length && lines[i].trim().startsWith("|")) {
|
|
1301
|
+
i++;
|
|
1302
|
+
}
|
|
1303
|
+
emitLimitedTable(lines.slice(tableStart, i));
|
|
1304
|
+
continue;
|
|
1305
|
+
}
|
|
1306
|
+
if (line.trim().startsWith("|")) {
|
|
1307
|
+
const tableStart = i;
|
|
1308
|
+
while (i < lines.length && lines[i].trim().startsWith("|")) {
|
|
1309
|
+
i++;
|
|
1310
|
+
}
|
|
1311
|
+
emitLimitedTable(lines.slice(tableStart, i));
|
|
1312
|
+
continue;
|
|
1313
|
+
}
|
|
1314
|
+
out.push(line);
|
|
1315
|
+
i++;
|
|
1316
|
+
}
|
|
1317
|
+
if (truncatedAny) {
|
|
1318
|
+
warnings.push(
|
|
1319
|
+
`[docmind-markdown:spreadsheet] maxRowsPerSheet:${maxRowsPerSheet}: truncated data rows in one or more sheet tables.`
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
return { markdown: out.join("\n"), warnings };
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1200
1325
|
// src/cognipeer-file-markdown.ts
|
|
1201
1326
|
var BROWSER = (label) => `@dragon708/docmind-markdown: ${label} \u2192 Markdown via @cognipeer/to-markdown requires Node.js. In the browser, use a server-side conversion or supply structured input / structuredFallback.`;
|
|
1202
1327
|
function cognipeerOpts(options) {
|
|
@@ -1359,6 +1484,9 @@ async function convertCognipeerFileToMarkdown(format, defaultTempFile, input, op
|
|
|
1359
1484
|
fallbackReason: "empty"
|
|
1360
1485
|
};
|
|
1361
1486
|
}
|
|
1487
|
+
if (format === "spreadsheet") {
|
|
1488
|
+
markdown = splitJammedSpreadsheetPipeTableLines(markdown);
|
|
1489
|
+
}
|
|
1362
1490
|
return { markdown, warnings, source: "cognipeer" };
|
|
1363
1491
|
} finally {
|
|
1364
1492
|
if (cleanup) {
|
|
@@ -1428,109 +1556,6 @@ async function convertHtmlToMarkdown(input, options) {
|
|
|
1428
1556
|
return convertCognipeerFileToMarkdown("html", "document.html", input, cognipeerOptions);
|
|
1429
1557
|
}
|
|
1430
1558
|
|
|
1431
|
-
// src/tabular-markdown-postprocess.ts
|
|
1432
|
-
function compactMarkdownOutput(markdown) {
|
|
1433
|
-
return markdown.replace(/\n{3,}/g, "\n\n").split("\n").map((l) => l.trimEnd()).join("\n").trim();
|
|
1434
|
-
}
|
|
1435
|
-
function countCsvColumns(firstLine) {
|
|
1436
|
-
let n = 1;
|
|
1437
|
-
let inQuotes = false;
|
|
1438
|
-
for (let i = 0; i < firstLine.length; i++) {
|
|
1439
|
-
const c = firstLine[i];
|
|
1440
|
-
if (c === '"') {
|
|
1441
|
-
inQuotes = !inQuotes;
|
|
1442
|
-
} else if (c === "," && !inQuotes) {
|
|
1443
|
-
n++;
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
return n;
|
|
1447
|
-
}
|
|
1448
|
-
function prepareCsvTextForCognipeer(text, options) {
|
|
1449
|
-
const warnings = [];
|
|
1450
|
-
const includeHeader = options?.includeHeader !== false;
|
|
1451
|
-
const maxRows = options?.maxRows;
|
|
1452
|
-
let lines = text.split(/\r?\n/).filter((l) => l.length > 0);
|
|
1453
|
-
if (lines.length === 0) {
|
|
1454
|
-
return { text, warnings };
|
|
1455
|
-
}
|
|
1456
|
-
if (!includeHeader) {
|
|
1457
|
-
const colCount = Math.max(1, countCsvColumns(lines[0]));
|
|
1458
|
-
const synth = Array.from({ length: colCount }, (_, i) => `Column ${i + 1}`).join(",");
|
|
1459
|
-
lines = [synth, ...lines];
|
|
1460
|
-
warnings.push(
|
|
1461
|
-
"[docmind-markdown:csv] includeHeader:false: prepended synthetic header row so the first CSV row appears as table data."
|
|
1462
|
-
);
|
|
1463
|
-
}
|
|
1464
|
-
if (maxRows != null && maxRows >= 0) {
|
|
1465
|
-
const header = lines[0];
|
|
1466
|
-
const rest = lines.slice(1);
|
|
1467
|
-
const data = rest.slice(0, maxRows);
|
|
1468
|
-
if (rest.length > maxRows) {
|
|
1469
|
-
warnings.push(
|
|
1470
|
-
`[docmind-markdown:csv] maxRows:${maxRows}: truncated data rows before conversion (line-based; quoted newlines inside fields may skew counts).`
|
|
1471
|
-
);
|
|
1472
|
-
}
|
|
1473
|
-
lines = [header, ...data];
|
|
1474
|
-
}
|
|
1475
|
-
return { text: lines.join("\n"), warnings };
|
|
1476
|
-
}
|
|
1477
|
-
function stripSpreadsheetSheetHeadings(markdown) {
|
|
1478
|
-
return markdown.replace(/^##[^\n]+\n+/gm, "");
|
|
1479
|
-
}
|
|
1480
|
-
function limitSpreadsheetMarkdownRowsPerSheet(markdown, maxRowsPerSheet) {
|
|
1481
|
-
const warnings = [];
|
|
1482
|
-
if (maxRowsPerSheet < 0) return { markdown, warnings };
|
|
1483
|
-
const lines = markdown.split("\n");
|
|
1484
|
-
const out = [];
|
|
1485
|
-
let i = 0;
|
|
1486
|
-
let truncatedAny = false;
|
|
1487
|
-
const emitLimitedTable = (tableLines) => {
|
|
1488
|
-
if (tableLines.length >= 3) {
|
|
1489
|
-
const header = tableLines[0];
|
|
1490
|
-
const sep = tableLines[1];
|
|
1491
|
-
const body = tableLines.slice(2, 2 + maxRowsPerSheet);
|
|
1492
|
-
if (tableLines.length - 2 > maxRowsPerSheet) truncatedAny = true;
|
|
1493
|
-
out.push(header, sep, ...body);
|
|
1494
|
-
} else {
|
|
1495
|
-
out.push(...tableLines);
|
|
1496
|
-
}
|
|
1497
|
-
};
|
|
1498
|
-
while (i < lines.length) {
|
|
1499
|
-
const line = lines[i];
|
|
1500
|
-
const isSheetTitle = /^##\s+.+$/.test(line);
|
|
1501
|
-
if (isSheetTitle) {
|
|
1502
|
-
out.push(line);
|
|
1503
|
-
i++;
|
|
1504
|
-
while (i < lines.length && lines[i].trim() === "") {
|
|
1505
|
-
out.push(lines[i]);
|
|
1506
|
-
i++;
|
|
1507
|
-
}
|
|
1508
|
-
const tableStart = i;
|
|
1509
|
-
while (i < lines.length && lines[i].trim().startsWith("|")) {
|
|
1510
|
-
i++;
|
|
1511
|
-
}
|
|
1512
|
-
emitLimitedTable(lines.slice(tableStart, i));
|
|
1513
|
-
continue;
|
|
1514
|
-
}
|
|
1515
|
-
if (line.trim().startsWith("|")) {
|
|
1516
|
-
const tableStart = i;
|
|
1517
|
-
while (i < lines.length && lines[i].trim().startsWith("|")) {
|
|
1518
|
-
i++;
|
|
1519
|
-
}
|
|
1520
|
-
emitLimitedTable(lines.slice(tableStart, i));
|
|
1521
|
-
continue;
|
|
1522
|
-
}
|
|
1523
|
-
out.push(line);
|
|
1524
|
-
i++;
|
|
1525
|
-
}
|
|
1526
|
-
if (truncatedAny) {
|
|
1527
|
-
warnings.push(
|
|
1528
|
-
`[docmind-markdown:spreadsheet] maxRowsPerSheet:${maxRowsPerSheet}: truncated data rows in one or more sheet tables.`
|
|
1529
|
-
);
|
|
1530
|
-
}
|
|
1531
|
-
return { markdown: out.join("\n"), warnings };
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
1559
|
// src/csv-markdown.ts
|
|
1535
1560
|
function looksLikeCsvContent(s) {
|
|
1536
1561
|
return s.includes(",") && /[\r\n]/.test(s);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dragon708/docmind-markdown",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "StructuredDocumentResult → Markdown and LLM-oriented plain text for DocMind.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@cognipeer/to-markdown": "^2.0.1",
|
|
42
|
-
"@dragon708/docmind-shared": "^1.
|
|
42
|
+
"@dragon708/docmind-shared": "^1.3.0",
|
|
43
43
|
"mammoth": "^1.6.0",
|
|
44
44
|
"turndown": "^7.0.0",
|
|
45
45
|
"turndown-plugin-gfm": "^1.0.2"
|