mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 14:03:33 +09:00
## Description 1. Don't handle global paste even when inside content-editable (before that when you paste inside texteditable, it would insert an instance additionally outside) 2. Insert links in paragraphs as RichTextLink 3. Make sure rich text link has the same props as link ## Code Review - [ ] hi @TrySound , I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio-builder/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env.example` and the `builder/env-check.js` if mandatory
602 lines
13 KiB
TypeScript
602 lines
13 KiB
TypeScript
import { describe, expect } from "@jest/globals";
|
|
import { Instance, Prop } from "@webstudio-is/project-build";
|
|
import { parse } from "./plugin-markdown";
|
|
|
|
const parseInstanceData = (data?: {
|
|
children: Instance["children"];
|
|
props: Array<Prop>;
|
|
}) => {
|
|
if (data === undefined) {
|
|
return;
|
|
}
|
|
const { children, props } = data;
|
|
for (const child of children) {
|
|
if (child.type === "instance") {
|
|
Instance.parse(child);
|
|
parseInstanceData({ children: child.children, props });
|
|
}
|
|
}
|
|
for (const prop of props) {
|
|
Prop.parse(prop);
|
|
}
|
|
return { children, props };
|
|
};
|
|
|
|
const options = { generateId: () => "123" };
|
|
|
|
describe("Plugin Markdown", () => {
|
|
test("paragraph", () => {
|
|
expect(parseInstanceData(parse("xyz", options))).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "xyz",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("h1", () => {
|
|
expect(parseInstanceData(parse("# heading", options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "heading",
|
|
},
|
|
],
|
|
"component": "Heading",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "tag",
|
|
"type": "string",
|
|
"value": "h1",
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("h6", () => {
|
|
expect(parseInstanceData(parse("###### heading", options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "heading",
|
|
},
|
|
],
|
|
"component": "Heading",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "tag",
|
|
"type": "string",
|
|
"value": "h6",
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("bold 1", () => {
|
|
expect(parseInstanceData(parse("__bold__", options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "bold",
|
|
},
|
|
],
|
|
"component": "Bold",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("bold 2", () => {
|
|
expect(parseInstanceData(parse("**bold**", options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "bold",
|
|
},
|
|
],
|
|
"component": "Bold",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("italic 1", () => {
|
|
expect(parseInstanceData(parse("_italic_", options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "italic",
|
|
},
|
|
],
|
|
"component": "Italic",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("italic 2", () => {
|
|
expect(parseInstanceData(parse("*italic*", options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "italic",
|
|
},
|
|
],
|
|
"component": "Italic",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("link", () => {
|
|
expect(parseInstanceData(parse('[link](/uri "Title")', options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "link",
|
|
},
|
|
],
|
|
"component": "RichTextLink",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "href",
|
|
"type": "string",
|
|
"value": "/uri",
|
|
},
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "title",
|
|
"type": "string",
|
|
"value": "Title",
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("image", () => {
|
|
expect(parseInstanceData(parse('', options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [],
|
|
"component": "Image",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "src",
|
|
"type": "string",
|
|
"value": "/url",
|
|
},
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "title",
|
|
"type": "string",
|
|
"value": "title",
|
|
},
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "alt",
|
|
"type": "string",
|
|
"value": "foo",
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("hard line break", () => {
|
|
expect(
|
|
parseInstanceData(
|
|
parse(
|
|
`foo
|
|
baz`,
|
|
options
|
|
)
|
|
)
|
|
).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "foo",
|
|
},
|
|
{
|
|
"type": "text",
|
|
"value": "baz",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("soft line break", () => {
|
|
expect(
|
|
parseInstanceData(
|
|
parse(
|
|
`foo
|
|
baz`,
|
|
options
|
|
)
|
|
)
|
|
).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "foo
|
|
baz",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("blockquote", () => {
|
|
expect(parseInstanceData(parse("> bar", options))).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "bar",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Blockquote",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("inline code", () => {
|
|
expect(parseInstanceData(parse("`foo`", options))).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "foo",
|
|
},
|
|
],
|
|
"component": "Code",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "inline",
|
|
"type": "boolean",
|
|
"value": true,
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("code", () => {
|
|
expect(parseInstanceData(parse("```js meta\nfoo\n```", options)))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "foo",
|
|
},
|
|
],
|
|
"component": "Code",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "inline",
|
|
"type": "boolean",
|
|
"value": false,
|
|
},
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "lang",
|
|
"type": "string",
|
|
"value": "js",
|
|
},
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "meta",
|
|
"type": "string",
|
|
"value": "meta",
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("list unordered", () => {
|
|
expect(parseInstanceData(parse("- one", options))).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "one",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "ListItem",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "List",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "ordered",
|
|
"type": "boolean",
|
|
"value": false,
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("list ordered", () => {
|
|
expect(parseInstanceData(parse("3. one", options))).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [
|
|
{
|
|
"type": "text",
|
|
"value": "one",
|
|
},
|
|
],
|
|
"component": "Paragraph",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "ListItem",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"component": "List",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "ordered",
|
|
"type": "boolean",
|
|
"value": true,
|
|
},
|
|
{
|
|
"id": "123",
|
|
"instanceId": "123",
|
|
"name": "start",
|
|
"type": "number",
|
|
"value": 3,
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("thematic break | separator", () => {
|
|
expect(parseInstanceData(parse("---", options))).toMatchInlineSnapshot(`
|
|
{
|
|
"children": [
|
|
{
|
|
"children": [],
|
|
"component": "Separator",
|
|
"id": "123",
|
|
"type": "instance",
|
|
},
|
|
],
|
|
"props": [],
|
|
}
|
|
`);
|
|
});
|
|
|
|
// @todo For some reason doesn't work
|
|
test.skip("strikethrough", () => {
|
|
expect(
|
|
parseInstanceData(parse("~One~ ~~two~~ ~~~three~~~.", options))
|
|
).toMatchInlineSnapshot();
|
|
});
|
|
});
|