testomatio-editor-blocks 0.4.62 → 0.4.64
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.
|
@@ -93,13 +93,8 @@ export function canInsertStepOrSnippet(editor, referenceBlockId) {
|
|
|
93
93
|
* Returns the inserted step's block ID (for focusing), or null.
|
|
94
94
|
*/
|
|
95
95
|
export function addStepsBlock(editor) {
|
|
96
|
-
var _a, _b, _c, _d;
|
|
96
|
+
var _a, _b, _c, _d, _e, _f;
|
|
97
97
|
const allBlocks = editor.document;
|
|
98
|
-
const emptyStep = {
|
|
99
|
-
type: "testStep",
|
|
100
|
-
props: { stepTitle: "", stepData: "", expectedResult: "" },
|
|
101
|
-
children: [],
|
|
102
|
-
};
|
|
103
98
|
let stepsHeadingIndex = -1;
|
|
104
99
|
for (let i = 0; i < allBlocks.length; i++) {
|
|
105
100
|
const b = allBlocks[i];
|
|
@@ -129,8 +124,17 @@ export function addStepsBlock(editor) {
|
|
|
129
124
|
continue;
|
|
130
125
|
break;
|
|
131
126
|
}
|
|
132
|
-
const
|
|
133
|
-
|
|
127
|
+
const previousStep = allBlocks[lastIndex];
|
|
128
|
+
const inheritedListStyle = (previousStep === null || previousStep === void 0 ? void 0 : previousStep.type) === "testStep"
|
|
129
|
+
? ((_b = (_a = previousStep.props) === null || _a === void 0 ? void 0 : _a.listStyle) !== null && _b !== void 0 ? _b : "bullet")
|
|
130
|
+
: "bullet";
|
|
131
|
+
const emptyStep = {
|
|
132
|
+
type: "testStep",
|
|
133
|
+
props: { stepTitle: "", stepData: "", expectedResult: "", listStyle: inheritedListStyle },
|
|
134
|
+
children: [],
|
|
135
|
+
};
|
|
136
|
+
const inserted = editor.insertBlocks([emptyStep], previousStep.id, "after");
|
|
137
|
+
return (_d = (_c = inserted === null || inserted === void 0 ? void 0 : inserted[0]) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : null;
|
|
134
138
|
}
|
|
135
139
|
const lastBlock = allBlocks[allBlocks.length - 1];
|
|
136
140
|
const stepsHeading = {
|
|
@@ -139,8 +143,13 @@ export function addStepsBlock(editor) {
|
|
|
139
143
|
content: [{ type: "text", text: "Steps" }],
|
|
140
144
|
children: [],
|
|
141
145
|
};
|
|
146
|
+
const emptyStep = {
|
|
147
|
+
type: "testStep",
|
|
148
|
+
props: { stepTitle: "", stepData: "", expectedResult: "" },
|
|
149
|
+
children: [],
|
|
150
|
+
};
|
|
142
151
|
const inserted = editor.insertBlocks([stepsHeading, emptyStep], lastBlock.id, "after");
|
|
143
|
-
return (
|
|
152
|
+
return (_f = (_e = inserted === null || inserted === void 0 ? void 0 : inserted[1]) === null || _e === void 0 ? void 0 : _e.id) !== null && _f !== void 0 ? _f : null;
|
|
144
153
|
}
|
|
145
154
|
/**
|
|
146
155
|
* Programmatically add an empty snippet block to the editor.
|
|
@@ -346,12 +355,14 @@ export const stepBlock = createReactBlockSpec({
|
|
|
346
355
|
});
|
|
347
356
|
}, [editor, block.id, expectedResult]);
|
|
348
357
|
const handleInsertNextStep = useCallback(() => {
|
|
358
|
+
var _a;
|
|
349
359
|
const allBlocks = editor.document;
|
|
350
360
|
const idx = allBlocks.findIndex((b) => b.id === block.id);
|
|
351
361
|
const next = idx >= 0 ? allBlocks[idx + 1] : null;
|
|
352
362
|
if (next && isEmptyParagraph(next)) {
|
|
353
363
|
editor.removeBlocks([next.id]);
|
|
354
364
|
}
|
|
365
|
+
const currentListStyle = (_a = block.props.listStyle) !== null && _a !== void 0 ? _a : "bullet";
|
|
355
366
|
editor.insertBlocks([
|
|
356
367
|
{
|
|
357
368
|
type: "testStep",
|
|
@@ -359,11 +370,12 @@ export const stepBlock = createReactBlockSpec({
|
|
|
359
370
|
stepTitle: "",
|
|
360
371
|
stepData: "",
|
|
361
372
|
expectedResult: "",
|
|
373
|
+
listStyle: currentListStyle,
|
|
362
374
|
},
|
|
363
375
|
children: [],
|
|
364
376
|
},
|
|
365
377
|
], block.id, "after");
|
|
366
|
-
}, [editor, block.id]);
|
|
378
|
+
}, [editor, block.id, block.props]);
|
|
367
379
|
const handleFieldFocus = useCallback(() => {
|
|
368
380
|
var _a, _b, _c;
|
|
369
381
|
const selection = editor.getSelection();
|
|
@@ -262,7 +262,8 @@ function serializeBlock(block, ctx, orderedIndex, stepIndex) {
|
|
|
262
262
|
return lines;
|
|
263
263
|
}
|
|
264
264
|
case "codeBlock": {
|
|
265
|
-
const
|
|
265
|
+
const rawLanguage = block.props.language || "";
|
|
266
|
+
const language = /[\s`]/.test(rawLanguage) ? "" : rawLanguage;
|
|
266
267
|
const fence = "```" + language;
|
|
267
268
|
const body = inlineContentToPlainText(block.content);
|
|
268
269
|
lines.push(fence);
|
|
@@ -1087,8 +1088,17 @@ function parseCodeBlock(lines, index) {
|
|
|
1087
1088
|
nextIndex: index + 1,
|
|
1088
1089
|
};
|
|
1089
1090
|
}
|
|
1090
|
-
const
|
|
1091
|
+
const info = afterOpening.trim();
|
|
1092
|
+
let language = "";
|
|
1091
1093
|
const body = [];
|
|
1094
|
+
if (info.length > 0) {
|
|
1095
|
+
if (/[\s`]/.test(info)) {
|
|
1096
|
+
body.push(afterOpening);
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1099
|
+
language = info;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1092
1102
|
let next = index + 1;
|
|
1093
1103
|
while (next < lines.length && !lines[next].startsWith("```")) {
|
|
1094
1104
|
body.push(lines[next]);
|
package/package.json
CHANGED
|
@@ -108,11 +108,6 @@ export function addStepsBlock(editor: {
|
|
|
108
108
|
insertBlocks: (blocks: any[], referenceId: string, placement: "before" | "after") => any[];
|
|
109
109
|
}): string | null {
|
|
110
110
|
const allBlocks = editor.document;
|
|
111
|
-
const emptyStep = {
|
|
112
|
-
type: "testStep" as const,
|
|
113
|
-
props: { stepTitle: "", stepData: "", expectedResult: "" },
|
|
114
|
-
children: [],
|
|
115
|
-
};
|
|
116
111
|
|
|
117
112
|
let stepsHeadingIndex = -1;
|
|
118
113
|
for (let i = 0; i < allBlocks.length; i++) {
|
|
@@ -142,7 +137,17 @@ export function addStepsBlock(editor: {
|
|
|
142
137
|
if (isEmptyParagraph(b)) continue;
|
|
143
138
|
break;
|
|
144
139
|
}
|
|
145
|
-
const
|
|
140
|
+
const previousStep = allBlocks[lastIndex];
|
|
141
|
+
const inheritedListStyle =
|
|
142
|
+
previousStep?.type === "testStep"
|
|
143
|
+
? ((previousStep.props as any)?.listStyle ?? "bullet")
|
|
144
|
+
: "bullet";
|
|
145
|
+
const emptyStep = {
|
|
146
|
+
type: "testStep" as const,
|
|
147
|
+
props: { stepTitle: "", stepData: "", expectedResult: "", listStyle: inheritedListStyle },
|
|
148
|
+
children: [],
|
|
149
|
+
};
|
|
150
|
+
const inserted = editor.insertBlocks([emptyStep], previousStep.id, "after");
|
|
146
151
|
return inserted?.[0]?.id ?? null;
|
|
147
152
|
}
|
|
148
153
|
|
|
@@ -153,6 +158,11 @@ export function addStepsBlock(editor: {
|
|
|
153
158
|
content: [{ type: "text" as const, text: "Steps" }],
|
|
154
159
|
children: [],
|
|
155
160
|
};
|
|
161
|
+
const emptyStep = {
|
|
162
|
+
type: "testStep" as const,
|
|
163
|
+
props: { stepTitle: "", stepData: "", expectedResult: "" },
|
|
164
|
+
children: [],
|
|
165
|
+
};
|
|
156
166
|
const inserted = editor.insertBlocks([stepsHeading, emptyStep], lastBlock.id, "after");
|
|
157
167
|
return inserted?.[1]?.id ?? null;
|
|
158
168
|
}
|
|
@@ -399,6 +409,7 @@ export const stepBlock = createReactBlockSpec(
|
|
|
399
409
|
if (next && isEmptyParagraph(next)) {
|
|
400
410
|
editor.removeBlocks([next.id]);
|
|
401
411
|
}
|
|
412
|
+
const currentListStyle = (block.props as any).listStyle ?? "bullet";
|
|
402
413
|
editor.insertBlocks(
|
|
403
414
|
[
|
|
404
415
|
{
|
|
@@ -407,6 +418,7 @@ export const stepBlock = createReactBlockSpec(
|
|
|
407
418
|
stepTitle: "",
|
|
408
419
|
stepData: "",
|
|
409
420
|
expectedResult: "",
|
|
421
|
+
listStyle: currentListStyle,
|
|
410
422
|
},
|
|
411
423
|
children: [],
|
|
412
424
|
},
|
|
@@ -414,7 +426,7 @@ export const stepBlock = createReactBlockSpec(
|
|
|
414
426
|
block.id,
|
|
415
427
|
"after",
|
|
416
428
|
);
|
|
417
|
-
}, [editor, block.id]);
|
|
429
|
+
}, [editor, block.id, block.props]);
|
|
418
430
|
|
|
419
431
|
const handleFieldFocus = useCallback(() => {
|
|
420
432
|
const selection = editor.getSelection();
|
|
@@ -1696,6 +1696,36 @@ describe("markdownToBlocks", () => {
|
|
|
1696
1696
|
expect(stepBlocks[1].props).toMatchObject({ stepTitle: "Second step", listStyle: "ordered" });
|
|
1697
1697
|
});
|
|
1698
1698
|
|
|
1699
|
+
it("serializes a new ordered step appended to a numbered list as N.", () => {
|
|
1700
|
+
const orderedSteps: CustomEditorBlock[] = [
|
|
1701
|
+
{
|
|
1702
|
+
id: "s1",
|
|
1703
|
+
type: "testStep",
|
|
1704
|
+
props: { stepTitle: "First step", stepData: "", expectedResult: "", listStyle: "ordered" },
|
|
1705
|
+
content: undefined as any,
|
|
1706
|
+
children: [],
|
|
1707
|
+
} as any,
|
|
1708
|
+
{
|
|
1709
|
+
id: "s2",
|
|
1710
|
+
type: "testStep",
|
|
1711
|
+
props: { stepTitle: "Second step", stepData: "", expectedResult: "", listStyle: "ordered" },
|
|
1712
|
+
content: undefined as any,
|
|
1713
|
+
children: [],
|
|
1714
|
+
} as any,
|
|
1715
|
+
{
|
|
1716
|
+
id: "s3",
|
|
1717
|
+
type: "testStep",
|
|
1718
|
+
props: { stepTitle: "Newly added step", stepData: "", expectedResult: "", listStyle: "ordered" },
|
|
1719
|
+
content: undefined as any,
|
|
1720
|
+
children: [],
|
|
1721
|
+
} as any,
|
|
1722
|
+
];
|
|
1723
|
+
|
|
1724
|
+
expect(blocksToMarkdown(orderedSteps)).toBe(
|
|
1725
|
+
["1. First step", "2. Second step", "3. Newly added step"].join("\n"),
|
|
1726
|
+
);
|
|
1727
|
+
});
|
|
1728
|
+
|
|
1699
1729
|
it("parses steps under an h4 'step' heading (lowercase)", () => {
|
|
1700
1730
|
const markdown = ["#### step", "", "* Do something"].join("\n");
|
|
1701
1731
|
const blocks = markdownToBlocks(markdown);
|
|
@@ -2655,6 +2685,90 @@ describe("markdownToBlocks", () => {
|
|
|
2655
2685
|
},
|
|
2656
2686
|
]);
|
|
2657
2687
|
});
|
|
2688
|
+
|
|
2689
|
+
it("preserves opening-fence content when it is not a clean language identifier", () => {
|
|
2690
|
+
const markdown = [
|
|
2691
|
+
"```curl `http://localhost:3000/projects/classic-project/test/e1c1b38c/edit` \\",
|
|
2692
|
+
"{{baseURL}}/endpoint?query_param_one=value_one&query_param_two=value_two",
|
|
2693
|
+
"```",
|
|
2694
|
+
].join("\n");
|
|
2695
|
+
const blocks = markdownToBlocks(markdown);
|
|
2696
|
+
expect(blocks).toEqual([
|
|
2697
|
+
{
|
|
2698
|
+
type: "codeBlock",
|
|
2699
|
+
props: { language: "" },
|
|
2700
|
+
content: [
|
|
2701
|
+
{
|
|
2702
|
+
type: "text",
|
|
2703
|
+
text: [
|
|
2704
|
+
"curl `http://localhost:3000/projects/classic-project/test/e1c1b38c/edit` \\",
|
|
2705
|
+
"{{baseURL}}/endpoint?query_param_one=value_one&query_param_two=value_two",
|
|
2706
|
+
].join("\n"),
|
|
2707
|
+
styles: {},
|
|
2708
|
+
},
|
|
2709
|
+
],
|
|
2710
|
+
children: [],
|
|
2711
|
+
},
|
|
2712
|
+
]);
|
|
2713
|
+
});
|
|
2714
|
+
|
|
2715
|
+
it("round-trips an opening-fence-with-content code block to stable markdown", () => {
|
|
2716
|
+
const markdown = [
|
|
2717
|
+
"```curl `http://localhost:3000/projects/classic-project/test/e1c1b38c/edit` \\",
|
|
2718
|
+
"{{baseURL}}/endpoint?query_param_one=value_one&query_param_two=value_two",
|
|
2719
|
+
"```",
|
|
2720
|
+
].join("\n");
|
|
2721
|
+
const blocks = markdownToBlocks(markdown);
|
|
2722
|
+
const serialized = blocksToMarkdown(blocks as CustomEditorBlock[]);
|
|
2723
|
+
expect(serialized).toBe(
|
|
2724
|
+
[
|
|
2725
|
+
"```",
|
|
2726
|
+
"curl `http://localhost:3000/projects/classic-project/test/e1c1b38c/edit` \\",
|
|
2727
|
+
"{{baseURL}}/endpoint?query_param_one=value_one&query_param_two=value_two",
|
|
2728
|
+
"```",
|
|
2729
|
+
].join("\n"),
|
|
2730
|
+
);
|
|
2731
|
+
expect(markdownToBlocks(serialized)).toEqual(blocks);
|
|
2732
|
+
});
|
|
2733
|
+
|
|
2734
|
+
it("preserves hyphenated language identifiers like shell-session", () => {
|
|
2735
|
+
const markdown = ["```shell-session", "$ ls", "```"].join("\n");
|
|
2736
|
+
const blocks = markdownToBlocks(markdown);
|
|
2737
|
+
expect(blocks).toEqual([
|
|
2738
|
+
{
|
|
2739
|
+
type: "codeBlock",
|
|
2740
|
+
props: { language: "shell-session" },
|
|
2741
|
+
content: [{ type: "text", text: "$ ls", styles: {} }],
|
|
2742
|
+
children: [],
|
|
2743
|
+
},
|
|
2744
|
+
]);
|
|
2745
|
+
});
|
|
2746
|
+
|
|
2747
|
+
it("preserves digit-prefixed language identifiers like 1c-enterprise", () => {
|
|
2748
|
+
const markdown = ["```1c-enterprise", "code", "```"].join("\n");
|
|
2749
|
+
const blocks = markdownToBlocks(markdown);
|
|
2750
|
+
expect(blocks).toEqual([
|
|
2751
|
+
{
|
|
2752
|
+
type: "codeBlock",
|
|
2753
|
+
props: { language: "1c-enterprise" },
|
|
2754
|
+
content: [{ type: "text", text: "code", styles: {} }],
|
|
2755
|
+
children: [],
|
|
2756
|
+
},
|
|
2757
|
+
]);
|
|
2758
|
+
});
|
|
2759
|
+
|
|
2760
|
+
it("sanitizes a malformed in-memory language prop on serialize", () => {
|
|
2761
|
+
const blocks: CustomEditorBlock[] = [
|
|
2762
|
+
{
|
|
2763
|
+
id: "1",
|
|
2764
|
+
type: "codeBlock",
|
|
2765
|
+
props: { ...baseProps, language: "curl http://x" } as any,
|
|
2766
|
+
content: [{ type: "text", text: "body", styles: {} }] as any,
|
|
2767
|
+
children: [],
|
|
2768
|
+
},
|
|
2769
|
+
];
|
|
2770
|
+
expect(blocksToMarkdown(blocks)).toBe(["```", "body", "```"].join("\n"));
|
|
2771
|
+
});
|
|
2658
2772
|
});
|
|
2659
2773
|
|
|
2660
2774
|
describe("file block serialization", () => {
|
|
@@ -334,7 +334,8 @@ function serializeBlock(
|
|
|
334
334
|
return lines;
|
|
335
335
|
}
|
|
336
336
|
case "codeBlock": {
|
|
337
|
-
const
|
|
337
|
+
const rawLanguage = (block.props as any).language || "";
|
|
338
|
+
const language = /[\s`]/.test(rawLanguage) ? "" : rawLanguage;
|
|
338
339
|
const fence = "```" + language;
|
|
339
340
|
const body = inlineContentToPlainText(block.content);
|
|
340
341
|
lines.push(fence);
|
|
@@ -1290,8 +1291,16 @@ function parseCodeBlock(lines: string[], index: number): { block: CustomPartialB
|
|
|
1290
1291
|
};
|
|
1291
1292
|
}
|
|
1292
1293
|
|
|
1293
|
-
const
|
|
1294
|
+
const info = afterOpening.trim();
|
|
1295
|
+
let language = "";
|
|
1294
1296
|
const body: string[] = [];
|
|
1297
|
+
if (info.length > 0) {
|
|
1298
|
+
if (/[\s`]/.test(info)) {
|
|
1299
|
+
body.push(afterOpening);
|
|
1300
|
+
} else {
|
|
1301
|
+
language = info;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1295
1304
|
let next = index + 1;
|
|
1296
1305
|
while (next < lines.length && !lines[next].startsWith("```") ) {
|
|
1297
1306
|
body.push(lines[next]);
|