@cogenta/import 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 (45) hide show
  1. package/dist/index.d.ts +14 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +8 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/wordpress/collections.d.ts +232 -0
  6. package/dist/wordpress/collections.d.ts.map +1 -0
  7. package/dist/wordpress/collections.js +133 -0
  8. package/dist/wordpress/collections.js.map +1 -0
  9. package/dist/wordpress/content-convert.d.ts +50 -0
  10. package/dist/wordpress/content-convert.d.ts.map +1 -0
  11. package/dist/wordpress/content-convert.js +222 -0
  12. package/dist/wordpress/content-convert.js.map +1 -0
  13. package/dist/wordpress/gutenberg.d.ts +27 -0
  14. package/dist/wordpress/gutenberg.d.ts.map +1 -0
  15. package/dist/wordpress/gutenberg.js +83 -0
  16. package/dist/wordpress/gutenberg.js.map +1 -0
  17. package/dist/wordpress/html-to-richtext.d.ts +23 -0
  18. package/dist/wordpress/html-to-richtext.d.ts.map +1 -0
  19. package/dist/wordpress/html-to-richtext.js +209 -0
  20. package/dist/wordpress/html-to-richtext.js.map +1 -0
  21. package/dist/wordpress/import.d.ts +19 -0
  22. package/dist/wordpress/import.d.ts.map +1 -0
  23. package/dist/wordpress/import.js +241 -0
  24. package/dist/wordpress/import.js.map +1 -0
  25. package/dist/wordpress/media.d.ts +27 -0
  26. package/dist/wordpress/media.d.ts.map +1 -0
  27. package/dist/wordpress/media.js +68 -0
  28. package/dist/wordpress/media.js.map +1 -0
  29. package/dist/wordpress/parse.d.ts +12 -0
  30. package/dist/wordpress/parse.d.ts.map +1 -0
  31. package/dist/wordpress/parse.js +95 -0
  32. package/dist/wordpress/parse.js.map +1 -0
  33. package/dist/wordpress/report.d.ts +45 -0
  34. package/dist/wordpress/report.d.ts.map +1 -0
  35. package/dist/wordpress/report.js +41 -0
  36. package/dist/wordpress/report.js.map +1 -0
  37. package/dist/wordpress/types.d.ts +66 -0
  38. package/dist/wordpress/types.d.ts.map +1 -0
  39. package/dist/wordpress/types.js +10 -0
  40. package/dist/wordpress/types.js.map +1 -0
  41. package/dist/wordpress/xml.d.ts +33 -0
  42. package/dist/wordpress/xml.d.ts.map +1 -0
  43. package/dist/wordpress/xml.js +262 -0
  44. package/dist/wordpress/xml.js.map +1 -0
  45. package/package.json +44 -0
@@ -0,0 +1,222 @@
1
+ import { splitContentSegments } from './gutenberg.js';
2
+ import { htmlToRichText } from './html-to-richtext.js';
3
+ let keyCounter = 0;
4
+ function nextKey(prefix) {
5
+ keyCounter += 1;
6
+ return `import-${prefix}-${keyCounter}`;
7
+ }
8
+ function firstAttr(html, name) {
9
+ const match = new RegExp(`${name}=["']([^"']*)["']`, 'i').exec(html);
10
+ return match?.[1] ?? null;
11
+ }
12
+ function extractImageUrls(html) {
13
+ const found = [];
14
+ const imgPattern = /<img\b[^>]*>/gi;
15
+ let match = imgPattern.exec(html);
16
+ while (match !== null) {
17
+ const src = firstAttr(match[0], 'src');
18
+ if (src !== null)
19
+ found.push({ url: src, alt: firstAttr(match[0], 'alt') ?? '' });
20
+ match = imgPattern.exec(html);
21
+ }
22
+ return found;
23
+ }
24
+ function proseFrom(document) {
25
+ if (document.length === 0)
26
+ return null;
27
+ return { _key: nextKey('prose'), _type: 'prose', body: document };
28
+ }
29
+ const YOUTUBE = /youtu\.?be/i;
30
+ const VIMEO = /vimeo\.com/i;
31
+ const DAILYMOTION = /dailymotion\.com/i;
32
+ const SPOTIFY = /spotify\.com/i;
33
+ const SOUNDCLOUD = /soundcloud\.com/i;
34
+ const BLUESKY = /bsky\.app/i;
35
+ const MASTODON = /mastodon\.[a-z.]+/i;
36
+ function embedProviderFor(url) {
37
+ if (YOUTUBE.test(url))
38
+ return 'youtube';
39
+ if (VIMEO.test(url))
40
+ return 'vimeo';
41
+ if (DAILYMOTION.test(url))
42
+ return 'dailymotion';
43
+ if (SPOTIFY.test(url))
44
+ return 'spotify';
45
+ if (SOUNDCLOUD.test(url))
46
+ return 'soundcloud';
47
+ if (BLUESKY.test(url))
48
+ return 'bluesky';
49
+ if (MASTODON.test(url))
50
+ return 'mastodon';
51
+ return 'other';
52
+ }
53
+ function convertSegment(segment, notes) {
54
+ if (segment.kind === 'html') {
55
+ const { document, unknownTags } = htmlToRichText(segment.html);
56
+ for (const tag of unknownTags) {
57
+ notes.push({
58
+ source: `html:${tag}`,
59
+ reason: 'No rich-text mapping for this HTML tag; its content was kept as plain text where possible.',
60
+ });
61
+ }
62
+ const prose = proseFrom(document);
63
+ return prose === null ? [] : [prose];
64
+ }
65
+ const { name, innerHtml } = segment;
66
+ if (name === 'paragraph' || name === 'heading' || name === 'list' || name === 'list-item') {
67
+ const { document, unknownTags } = htmlToRichText(innerHtml);
68
+ for (const tag of unknownTags) {
69
+ notes.push({
70
+ source: `html:${tag}`,
71
+ reason: 'No rich-text mapping for this HTML tag inside a Gutenberg block.',
72
+ });
73
+ }
74
+ const prose = proseFrom(document);
75
+ return prose === null ? [] : [prose];
76
+ }
77
+ if (name === 'quote' || name === 'pullquote') {
78
+ const { document } = htmlToRichText(innerHtml);
79
+ const text = document
80
+ .filter((node) => node._type === 'block')
81
+ .flatMap((node) => node.children.map((child) => child.text))
82
+ .join(' ')
83
+ .trim();
84
+ const cite = /<cite[^>]*>([\s\S]*?)<\/cite>/i
85
+ .exec(innerHtml)?.[1]
86
+ ?.replace(/<[^>]*>/g, '')
87
+ .trim();
88
+ if (text.length === 0)
89
+ return [];
90
+ const block = {
91
+ _key: nextKey('quote'),
92
+ _type: 'quote',
93
+ text: text.slice(0, 1000),
94
+ ...(cite === undefined || cite.length === 0 ? {} : { author: cite.slice(0, 160) }),
95
+ };
96
+ return [block];
97
+ }
98
+ if (name === 'image') {
99
+ const [image] = extractImageUrls(innerHtml);
100
+ if (image === undefined) {
101
+ notes.push({
102
+ source: `wp:${name}`,
103
+ reason: 'An image block with no <img src> could be found in its markup.',
104
+ });
105
+ return [];
106
+ }
107
+ const captionMatch = /<figcaption[^>]*>([\s\S]*?)<\/figcaption>/i.exec(innerHtml)?.[1];
108
+ const caption = captionMatch?.replace(/<[^>]*>/g, '').trim();
109
+ const block = {
110
+ _key: nextKey('mediaFigure'),
111
+ _type: 'mediaFigure',
112
+ media: image.url,
113
+ ...(caption === undefined || caption.length === 0 ? {} : { caption: caption.slice(0, 320) }),
114
+ };
115
+ return [block];
116
+ }
117
+ if (name === 'gallery') {
118
+ const images = extractImageUrls(innerHtml);
119
+ if (images.length === 0) {
120
+ notes.push({
121
+ source: `wp:${name}`,
122
+ reason: 'A gallery block with no <img src> images could be found in its markup.',
123
+ });
124
+ return [];
125
+ }
126
+ const block = {
127
+ _key: nextKey('gallery'),
128
+ _type: 'gallery',
129
+ items: images.map((image) => ({ _key: nextKey('galleryItem'), media: image.url })),
130
+ layout: 'grid',
131
+ };
132
+ return [block];
133
+ }
134
+ if (name === 'embed' || name.startsWith('core-embed/') || name === 'embed/embed') {
135
+ const url = firstAttr(innerHtml, 'src') ?? innerHtml.match(/https?:\/\/\S+/)?.[0]?.replace(/<[^>]*$/, '');
136
+ if (url === undefined || url === null || url.length === 0) {
137
+ notes.push({ source: `wp:${name}`, reason: 'An embed block with no discoverable URL.' });
138
+ return [];
139
+ }
140
+ const cleanUrl = url.replace(/["'<].*$/, '');
141
+ const block = {
142
+ _key: nextKey('embed'),
143
+ _type: 'embed',
144
+ provider: embedProviderFor(cleanUrl),
145
+ url: cleanUrl.slice(0, 2048),
146
+ consentRequired: true,
147
+ };
148
+ return [block];
149
+ }
150
+ notes.push({
151
+ source: `wp:${name}`,
152
+ reason: 'No block of the vocabulary (contract B) represents this Gutenberg block; it was dropped rather than stored as raw HTML.',
153
+ });
154
+ return [];
155
+ }
156
+ /**
157
+ * Converts a post's `content:encoded` into the block vocabulary (contract B),
158
+ * best-effort. Everything that cannot be represented is named in `notes`
159
+ * rather than silently dropped or coerced into `prose` as raw HTML (rule R3).
160
+ */
161
+ export function convertContent(content) {
162
+ const notes = [];
163
+ const segments = splitContentSegments(content);
164
+ const blocks = segments.flatMap((segment) => convertSegment(segment, notes));
165
+ return { blocks, notes };
166
+ }
167
+ /** Every source URL a draft's blocks reference, so the caller can download them once, up front. */
168
+ export function mediaUrlsOf(blocks) {
169
+ const urls = new Set();
170
+ for (const block of blocks) {
171
+ if (block._type === 'mediaFigure')
172
+ urls.add(block.media);
173
+ if (block._type === 'gallery')
174
+ for (const item of block.items)
175
+ urls.add(item.media);
176
+ }
177
+ return [...urls];
178
+ }
179
+ /**
180
+ * Substitutes real media ids for the source URLs `convertContent` left in
181
+ * place. A block whose image never downloaded is dropped rather than written
182
+ * with a dangling reference; a gallery that loses every item is dropped too.
183
+ */
184
+ export function resolveMediaReferences(blocks, urlToMediaId, notes) {
185
+ const resolved = [];
186
+ for (const block of blocks) {
187
+ if (block._type === 'mediaFigure') {
188
+ const id = urlToMediaId.get(block.media);
189
+ if (id === undefined) {
190
+ notes.push({
191
+ source: 'media',
192
+ reason: `Image "${block.media}" could not be downloaded; the block was dropped.`,
193
+ });
194
+ continue;
195
+ }
196
+ resolved.push({ ...block, media: id });
197
+ continue;
198
+ }
199
+ if (block._type === 'gallery') {
200
+ const items = block.items
201
+ .map((item) => {
202
+ const id = urlToMediaId.get(item.media);
203
+ if (id === undefined)
204
+ return null;
205
+ return { ...item, media: id };
206
+ })
207
+ .filter((item) => item !== null);
208
+ if (items.length === 0) {
209
+ notes.push({
210
+ source: 'media',
211
+ reason: 'Every image in a gallery block failed to download; the block was dropped.',
212
+ });
213
+ continue;
214
+ }
215
+ resolved.push({ ...block, items });
216
+ continue;
217
+ }
218
+ resolved.push(block);
219
+ }
220
+ return resolved;
221
+ }
222
+ //# sourceMappingURL=content-convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-convert.js","sourceRoot":"","sources":["../../src/wordpress/content-convert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Splits WordPress post content into its top-level pieces.
3
+ *
4
+ * Since WordPress 5.0, `content:encoded` is HTML interleaved with Gutenberg
5
+ * block comments (`<!-- wp:paragraph -->…<!-- /wp:paragraph -->`); content
6
+ * from the classic editor, or a site that never touched the block editor, is
7
+ * just HTML with no such comments. Both are handled: a document with block
8
+ * comments is split at the top level only (a block nested inside a
9
+ * `wp:group`/`wp:columns` container is not descended into — the container
10
+ * itself is reported as unconverted, its children are not individually
11
+ * salvaged); a document with none is returned as one `html` segment.
12
+ */
13
+ export interface GutenbergBlockSegment {
14
+ readonly kind: 'block';
15
+ /** e.g. `"paragraph"`, `"core-embed/youtube"`, `"my-plugin/custom"`. */
16
+ readonly name: string;
17
+ readonly attrs: Readonly<Record<string, unknown>>;
18
+ readonly innerHtml: string;
19
+ }
20
+ export interface HtmlSegment {
21
+ readonly kind: 'html';
22
+ readonly html: string;
23
+ }
24
+ export type ContentSegment = GutenbergBlockSegment | HtmlSegment;
25
+ /** Splits `content:encoded` into top-level Gutenberg blocks, or one HTML segment when it uses none. */
26
+ export declare function splitContentSegments(content: string): readonly ContentSegment[];
27
+ //# sourceMappingURL=gutenberg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gutenberg.d.ts","sourceRoot":"","sources":["../../src/wordpress/gutenberg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,cAAc,GAAG,qBAAqB,GAAG,WAAW,CAAA;AAchE,uGAAuG;AACvG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE,CA2D/E"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Splits WordPress post content into its top-level pieces.
3
+ *
4
+ * Since WordPress 5.0, `content:encoded` is HTML interleaved with Gutenberg
5
+ * block comments (`<!-- wp:paragraph -->…<!-- /wp:paragraph -->`); content
6
+ * from the classic editor, or a site that never touched the block editor, is
7
+ * just HTML with no such comments. Both are handled: a document with block
8
+ * comments is split at the top level only (a block nested inside a
9
+ * `wp:group`/`wp:columns` container is not descended into — the container
10
+ * itself is reported as unconverted, its children are not individually
11
+ * salvaged); a document with none is returned as one `html` segment.
12
+ */
13
+ const BLOCK_COMMENT = /<!--\s*(\/)?wp:([a-zA-Z0-9][\w/-]*)\s*({[^}]*})?\s*(\/)?-->/g;
14
+ function parseAttrs(raw) {
15
+ if (raw === undefined)
16
+ return {};
17
+ try {
18
+ const parsed = JSON.parse(raw);
19
+ return typeof parsed === 'object' && parsed !== null ? parsed : {};
20
+ }
21
+ catch {
22
+ return {};
23
+ }
24
+ }
25
+ /** Splits `content:encoded` into top-level Gutenberg blocks, or one HTML segment when it uses none. */
26
+ export function splitContentSegments(content) {
27
+ if (!content.includes('<!-- wp:')) {
28
+ return content.trim().length === 0 ? [] : [{ kind: 'html', html: content }];
29
+ }
30
+ const segments = [];
31
+ let cursor = 0;
32
+ let depth = 0;
33
+ let currentName = null;
34
+ let currentAttrs = {};
35
+ let currentInnerStart = 0;
36
+ BLOCK_COMMENT.lastIndex = 0;
37
+ let match = BLOCK_COMMENT.exec(content);
38
+ while (match !== null) {
39
+ const isClose = match[1] === '/';
40
+ const name = match[2] ?? '';
41
+ const attrsRaw = match[3];
42
+ const selfClosed = match[4] === '/';
43
+ if (depth === 0 && !isClose) {
44
+ // Anything between the previous top-level block and this one is loose
45
+ // HTML (or whitespace) — kept as its own segment rather than dropped.
46
+ const between = content.slice(cursor, match.index).trim();
47
+ if (between.length > 0)
48
+ segments.push({ kind: 'html', html: between });
49
+ if (selfClosed) {
50
+ segments.push({ kind: 'block', name, attrs: parseAttrs(attrsRaw), innerHtml: '' });
51
+ cursor = match.index + match[0].length;
52
+ }
53
+ else {
54
+ currentName = name;
55
+ currentAttrs = parseAttrs(attrsRaw);
56
+ currentInnerStart = match.index + match[0].length;
57
+ depth = 1;
58
+ }
59
+ }
60
+ else if (!isClose && !selfClosed && name === currentName) {
61
+ // A same-named nested block (e.g. wp:group inside wp:group) — tracked
62
+ // only to find the matching close comment; its own children are not
63
+ // separately extracted (see module doc).
64
+ depth += 1;
65
+ }
66
+ else if (isClose && name === currentName) {
67
+ depth -= 1;
68
+ if (depth === 0) {
69
+ const innerHtml = content.slice(currentInnerStart, match.index);
70
+ segments.push({ kind: 'block', name: currentName, attrs: currentAttrs, innerHtml });
71
+ cursor = match.index + match[0].length;
72
+ currentName = null;
73
+ currentAttrs = {};
74
+ }
75
+ }
76
+ match = BLOCK_COMMENT.exec(content);
77
+ }
78
+ const tail = content.slice(cursor).trim();
79
+ if (tail.length > 0)
80
+ segments.push({ kind: 'html', html: tail });
81
+ return segments;
82
+ }
83
+ //# sourceMappingURL=gutenberg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gutenberg.js","sourceRoot":"","sources":["../../src/wordpress/gutenberg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { RichTextDocument } from '@cogenta/schema';
2
+ /**
3
+ * A narrow HTML-fragment reader, scoped to the handful of tags WordPress
4
+ * content actually uses and contract A's rich-text vocabulary can actually
5
+ * represent: paragraphs, `h2`–`h4` (contract A has no `h1` in body text — see
6
+ * `packages/schema/src/rich-text.ts`), blockquotes, lists, and the `strong`,
7
+ * `em`, `code` and `link` marks. Anything else is dropped from the returned
8
+ * document and named in `unknownTags`, never smuggled through as stored HTML
9
+ * (rule R3).
10
+ */
11
+ export interface HtmlToRichTextResult {
12
+ readonly document: RichTextDocument;
13
+ /** Tag names this converter has no mapping for — reported, not guessed at. */
14
+ readonly unknownTags: readonly string[];
15
+ }
16
+ /**
17
+ * Converts one HTML fragment (a Gutenberg block's inner HTML, or a classic
18
+ * post body) into a rich-text document. Best-effort: content this converter
19
+ * cannot map is dropped from the output and named in `unknownTags`, never
20
+ * emitted as raw markup.
21
+ */
22
+ export declare function htmlToRichText(html: string): HtmlToRichTextResult;
23
+ //# sourceMappingURL=html-to-richtext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-to-richtext.d.ts","sourceRoot":"","sources":["../../src/wordpress/html-to-richtext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,iBAAiB,CAAA;AAEtE;;;;;;;;GAQG;AAEH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;AAgKD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAuDjE"}
@@ -0,0 +1,209 @@
1
+ let keyCounter = 0;
2
+ function nextKey(prefix) {
3
+ keyCounter += 1;
4
+ return `${prefix}-${keyCounter}`;
5
+ }
6
+ const HEADING_STYLE = {
7
+ h2: 'h2',
8
+ h3: 'h3',
9
+ h4: 'h4',
10
+ // Contract A has no h1 in body text (the page title is the only h1) and no
11
+ // h5/h6 at all — both fold to the closest style the vocabulary has.
12
+ h1: 'h2',
13
+ h5: 'h4',
14
+ h6: 'h4',
15
+ };
16
+ const TRANSPARENT_TAGS = new Set(['p', 'div', 'span', 'figure', 'figcaption']);
17
+ /** Strips tags from an inline HTML fragment into spans carrying marks — no tag ever survives into `text`. */
18
+ function inlineToSpans(html, unknownTags) {
19
+ const spans = [];
20
+ const markStack = [];
21
+ let hrefStack = [null];
22
+ let buffer = '';
23
+ const flush = () => {
24
+ if (buffer.length === 0)
25
+ return;
26
+ spans.push({ text: buffer, marks: [...markStack], href: hrefStack.at(-1) ?? null });
27
+ buffer = '';
28
+ };
29
+ const tagPattern = /<\/?([a-zA-Z][a-zA-Z0-9]*)\b([^>]*)>/g;
30
+ let last = 0;
31
+ let match = tagPattern.exec(html);
32
+ while (match !== null) {
33
+ buffer += decodeHtmlEntities(html.slice(last, match.index));
34
+ const isClose = match[0].startsWith('</');
35
+ const tag = (match[1] ?? '').toLowerCase();
36
+ const attrs = match[2] ?? '';
37
+ if (tag === 'strong' || tag === 'b') {
38
+ if (isClose)
39
+ markStack.splice(markStack.indexOf('strong'), 1);
40
+ else {
41
+ flush();
42
+ markStack.push('strong');
43
+ }
44
+ }
45
+ else if (tag === 'em' || tag === 'i') {
46
+ if (isClose)
47
+ markStack.splice(markStack.indexOf('em'), 1);
48
+ else {
49
+ flush();
50
+ markStack.push('em');
51
+ }
52
+ }
53
+ else if (tag === 'code') {
54
+ if (isClose)
55
+ markStack.splice(markStack.indexOf('code'), 1);
56
+ else {
57
+ flush();
58
+ markStack.push('code');
59
+ }
60
+ }
61
+ else if (tag === 'a') {
62
+ if (isClose) {
63
+ flush();
64
+ hrefStack.pop();
65
+ }
66
+ else {
67
+ flush();
68
+ const hrefMatch = /href=["']([^"']*)["']/.exec(attrs);
69
+ hrefStack.push(hrefMatch?.[1] ?? null);
70
+ }
71
+ }
72
+ else if (tag === 'br') {
73
+ buffer += '\n';
74
+ }
75
+ else if (TRANSPARENT_TAGS.has(tag)) {
76
+ // A grouping wrapper (`<p>` inside a `<blockquote>`, `<figure>`/`<figcaption>`
77
+ // around an image caption, …) carries no rich-text-relevant meaning once
78
+ // its content is already being flattened into spans — dropped silently,
79
+ // not reported as unmapped.
80
+ }
81
+ else if (tag.length > 0) {
82
+ unknownTags.add(tag);
83
+ }
84
+ last = tagPattern.lastIndex;
85
+ match = tagPattern.exec(html);
86
+ }
87
+ buffer += decodeHtmlEntities(html.slice(last));
88
+ flush();
89
+ hrefStack = [];
90
+ return spans.filter((span) => span.text.length > 0);
91
+ }
92
+ const HTML_NAMED_ENTITIES = {
93
+ amp: '&',
94
+ lt: '<',
95
+ gt: '>',
96
+ quot: '"',
97
+ apos: "'",
98
+ nbsp: ' ',
99
+ rsquo: '’',
100
+ lsquo: '‘',
101
+ rdquo: '”',
102
+ ldquo: '“',
103
+ mdash: '—',
104
+ ndash: '–',
105
+ hellip: '…',
106
+ };
107
+ function decodeHtmlEntities(text) {
108
+ return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (match, body) => {
109
+ if (body.startsWith('#x') || body.startsWith('#X')) {
110
+ const code = Number.parseInt(body.slice(2), 16);
111
+ return Number.isFinite(code) ? String.fromCodePoint(code) : match;
112
+ }
113
+ if (body.startsWith('#')) {
114
+ const code = Number.parseInt(body.slice(1), 10);
115
+ return Number.isFinite(code) ? String.fromCodePoint(code) : match;
116
+ }
117
+ return HTML_NAMED_ENTITIES[body] ?? match;
118
+ });
119
+ }
120
+ function spansToBlock(spans, style, listItem) {
121
+ const markDefs = [];
122
+ const hrefKey = new Map();
123
+ const children = spans.map((span) => {
124
+ const marks = [...span.marks];
125
+ if (span.href !== null) {
126
+ let key = hrefKey.get(span.href);
127
+ if (key === undefined) {
128
+ key = nextKey('link');
129
+ hrefKey.set(span.href, key);
130
+ markDefs.push({ _key: key, _type: 'link', href: span.href });
131
+ }
132
+ marks.push(key);
133
+ }
134
+ return { _key: nextKey('span'), _type: 'span', text: span.text, marks };
135
+ });
136
+ const block = {
137
+ _key: nextKey('block'),
138
+ _type: 'block',
139
+ style,
140
+ children,
141
+ markDefs,
142
+ ...(listItem === undefined ? {} : { listItem, level: 1 }),
143
+ };
144
+ return block;
145
+ }
146
+ /**
147
+ * Converts one HTML fragment (a Gutenberg block's inner HTML, or a classic
148
+ * post body) into a rich-text document. Best-effort: content this converter
149
+ * cannot map is dropped from the output and named in `unknownTags`, never
150
+ * emitted as raw markup.
151
+ */
152
+ export function htmlToRichText(html) {
153
+ const unknownTags = new Set();
154
+ const document = [];
155
+ const blockPattern = /<(p|h1|h2|h3|h4|h5|h6|blockquote|ul|ol)\b[^>]*>([\s\S]*?)<\/\1>/gi;
156
+ let last = 0;
157
+ let match = blockPattern.exec(html);
158
+ let matchedAny = false;
159
+ while (match !== null) {
160
+ matchedAny = true;
161
+ const between = html.slice(last, match.index).trim();
162
+ if (between.length > 0) {
163
+ const spans = inlineToSpans(between, unknownTags);
164
+ if (spans.length > 0)
165
+ document.push(spansToBlock(spans, 'normal'));
166
+ }
167
+ const tag = (match[1] ?? '').toLowerCase();
168
+ const inner = match[2] ?? '';
169
+ if (tag === 'ul' || tag === 'ol') {
170
+ const itemPattern = /<li\b[^>]*>([\s\S]*?)<\/li>/gi;
171
+ let itemMatch = itemPattern.exec(inner);
172
+ while (itemMatch !== null) {
173
+ const spans = inlineToSpans(itemMatch[1] ?? '', unknownTags);
174
+ if (spans.length > 0) {
175
+ document.push(spansToBlock(spans, 'normal', tag === 'ol' ? 'number' : 'bullet'));
176
+ }
177
+ itemMatch = itemPattern.exec(inner);
178
+ }
179
+ }
180
+ else if (tag === 'blockquote') {
181
+ const spans = inlineToSpans(inner, unknownTags);
182
+ if (spans.length > 0)
183
+ document.push(spansToBlock(spans, 'blockquote'));
184
+ }
185
+ else {
186
+ const style = HEADING_STYLE[tag] ?? 'normal';
187
+ const spans = inlineToSpans(inner, unknownTags);
188
+ if (spans.length > 0)
189
+ document.push(spansToBlock(spans, style));
190
+ }
191
+ last = blockPattern.lastIndex;
192
+ match = blockPattern.exec(html);
193
+ }
194
+ const rest = html.slice(last).trim();
195
+ if (!matchedAny && rest.length > 0) {
196
+ // Plain inline content with no block-level wrapper at all (rare, but
197
+ // classic-editor content sometimes omits the outer <p>).
198
+ const spans = inlineToSpans(rest, unknownTags);
199
+ if (spans.length > 0)
200
+ document.push(spansToBlock(spans, 'normal'));
201
+ }
202
+ else if (rest.length > 0) {
203
+ const spans = inlineToSpans(rest, unknownTags);
204
+ if (spans.length > 0)
205
+ document.push(spansToBlock(spans, 'normal'));
206
+ }
207
+ return { document, unknownTags: [...unknownTags] };
208
+ }
209
+ //# sourceMappingURL=html-to-richtext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-to-richtext.js","sourceRoot":"","sources":["../../src/wordpress/html-to-richtext.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type DatabaseHandle, type StorageDriver } from '@cogenta/core';
2
+ import { type ConversionReport } from './report.js';
3
+ export interface ImportWordPressOptions {
4
+ readonly db: DatabaseHandle;
5
+ readonly storage: StorageDriver;
6
+ /** Injected for tests — real `fetch` by default. */
7
+ readonly fetchImpl?: typeof fetch;
8
+ }
9
+ /**
10
+ * Imports a WordPress "Export All Content" WXR file into Cogenta.
11
+ *
12
+ * Every step degrades to a report entry rather than aborting the import: a
13
+ * dead media URL, an unmappable Gutenberg block, an author with no email, a
14
+ * redirect that would loop — none of them stop the run, because the lot's own
15
+ * framing is explicit that a reported partial loss beats a silent one. The
16
+ * only thing that stops the run is a document `parseWxr` cannot read at all.
17
+ */
18
+ export declare function importWordPress(xml: string, options: ImportWordPressOptions): Promise<ConversionReport>;
19
+ //# sourceMappingURL=import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/wordpress/import.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAwBjG,OAAO,EAAE,KAAK,gBAAgB,EAAqC,MAAM,aAAa,CAAA;AAGtF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAClC;AAyCD;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CA6O3B"}