@uniweb/content-reader 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/package.json +2 -1
- package/src/parser/block.js +60 -12
- package/tests/code.test.js +5 -14
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ Full support for aligned columns:
|
|
|
139
139
|
## Installation
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
|
-
npm install @
|
|
142
|
+
npm install @uniweb/content-reader
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
## Usage
|
|
@@ -147,7 +147,7 @@ npm install @uniwebcms/content-reader
|
|
|
147
147
|
Basic usage:
|
|
148
148
|
|
|
149
149
|
```javascript
|
|
150
|
-
const { markdownToProseMirror } = require("@
|
|
150
|
+
const { markdownToProseMirror } = require("@uniweb/content-reader");
|
|
151
151
|
|
|
152
152
|
const markdown = `
|
|
153
153
|
# Hello World
|
|
@@ -168,7 +168,7 @@ The library is designed to work seamlessly with TipTap editors:
|
|
|
168
168
|
|
|
169
169
|
```javascript
|
|
170
170
|
import { Editor } from "@tiptap/core";
|
|
171
|
-
import { markdownToProseMirror } from "@
|
|
171
|
+
import { markdownToProseMirror } from "@uniweb/content-reader";
|
|
172
172
|
|
|
173
173
|
const editor = new Editor({
|
|
174
174
|
content: markdownToProseMirror(markdown),
|
|
@@ -243,7 +243,7 @@ We welcome contributions! Please see our contributing guidelines for details.
|
|
|
243
243
|
1. Clone the repository:
|
|
244
244
|
|
|
245
245
|
```bash
|
|
246
|
-
git clone https://github.com/
|
|
246
|
+
git clone https://github.com/uniweb/content-reader.git
|
|
247
247
|
```
|
|
248
248
|
|
|
249
249
|
2. Install dependencies:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/content-reader",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Markdown to ProseMirror document structure converter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"author": "Proximify Inc.",
|
|
17
17
|
"license": "GPL-3.0-or-later",
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"js-yaml": "^4.1.0",
|
|
19
20
|
"marked": "^11.1.0"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
package/src/parser/block.js
CHANGED
|
@@ -3,22 +3,23 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { marked } from "marked";
|
|
6
|
+
import yaml from "js-yaml";
|
|
6
7
|
import { parseInline } from "./inline.js";
|
|
7
8
|
import { parseList } from "./lists.js";
|
|
8
9
|
import { parseTable } from "./tables.js";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* Process code block info string (e.g., "
|
|
12
|
+
* Process code block info string (e.g., "json:tag-name")
|
|
12
13
|
* @param {string} info - Code block info string
|
|
13
|
-
* @returns {Object} Language and
|
|
14
|
+
* @returns {Object} Language and optional tag
|
|
14
15
|
*/
|
|
15
16
|
function processCodeInfo(info) {
|
|
16
|
-
if (!info) return { language: null,
|
|
17
|
+
if (!info) return { language: null, tag: null };
|
|
17
18
|
|
|
18
19
|
const parts = info.split(":");
|
|
19
20
|
return {
|
|
20
21
|
language: parts[0] || null,
|
|
21
|
-
|
|
22
|
+
tag: parts[1] || null,
|
|
22
23
|
};
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -39,6 +40,37 @@ function cleanCodeText(text) {
|
|
|
39
40
|
.trim();
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Parse code block content based on language
|
|
45
|
+
* Only parses tagged blocks with json/yaml language
|
|
46
|
+
* @param {string} text - Raw code block text
|
|
47
|
+
* @param {string} language - Code block language
|
|
48
|
+
* @returns {*} Parsed data or null if not parseable
|
|
49
|
+
*/
|
|
50
|
+
function parseCodeBlockData(text, language) {
|
|
51
|
+
if (!text) return null;
|
|
52
|
+
|
|
53
|
+
const lang = (language || "").toLowerCase();
|
|
54
|
+
|
|
55
|
+
if (lang === "json") {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(text);
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (lang === "yaml" || lang === "yml") {
|
|
64
|
+
try {
|
|
65
|
+
return yaml.load(text);
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
42
74
|
/**
|
|
43
75
|
* Parse a paragraph's content by tokenizing with marked
|
|
44
76
|
* @param {Object} token - Marked token for paragraph
|
|
@@ -142,16 +174,32 @@ function parseBlock(token, schema) {
|
|
|
142
174
|
}
|
|
143
175
|
|
|
144
176
|
if (token.type === "code") {
|
|
145
|
-
const { language,
|
|
177
|
+
const { language, tag } = processCodeInfo(token.lang);
|
|
178
|
+
const rawText = cleanCodeText(token.text);
|
|
179
|
+
|
|
180
|
+
// Tagged blocks become dataBlocks (structured data, not code for display)
|
|
181
|
+
if (tag) {
|
|
182
|
+
const parsedData = parseCodeBlockData(rawText, language);
|
|
183
|
+
if (parsedData !== null) {
|
|
184
|
+
// Successfully parsed - it's a dataBlock
|
|
185
|
+
return {
|
|
186
|
+
type: "dataBlock",
|
|
187
|
+
attrs: { tag, data: parsedData },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// Parsing failed - fall back to codeBlock with language for runtime fallback
|
|
191
|
+
return {
|
|
192
|
+
type: "codeBlock",
|
|
193
|
+
attrs: { language, tag },
|
|
194
|
+
content: [{ type: "text", text: rawText }],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Untagged code block - for display with syntax highlighting
|
|
146
199
|
return {
|
|
147
200
|
type: "codeBlock",
|
|
148
|
-
attrs: { language
|
|
149
|
-
content: [
|
|
150
|
-
{
|
|
151
|
-
type: "text",
|
|
152
|
-
text: cleanCodeText(token.text),
|
|
153
|
-
},
|
|
154
|
-
],
|
|
201
|
+
attrs: { language },
|
|
202
|
+
content: [{ type: "text", text: rawText }],
|
|
155
203
|
};
|
|
156
204
|
}
|
|
157
205
|
|
package/tests/code.test.js
CHANGED
|
@@ -12,7 +12,6 @@ describe("Code Parsing", () => {
|
|
|
12
12
|
type: "codeBlock",
|
|
13
13
|
attrs: {
|
|
14
14
|
language: "javascript",
|
|
15
|
-
filename: null,
|
|
16
15
|
},
|
|
17
16
|
content: [
|
|
18
17
|
{
|
|
@@ -25,25 +24,19 @@ describe("Code Parsing", () => {
|
|
|
25
24
|
});
|
|
26
25
|
});
|
|
27
26
|
|
|
28
|
-
test("parses code blocks
|
|
29
|
-
const markdown = "```
|
|
27
|
+
test("parses tagged code blocks as dataBlocks", () => {
|
|
28
|
+
const markdown = "```json:nav-links\n[{\"label\": \"Home\"}]\n```";
|
|
30
29
|
const result = markdownToProseMirror(markdown);
|
|
31
30
|
|
|
32
31
|
expect(result).toEqual({
|
|
33
32
|
type: "doc",
|
|
34
33
|
content: [
|
|
35
34
|
{
|
|
36
|
-
type: "
|
|
35
|
+
type: "dataBlock", // Structured data, not code for display
|
|
37
36
|
attrs: {
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
tag: "nav-links",
|
|
38
|
+
data: [{ label: "Home" }],
|
|
40
39
|
},
|
|
41
|
-
content: [
|
|
42
|
-
{
|
|
43
|
-
type: "text",
|
|
44
|
-
text: "const x = 1;",
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
40
|
},
|
|
48
41
|
],
|
|
49
42
|
});
|
|
@@ -60,7 +53,6 @@ describe("Code Parsing", () => {
|
|
|
60
53
|
type: "codeBlock",
|
|
61
54
|
attrs: {
|
|
62
55
|
language: null,
|
|
63
|
-
filename: null,
|
|
64
56
|
},
|
|
65
57
|
content: [
|
|
66
58
|
{
|
|
@@ -107,7 +99,6 @@ describe("Code Parsing", () => {
|
|
|
107
99
|
type: "codeBlock",
|
|
108
100
|
attrs: {
|
|
109
101
|
language: null,
|
|
110
|
-
filename: null,
|
|
111
102
|
},
|
|
112
103
|
content: [
|
|
113
104
|
{
|