@unisim/doc 0.1.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.
Files changed (90) hide show
  1. package/README.md +91 -0
  2. package/dist/convert.d.ts +54 -0
  3. package/dist/convert.d.ts.map +1 -0
  4. package/dist/convert.js +216 -0
  5. package/dist/convert.js.map +1 -0
  6. package/dist/image.d.ts +17 -0
  7. package/dist/image.d.ts.map +1 -0
  8. package/dist/image.js +66 -0
  9. package/dist/image.js.map +1 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +51 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/merge.d.ts +14 -0
  15. package/dist/merge.d.ts.map +1 -0
  16. package/dist/merge.js +51 -0
  17. package/dist/merge.js.map +1 -0
  18. package/dist/metrics.d.ts +19 -0
  19. package/dist/metrics.d.ts.map +1 -0
  20. package/dist/metrics.js +151 -0
  21. package/dist/metrics.js.map +1 -0
  22. package/dist/model.d.ts +114 -0
  23. package/dist/model.d.ts.map +1 -0
  24. package/dist/model.js +121 -0
  25. package/dist/model.js.map +1 -0
  26. package/dist/pdfcore.d.ts +118 -0
  27. package/dist/pdfcore.d.ts.map +1 -0
  28. package/dist/pdfcore.js +398 -0
  29. package/dist/pdfcore.js.map +1 -0
  30. package/dist/read/csv.d.ts +17 -0
  31. package/dist/read/csv.d.ts.map +1 -0
  32. package/dist/read/csv.js +167 -0
  33. package/dist/read/csv.js.map +1 -0
  34. package/dist/read/doc.d.ts +3 -0
  35. package/dist/read/doc.d.ts.map +1 -0
  36. package/dist/read/doc.js +360 -0
  37. package/dist/read/doc.js.map +1 -0
  38. package/dist/read/docx.d.ts +3 -0
  39. package/dist/read/docx.d.ts.map +1 -0
  40. package/dist/read/docx.js +455 -0
  41. package/dist/read/docx.js.map +1 -0
  42. package/dist/read/html.d.ts +4 -0
  43. package/dist/read/html.d.ts.map +1 -0
  44. package/dist/read/html.js +236 -0
  45. package/dist/read/html.js.map +1 -0
  46. package/dist/read/json.d.ts +9 -0
  47. package/dist/read/json.d.ts.map +1 -0
  48. package/dist/read/json.js +105 -0
  49. package/dist/read/json.js.map +1 -0
  50. package/dist/read/markdown.d.ts +4 -0
  51. package/dist/read/markdown.d.ts.map +1 -0
  52. package/dist/read/markdown.js +247 -0
  53. package/dist/read/markdown.js.map +1 -0
  54. package/dist/read/odt.d.ts +3 -0
  55. package/dist/read/odt.d.ts.map +1 -0
  56. package/dist/read/odt.js +359 -0
  57. package/dist/read/odt.js.map +1 -0
  58. package/dist/read/rtf.d.ts +3 -0
  59. package/dist/read/rtf.d.ts.map +1 -0
  60. package/dist/read/rtf.js +341 -0
  61. package/dist/read/rtf.js.map +1 -0
  62. package/dist/read/text.d.ts +4 -0
  63. package/dist/read/text.d.ts.map +1 -0
  64. package/dist/read/text.js +62 -0
  65. package/dist/read/text.js.map +1 -0
  66. package/dist/unzip.d.ts +23 -0
  67. package/dist/unzip.d.ts.map +1 -0
  68. package/dist/unzip.js +152 -0
  69. package/dist/unzip.js.map +1 -0
  70. package/dist/write/data.d.ts +16 -0
  71. package/dist/write/data.d.ts.map +1 -0
  72. package/dist/write/data.js +89 -0
  73. package/dist/write/data.js.map +1 -0
  74. package/dist/write/pdf.d.ts +10 -0
  75. package/dist/write/pdf.d.ts.map +1 -0
  76. package/dist/write/pdf.js +696 -0
  77. package/dist/write/pdf.js.map +1 -0
  78. package/dist/write/pdfSettings.d.ts +13 -0
  79. package/dist/write/pdfSettings.d.ts.map +1 -0
  80. package/dist/write/pdfSettings.js +26 -0
  81. package/dist/write/pdfSettings.js.map +1 -0
  82. package/dist/write/text.d.ts +5 -0
  83. package/dist/write/text.d.ts.map +1 -0
  84. package/dist/write/text.js +341 -0
  85. package/dist/write/text.js.map +1 -0
  86. package/dist/xml.d.ts +22 -0
  87. package/dist/xml.d.ts.map +1 -0
  88. package/dist/xml.js +83 -0
  89. package/dist/xml.js.map +1 -0
  90. package/package.json +31 -0
@@ -0,0 +1,236 @@
1
+ // ---------------------------------------------------------------------------
2
+ // HTML → RichDoc.
3
+ //
4
+ // The browser is already the best HTML parser in the room, so this does not
5
+ // write one: `DOMParser` with 'text/html' builds the tree, and this walks it.
6
+ //
7
+ // ⚠️ `DOMParser` DOES NOT RUN SCRIPTS AND DOES NOT FETCH ANYTHING. The document
8
+ // it returns is inert — `<script>` is parsed as an element and never executed,
9
+ // `<img>` never issues a request, and nothing is attached to this page. That is
10
+ // what makes it safe to point at a file somebody was emailed, and it is the
11
+ // reason this is a parse rather than an iframe. `innerHTML` on a live element
12
+ // would be a different and much worse decision.
13
+ //
14
+ // The walk is deliberately shallow on layout: a `<div>` is a paragraph if it
15
+ // holds text, tables come through as tables, and everything positional —
16
+ // floats, columns, absolute placement, CSS of any kind — is ignored. The output
17
+ // is a flowed document, so honouring a two-column layout would mean interleaving
18
+ // the columns line by line, which is worse than not honouring it.
19
+ // ---------------------------------------------------------------------------
20
+ import { addNotice, mergeRuns, tidy, } from '../model.js';
21
+ /** Elements whose content is not document text. */
22
+ const IGNORED = new Set([
23
+ 'SCRIPT', 'STYLE', 'NOSCRIPT', 'TEMPLATE', 'HEAD', 'META', 'LINK', 'TITLE',
24
+ 'NAV', 'SVG', 'CANVAS', 'IFRAME', 'AUDIO', 'VIDEO', 'OBJECT', 'EMBED',
25
+ 'FORM', 'INPUT', 'BUTTON', 'SELECT', 'TEXTAREA', 'DIALOG',
26
+ ]);
27
+ const BLOCKISH = new Set([
28
+ 'DIV', 'SECTION', 'ARTICLE', 'MAIN', 'ASIDE', 'HEADER', 'FOOTER', 'FIGURE',
29
+ 'FIGCAPTION', 'ADDRESS', 'DETAILS', 'SUMMARY', 'FIELDSET', 'BODY', 'DD', 'DT', 'DL',
30
+ ]);
31
+ export async function readHtml(file) {
32
+ return parseHtmlDoc(await file.text(), file.name);
33
+ }
34
+ export function parseHtmlDoc(source, filename) {
35
+ const parsed = new DOMParser().parseFromString(source, 'text/html');
36
+ const doc = { blocks: [], notices: [] };
37
+ const body = parsed.body;
38
+ if (!body)
39
+ throw new Error('This HTML file has no body to read.');
40
+ walk(body, doc, doc.blocks, {});
41
+ if (parsed.querySelector('img[src]')) {
42
+ // A page's pictures are separate files it points AT. The drop had one file
43
+ // in it, so there is nothing to embed — said plainly, because a converted
44
+ // page with its images missing otherwise looks like a bug.
45
+ addNotice(doc, 'Pictures were left out — an HTML page links to its images rather than containing them, and only this file was dropped.');
46
+ }
47
+ if (parsed.querySelector('[style], style')) {
48
+ addNotice(doc, 'Styling was ignored — colours, fonts and layout come out as this converter’s own.', 'info');
49
+ }
50
+ doc.title = parsed.title?.trim() || filename?.replace(/\.x?html?$/i, '');
51
+ if (!doc.blocks.length)
52
+ throw new Error('No readable text was found in this HTML.');
53
+ return tidy(doc);
54
+ }
55
+ function walk(node, doc, out, inherited) {
56
+ for (const child of Array.from(node.childNodes)) {
57
+ if (child.nodeType === 3) {
58
+ // Loose text directly under a block element — common in hand-written
59
+ // HTML, where a paragraph is not always wrapped in a <p>.
60
+ const text = collapse(child.nodeValue ?? '');
61
+ if (text.trim())
62
+ out.push({ kind: 'paragraph', runs: [{ ...inherited, text }] });
63
+ continue;
64
+ }
65
+ if (child.nodeType !== 1)
66
+ continue;
67
+ const el = child;
68
+ const tag = el.tagName.toUpperCase();
69
+ if (IGNORED.has(tag))
70
+ continue;
71
+ switch (tag) {
72
+ case 'H1':
73
+ case 'H2':
74
+ case 'H3':
75
+ case 'H4':
76
+ case 'H5':
77
+ case 'H6': {
78
+ const level = Math.min(4, Number(tag[1]));
79
+ out.push({ kind: 'heading', level, runs: mergeRuns(inline(el, inherited)) });
80
+ break;
81
+ }
82
+ case 'P':
83
+ out.push({ kind: 'paragraph', runs: mergeRuns(inline(el, inherited)) });
84
+ break;
85
+ case 'BLOCKQUOTE':
86
+ out.push({ kind: 'quote', runs: mergeRuns(inline(el, inherited)) });
87
+ break;
88
+ case 'PRE':
89
+ // `textContent`, not the inline walk: whitespace IS the content here,
90
+ // and the walk collapses it.
91
+ out.push({ kind: 'code', text: (el.textContent ?? '').replace(/\n+$/, '') });
92
+ break;
93
+ case 'HR':
94
+ out.push({ kind: 'rule' });
95
+ break;
96
+ case 'UL':
97
+ case 'OL': {
98
+ const items = [];
99
+ collectListItems(el, items, 0, inherited);
100
+ if (items.length)
101
+ out.push({ kind: 'list', ordered: tag === 'OL', items });
102
+ break;
103
+ }
104
+ case 'TABLE':
105
+ out.push(readTable(el, inherited));
106
+ break;
107
+ case 'BR':
108
+ break;
109
+ default:
110
+ if (BLOCKISH.has(tag)) {
111
+ // A container. If it holds any block-level child, recurse; if it is
112
+ // just a wrapper round some text, it IS the paragraph.
113
+ if (el.querySelector('p, div, h1, h2, h3, h4, h5, h6, ul, ol, table, pre, blockquote, section, article')) {
114
+ walk(el, doc, out, inherited);
115
+ }
116
+ else {
117
+ const runs = mergeRuns(inline(el, inherited));
118
+ if (runs.length)
119
+ out.push({ kind: 'paragraph', runs });
120
+ }
121
+ }
122
+ else {
123
+ // An inline element sitting where a block was expected — <span>,
124
+ // <a>, <strong> loose in a body. It is a paragraph's worth of text.
125
+ const runs = mergeRuns(inline(el, inherited));
126
+ if (runs.length)
127
+ out.push({ kind: 'paragraph', runs });
128
+ }
129
+ break;
130
+ }
131
+ }
132
+ }
133
+ function collectListItems(list, out, level, inherited) {
134
+ for (const li of Array.from(list.children)) {
135
+ if (li.tagName.toUpperCase() !== 'LI')
136
+ continue;
137
+ // The item's own text, not its nested list's — so the nested list is taken
138
+ // out of the run walk and recursed into separately, at one level deeper.
139
+ const nested = Array.from(li.children).filter((c) => /^(UL|OL)$/i.test(c.tagName));
140
+ const runs = [];
141
+ for (const node of Array.from(li.childNodes)) {
142
+ if (node.nodeType === 1 && /^(UL|OL)$/i.test(node.tagName))
143
+ continue;
144
+ runs.push(...inlineNode(node, inherited));
145
+ }
146
+ const merged = mergeRuns(runs);
147
+ if (merged.length)
148
+ out.push({ runs: merged, level });
149
+ for (const child of nested)
150
+ collectListItems(child, out, Math.min(4, level + 1), inherited);
151
+ }
152
+ }
153
+ function readTable(table, inherited) {
154
+ const rows = [];
155
+ let headerCount = 0;
156
+ for (const tr of Array.from(table.querySelectorAll('tr'))) {
157
+ const cells = [];
158
+ let allHeaders = true;
159
+ for (const cell of Array.from(tr.children)) {
160
+ const tag = cell.tagName.toUpperCase();
161
+ if (tag !== 'TD' && tag !== 'TH')
162
+ continue;
163
+ if (tag !== 'TH')
164
+ allHeaders = false;
165
+ cells.push(mergeRuns(inline(cell, inherited)));
166
+ }
167
+ if (!cells.length)
168
+ continue;
169
+ if (allHeaders && rows.length === headerCount)
170
+ headerCount += 1;
171
+ rows.push(cells);
172
+ }
173
+ if (!rows.length)
174
+ return { kind: 'paragraph', runs: [{ text: ' ' }] };
175
+ const useHeader = headerCount > 0 || rows.length > 1;
176
+ return {
177
+ kind: 'table',
178
+ header: useHeader ? rows[0] : null,
179
+ rows: useHeader ? rows.slice(1) : rows,
180
+ };
181
+ }
182
+ /** Inline content of an element, flattened to runs. */
183
+ function inline(el, inherited) {
184
+ const out = [];
185
+ for (const node of Array.from(el.childNodes))
186
+ out.push(...inlineNode(node, inherited));
187
+ return out;
188
+ }
189
+ function inlineNode(node, inherited) {
190
+ if (node.nodeType === 3) {
191
+ return [{ ...inherited, text: collapse(node.nodeValue ?? '') }];
192
+ }
193
+ if (node.nodeType !== 1)
194
+ return [];
195
+ const el = node;
196
+ const tag = el.tagName.toUpperCase();
197
+ if (IGNORED.has(tag))
198
+ return [];
199
+ if (tag === 'BR')
200
+ return [{ ...inherited, text: '\n' }];
201
+ if (tag === 'IMG') {
202
+ const alt = el.getAttribute('alt')?.trim();
203
+ return alt ? [{ ...inherited, text: `[${alt}]`, italic: true }] : [];
204
+ }
205
+ const style = { ...inherited };
206
+ if (tag === 'B' || tag === 'STRONG')
207
+ style.bold = true;
208
+ if (tag === 'I' || tag === 'EM' || tag === 'CITE' || tag === 'VAR')
209
+ style.italic = true;
210
+ if (tag === 'U' || tag === 'INS')
211
+ style.underline = true;
212
+ if (tag === 'S' || tag === 'STRIKE' || tag === 'DEL')
213
+ style.strike = true;
214
+ if (tag === 'CODE' || tag === 'KBD' || tag === 'SAMP' || tag === 'TT')
215
+ style.code = true;
216
+ if (tag === 'A') {
217
+ const href = el.getAttribute('href')?.trim();
218
+ // Only absolute http(s) survives. A relative path or an in-page anchor
219
+ // points somewhere the PDF is not, so it would be a hotspot to nowhere.
220
+ if (href && /^https?:\/\//i.test(href))
221
+ style.link = href;
222
+ }
223
+ const out = [];
224
+ for (const child of Array.from(el.childNodes))
225
+ out.push(...inlineNode(child, style));
226
+ // A block element nested inside an inline walk (a <div> inside a <td>) needs
227
+ // its own line, or two paragraphs run together into one sentence.
228
+ if (BLOCKISH.has(tag) || tag === 'P')
229
+ out.push({ ...inherited, text: '\n' });
230
+ return out;
231
+ }
232
+ /** HTML collapses runs of whitespace to one space; so does this. */
233
+ function collapse(text) {
234
+ return text.replace(/\s+/g, ' ');
235
+ }
236
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/read/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type Grid, type RichDoc } from '../model.js';
2
+ export interface JsonResult {
3
+ doc: RichDoc;
4
+ /** Null when the file is not an array of flat records. */
5
+ grid: Grid | null;
6
+ }
7
+ export declare function readJson(file: File): Promise<JsonResult>;
8
+ export declare function parseJsonFile(source: string, filename?: string): JsonResult;
9
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/read/json.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAoB,KAAK,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAA;AAEvE,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,OAAO,CAAA;IACZ,0DAA0D;IAC1D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;CAClB;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAE9D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAgC3E"}
@@ -0,0 +1,105 @@
1
+ // ---------------------------------------------------------------------------
2
+ // JSON → Grid (and a RichDoc).
3
+ //
4
+ // JSON is a TREE and a spreadsheet is a GRID, and only one shape of JSON is
5
+ // honestly both: an array of flat objects, which is what an API endpoint or a
6
+ // database export gives you. That case flattens perfectly, so it is the case
7
+ // this handles properly — union of every key as the columns, one row per
8
+ // element, in first-seen key order.
9
+ //
10
+ // Anything else is NOT forced into a grid. A nested object becomes its JSON
11
+ // text in the cell rather than being exploded into `address.city` columns:
12
+ // flattening reads well on the two records you tested and produces a
13
+ // four-hundred-column sheet on a real file, and there is no way to un-flatten
14
+ // it afterwards. For a document target, a non-tabular file is pretty-printed as
15
+ // a code block instead, which is at least readable.
16
+ // ---------------------------------------------------------------------------
17
+ import { tidy } from '../model.js';
18
+ export async function readJson(file) {
19
+ return parseJsonFile(await file.text(), file.name);
20
+ }
21
+ export function parseJsonFile(source, filename) {
22
+ let value;
23
+ try {
24
+ value = JSON.parse(source);
25
+ }
26
+ catch (err) {
27
+ // The parser's own message names the character offset, which is genuinely
28
+ // the most useful thing anybody can be told about broken JSON.
29
+ throw new Error(`That isn’t valid JSON — ${err instanceof Error ? err.message : 'it could not be parsed'}.`);
30
+ }
31
+ const title = filename?.replace(/\.json$/i, '');
32
+ const grid = toGrid(value);
33
+ const blocks = [];
34
+ if (grid) {
35
+ blocks.push({
36
+ kind: 'table',
37
+ header: grid.header.map((cell) => [{ text: cell }]),
38
+ rows: grid.rows.map((row) => row.map((cell) => [{ text: cell }])),
39
+ });
40
+ }
41
+ else {
42
+ blocks.push({ kind: 'code', text: JSON.stringify(value, null, 2) });
43
+ }
44
+ const doc = tidy({ blocks, notices: [], title });
45
+ if (!grid) {
46
+ doc.notices.push({
47
+ severity: 'info',
48
+ message: 'This JSON isn’t a list of records, so it comes through as formatted text rather than a table. Only an array of flat objects converts to CSV.',
49
+ });
50
+ }
51
+ return { doc, grid };
52
+ }
53
+ /**
54
+ * The array-of-flat-objects case, or null.
55
+ *
56
+ * The columns are the union of every element's keys in FIRST-SEEN ORDER, not
57
+ * the first element's keys: records with optional fields are normal, and taking
58
+ * only the first record's shape silently drops every column that happens to be
59
+ * absent from row one.
60
+ */
61
+ function toGrid(value) {
62
+ const records = Array.isArray(value)
63
+ ? value
64
+ // A single object wrapping the real array — `{ "results": [ … ] }` — is
65
+ // how most APIs answer, so one wrapper is unwrapped.
66
+ : isRecord(value)
67
+ ? Object.values(value).find((v) => Array.isArray(v) && v.length && isRecord(v[0]))
68
+ : null;
69
+ if (!Array.isArray(records) || !records.length)
70
+ return null;
71
+ if (!records.every(isRecord))
72
+ return null;
73
+ const header = [];
74
+ for (const record of records) {
75
+ for (const key of Object.keys(record)) {
76
+ if (!header.includes(key))
77
+ header.push(key);
78
+ }
79
+ }
80
+ if (!header.length)
81
+ return null;
82
+ const rows = records.map((record) => header.map((key) => cellText(record[key])));
83
+ return { header, rows };
84
+ }
85
+ function isRecord(value) {
86
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
87
+ }
88
+ /**
89
+ * One value as a cell.
90
+ *
91
+ * `null` and `undefined` become empty rather than the strings "null" and
92
+ * "undefined" — a blank cell is what a missing value means in a sheet. Nested
93
+ * structures keep their JSON, so nothing is lost even though nothing is
94
+ * flattened.
95
+ */
96
+ function cellText(value) {
97
+ if (value === null || value === undefined)
98
+ return '';
99
+ if (typeof value === 'string')
100
+ return value;
101
+ if (typeof value === 'number' || typeof value === 'boolean')
102
+ return String(value);
103
+ return JSON.stringify(value);
104
+ }
105
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/read/json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type RichDoc } from '../model.js';
2
+ export declare function readMarkdown(file: File): Promise<RichDoc>;
3
+ export declare function parseMarkdownDoc(source: string, filename?: string): RichDoc;
4
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/read/markdown.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAmC,KAAK,OAAO,EAAY,MAAM,aAAa,CAAA;AAErF,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAE/D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAI3E"}
@@ -0,0 +1,247 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Markdown → RichDoc.
3
+ //
4
+ // ⚠️ THIS IS A PORT, NOT A NEW PARSER. It is Universal PDF's
5
+ // `src/lib/markdownToPdf.ts` — its `parseMarkdown`, `parseInline` and
6
+ // `parseTableRow` — lifted out of that file's renderer and pointed at the
7
+ // RichDoc model instead of straight at pdf-lib. Deliberately kept recognisable:
8
+ // the block order, the regexes and the fenced-code handling are the same, so a
9
+ // bug found in one is findable in the other.
10
+ //
11
+ // (The obvious next move is one shared parser in `@unisim/sdk` that both apps
12
+ // import. That is a change to a shipped app for a benefit neither has yet, so
13
+ // it is written down in the backlog rather than done in passing here.)
14
+ //
15
+ // The additions on this side are nested lists — the model has a `level` and
16
+ // Universal PDF's flat `items` did not — and setext headings, which turn up in
17
+ // hand-written READMEs.
18
+ // ---------------------------------------------------------------------------
19
+ import { tidy } from '../model.js';
20
+ export async function readMarkdown(file) {
21
+ return parseMarkdownDoc(await file.text(), file.name);
22
+ }
23
+ export function parseMarkdownDoc(source, filename) {
24
+ const doc = { blocks: parseBlocks(source), notices: [] };
25
+ doc.title = guessTitle(source) || filename?.replace(/\.(md|markdown|mdown)$/i, '');
26
+ return tidy(doc);
27
+ }
28
+ function parseBlocks(source) {
29
+ const lines = source.replace(/\r\n?/g, '\n').split('\n');
30
+ const blocks = [];
31
+ let i = 0;
32
+ while (i < lines.length) {
33
+ const line = lines[i];
34
+ if (!line.trim()) {
35
+ i += 1;
36
+ continue;
37
+ }
38
+ // Fenced code. Taken first and taken whole: everything between the fences
39
+ // is literal, so testing it for headings or lists would find markup that
40
+ // the author wrote as an example.
41
+ if (/^\s*(```|~~~)/.test(line)) {
42
+ const fence = /^\s*(```|~~~)/.exec(line)[1];
43
+ i += 1;
44
+ const buffer = [];
45
+ while (i < lines.length && !lines[i].trimStart().startsWith(fence)) {
46
+ buffer.push(lines[i]);
47
+ i += 1;
48
+ }
49
+ if (i < lines.length)
50
+ i += 1;
51
+ blocks.push({ kind: 'code', text: buffer.join('\n') });
52
+ continue;
53
+ }
54
+ const atx = /^(#{1,6})\s+(.*?)\s*#*$/.exec(line);
55
+ if (atx) {
56
+ blocks.push({ kind: 'heading', level: clampLevel(atx[1].length), runs: parseInline(atx[2]) });
57
+ i += 1;
58
+ continue;
59
+ }
60
+ // Setext: a line of text underlined with === or ---. Checked before the
61
+ // horizontal rule, because `---` under a paragraph is a heading and `---`
62
+ // on its own is a rule, and only the line above tells them apart.
63
+ const underline = lines[i + 1];
64
+ if (underline && /^\s*(=+|-{2,})\s*$/.test(underline) && !isBlockStart(line)) {
65
+ blocks.push({
66
+ kind: 'heading',
67
+ level: underline.trim().startsWith('=') ? 1 : 2,
68
+ runs: parseInline(line.trim()),
69
+ });
70
+ i += 2;
71
+ continue;
72
+ }
73
+ if (/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
74
+ blocks.push({ kind: 'rule' });
75
+ i += 1;
76
+ continue;
77
+ }
78
+ // A pipe table needs its separator row to be a table at all — otherwise a
79
+ // paragraph that happens to contain pipes becomes a one-row grid.
80
+ if (line.trimStart().startsWith('|') && /^\s*\|?[\s:|-]*-[\s:|-]*\|?\s*$/.test(lines[i + 1] ?? '')) {
81
+ const header = parseTableRow(line);
82
+ i += 2;
83
+ const rows = [];
84
+ while (i < lines.length && lines[i].trimStart().startsWith('|')) {
85
+ rows.push(parseTableRow(lines[i]));
86
+ i += 1;
87
+ }
88
+ blocks.push({ kind: 'table', header, rows });
89
+ continue;
90
+ }
91
+ if (/^\s*>/.test(line)) {
92
+ const buffer = [];
93
+ while (i < lines.length && /^\s*>/.test(lines[i])) {
94
+ buffer.push(lines[i].replace(/^\s*>\s?/, ''));
95
+ i += 1;
96
+ }
97
+ blocks.push({ kind: 'quote', runs: parseInline(buffer.join(' ')) });
98
+ continue;
99
+ }
100
+ const bullet = /^(\s*)([-*+])\s+/.exec(line);
101
+ const numbered = /^(\s*)(\d+)[.)]\s+/.exec(line);
102
+ if (bullet || numbered) {
103
+ const ordered = !!numbered;
104
+ const items = [];
105
+ while (i < lines.length) {
106
+ const match = ordered
107
+ ? /^(\s*)(\d+)[.)]\s+(.*)$/.exec(lines[i])
108
+ : /^(\s*)([-*+])\s+(.*)$/.exec(lines[i]);
109
+ if (!match) {
110
+ // A plain indented line continues the item above rather than starting
111
+ // a new one — how a wrapped bullet is written by hand.
112
+ if (items.length && /^\s{2,}\S/.test(lines[i]) && lines[i].trim()) {
113
+ items[items.length - 1].runs.push({ text: ' ' }, ...parseInline(lines[i].trim()));
114
+ i += 1;
115
+ continue;
116
+ }
117
+ break;
118
+ }
119
+ // Two spaces per level is the common convention, four is the other; a
120
+ // divisor of 2 puts a four-space indent at level 2, which reads right
121
+ // either way.
122
+ items.push({ runs: parseInline(match[3]), level: Math.min(4, Math.floor(match[1].length / 2)) });
123
+ i += 1;
124
+ }
125
+ if (items.length)
126
+ blocks.push({ kind: 'list', ordered, items });
127
+ continue;
128
+ }
129
+ // An indented code block: four spaces or a tab, run together.
130
+ if (/^(\t| {4})/.test(line)) {
131
+ const buffer = [];
132
+ while (i < lines.length && (/^(\t| {4})/.test(lines[i]) || !lines[i].trim())) {
133
+ buffer.push(lines[i].replace(/^(\t| {4})/, ''));
134
+ i += 1;
135
+ }
136
+ while (buffer.length && !buffer[buffer.length - 1].trim())
137
+ buffer.pop();
138
+ blocks.push({ kind: 'code', text: buffer.join('\n') });
139
+ continue;
140
+ }
141
+ const buffer = [line];
142
+ i += 1;
143
+ while (i < lines.length && lines[i].trim() && !isBlockStart(lines[i])) {
144
+ buffer.push(lines[i]);
145
+ i += 1;
146
+ }
147
+ blocks.push({ kind: 'paragraph', runs: parseInline(buffer.join(' ')) });
148
+ }
149
+ return blocks;
150
+ }
151
+ function clampLevel(n) {
152
+ return Math.min(4, Math.max(1, n));
153
+ }
154
+ function isBlockStart(line) {
155
+ if (!line.trim())
156
+ return false;
157
+ if (/^#{1,6}\s/.test(line))
158
+ return true;
159
+ if (/^\s*(```|~~~)/.test(line))
160
+ return true;
161
+ if (/^\s*>/.test(line))
162
+ return true;
163
+ if (/^\s*[-*+]\s+/.test(line))
164
+ return true;
165
+ if (/^\s*\d+[.)]\s+/.test(line))
166
+ return true;
167
+ if (/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(line))
168
+ return true;
169
+ if (line.trimStart().startsWith('|'))
170
+ return true;
171
+ return false;
172
+ }
173
+ /**
174
+ * Inline emphasis, code, links and images.
175
+ *
176
+ * One regex with alternatives rather than a character-by-character scanner —
177
+ * Universal PDF's approach, and right for the same reason: markdown emphasis
178
+ * has no nesting rules worth honouring at this fidelity, and a scanner that
179
+ * tried would spend most of its lines on cases nobody writes.
180
+ */
181
+ function parseInline(text) {
182
+ const runs = [];
183
+ const PATTERN = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|\*[^*\n]+\*|_[^_\n]+_|~~[^~\n]+~~|`[^`\n]+`|!?\[[^\]\n]*\]\([^)\n]+\)|<https?:\/\/[^>\s]+>)/g;
184
+ let last = 0;
185
+ let match;
186
+ while ((match = PATTERN.exec(text)) !== null) {
187
+ if (match.index > last)
188
+ runs.push({ text: text.slice(last, match.index) });
189
+ const token = match[0];
190
+ if (token.startsWith('***')) {
191
+ runs.push({ text: token.slice(3, -3), bold: true, italic: true });
192
+ }
193
+ else if (token.startsWith('**') || token.startsWith('__')) {
194
+ runs.push({ text: token.slice(2, -2), bold: true });
195
+ }
196
+ else if (token.startsWith('~~')) {
197
+ runs.push({ text: token.slice(2, -2), strike: true });
198
+ }
199
+ else if (token[0] === '*' || token[0] === '_') {
200
+ runs.push({ text: token.slice(1, -1), italic: true });
201
+ }
202
+ else if (token[0] === '`') {
203
+ runs.push({ text: token.slice(1, -1), code: true });
204
+ }
205
+ else if (token[0] === '<') {
206
+ const url = token.slice(1, -1);
207
+ runs.push({ text: url, link: url });
208
+ }
209
+ else if (token.startsWith('!')) {
210
+ // An image reference. The file it names is not in the drop, so the alt
211
+ // text stands in — silently dropping it loses the caption too.
212
+ const alt = /^!\[([^\]]*)\]/.exec(token)?.[1] ?? '';
213
+ if (alt)
214
+ runs.push({ text: `[${alt}]`, italic: true });
215
+ }
216
+ else {
217
+ const link = /^\[([^\]]*)\]\(([^)\s]+)/.exec(token);
218
+ if (link)
219
+ runs.push({ text: link[1] || link[2], link: link[2] });
220
+ }
221
+ last = match.index + token.length;
222
+ }
223
+ if (last < text.length)
224
+ runs.push({ text: text.slice(last) });
225
+ return runs.length ? runs : [{ text }];
226
+ }
227
+ function parseTableRow(line) {
228
+ return line
229
+ .trim()
230
+ .replace(/^\|/, '')
231
+ .replace(/\|$/, '')
232
+ .split('|')
233
+ .map((cell) => parseInline(cell.trim()));
234
+ }
235
+ function guessTitle(source) {
236
+ for (const raw of source.split('\n')) {
237
+ const line = raw.trim();
238
+ if (!line)
239
+ continue;
240
+ const heading = /^#{1,3}\s+(.+)$/.exec(line);
241
+ if (heading)
242
+ return heading[1].replace(/[*_`]+/g, '').trim();
243
+ break;
244
+ }
245
+ return undefined;
246
+ }
247
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/read/markdown.ts"],"names":[],"mappings":"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"}