testomatio-editor-blocks 0.4.60 → 0.4.61
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.
|
@@ -22,7 +22,7 @@ const headingPrefixes = {
|
|
|
22
22
|
5: "#####",
|
|
23
23
|
6: "######",
|
|
24
24
|
};
|
|
25
|
-
const SPECIAL_CHAR_REGEX = /([*_`~()
|
|
25
|
+
const SPECIAL_CHAR_REGEX = /([*_`~()\\])/g;
|
|
26
26
|
const HTML_COMMENT_REGEX = /<!--[\s\S]*?-->/g;
|
|
27
27
|
const HTML_SPAN_REGEX = /<\/?span[^>]*>/g;
|
|
28
28
|
const HTML_UNDERLINE_REGEX = /<\/?u>/g;
|
|
@@ -157,6 +157,7 @@ function applyTextStyles(text, styles) {
|
|
|
157
157
|
return wrapped.join("\n");
|
|
158
158
|
}
|
|
159
159
|
function inlineToMarkdown(content) {
|
|
160
|
+
var _a;
|
|
160
161
|
if (!content || !Array.isArray(content)) {
|
|
161
162
|
return "";
|
|
162
163
|
}
|
|
@@ -174,7 +175,9 @@ function inlineToMarkdown(content) {
|
|
|
174
175
|
i += 2;
|
|
175
176
|
continue;
|
|
176
177
|
}
|
|
177
|
-
|
|
178
|
+
const isCode = ((_a = item.styles) === null || _a === void 0 ? void 0 : _a.code) === true;
|
|
179
|
+
const rendered = isCode ? item.text : escapeMarkdown(item.text);
|
|
180
|
+
result.push(applyTextStyles(rendered, item.styles));
|
|
178
181
|
i += 1;
|
|
179
182
|
continue;
|
|
180
183
|
}
|
|
@@ -261,7 +264,7 @@ function serializeBlock(block, ctx, orderedIndex, stepIndex) {
|
|
|
261
264
|
case "codeBlock": {
|
|
262
265
|
const language = block.props.language || "";
|
|
263
266
|
const fence = "```" + language;
|
|
264
|
-
const body =
|
|
267
|
+
const body = inlineContentToPlainText(block.content);
|
|
265
268
|
lines.push(fence);
|
|
266
269
|
if (body.length > 0) {
|
|
267
270
|
lines.push(body);
|
package/package.json
CHANGED
|
@@ -62,7 +62,7 @@ describe("blocksToMarkdown", () => {
|
|
|
62
62
|
expect(blocksToMarkdown(blocks)).toBe("<!-- ai/agent generated description -->");
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
it("preserves HTML comments inline among text
|
|
65
|
+
it("preserves HTML comments inline among text without escaping stray angle brackets", () => {
|
|
66
66
|
const blocks: CustomEditorBlock[] = [
|
|
67
67
|
{
|
|
68
68
|
id: "c2",
|
|
@@ -75,7 +75,98 @@ describe("blocksToMarkdown", () => {
|
|
|
75
75
|
},
|
|
76
76
|
];
|
|
77
77
|
|
|
78
|
-
expect(blocksToMarkdown(blocks)).toBe("before <!-- note --> after
|
|
78
|
+
expect(blocksToMarkdown(blocks)).toBe("before <!-- note --> after <div>");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("does not escape `<` in plain text (e.g. comparison operators)", () => {
|
|
82
|
+
const blocks: CustomEditorBlock[] = [
|
|
83
|
+
{
|
|
84
|
+
id: "p_lt",
|
|
85
|
+
type: "paragraph",
|
|
86
|
+
props: baseProps,
|
|
87
|
+
content: [
|
|
88
|
+
{ type: "text", text: "< 768px is mobile", styles: {} },
|
|
89
|
+
],
|
|
90
|
+
children: [],
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
expect(blocksToMarkdown(blocks)).toBe("< 768px is mobile");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("does not escape `<` in table cells (viewport breakpoints case)", () => {
|
|
98
|
+
const markdown = [
|
|
99
|
+
"| Viewport Width | Layout Expected | Nav Behavior |",
|
|
100
|
+
"| --- | --- | --- |",
|
|
101
|
+
"| < 768px | Single column | Hamburger menu |",
|
|
102
|
+
"| 768px – 1024px | Two column | Collapsed sidebar |",
|
|
103
|
+
"| > 1024px | Full desktop layout | Full nav visible |",
|
|
104
|
+
].join("\n");
|
|
105
|
+
|
|
106
|
+
const blocks = markdownToBlocks(markdown);
|
|
107
|
+
const out = blocksToMarkdown(blocks as CustomEditorBlock[]);
|
|
108
|
+
expect(out).toBe(markdown);
|
|
109
|
+
expect(out).not.toContain("\\<");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("does not escape markdown chars inside inline code", () => {
|
|
113
|
+
const blocks: CustomEditorBlock[] = [
|
|
114
|
+
{
|
|
115
|
+
id: "p_code",
|
|
116
|
+
type: "paragraph",
|
|
117
|
+
props: baseProps,
|
|
118
|
+
content: [
|
|
119
|
+
{ type: "text", text: "**bold**", styles: { code: true } },
|
|
120
|
+
],
|
|
121
|
+
children: [],
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
expect(blocksToMarkdown(blocks)).toBe("`**bold**`");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("does not escape markdown chars inside inline code in a table (syntax/rendered case)", () => {
|
|
129
|
+
const markdown = [
|
|
130
|
+
"| Syntax | Rendered As |",
|
|
131
|
+
"| --- | --- |",
|
|
132
|
+
"| `**bold**` | **bold** |",
|
|
133
|
+
"| `*italic*` | _italic_ |",
|
|
134
|
+
"| `~~strike~~` | ~~strike~~ |",
|
|
135
|
+
].join("\n");
|
|
136
|
+
|
|
137
|
+
const blocks = markdownToBlocks(markdown);
|
|
138
|
+
const out = blocksToMarkdown(blocks as CustomEditorBlock[]);
|
|
139
|
+
expect(out).toBe(markdown);
|
|
140
|
+
expect(out).not.toMatch(/\\[*_~]/);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("does not escape markdown chars inside fenced code blocks", () => {
|
|
144
|
+
const markdown = [
|
|
145
|
+
"```",
|
|
146
|
+
"**bold** _italic_ ~~strike~~ <div>",
|
|
147
|
+
"```",
|
|
148
|
+
].join("\n");
|
|
149
|
+
|
|
150
|
+
const blocks = markdownToBlocks(markdown);
|
|
151
|
+
const out = blocksToMarkdown(blocks as CustomEditorBlock[]);
|
|
152
|
+
expect(out).toBe(markdown);
|
|
153
|
+
expect(out).not.toMatch(/\\[*_~<]/);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("still escapes literal backticks inside inline code", () => {
|
|
157
|
+
const blocks: CustomEditorBlock[] = [
|
|
158
|
+
{
|
|
159
|
+
id: "p_tick",
|
|
160
|
+
type: "paragraph",
|
|
161
|
+
props: baseProps,
|
|
162
|
+
content: [
|
|
163
|
+
{ type: "text", text: "a`b", styles: { code: true } },
|
|
164
|
+
],
|
|
165
|
+
children: [],
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
expect(blocksToMarkdown(blocks)).toBe("`a\\`b`");
|
|
79
170
|
});
|
|
80
171
|
|
|
81
172
|
it("places bold markers outside leading/trailing spaces", () => {
|
|
@@ -60,7 +60,7 @@ const headingPrefixes: Record<number, string> = {
|
|
|
60
60
|
6: "######",
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
const SPECIAL_CHAR_REGEX = /([*_`~()
|
|
63
|
+
const SPECIAL_CHAR_REGEX = /([*_`~()\\])/g;
|
|
64
64
|
const HTML_COMMENT_REGEX = /<!--[\s\S]*?-->/g;
|
|
65
65
|
const HTML_SPAN_REGEX = /<\/?span[^>]*>/g;
|
|
66
66
|
const HTML_UNDERLINE_REGEX = /<\/?u>/g;
|
|
@@ -234,7 +234,9 @@ function inlineToMarkdown(content: CustomEditorBlock["content"]): string {
|
|
|
234
234
|
i += 2;
|
|
235
235
|
continue;
|
|
236
236
|
}
|
|
237
|
-
|
|
237
|
+
const isCode = (item.styles as any)?.code === true;
|
|
238
|
+
const rendered = isCode ? item.text : escapeMarkdown(item.text);
|
|
239
|
+
result.push(applyTextStyles(rendered, item.styles));
|
|
238
240
|
i += 1;
|
|
239
241
|
continue;
|
|
240
242
|
}
|
|
@@ -334,7 +336,7 @@ function serializeBlock(
|
|
|
334
336
|
case "codeBlock": {
|
|
335
337
|
const language = (block.props as any).language || "";
|
|
336
338
|
const fence = "```" + language;
|
|
337
|
-
const body =
|
|
339
|
+
const body = inlineContentToPlainText(block.content);
|
|
338
340
|
lines.push(fence);
|
|
339
341
|
if (body.length > 0) {
|
|
340
342
|
lines.push(body);
|