@se-studio/markdown-renderer 1.0.9 → 1.0.11
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/CHANGELOG.md +89 -0
- package/README.md +93 -0
- package/dist/MarkdownConverter.d.ts +15 -0
- package/dist/MarkdownConverter.d.ts.map +1 -0
- package/dist/MarkdownConverter.js +122 -0
- package/dist/MarkdownConverter.js.map +1 -0
- package/dist/MarkdownExporter.d.ts +12 -0
- package/dist/MarkdownExporter.d.ts.map +1 -0
- package/dist/MarkdownExporter.js +84 -0
- package/dist/MarkdownExporter.js.map +1 -0
- package/dist/index.d.ts +4 -42
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -332
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/richTextConverter.d.ts +6 -0
- package/dist/utils/richTextConverter.d.ts.map +1 -0
- package/dist/utils/richTextConverter.js +92 -0
- package/dist/utils/richTextConverter.js.map +1 -0
- package/package.json +8 -7
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# @se-studio/markdown-renderer
|
|
2
|
+
|
|
3
|
+
## 1.0.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @se-studio/contentful-rest-api@1.0.47
|
|
9
|
+
- @se-studio/core-data-types@1.0.47
|
|
10
|
+
|
|
11
|
+
## 1.0.10
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Updated dependencies
|
|
16
|
+
- @se-studio/contentful-rest-api@1.0.46
|
|
17
|
+
- @se-studio/core-data-types@1.0.46
|
|
18
|
+
|
|
19
|
+
## 1.0.9
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies
|
|
24
|
+
- @se-studio/contentful-rest-api@1.0.45
|
|
25
|
+
- @se-studio/core-data-types@1.0.45
|
|
26
|
+
|
|
27
|
+
## 1.0.8
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies
|
|
32
|
+
- @se-studio/contentful-rest-api@1.0.44
|
|
33
|
+
- @se-studio/core-data-types@1.0.44
|
|
34
|
+
|
|
35
|
+
## 1.0.7
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Updated dependencies
|
|
40
|
+
- @se-studio/contentful-rest-api@1.0.43
|
|
41
|
+
- @se-studio/core-data-types@1.0.43
|
|
42
|
+
|
|
43
|
+
## 1.0.6
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- Updated dependencies
|
|
48
|
+
- @se-studio/contentful-rest-api@1.0.42
|
|
49
|
+
- @se-studio/core-data-types@1.0.42
|
|
50
|
+
|
|
51
|
+
## 1.0.5
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- Updated dependencies
|
|
56
|
+
- @se-studio/contentful-rest-api@1.0.41
|
|
57
|
+
- @se-studio/core-data-types@1.0.41
|
|
58
|
+
|
|
59
|
+
## 1.0.4
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- Updated dependencies
|
|
64
|
+
- @se-studio/contentful-rest-api@1.0.40
|
|
65
|
+
- @se-studio/core-data-types@1.0.40
|
|
66
|
+
|
|
67
|
+
## 1.0.3
|
|
68
|
+
|
|
69
|
+
### Patch Changes
|
|
70
|
+
|
|
71
|
+
- Updated dependencies
|
|
72
|
+
- @se-studio/contentful-rest-api@1.0.39
|
|
73
|
+
- @se-studio/core-data-types@1.0.39
|
|
74
|
+
|
|
75
|
+
## 1.0.2
|
|
76
|
+
|
|
77
|
+
### Patch Changes
|
|
78
|
+
|
|
79
|
+
- Updated dependencies
|
|
80
|
+
- @se-studio/contentful-rest-api@1.0.38
|
|
81
|
+
- @se-studio/core-data-types@1.0.38
|
|
82
|
+
|
|
83
|
+
## 1.0.1
|
|
84
|
+
|
|
85
|
+
### Patch Changes
|
|
86
|
+
|
|
87
|
+
- Updated dependencies
|
|
88
|
+
- @se-studio/contentful-rest-api@1.0.37
|
|
89
|
+
- @se-studio/core-data-types@1.0.37
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# @se-studio/markdown-renderer
|
|
2
|
+
|
|
3
|
+
Utilities for converting Contentful content into Markdown format. This package provides tools to export pages, articles, and custom types from Contentful and convert them into structured Markdown, suitable for LLM consumption or static site generation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Content Export**: Fetch content from Contentful (Pages, Articles, Custom Types) with full context.
|
|
8
|
+
- **Markdown Conversion**: Convert structured Contentful data into clean, readable Markdown.
|
|
9
|
+
- **Rich Text Support**: Automatically converts Contentful Rich Text fields to Markdown.
|
|
10
|
+
- **Component & Collection Handling**: Recursively processes nested components and collections.
|
|
11
|
+
- **Frontmatter Generation**: meaningful YAML frontmatter for exported content.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @se-studio/markdown-renderer
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Export & Conversion
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { createContentfulClient } from '@se-studio/contentful-rest-api';
|
|
25
|
+
import { MarkdownExporter, MarkdownConverter } from '@se-studio/markdown-renderer';
|
|
26
|
+
|
|
27
|
+
// 1. Setup Client and Exporter
|
|
28
|
+
const config = {
|
|
29
|
+
spaceId: process.env.CONTENTFUL_SPACE_ID!,
|
|
30
|
+
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
|
|
31
|
+
environment: 'master'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const exporter = new MarkdownExporter(config);
|
|
35
|
+
const converter = new MarkdownConverter();
|
|
36
|
+
|
|
37
|
+
// 2. Fetch Content
|
|
38
|
+
// Supported types: 'page', 'article', 'blogPost', 'customType'
|
|
39
|
+
const contentData = await exporter.fetchContent('page', 'home');
|
|
40
|
+
|
|
41
|
+
if (contentData) {
|
|
42
|
+
// 3. Convert to Markdown
|
|
43
|
+
const markdown = await converter.convert(contentData, {
|
|
44
|
+
contentContext: contentData.context,
|
|
45
|
+
config: config
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
console.log(markdown);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API Reference
|
|
53
|
+
|
|
54
|
+
### `MarkdownExporter`
|
|
55
|
+
|
|
56
|
+
Handles fetching data from Contentful and preparing the context.
|
|
57
|
+
|
|
58
|
+
#### `constructor(config: ContentfulConfig, preview?: boolean)`
|
|
59
|
+
- `config`: Contentful configuration object.
|
|
60
|
+
- `preview`: Boolean to enable Preview API (default: `false`).
|
|
61
|
+
|
|
62
|
+
#### `fetchContent(type, slug, params?)`
|
|
63
|
+
Fetches content by slug and returns a `ContentData` object.
|
|
64
|
+
- `type`: `'page' | 'article' | 'blogPost' | 'customType'`
|
|
65
|
+
- `slug`: The slug of the entry.
|
|
66
|
+
- `params`: Optional parameters (e.g., `{ articleType: 'blog' }`).
|
|
67
|
+
|
|
68
|
+
### `MarkdownConverter`
|
|
69
|
+
|
|
70
|
+
Handles the transformation of `ContentData` into a Markdown string.
|
|
71
|
+
|
|
72
|
+
#### `convert(contentData, context)`
|
|
73
|
+
- `contentData`: The data object returned by `MarkdownExporter`.
|
|
74
|
+
- `context`: Context object containing `contentContext` and `config`.
|
|
75
|
+
|
|
76
|
+
### Types
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
interface ContentData {
|
|
80
|
+
contentType: 'page' | 'article' | 'customType';
|
|
81
|
+
data: IBasePage | IBaseArticle | IBaseCustomType;
|
|
82
|
+
context: IContentContext;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface MarkdownConverterContext {
|
|
86
|
+
contentContext: IContentContext;
|
|
87
|
+
config: ContentfulConfig;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ContentData, MarkdownConverterContext } from './types';
|
|
2
|
+
export declare class MarkdownConverter {
|
|
3
|
+
convert(contentData: ContentData, context: MarkdownConverterContext): Promise<string>;
|
|
4
|
+
private generateFrontmatter;
|
|
5
|
+
private convertModule;
|
|
6
|
+
private convertGenericComponent;
|
|
7
|
+
private convertGenericCollection;
|
|
8
|
+
private renderPreHeading;
|
|
9
|
+
private renderPostHeading;
|
|
10
|
+
private renderBody;
|
|
11
|
+
private renderAdditionalCopy;
|
|
12
|
+
private renderVisual;
|
|
13
|
+
private renderLinks;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=MarkdownConverter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownConverter.d.ts","sourceRoot":"","sources":["../src/MarkdownConverter.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAGrE,qBAAa,iBAAiB;IACtB,OAAO,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC;IA0B3F,OAAO,CAAC,mBAAmB;YAkBb,aAAa;IAgB3B,OAAO,CAAC,uBAAuB;YAwBjB,wBAAwB;IAwBtC,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,WAAW;CAYpB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import yaml from 'js-yaml';
|
|
2
|
+
import { convertRichTextToMarkdown } from './utils/richTextConverter';
|
|
3
|
+
export class MarkdownConverter {
|
|
4
|
+
async convert(contentData, context) {
|
|
5
|
+
const { data, contentType } = contentData;
|
|
6
|
+
const frontmatter = this.generateFrontmatter(data, contentType);
|
|
7
|
+
let markdown = `---\n${yaml.dump(frontmatter)}---\n\n`;
|
|
8
|
+
// Add Title and basic body
|
|
9
|
+
if (data.title) {
|
|
10
|
+
markdown += `# ${data.title}\n\n`;
|
|
11
|
+
}
|
|
12
|
+
if (data.description) {
|
|
13
|
+
markdown += `> ${data.description}\n\n`;
|
|
14
|
+
}
|
|
15
|
+
// Page modules / contents
|
|
16
|
+
if (data.contents) {
|
|
17
|
+
for (const item of data.contents) {
|
|
18
|
+
if (!item)
|
|
19
|
+
continue;
|
|
20
|
+
markdown += await this.convertModule(item, context);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return markdown;
|
|
24
|
+
}
|
|
25
|
+
generateFrontmatter(data, type) {
|
|
26
|
+
const slug = data.slug;
|
|
27
|
+
return {
|
|
28
|
+
contentType: type,
|
|
29
|
+
title: data.title,
|
|
30
|
+
slug: slug,
|
|
31
|
+
id: data.id,
|
|
32
|
+
description: data.description,
|
|
33
|
+
// Add more specific fields for Article if needed (date, author, etc)
|
|
34
|
+
...(type === 'article'
|
|
35
|
+
? {
|
|
36
|
+
date: data.date,
|
|
37
|
+
articleType: data.articleType?.name,
|
|
38
|
+
}
|
|
39
|
+
: {}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async convertModule(item, context) {
|
|
43
|
+
if (item.type === 'Component') {
|
|
44
|
+
const component = item;
|
|
45
|
+
// Use generic fallback for all components
|
|
46
|
+
return this.convertGenericComponent(component, context);
|
|
47
|
+
}
|
|
48
|
+
if (item.type === 'Collection') {
|
|
49
|
+
const collection = item;
|
|
50
|
+
// Use generic fallback for all collections
|
|
51
|
+
return this.convertGenericCollection(collection, context);
|
|
52
|
+
}
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
convertGenericComponent(component, context) {
|
|
56
|
+
let md = '';
|
|
57
|
+
// Add heading hierarchy
|
|
58
|
+
if (component.heading) {
|
|
59
|
+
md += `## ${component.heading}\n\n`;
|
|
60
|
+
}
|
|
61
|
+
else if (component.componentType) {
|
|
62
|
+
// Fallback to component type if no heading, but NOT cmsLabel
|
|
63
|
+
md += `## ${component.componentType}\n\n`;
|
|
64
|
+
}
|
|
65
|
+
md += this.renderPreHeading(component.preHeading);
|
|
66
|
+
md += this.renderPostHeading(component.postHeading);
|
|
67
|
+
md += this.renderBody(component.body, context);
|
|
68
|
+
md += this.renderAdditionalCopy(component.additionalCopy, context);
|
|
69
|
+
md += this.renderVisual(component.visual);
|
|
70
|
+
md += this.renderLinks(component.links);
|
|
71
|
+
return md;
|
|
72
|
+
}
|
|
73
|
+
async convertGenericCollection(collection, context) {
|
|
74
|
+
let md = `## ${collection.heading || collection.collectionType || 'Collection'}\n\n`;
|
|
75
|
+
md += this.renderPreHeading(collection.preHeading);
|
|
76
|
+
md += this.renderPostHeading(collection.postHeading);
|
|
77
|
+
md += this.renderBody(collection.body, context);
|
|
78
|
+
md += this.renderLinks(collection.links);
|
|
79
|
+
if (collection.contents) {
|
|
80
|
+
for (const item of collection.contents) {
|
|
81
|
+
if (!item)
|
|
82
|
+
continue;
|
|
83
|
+
md += await this.convertModule(item, context);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
md += this.renderAdditionalCopy(collection.additionalCopy, context);
|
|
87
|
+
md += this.renderVisual(collection.visual);
|
|
88
|
+
return md;
|
|
89
|
+
}
|
|
90
|
+
renderPreHeading(preHeading) {
|
|
91
|
+
return preHeading ? `**${preHeading}**\n\n` : '';
|
|
92
|
+
}
|
|
93
|
+
renderPostHeading(postHeading) {
|
|
94
|
+
return postHeading ? `*${postHeading}*\n\n` : '';
|
|
95
|
+
}
|
|
96
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic content body
|
|
97
|
+
renderBody(body, context) {
|
|
98
|
+
return body ? convertRichTextToMarkdown(body, context) : '';
|
|
99
|
+
}
|
|
100
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic additional copy
|
|
101
|
+
renderAdditionalCopy(additionalCopy, context) {
|
|
102
|
+
return additionalCopy ? `\n\n${convertRichTextToMarkdown(additionalCopy, context)}` : '';
|
|
103
|
+
}
|
|
104
|
+
renderVisual(visual) {
|
|
105
|
+
const image = visual?.visual?.image;
|
|
106
|
+
if (!image)
|
|
107
|
+
return '';
|
|
108
|
+
const title = image.name || 'Image';
|
|
109
|
+
const url = image.src || image.svgSrc;
|
|
110
|
+
return url ? `\n\n` : '';
|
|
111
|
+
}
|
|
112
|
+
renderLinks(links) {
|
|
113
|
+
if (!links?.length)
|
|
114
|
+
return '';
|
|
115
|
+
let md = '\n';
|
|
116
|
+
for (const link of links) {
|
|
117
|
+
md += `- [${link.text || link.name}](${link.href || '#'}) \n`;
|
|
118
|
+
}
|
|
119
|
+
return `${md}\n`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=MarkdownConverter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownConverter.js","sourceRoot":"","sources":["../src/MarkdownConverter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ContentfulConfig } from '@se-studio/contentful-rest-api';
|
|
2
|
+
import type { ContentData } from './types';
|
|
3
|
+
export declare class MarkdownExporter {
|
|
4
|
+
private config;
|
|
5
|
+
private preview;
|
|
6
|
+
constructor(config: ContentfulConfig, preview?: boolean);
|
|
7
|
+
fetchContent(type: 'page' | 'article' | 'blogPost' | 'customType', slug: string, params?: {
|
|
8
|
+
articleType?: string;
|
|
9
|
+
}): Promise<ContentData | null>;
|
|
10
|
+
private createContext;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=MarkdownExporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownExporter.d.ts","sourceRoot":"","sources":["../src/MarkdownExporter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EAMtB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,OAAO,CAAU;gBAEb,MAAM,EAAE,gBAAgB,EAAE,OAAO,UAAQ;IAK/C,YAAY,CAChB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,EACpD,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAChC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAoE9B,OAAO,CAAC,aAAa;CAetB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { contentfulArticleRest, contentfulCustomTypeRest, contentfulPageRest, createBaseConverterContext, } from '@se-studio/contentful-rest-api';
|
|
2
|
+
export class MarkdownExporter {
|
|
3
|
+
config;
|
|
4
|
+
preview;
|
|
5
|
+
constructor(config, preview = false) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
this.preview = preview;
|
|
8
|
+
}
|
|
9
|
+
async fetchContent(type, slug, params) {
|
|
10
|
+
const context = this.createContext();
|
|
11
|
+
if (type === 'page') {
|
|
12
|
+
const response = await contentfulPageRest(context, this.config, slug, {
|
|
13
|
+
preview: this.preview,
|
|
14
|
+
});
|
|
15
|
+
if (!response.data)
|
|
16
|
+
return null;
|
|
17
|
+
const page = response.data;
|
|
18
|
+
return {
|
|
19
|
+
contentType: 'page',
|
|
20
|
+
data: page,
|
|
21
|
+
context: {
|
|
22
|
+
pageContext: {
|
|
23
|
+
page,
|
|
24
|
+
},
|
|
25
|
+
current: { type: 'Page', id: page.id },
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (type === 'article' || type === 'blogPost') {
|
|
30
|
+
const articleType = params?.articleType || 'blog';
|
|
31
|
+
const response = await contentfulArticleRest(context, this.config, slug, articleType, {
|
|
32
|
+
preview: this.preview,
|
|
33
|
+
});
|
|
34
|
+
if (!response.data)
|
|
35
|
+
return null;
|
|
36
|
+
const article = response.data;
|
|
37
|
+
return {
|
|
38
|
+
contentType: 'article',
|
|
39
|
+
data: article,
|
|
40
|
+
context: {
|
|
41
|
+
pageContext: {
|
|
42
|
+
article,
|
|
43
|
+
articleType: article.articleType,
|
|
44
|
+
},
|
|
45
|
+
current: { type: 'Article', id: article.id },
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (type === 'customType') {
|
|
50
|
+
const response = await contentfulCustomTypeRest(context, this.config, slug, {
|
|
51
|
+
preview: this.preview,
|
|
52
|
+
});
|
|
53
|
+
if (!response.data)
|
|
54
|
+
return null;
|
|
55
|
+
const customType = response.data;
|
|
56
|
+
return {
|
|
57
|
+
contentType: 'customType',
|
|
58
|
+
data: customType,
|
|
59
|
+
context: {
|
|
60
|
+
pageContext: {
|
|
61
|
+
customType,
|
|
62
|
+
},
|
|
63
|
+
current: { type: 'CustomType', id: customType.id },
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
createContext() {
|
|
70
|
+
// Basic context for fetching - we might need to make this configurable if URL calculation differs per app
|
|
71
|
+
// For now using simple defaults that produce relative paths
|
|
72
|
+
const urlCalculators = {
|
|
73
|
+
page: (slug) => `/${slug}`,
|
|
74
|
+
pageVariant: (slug) => `/${slug}`,
|
|
75
|
+
article: (type, slug) => `/${type}/${slug}`,
|
|
76
|
+
articleType: (slug) => `/${slug}`,
|
|
77
|
+
tag: (slug) => `/topics/${slug}`,
|
|
78
|
+
person: (slug) => `/team/${slug}`,
|
|
79
|
+
customType: (slug) => `/${slug}`,
|
|
80
|
+
};
|
|
81
|
+
return createBaseConverterContext(urlCalculators);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=MarkdownExporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownExporter.js","sourceRoot":"","sources":["../src/MarkdownExporter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,42 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
contentType: 'page' | 'article' | 'customType';
|
|
6
|
-
data: IBasePage | IBaseArticle | IBaseCustomType;
|
|
7
|
-
context: IContentContext;
|
|
8
|
-
}
|
|
9
|
-
interface MarkdownConverterContext {
|
|
10
|
-
contentContext: IContentContext;
|
|
11
|
-
config: ContentfulConfig;
|
|
12
|
-
}
|
|
13
|
-
interface ConverterResult {
|
|
14
|
-
markdown: string;
|
|
15
|
-
}
|
|
16
|
-
type ConverterFunction<T = any> = (data: T, context: MarkdownConverterContext) => Promise<string> | string;
|
|
17
|
-
|
|
18
|
-
declare class MarkdownConverter {
|
|
19
|
-
convert(contentData: ContentData, context: MarkdownConverterContext): Promise<string>;
|
|
20
|
-
private generateFrontmatter;
|
|
21
|
-
private convertModule;
|
|
22
|
-
private convertGenericComponent;
|
|
23
|
-
private convertGenericCollection;
|
|
24
|
-
private renderPreHeading;
|
|
25
|
-
private renderPostHeading;
|
|
26
|
-
private renderBody;
|
|
27
|
-
private renderAdditionalCopy;
|
|
28
|
-
private renderVisual;
|
|
29
|
-
private renderLinks;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
declare class MarkdownExporter {
|
|
33
|
-
private config;
|
|
34
|
-
private preview;
|
|
35
|
-
constructor(config: ContentfulConfig, preview?: boolean);
|
|
36
|
-
fetchContent(type: 'page' | 'article' | 'blogPost' | 'customType', slug: string, params?: {
|
|
37
|
-
articleType?: string;
|
|
38
|
-
}): Promise<ContentData | null>;
|
|
39
|
-
private createContext;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export { type ContentData, type ConverterFunction, type ConverterResult, MarkdownConverter, type MarkdownConverterContext, MarkdownExporter };
|
|
1
|
+
export * from './MarkdownConverter';
|
|
2
|
+
export * from './MarkdownExporter';
|
|
3
|
+
export * from './types';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,333 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// src/utils/richTextConverter.ts
|
|
5
|
-
import {
|
|
6
|
-
BLOCKS,
|
|
7
|
-
INLINES,
|
|
8
|
-
MARKS
|
|
9
|
-
} from "@contentful/rich-text-types";
|
|
10
|
-
function convertRichTextToMarkdown(richText, context) {
|
|
11
|
-
if (!richText) return "";
|
|
12
|
-
const document = "json" in richText ? richText.json : richText;
|
|
13
|
-
if (!document) return "";
|
|
14
|
-
return convertNode(document, context);
|
|
15
|
-
}
|
|
16
|
-
function convertNode(node, context) {
|
|
17
|
-
if (node.nodeType === "text") {
|
|
18
|
-
return convertText(node);
|
|
19
|
-
}
|
|
20
|
-
const content = (node.content || []).map((child) => convertNode(child, context)).join("");
|
|
21
|
-
switch (node.nodeType) {
|
|
22
|
-
case BLOCKS.DOCUMENT:
|
|
23
|
-
return content;
|
|
24
|
-
case BLOCKS.PARAGRAPH:
|
|
25
|
-
return `${content}
|
|
26
|
-
|
|
27
|
-
`;
|
|
28
|
-
case BLOCKS.HEADING_1:
|
|
29
|
-
return `# ${content}
|
|
30
|
-
|
|
31
|
-
`;
|
|
32
|
-
case BLOCKS.HEADING_2:
|
|
33
|
-
return `## ${content}
|
|
34
|
-
|
|
35
|
-
`;
|
|
36
|
-
case BLOCKS.HEADING_3:
|
|
37
|
-
return `### ${content}
|
|
38
|
-
|
|
39
|
-
`;
|
|
40
|
-
case BLOCKS.HEADING_4:
|
|
41
|
-
return `#### ${content}
|
|
42
|
-
|
|
43
|
-
`;
|
|
44
|
-
case BLOCKS.HEADING_5:
|
|
45
|
-
return `##### ${content}
|
|
46
|
-
|
|
47
|
-
`;
|
|
48
|
-
case BLOCKS.HEADING_6:
|
|
49
|
-
return `###### ${content}
|
|
50
|
-
|
|
51
|
-
`;
|
|
52
|
-
case BLOCKS.UL_LIST:
|
|
53
|
-
return `${content}
|
|
54
|
-
`;
|
|
55
|
-
case BLOCKS.OL_LIST:
|
|
56
|
-
return `${content}
|
|
57
|
-
`;
|
|
58
|
-
case BLOCKS.LIST_ITEM:
|
|
59
|
-
return `- ${content.trim()}
|
|
60
|
-
`;
|
|
61
|
-
case BLOCKS.QUOTE:
|
|
62
|
-
return `> ${content.replace(/\n/g, "\n> ")}
|
|
63
|
-
|
|
64
|
-
`;
|
|
65
|
-
case BLOCKS.HR:
|
|
66
|
-
return `---
|
|
67
|
-
|
|
68
|
-
`;
|
|
69
|
-
case INLINES.HYPERLINK:
|
|
70
|
-
return `[${content}](${node.data.uri})`;
|
|
71
|
-
case INLINES.ENTRY_HYPERLINK:
|
|
72
|
-
return `[${content}](#${node.data.target?.sys?.id || "entry-link"})`;
|
|
73
|
-
case INLINES.ASSET_HYPERLINK:
|
|
74
|
-
return `[${content}](${node.data.target?.fields?.file?.url || "#"})`;
|
|
75
|
-
case BLOCKS.EMBEDDED_ASSET: {
|
|
76
|
-
const title = node.data.target?.fields?.title || "Image";
|
|
77
|
-
const url = node.data.target?.fields?.file?.url;
|
|
78
|
-
return url ? `
|
|
79
|
-
|
|
80
|
-
` : "";
|
|
81
|
-
}
|
|
82
|
-
case BLOCKS.EMBEDDED_ENTRY:
|
|
83
|
-
return `
|
|
84
|
-
|
|
85
|
-
[Embedded Entry: ${node.data.target?.sys?.id}]
|
|
86
|
-
|
|
87
|
-
`;
|
|
88
|
-
default:
|
|
89
|
-
return content;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function convertText(node) {
|
|
93
|
-
let value = node.value;
|
|
94
|
-
if (node.marks) {
|
|
95
|
-
node.marks.forEach((mark) => {
|
|
96
|
-
switch (mark.type) {
|
|
97
|
-
case MARKS.BOLD:
|
|
98
|
-
value = `**${value}**`;
|
|
99
|
-
break;
|
|
100
|
-
case MARKS.ITALIC:
|
|
101
|
-
value = `*${value}*`;
|
|
102
|
-
break;
|
|
103
|
-
case MARKS.CODE:
|
|
104
|
-
value = `\`${value}\``;
|
|
105
|
-
break;
|
|
106
|
-
case MARKS.UNDERLINE:
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
return value;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// src/MarkdownConverter.ts
|
|
115
|
-
var MarkdownConverter = class {
|
|
116
|
-
async convert(contentData, context) {
|
|
117
|
-
const { data, contentType } = contentData;
|
|
118
|
-
const frontmatter = this.generateFrontmatter(data, contentType);
|
|
119
|
-
let markdown = `---
|
|
120
|
-
${yaml.dump(frontmatter)}---
|
|
121
|
-
|
|
122
|
-
`;
|
|
123
|
-
if (data.title) {
|
|
124
|
-
markdown += `# ${data.title}
|
|
125
|
-
|
|
126
|
-
`;
|
|
127
|
-
}
|
|
128
|
-
if (data.description) {
|
|
129
|
-
markdown += `> ${data.description}
|
|
130
|
-
|
|
131
|
-
`;
|
|
132
|
-
}
|
|
133
|
-
if (data.contents) {
|
|
134
|
-
for (const item of data.contents) {
|
|
135
|
-
if (!item) continue;
|
|
136
|
-
markdown += await this.convertModule(item, context);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return markdown;
|
|
140
|
-
}
|
|
141
|
-
generateFrontmatter(data, type) {
|
|
142
|
-
const slug = data.slug;
|
|
143
|
-
return {
|
|
144
|
-
contentType: type,
|
|
145
|
-
title: data.title,
|
|
146
|
-
slug,
|
|
147
|
-
id: data.id,
|
|
148
|
-
description: data.description,
|
|
149
|
-
// Add more specific fields for Article if needed (date, author, etc)
|
|
150
|
-
...type === "article" ? {
|
|
151
|
-
date: data.date,
|
|
152
|
-
articleType: data.articleType?.name
|
|
153
|
-
} : {}
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
async convertModule(item, context) {
|
|
157
|
-
if (item.type === "Component") {
|
|
158
|
-
const component = item;
|
|
159
|
-
return this.convertGenericComponent(component, context);
|
|
160
|
-
}
|
|
161
|
-
if (item.type === "Collection") {
|
|
162
|
-
const collection = item;
|
|
163
|
-
return this.convertGenericCollection(collection, context);
|
|
164
|
-
}
|
|
165
|
-
return "";
|
|
166
|
-
}
|
|
167
|
-
convertGenericComponent(component, context) {
|
|
168
|
-
let md = "";
|
|
169
|
-
if (component.heading) {
|
|
170
|
-
md += `## ${component.heading}
|
|
171
|
-
|
|
172
|
-
`;
|
|
173
|
-
} else if (component.componentType) {
|
|
174
|
-
md += `## ${component.componentType}
|
|
175
|
-
|
|
176
|
-
`;
|
|
177
|
-
}
|
|
178
|
-
md += this.renderPreHeading(component.preHeading);
|
|
179
|
-
md += this.renderPostHeading(component.postHeading);
|
|
180
|
-
md += this.renderBody(component.body, context);
|
|
181
|
-
md += this.renderAdditionalCopy(component.additionalCopy, context);
|
|
182
|
-
md += this.renderVisual(component.visual);
|
|
183
|
-
md += this.renderLinks(component.links);
|
|
184
|
-
return md;
|
|
185
|
-
}
|
|
186
|
-
async convertGenericCollection(collection, context) {
|
|
187
|
-
let md = `## ${collection.heading || collection.collectionType || "Collection"}
|
|
188
|
-
|
|
189
|
-
`;
|
|
190
|
-
md += this.renderPreHeading(collection.preHeading);
|
|
191
|
-
md += this.renderPostHeading(collection.postHeading);
|
|
192
|
-
md += this.renderBody(collection.body, context);
|
|
193
|
-
md += this.renderLinks(collection.links);
|
|
194
|
-
if (collection.contents) {
|
|
195
|
-
for (const item of collection.contents) {
|
|
196
|
-
if (!item) continue;
|
|
197
|
-
md += await this.convertModule(item, context);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
md += this.renderAdditionalCopy(collection.additionalCopy, context);
|
|
201
|
-
md += this.renderVisual(collection.visual);
|
|
202
|
-
return md;
|
|
203
|
-
}
|
|
204
|
-
renderPreHeading(preHeading) {
|
|
205
|
-
return preHeading ? `**${preHeading}**
|
|
206
|
-
|
|
207
|
-
` : "";
|
|
208
|
-
}
|
|
209
|
-
renderPostHeading(postHeading) {
|
|
210
|
-
return postHeading ? `*${postHeading}*
|
|
211
|
-
|
|
212
|
-
` : "";
|
|
213
|
-
}
|
|
214
|
-
// biome-ignore lint/suspicious/noExplicitAny: generic content body
|
|
215
|
-
renderBody(body, context) {
|
|
216
|
-
return body ? convertRichTextToMarkdown(body, context) : "";
|
|
217
|
-
}
|
|
218
|
-
// biome-ignore lint/suspicious/noExplicitAny: generic additional copy
|
|
219
|
-
renderAdditionalCopy(additionalCopy, context) {
|
|
220
|
-
return additionalCopy ? `
|
|
221
|
-
|
|
222
|
-
${convertRichTextToMarkdown(additionalCopy, context)}` : "";
|
|
223
|
-
}
|
|
224
|
-
renderVisual(visual) {
|
|
225
|
-
const image = visual?.visual?.image;
|
|
226
|
-
if (!image) return "";
|
|
227
|
-
const title = image.name || "Image";
|
|
228
|
-
const url = image.src || image.svgSrc;
|
|
229
|
-
return url ? `
|
|
230
|
-
|
|
231
|
-
` : "";
|
|
232
|
-
}
|
|
233
|
-
renderLinks(links) {
|
|
234
|
-
if (!links?.length) return "";
|
|
235
|
-
let md = "\n";
|
|
236
|
-
for (const link of links) {
|
|
237
|
-
md += `- [${link.text || link.name}](${link.href || "#"})
|
|
238
|
-
`;
|
|
239
|
-
}
|
|
240
|
-
return `${md}
|
|
241
|
-
`;
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
// src/MarkdownExporter.ts
|
|
246
|
-
import {
|
|
247
|
-
contentfulArticleRest,
|
|
248
|
-
contentfulCustomTypeRest,
|
|
249
|
-
contentfulPageRest,
|
|
250
|
-
createBaseConverterContext
|
|
251
|
-
} from "@se-studio/contentful-rest-api";
|
|
252
|
-
var MarkdownExporter = class {
|
|
253
|
-
config;
|
|
254
|
-
preview;
|
|
255
|
-
constructor(config, preview = false) {
|
|
256
|
-
this.config = config;
|
|
257
|
-
this.preview = preview;
|
|
258
|
-
}
|
|
259
|
-
async fetchContent(type, slug, params) {
|
|
260
|
-
const context = this.createContext();
|
|
261
|
-
if (type === "page") {
|
|
262
|
-
const response = await contentfulPageRest(context, this.config, slug, {
|
|
263
|
-
preview: this.preview
|
|
264
|
-
});
|
|
265
|
-
if (!response.data) return null;
|
|
266
|
-
const page = response.data;
|
|
267
|
-
return {
|
|
268
|
-
contentType: "page",
|
|
269
|
-
data: page,
|
|
270
|
-
context: {
|
|
271
|
-
pageContext: {
|
|
272
|
-
page
|
|
273
|
-
},
|
|
274
|
-
current: { type: "Page", id: page.id }
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
if (type === "article" || type === "blogPost") {
|
|
279
|
-
const articleType = params?.articleType || "blog";
|
|
280
|
-
const response = await contentfulArticleRest(context, this.config, slug, articleType, {
|
|
281
|
-
preview: this.preview
|
|
282
|
-
});
|
|
283
|
-
if (!response.data) return null;
|
|
284
|
-
const article = response.data;
|
|
285
|
-
return {
|
|
286
|
-
contentType: "article",
|
|
287
|
-
data: article,
|
|
288
|
-
context: {
|
|
289
|
-
pageContext: {
|
|
290
|
-
article,
|
|
291
|
-
articleType: article.articleType
|
|
292
|
-
},
|
|
293
|
-
current: { type: "Article", id: article.id }
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
if (type === "customType") {
|
|
298
|
-
const response = await contentfulCustomTypeRest(context, this.config, slug, {
|
|
299
|
-
preview: this.preview
|
|
300
|
-
});
|
|
301
|
-
if (!response.data) return null;
|
|
302
|
-
const customType = response.data;
|
|
303
|
-
return {
|
|
304
|
-
contentType: "customType",
|
|
305
|
-
data: customType,
|
|
306
|
-
context: {
|
|
307
|
-
pageContext: {
|
|
308
|
-
customType
|
|
309
|
-
},
|
|
310
|
-
current: { type: "CustomType", id: customType.id }
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
return null;
|
|
315
|
-
}
|
|
316
|
-
createContext() {
|
|
317
|
-
const urlCalculators = {
|
|
318
|
-
page: (slug) => `/${slug}`,
|
|
319
|
-
pageVariant: (slug) => `/${slug}`,
|
|
320
|
-
article: (type, slug) => `/${type}/${slug}`,
|
|
321
|
-
articleType: (slug) => `/${slug}`,
|
|
322
|
-
tag: (slug) => `/topics/${slug}`,
|
|
323
|
-
person: (slug) => `/team/${slug}`,
|
|
324
|
-
customType: (slug) => `/${slug}`
|
|
325
|
-
};
|
|
326
|
-
return createBaseConverterContext(urlCalculators);
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
export {
|
|
330
|
-
MarkdownConverter,
|
|
331
|
-
MarkdownExporter
|
|
332
|
-
};
|
|
1
|
+
export * from './MarkdownConverter';
|
|
2
|
+
export * from './MarkdownExporter';
|
|
3
|
+
export * from './types';
|
|
333
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/MarkdownConverter.ts","../src/utils/richTextConverter.ts","../src/MarkdownExporter.ts"],"sourcesContent":["import type { IContentfulCollection, IContentfulComponent } from '@se-studio/contentful-rest-api';\nimport type {\n IBaseArticle,\n IBaseCustomType,\n IBasePage,\n IPicture,\n IResponsiveVisual,\n ISvgImage,\n ITyped,\n} from '@se-studio/core-data-types';\nimport yaml from 'js-yaml';\nimport type { ContentData, MarkdownConverterContext } from './types';\nimport { convertRichTextToMarkdown } from './utils/richTextConverter';\n\nexport class MarkdownConverter {\n async convert(contentData: ContentData, context: MarkdownConverterContext): Promise<string> {\n const { data, contentType } = contentData;\n const frontmatter = this.generateFrontmatter(data, contentType);\n\n let markdown = `---\\n${yaml.dump(frontmatter)}---\\n\\n`;\n\n // Add Title and basic body\n if (data.title) {\n markdown += `# ${data.title}\\n\\n`;\n }\n\n if (data.description) {\n markdown += `> ${data.description}\\n\\n`;\n }\n\n // Page modules / contents\n if (data.contents) {\n for (const item of data.contents) {\n if (!item) continue;\n markdown += await this.convertModule(item, context);\n }\n }\n\n return markdown;\n }\n\n private generateFrontmatter(data: IBasePage | IBaseArticle | IBaseCustomType, type: string) {\n const slug = data.slug;\n return {\n contentType: type,\n title: data.title,\n slug: slug,\n id: data.id,\n description: data.description,\n // Add more specific fields for Article if needed (date, author, etc)\n ...(type === 'article'\n ? {\n date: (data as IBaseArticle).date,\n articleType: (data as IBaseArticle).articleType?.name,\n }\n : {}),\n };\n }\n\n private async convertModule(item: ITyped, context: MarkdownConverterContext): Promise<string> {\n if (item.type === 'Component') {\n const component = item as IContentfulComponent & { componentType: string };\n // Use generic fallback for all components\n return this.convertGenericComponent(component, context);\n }\n\n if (item.type === 'Collection') {\n const collection = item as IContentfulCollection & { collectionType: string };\n // Use generic fallback for all collections\n return this.convertGenericCollection(collection, context);\n }\n\n return '';\n }\n\n private convertGenericComponent(\n component: IContentfulComponent & { componentType: string },\n context: MarkdownConverterContext,\n ): string {\n let md = '';\n\n // Add heading hierarchy\n if (component.heading) {\n md += `## ${component.heading}\\n\\n`;\n } else if (component.componentType) {\n // Fallback to component type if no heading, but NOT cmsLabel\n md += `## ${component.componentType}\\n\\n`;\n }\n\n md += this.renderPreHeading(component.preHeading);\n md += this.renderPostHeading(component.postHeading);\n md += this.renderBody(component.body, context);\n md += this.renderAdditionalCopy(component.additionalCopy, context);\n md += this.renderVisual(component.visual);\n md += this.renderLinks(component.links);\n\n return md;\n }\n\n private async convertGenericCollection(\n collection: IContentfulCollection & { collectionType: string },\n context: MarkdownConverterContext,\n ): Promise<string> {\n let md = `## ${collection.heading || collection.collectionType || 'Collection'}\\n\\n`;\n\n md += this.renderPreHeading(collection.preHeading);\n md += this.renderPostHeading(collection.postHeading);\n md += this.renderBody(collection.body, context);\n md += this.renderLinks(collection.links);\n\n if (collection.contents) {\n for (const item of collection.contents) {\n if (!item) continue;\n md += await this.convertModule(item, context);\n }\n }\n\n md += this.renderAdditionalCopy(collection.additionalCopy, context);\n md += this.renderVisual(collection.visual);\n\n return md;\n }\n\n private renderPreHeading(preHeading: string | null | undefined): string {\n return preHeading ? `**${preHeading}**\\n\\n` : '';\n }\n\n private renderPostHeading(postHeading: string | null | undefined): string {\n return postHeading ? `*${postHeading}*\\n\\n` : '';\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: generic content body\n private renderBody(body: any, context: MarkdownConverterContext): string {\n return body ? convertRichTextToMarkdown(body, context) : '';\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: generic additional copy\n private renderAdditionalCopy(additionalCopy: any, context: MarkdownConverterContext): string {\n return additionalCopy ? `\\n\\n${convertRichTextToMarkdown(additionalCopy, context)}` : '';\n }\n\n private renderVisual(visual: IResponsiveVisual | undefined): string {\n const image = visual?.visual?.image;\n if (!image) return '';\n const title = image.name || 'Image';\n const url = (image as IPicture).src || (image as ISvgImage).svgSrc;\n return url ? `\\n\\n` : '';\n }\n\n private renderLinks(\n links:\n | readonly { text?: string | null; name?: string | null; href?: string | null }[]\n | undefined,\n ): string {\n if (!links?.length) return '';\n let md = '\\n';\n for (const link of links) {\n md += `- [${link.text || link.name}](${link.href || '#'}) \\n`;\n }\n return `${md}\\n`;\n }\n}\n","import {\n BLOCKS,\n type Block,\n type Document,\n INLINES,\n type Inline,\n MARKS,\n type Text,\n} from '@contentful/rich-text-types';\nimport type { MarkdownConverterContext } from '../types';\n\nexport function convertRichTextToMarkdown(\n richText: Document | { json: Document } | null | undefined,\n context: MarkdownConverterContext,\n): string {\n if (!richText) return '';\n\n // Handle IContentfulRichText wrapper\n const document = 'json' in richText ? richText.json : richText;\n if (!document) return '';\n\n return convertNode(document, context);\n}\n\nfunction convertNode(\n node: Block | Inline | Text | Document,\n context: MarkdownConverterContext,\n): string {\n if (node.nodeType === 'text') {\n return convertText(node as Text);\n }\n\n const content = ((node as Block | Inline | Document).content || [])\n .map((child) => convertNode(child, context))\n .join('');\n\n switch (node.nodeType) {\n case BLOCKS.DOCUMENT:\n return content;\n case BLOCKS.PARAGRAPH:\n return `${content}\\n\\n`;\n case BLOCKS.HEADING_1:\n return `# ${content}\\n\\n`;\n case BLOCKS.HEADING_2:\n return `## ${content}\\n\\n`;\n case BLOCKS.HEADING_3:\n return `### ${content}\\n\\n`;\n case BLOCKS.HEADING_4:\n return `#### ${content}\\n\\n`;\n case BLOCKS.HEADING_5:\n return `##### ${content}\\n\\n`;\n case BLOCKS.HEADING_6:\n return `###### ${content}\\n\\n`;\n case BLOCKS.UL_LIST:\n return `${content}\\n`;\n case BLOCKS.OL_LIST:\n return `${content}\\n`;\n case BLOCKS.LIST_ITEM:\n // This is a simplification. Proper nested list handling requires tracking depth.\n // For now, assuming direct child of list.\n // The parent UL/OL doesn't output anything, just its children.\n // But we need to know if it's UL or OL to prefix with - or 1.\n // Since we don't have parent context here easily without passing state,\n // we might need to adjust the structure or accept standard bullet for now.\n return `- ${content.trim()}\\n`;\n case BLOCKS.QUOTE:\n return `> ${content.replace(/\\n/g, '\\n> ')}\\n\\n`;\n case BLOCKS.HR:\n return `---\\n\\n`;\n case INLINES.HYPERLINK:\n return `[${content}](${node.data.uri})`;\n case INLINES.ENTRY_HYPERLINK:\n // TODO: Resolve entry link using context if possible\n // For now, falling back to a placeholder or just the content\n return `[${content}](#${node.data.target?.sys?.id || 'entry-link'})`;\n case INLINES.ASSET_HYPERLINK:\n return `[${content}](${node.data.target?.fields?.file?.url || '#'})`;\n case BLOCKS.EMBEDDED_ASSET: {\n const title = node.data.target?.fields?.title || 'Image';\n const url = node.data.target?.fields?.file?.url;\n return url ? `\\n\\n` : '';\n }\n case BLOCKS.EMBEDDED_ENTRY:\n return `\\n\\n[Embedded Entry: ${node.data.target?.sys?.id}]\\n\\n`;\n default:\n return content;\n }\n}\n\nfunction convertText(node: Text): string {\n let value = node.value;\n\n if (node.marks) {\n node.marks.forEach((mark) => {\n switch (mark.type) {\n case MARKS.BOLD:\n value = `**${value}**`;\n break;\n case MARKS.ITALIC:\n value = `*${value}*`;\n break;\n case MARKS.CODE:\n value = `\\`${value}\\``;\n break;\n case MARKS.UNDERLINE:\n // Markdown doesn't support underline natively, usually ignored or HTML\n break;\n }\n });\n }\n return value;\n}\n","import {\n type ContentfulConfig,\n contentfulArticleRest,\n contentfulCustomTypeRest,\n contentfulPageRest,\n createBaseConverterContext,\n type UrlCalculators,\n} from '@se-studio/contentful-rest-api';\nimport type { IContentContext } from '@se-studio/core-data-types';\nimport type { ContentData } from './types';\n\nexport class MarkdownExporter {\n private config: ContentfulConfig;\n private preview: boolean;\n\n constructor(config: ContentfulConfig, preview = false) {\n this.config = config;\n this.preview = preview;\n }\n\n async fetchContent(\n type: 'page' | 'article' | 'blogPost' | 'customType',\n slug: string,\n params?: { articleType?: string },\n ): Promise<ContentData | null> {\n const context = this.createContext();\n\n if (type === 'page') {\n const response = await contentfulPageRest(context, this.config, slug, {\n preview: this.preview,\n });\n\n if (!response.data) return null;\n\n const page = response.data;\n return {\n contentType: 'page',\n data: page,\n context: {\n pageContext: {\n page,\n },\n current: { type: 'Page', id: page.id },\n } as IContentContext,\n };\n }\n\n if (type === 'article' || type === 'blogPost') {\n const articleType = params?.articleType || 'blog';\n const response = await contentfulArticleRest(context, this.config, slug, articleType, {\n preview: this.preview,\n });\n\n if (!response.data) return null;\n\n const article = response.data;\n return {\n contentType: 'article',\n data: article,\n context: {\n pageContext: {\n article,\n articleType: article.articleType,\n },\n current: { type: 'Article', id: article.id },\n } as IContentContext,\n };\n }\n\n if (type === 'customType') {\n const response = await contentfulCustomTypeRest(context, this.config, slug, {\n preview: this.preview,\n });\n\n if (!response.data) return null;\n\n const customType = response.data;\n return {\n contentType: 'customType',\n data: customType,\n context: {\n pageContext: {\n customType,\n },\n current: { type: 'CustomType', id: customType.id },\n } as IContentContext,\n };\n }\n\n return null;\n }\n\n private createContext() {\n // Basic context for fetching - we might need to make this configurable if URL calculation differs per app\n // For now using simple defaults that produce relative paths\n const urlCalculators: UrlCalculators = {\n page: (slug) => `/${slug}`,\n pageVariant: (slug) => `/${slug}`,\n article: (type, slug) => `/${type}/${slug}`,\n articleType: (slug) => `/${slug}`,\n tag: (slug) => `/topics/${slug}`,\n person: (slug) => `/team/${slug}`,\n customType: (slug) => `/${slug}`,\n };\n\n return createBaseConverterContext(urlCalculators);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,SAAS,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ContentfulConfig } from '@se-studio/contentful-rest-api';
|
|
2
|
+
import type { IBaseArticle, IBaseCustomType, IBasePage, IContentContext } from '@se-studio/core-data-types';
|
|
3
|
+
export interface ContentData {
|
|
4
|
+
contentType: 'page' | 'article' | 'customType';
|
|
5
|
+
data: IBasePage | IBaseArticle | IBaseCustomType;
|
|
6
|
+
context: IContentContext;
|
|
7
|
+
}
|
|
8
|
+
export interface MarkdownConverterContext {
|
|
9
|
+
contentContext: IContentContext;
|
|
10
|
+
config: ContentfulConfig;
|
|
11
|
+
}
|
|
12
|
+
export interface ConverterResult {
|
|
13
|
+
markdown: string;
|
|
14
|
+
}
|
|
15
|
+
export type ConverterFunction<T = any> = (data: T, context: MarkdownConverterContext) => Promise<string> | string;
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,SAAS,EACT,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;IAC/C,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,eAAe,CAAC;IACjD,OAAO,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,eAAe,CAAC;IAChC,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,GAAG,GAAG,IAAI,CACvC,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type Document } from '@contentful/rich-text-types';
|
|
2
|
+
import type { MarkdownConverterContext } from '../types';
|
|
3
|
+
export declare function convertRichTextToMarkdown(richText: Document | {
|
|
4
|
+
json: Document;
|
|
5
|
+
} | null | undefined, context: MarkdownConverterContext): string;
|
|
6
|
+
//# sourceMappingURL=richTextConverter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"richTextConverter.d.ts","sourceRoot":"","sources":["../../src/utils/richTextConverter.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EAKd,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEzD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,QAAQ,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EAC1D,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAQR"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { BLOCKS, INLINES, MARKS, } from '@contentful/rich-text-types';
|
|
2
|
+
export function convertRichTextToMarkdown(richText, context) {
|
|
3
|
+
if (!richText)
|
|
4
|
+
return '';
|
|
5
|
+
// Handle IContentfulRichText wrapper
|
|
6
|
+
const document = 'json' in richText ? richText.json : richText;
|
|
7
|
+
if (!document)
|
|
8
|
+
return '';
|
|
9
|
+
return convertNode(document, context);
|
|
10
|
+
}
|
|
11
|
+
function convertNode(node, context) {
|
|
12
|
+
if (node.nodeType === 'text') {
|
|
13
|
+
return convertText(node);
|
|
14
|
+
}
|
|
15
|
+
const content = (node.content || [])
|
|
16
|
+
.map((child) => convertNode(child, context))
|
|
17
|
+
.join('');
|
|
18
|
+
switch (node.nodeType) {
|
|
19
|
+
case BLOCKS.DOCUMENT:
|
|
20
|
+
return content;
|
|
21
|
+
case BLOCKS.PARAGRAPH:
|
|
22
|
+
return `${content}\n\n`;
|
|
23
|
+
case BLOCKS.HEADING_1:
|
|
24
|
+
return `# ${content}\n\n`;
|
|
25
|
+
case BLOCKS.HEADING_2:
|
|
26
|
+
return `## ${content}\n\n`;
|
|
27
|
+
case BLOCKS.HEADING_3:
|
|
28
|
+
return `### ${content}\n\n`;
|
|
29
|
+
case BLOCKS.HEADING_4:
|
|
30
|
+
return `#### ${content}\n\n`;
|
|
31
|
+
case BLOCKS.HEADING_5:
|
|
32
|
+
return `##### ${content}\n\n`;
|
|
33
|
+
case BLOCKS.HEADING_6:
|
|
34
|
+
return `###### ${content}\n\n`;
|
|
35
|
+
case BLOCKS.UL_LIST:
|
|
36
|
+
return `${content}\n`;
|
|
37
|
+
case BLOCKS.OL_LIST:
|
|
38
|
+
return `${content}\n`;
|
|
39
|
+
case BLOCKS.LIST_ITEM:
|
|
40
|
+
// This is a simplification. Proper nested list handling requires tracking depth.
|
|
41
|
+
// For now, assuming direct child of list.
|
|
42
|
+
// The parent UL/OL doesn't output anything, just its children.
|
|
43
|
+
// But we need to know if it's UL or OL to prefix with - or 1.
|
|
44
|
+
// Since we don't have parent context here easily without passing state,
|
|
45
|
+
// we might need to adjust the structure or accept standard bullet for now.
|
|
46
|
+
return `- ${content.trim()}\n`;
|
|
47
|
+
case BLOCKS.QUOTE:
|
|
48
|
+
return `> ${content.replace(/\n/g, '\n> ')}\n\n`;
|
|
49
|
+
case BLOCKS.HR:
|
|
50
|
+
return `---\n\n`;
|
|
51
|
+
case INLINES.HYPERLINK:
|
|
52
|
+
return `[${content}](${node.data.uri})`;
|
|
53
|
+
case INLINES.ENTRY_HYPERLINK:
|
|
54
|
+
// TODO: Resolve entry link using context if possible
|
|
55
|
+
// For now, falling back to a placeholder or just the content
|
|
56
|
+
return `[${content}](#${node.data.target?.sys?.id || 'entry-link'})`;
|
|
57
|
+
case INLINES.ASSET_HYPERLINK:
|
|
58
|
+
return `[${content}](${node.data.target?.fields?.file?.url || '#'})`;
|
|
59
|
+
case BLOCKS.EMBEDDED_ASSET: {
|
|
60
|
+
const title = node.data.target?.fields?.title || 'Image';
|
|
61
|
+
const url = node.data.target?.fields?.file?.url;
|
|
62
|
+
return url ? `\n\n` : '';
|
|
63
|
+
}
|
|
64
|
+
case BLOCKS.EMBEDDED_ENTRY:
|
|
65
|
+
return `\n\n[Embedded Entry: ${node.data.target?.sys?.id}]\n\n`;
|
|
66
|
+
default:
|
|
67
|
+
return content;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function convertText(node) {
|
|
71
|
+
let value = node.value;
|
|
72
|
+
if (node.marks) {
|
|
73
|
+
node.marks.forEach((mark) => {
|
|
74
|
+
switch (mark.type) {
|
|
75
|
+
case MARKS.BOLD:
|
|
76
|
+
value = `**${value}**`;
|
|
77
|
+
break;
|
|
78
|
+
case MARKS.ITALIC:
|
|
79
|
+
value = `*${value}*`;
|
|
80
|
+
break;
|
|
81
|
+
case MARKS.CODE:
|
|
82
|
+
value = `\`${value}\``;
|
|
83
|
+
break;
|
|
84
|
+
case MARKS.UNDERLINE:
|
|
85
|
+
// Markdown doesn't support underline natively, usually ignored or HTML
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=richTextConverter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"richTextConverter.js","sourceRoot":"","sources":["../../src/utils/richTextConverter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@se-studio/markdown-renderer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Markdown renderer for Contentful content",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,24 +18,25 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
|
-
"dist"
|
|
21
|
+
"dist",
|
|
22
|
+
"*.md"
|
|
22
23
|
],
|
|
23
24
|
"dependencies": {
|
|
24
25
|
"@contentful/rich-text-types": "^17.2.5",
|
|
25
26
|
"js-yaml": "^4.1.1",
|
|
26
|
-
"@se-studio/contentful-rest-api": "1.0.
|
|
27
|
-
"@se-studio/core-data-types": "1.0.
|
|
27
|
+
"@se-studio/contentful-rest-api": "1.0.47",
|
|
28
|
+
"@se-studio/core-data-types": "1.0.47"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@biomejs/biome": "^2.3.10",
|
|
31
32
|
"@types/js-yaml": "^4.0.9",
|
|
32
|
-
"@types/node": "^
|
|
33
|
+
"@types/node": "^22.19.3",
|
|
33
34
|
"tsup": "^8.5.1",
|
|
34
35
|
"typescript": "^5.9.3"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
|
-
"build": "
|
|
38
|
-
"dev": "
|
|
38
|
+
"build": "tsc --project tsconfig.build.json",
|
|
39
|
+
"dev": "tsc --project tsconfig.build.json --watch",
|
|
39
40
|
"type-check": "tsc --noEmit",
|
|
40
41
|
"lint": "biome lint .",
|
|
41
42
|
"clean": "rm -rf dist .turbo *.tsbuildinfo"
|