@witchcraft/editor 0.0.8 → 0.1.0
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/dist/module.json +1 -1
- package/dist/module.mjs +2 -2
- package/dist/runtime/components/CodeBlockThemePicker.d.vue.ts +4 -2
- package/dist/runtime/components/CodeBlockThemePicker.vue +0 -1
- package/dist/runtime/components/CodeBlockThemePicker.vue.d.ts +4 -2
- package/dist/runtime/components/Commands.d.vue.ts +2 -1
- package/dist/runtime/components/Commands.vue.d.ts +2 -1
- package/dist/runtime/components/Editor.d.vue.ts +3 -12
- package/dist/runtime/components/Editor.vue.d.ts +3 -12
- package/dist/runtime/components/EditorDemoApp.d.vue.ts +2 -1
- package/dist/runtime/components/EditorDemoApp.vue.d.ts +2 -1
- package/dist/runtime/components/EditorDemoControls.d.vue.ts +4 -2
- package/dist/runtime/components/EditorDemoControls.vue.d.ts +4 -2
- package/dist/runtime/components/TestWrapper.d.vue.ts +2 -1
- package/dist/runtime/components/TestWrapper.vue.d.ts +2 -1
- package/dist/runtime/demo/App.d.vue.ts +2 -1
- package/dist/runtime/demo/App.vue.d.ts +2 -1
- package/dist/runtime/pm/features/Blocks/components/DragTreeHandle.d.vue.ts +2 -1
- package/dist/runtime/pm/features/Blocks/components/DragTreeHandle.vue.d.ts +2 -1
- package/dist/runtime/pm/features/Blocks/components/ItemMenu.d.vue.ts +2 -1
- package/dist/runtime/pm/features/Blocks/components/ItemMenu.vue.d.ts +2 -1
- package/dist/runtime/pm/features/Blocks/components/ItemNodeView.d.vue.ts +2 -1
- package/dist/runtime/pm/features/Blocks/components/ItemNodeView.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CodeBlock/components/CodeBlockView.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CodeBlock/components/CodeBlockView.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandBar.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandBar.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandBarItem.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandBarItem.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandMenuGroup.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandMenuGroup.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandMenuItem.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandMenuItem.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandMenuList.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/CommandMenuList.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/TextIcon.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/components/TextIcon.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/icons/HighlightIcon.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/icons/HighlightIcon.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/icons/SubscriptIcon.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/icons/SubscriptIcon.vue.d.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/icons/SuperscriptIcon.d.vue.ts +2 -1
- package/dist/runtime/pm/features/CommandsMenus/icons/SuperscriptIcon.vue.d.ts +2 -1
- package/dist/runtime/pm/features/DocumentApi/DocumentApi.d.ts +3 -0
- package/dist/runtime/pm/features/DocumentApi/DocumentApi.js +2 -0
- package/dist/runtime/pm/features/DocumentApi/composables/useTestDocumentApi.js +4 -1
- package/dist/runtime/pm/features/EmbeddedDocument/components/EmbeddedDocumentPicker.d.vue.ts +2 -1
- package/dist/runtime/pm/features/EmbeddedDocument/components/EmbeddedDocumentPicker.vue +3 -3
- package/dist/runtime/pm/features/EmbeddedDocument/components/EmbeddedDocumentPicker.vue.d.ts +2 -1
- package/dist/runtime/pm/features/EmbeddedDocument/components/EmbeddedNodeView.d.vue.ts +2 -1
- package/dist/runtime/pm/features/EmbeddedDocument/components/EmbeddedNodeView.vue.d.ts +2 -1
- package/dist/runtime/pm/features/FileLoader/components/FileLoaderNodeView.d.vue.ts +2 -1
- package/dist/runtime/pm/features/FileLoader/components/FileLoaderNodeView.vue.d.ts +2 -1
- package/dist/runtime/pm/features/Iframe/components/IframeNodeView.d.vue.ts +2 -1
- package/dist/runtime/pm/features/Iframe/components/IframeNodeView.vue +0 -1
- package/dist/runtime/pm/features/Iframe/components/IframeNodeView.vue.d.ts +2 -1
- package/dist/runtime/pm/features/Link/components/BubbleMenuExternalLink.d.vue.ts +4 -2
- package/dist/runtime/pm/features/Link/components/BubbleMenuExternalLink.vue.d.ts +4 -2
- package/dist/runtime/pm/features/Link/components/BubbleMenuInternalLink.d.vue.ts +4 -2
- package/dist/runtime/pm/features/Link/components/BubbleMenuInternalLink.vue.d.ts +4 -2
- package/dist/runtime/pm/features/Link/components/BubbleMenuLink.d.vue.ts +2 -1
- package/dist/runtime/pm/features/Link/components/BubbleMenuLink.vue.d.ts +2 -1
- package/dist/runtime/pm/features/Link/components/BubbleMenuLinkActions.d.vue.ts +2 -1
- package/dist/runtime/pm/features/Link/components/BubbleMenuLinkActions.vue.d.ts +2 -1
- package/dist/runtime/pm/features/Menus/components/MarkMenuManager.d.vue.ts +2 -1
- package/dist/runtime/pm/features/Menus/components/MarkMenuManager.vue.d.ts +2 -1
- package/dist/runtime/pm/generator.d.ts +30 -44
- package/dist/runtime/pm/generator.js +112 -109
- package/dist/runtime/pm/utils/generateRandomDoc.d.ts +3 -21
- package/dist/runtime/pm/utils/generateRandomDoc.js +36 -77
- package/dist/runtime/pm/utils/generator/createGeneratorConfig.d.ts +33 -0
- package/dist/runtime/pm/utils/generator/createGeneratorConfig.js +3 -0
- package/dist/runtime/pm/utils/generator/createPsuedoSentence.d.ts +4 -0
- package/dist/runtime/pm/utils/generator/createPsuedoSentence.js +16 -0
- package/dist/runtime/pm/utils/generator/createRandomChildCountGenerator.d.ts +14 -0
- package/dist/runtime/pm/utils/generator/createRandomChildCountGenerator.js +16 -0
- package/dist/runtime/pm/utils/generator/getTextOrMarkLength.d.ts +2 -0
- package/dist/runtime/pm/utils/generator/getTextOrMarkLength.js +7 -0
- package/dist/runtime/pm/utils/generator/influenceWithDepth.d.ts +6 -0
- package/dist/runtime/pm/utils/generator/influenceWithDepth.js +6 -0
- package/dist/runtime/pm/utils/generator/sometimesZero.d.ts +13 -0
- package/dist/runtime/pm/utils/generator/sometimesZero.js +7 -0
- package/package.json +59 -58
- package/src/runtime/components/CodeBlockThemePicker.vue +0 -1
- package/src/runtime/pm/features/DocumentApi/DocumentApi.ts +3 -0
- package/src/runtime/pm/features/DocumentApi/composables/useTestDocumentApi.ts +2 -1
- package/src/runtime/pm/features/EmbeddedDocument/components/EmbeddedDocumentPicker.vue +3 -4
- package/src/runtime/pm/features/Iframe/components/IframeNodeView.vue +0 -1
- package/src/runtime/pm/generator.ts +104 -151
- package/src/runtime/pm/schema.ts +2 -2
- package/src/runtime/pm/utils/generateRandomDoc.ts +47 -124
- package/src/runtime/pm/utils/generator/createGeneratorConfig.ts +56 -0
- package/src/runtime/pm/utils/generator/createPsuedoSentence.ts +18 -0
- package/src/runtime/pm/utils/generator/createRandomChildCountGenerator.ts +31 -0
- package/src/runtime/pm/utils/generator/getTextOrMarkLength.ts +9 -0
- package/src/runtime/pm/utils/generator/influenceWithDepth.ts +11 -0
- package/src/runtime/pm/utils/generator/sometimesZero.ts +16 -0
- package/dist/runtime/pm/utils/generateRandomTree.d.ts +0 -50
- package/dist/runtime/pm/utils/generateRandomTree.js +0 -38
- package/src/runtime/pm/utils/generateRandomTree.ts +0 -100
|
@@ -3,70 +3,63 @@ import { nanoid } from "nanoid";
|
|
|
3
3
|
import { builders } from "prosemirror-test-builder";
|
|
4
4
|
import { schema } from "./schema.js";
|
|
5
5
|
export const pm = builders(schema);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return textNodes.reduce((a, b) => a + b, 0);
|
|
12
|
-
}
|
|
13
|
-
export function createGeneratorConfig(config) {
|
|
14
|
-
return config;
|
|
15
|
-
}
|
|
16
|
-
function createPsuedoSentence() {
|
|
17
|
-
const sentenceLength = faker.number.int({ min: 0, max: 1e3 });
|
|
18
|
-
const sentence = Array.from(
|
|
19
|
-
{ length: sentenceLength },
|
|
20
|
-
() => faker.string.sample({ min: 0, max: 1e3 })
|
|
21
|
-
).join(" ");
|
|
22
|
-
return sentence;
|
|
23
|
-
}
|
|
6
|
+
import { highlightJsLanaguages } from "./features/CodeBlock/highlightJsInfo.js";
|
|
7
|
+
import { createGeneratorConfig } from "./utils/generator/createGeneratorConfig.js";
|
|
8
|
+
import { createPsuedoSentence } from "./utils/generator/createPsuedoSentence.js";
|
|
9
|
+
import { createRandomChildCountGenerator } from "./utils/generator/createRandomChildCountGenerator.js";
|
|
10
|
+
import { sometimesZero } from "./utils/generator/sometimesZero.js";
|
|
24
11
|
export const generatorConfig = [
|
|
25
12
|
createGeneratorConfig({
|
|
26
|
-
isRoot: true,
|
|
27
13
|
parents: { type: "node", names: ["doc"] },
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
children: {
|
|
15
|
+
type: "node",
|
|
16
|
+
names: [["item", 1]]
|
|
17
|
+
},
|
|
18
|
+
count: createRandomChildCountGenerator({ max: 50, zeroChance: 0 }),
|
|
19
|
+
create: (pm2, _parent, children) => {
|
|
31
20
|
if (!children || children.length === 0) {
|
|
32
|
-
return
|
|
21
|
+
return pm2.doc(pm2.list(pm2.item({ blockId: nanoid(10) }, pm2.paragraph({}, ""))));
|
|
33
22
|
}
|
|
34
|
-
return
|
|
23
|
+
return pm2.doc(pm2.list(...children));
|
|
35
24
|
}
|
|
36
25
|
}),
|
|
37
26
|
createGeneratorConfig({
|
|
38
|
-
parents: { type: "node", names: ["list"] },
|
|
39
|
-
children: { type: "node", names: [
|
|
40
|
-
|
|
27
|
+
parents: { type: "node", names: ["list", "doc"] },
|
|
28
|
+
children: { type: "node", names: [
|
|
29
|
+
["item", 1]
|
|
30
|
+
] },
|
|
31
|
+
count: createRandomChildCountGenerator({ max: 30 }),
|
|
32
|
+
create: (pm2, _parent, children) => {
|
|
41
33
|
if (!children || children.length === 0) {
|
|
42
|
-
return
|
|
34
|
+
return pm2.list(pm2.item({ blockId: nanoid(10) }, pm2.paragraph("")));
|
|
43
35
|
}
|
|
44
|
-
return
|
|
36
|
+
return pm2.list(...children);
|
|
45
37
|
}
|
|
46
38
|
}),
|
|
47
39
|
createGeneratorConfig({
|
|
48
40
|
parents: { type: "node", names: ["item"] },
|
|
49
41
|
children: { type: "node", names: [
|
|
50
|
-
"paragraph",
|
|
51
|
-
"heading",
|
|
52
|
-
"codeBlock",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
42
|
+
["paragraph", 14],
|
|
43
|
+
["heading", 4],
|
|
44
|
+
["codeBlock", 2],
|
|
45
|
+
["table", 2],
|
|
46
|
+
["image", 3],
|
|
47
|
+
["blockquote", 4],
|
|
48
|
+
["embeddedDoc", 1],
|
|
49
|
+
["iframe", 1]
|
|
58
50
|
] },
|
|
59
|
-
|
|
51
|
+
count: createRandomChildCountGenerator({ max: 20, depthInfluence: 0.5 }),
|
|
52
|
+
create: (pm2, _parent, children) => {
|
|
60
53
|
if (!children || children.length === 0) {
|
|
61
|
-
return
|
|
54
|
+
return pm2.item({ blockId: nanoid(10) }, pm2.paragraph(""));
|
|
62
55
|
}
|
|
63
|
-
return
|
|
56
|
+
return pm2.item(
|
|
64
57
|
{ blockId: nanoid(10) },
|
|
65
58
|
children[0],
|
|
66
|
-
...children.length > 1 ? [
|
|
59
|
+
...children.length > 1 ? [pm2.list(
|
|
67
60
|
{},
|
|
68
61
|
...children.slice(1).map(
|
|
69
|
-
(_) =>
|
|
62
|
+
(_) => pm2.item({ blockId: nanoid(10) }, _)
|
|
70
63
|
)
|
|
71
64
|
)] : []
|
|
72
65
|
);
|
|
@@ -74,8 +67,12 @@ export const generatorConfig = [
|
|
|
74
67
|
}),
|
|
75
68
|
createGeneratorConfig({
|
|
76
69
|
parents: { type: "node", names: ["blockquote"] },
|
|
77
|
-
children: { type: "node", names: [
|
|
78
|
-
|
|
70
|
+
children: { type: "node", names: [
|
|
71
|
+
["paragraph", 1],
|
|
72
|
+
["cite", 1]
|
|
73
|
+
] },
|
|
74
|
+
count: () => faker.number.int({ min: 1, max: 2 }),
|
|
75
|
+
create: (pm2, _parent, children) => {
|
|
79
76
|
const parTypes = [];
|
|
80
77
|
const citeTypes = [];
|
|
81
78
|
for (const child of children) {
|
|
@@ -86,77 +83,88 @@ export const generatorConfig = [
|
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
if (parTypes.length === 0) {
|
|
89
|
-
return
|
|
86
|
+
return pm2.blockquote({}, pm2.paragraph(""));
|
|
90
87
|
} else {
|
|
91
|
-
const someCite = citeTypes.find((_) => _.textContent.length > 0) ??
|
|
92
|
-
return
|
|
88
|
+
const someCite = citeTypes.find((_) => _.textContent.length > 0) ?? pm2.cite({}, createPsuedoSentence({ min: 1 }));
|
|
89
|
+
return pm2.blockquote({}, ...parTypes, someCite);
|
|
93
90
|
}
|
|
94
91
|
}
|
|
95
92
|
}),
|
|
96
93
|
createGeneratorConfig({
|
|
97
94
|
parents: { type: "node", names: ["table"] },
|
|
98
95
|
children: { type: "node", names: [
|
|
99
|
-
"
|
|
100
|
-
"tableCell"
|
|
96
|
+
["tableCell", 1]
|
|
101
97
|
] },
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
const cellType = [];
|
|
107
|
-
for (const child of children) {
|
|
108
|
-
if (child.type.name === "tableHeader") {
|
|
109
|
-
headerType.push(child);
|
|
110
|
-
} else if (child.type.name === "tableCell") {
|
|
111
|
-
cellType.push(child);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
const colNum = headerType.length;
|
|
115
|
-
if (colNum === 0) {
|
|
116
|
-
return pm.table({}, pm.tableRow({}, pm.tableCell(pm.paragraph(""))));
|
|
117
|
-
}
|
|
118
|
-
const rowCount = Math.ceil(cellType.length / colNum);
|
|
98
|
+
count: createRandomChildCountGenerator({ max: 50, depthInfluence: 0.5, zeroChance: 0 }),
|
|
99
|
+
create: (pm2, _parent, children) => {
|
|
100
|
+
const colNum = faker.number.int({ min: 1, max: Math.min(children.length, 10) });
|
|
101
|
+
const rowCount = Math.floor(children.length / colNum);
|
|
119
102
|
const rows = [];
|
|
103
|
+
const addHeader = faker.datatype.boolean();
|
|
104
|
+
if (addHeader) {
|
|
105
|
+
const nodes = Array.from(
|
|
106
|
+
{ length: colNum },
|
|
107
|
+
() => pm2.tableHeader({}, pm2.paragraph({}, createPsuedoSentence({ min: 1 })))
|
|
108
|
+
);
|
|
109
|
+
rows.push(pm2.tableRow({}, ...nodes));
|
|
110
|
+
}
|
|
120
111
|
for (let i = 0; i < rowCount; i++) {
|
|
121
|
-
|
|
112
|
+
const rowChildren = children.slice(i * colNum, (i + 1) * colNum);
|
|
113
|
+
if (rowChildren.length === 0) continue;
|
|
114
|
+
rows.push(pm2.tableRow({}, ...rowChildren));
|
|
122
115
|
}
|
|
123
|
-
|
|
116
|
+
if (rows.length === 0) return void 0;
|
|
117
|
+
return pm2.table({}, ...rows);
|
|
124
118
|
}
|
|
125
119
|
}),
|
|
126
120
|
createGeneratorConfig({
|
|
127
|
-
parents: { type: "node", names: ["
|
|
128
|
-
children: { type: "node", names: [
|
|
129
|
-
|
|
121
|
+
parents: { type: "node", names: ["tableCell"] },
|
|
122
|
+
children: { type: "node", names: [
|
|
123
|
+
["paragraph", 1]
|
|
124
|
+
] },
|
|
125
|
+
count: () => sometimesZero(1),
|
|
126
|
+
create: (pm2, _parent, children) => {
|
|
130
127
|
if (!children || children.length === 0) {
|
|
131
|
-
return
|
|
128
|
+
return pm2.tableCell(pm2.paragraph(""));
|
|
132
129
|
}
|
|
133
|
-
return
|
|
130
|
+
return pm2.tableCell(...children.slice(0, 1));
|
|
134
131
|
}
|
|
135
132
|
}),
|
|
136
133
|
createGeneratorConfig({
|
|
137
|
-
parents: { type: "
|
|
134
|
+
parents: { type: "text", names: ["paragraph", "heading", "codeBlock", "cite", "heading"] },
|
|
138
135
|
children: { type: "text", names: [
|
|
139
|
-
"bold",
|
|
140
|
-
"italic",
|
|
141
|
-
"underline",
|
|
142
|
-
"strike",
|
|
143
|
-
"subscript",
|
|
144
|
-
"superscript",
|
|
145
|
-
"code",
|
|
146
|
-
"link"
|
|
136
|
+
["bold", 1],
|
|
137
|
+
["italic", 1],
|
|
138
|
+
["underline", 1],
|
|
139
|
+
["strike", 1],
|
|
140
|
+
["subscript", 1],
|
|
141
|
+
["superscript", 1],
|
|
142
|
+
["code", 1],
|
|
143
|
+
["link", 1],
|
|
144
|
+
["text", 10]
|
|
147
145
|
] },
|
|
148
|
-
|
|
146
|
+
count: createRandomChildCountGenerator({ max: 5, depthInfluence: 0.2 }),
|
|
147
|
+
create(pm2, parent, children) {
|
|
149
148
|
if (parent === "heading") {
|
|
150
|
-
return
|
|
149
|
+
return pm2[parent]({ level: faker.number.int({ min: 1, max: 6 }) }, ...children);
|
|
151
150
|
}
|
|
152
151
|
if (parent === "cite") {
|
|
153
|
-
return
|
|
152
|
+
return pm2[parent]({}, faker.lorem.sentence());
|
|
154
153
|
}
|
|
155
154
|
if (parent === "paragraph") {
|
|
156
155
|
const someIndex = faker.number.int({ min: 0, max: children.length });
|
|
157
|
-
children.splice(someIndex, 0,
|
|
156
|
+
children.splice(someIndex, 0, pm2.hardBreak());
|
|
157
|
+
}
|
|
158
|
+
if (parent === "codeBlock") {
|
|
159
|
+
const lang = faker.helpers.arrayElement([...Object.keys(highlightJsLanaguages.aliases), void 0]);
|
|
160
|
+
const lines = faker.number.int({ min: 1, max: 10 });
|
|
161
|
+
const code = Array.from(
|
|
162
|
+
{ length: lines },
|
|
163
|
+
() => createPsuedoSentence()
|
|
164
|
+
).join("\n");
|
|
165
|
+
return pm2[parent]({ language: lang }, code);
|
|
158
166
|
}
|
|
159
|
-
return
|
|
167
|
+
return pm2[parent]({}, ...children);
|
|
160
168
|
}
|
|
161
169
|
}),
|
|
162
170
|
createGeneratorConfig({
|
|
@@ -172,33 +180,28 @@ export const generatorConfig = [
|
|
|
172
180
|
"link"
|
|
173
181
|
]
|
|
174
182
|
},
|
|
175
|
-
|
|
183
|
+
skipChild(parentType, childType, depth) {
|
|
184
|
+
if (depth > 20) return true;
|
|
185
|
+
return parentType === childType;
|
|
186
|
+
},
|
|
176
187
|
children: { type: "text", names: [
|
|
177
|
-
"bold",
|
|
178
|
-
"italic",
|
|
179
|
-
"underline",
|
|
180
|
-
"strike",
|
|
181
|
-
"subscript",
|
|
182
|
-
"superscript",
|
|
183
|
-
"link",
|
|
184
|
-
"text"
|
|
188
|
+
["bold", 1],
|
|
189
|
+
["italic", 1],
|
|
190
|
+
["underline", 1],
|
|
191
|
+
["strike", 1],
|
|
192
|
+
["subscript", 1],
|
|
193
|
+
["superscript", 1],
|
|
194
|
+
["link", 1],
|
|
195
|
+
["text", 10]
|
|
185
196
|
] },
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
// }
|
|
191
|
-
}),
|
|
192
|
-
createGeneratorConfig({
|
|
193
|
-
ignoreValidation: true,
|
|
194
|
-
// text is not a real node
|
|
195
|
-
parents: { type: "text", names: ["code"] },
|
|
196
|
-
children: { type: "text", names: ["text"] }
|
|
197
|
+
count: createRandomChildCountGenerator({ max: 5, depthInfluence: 0.7 }),
|
|
198
|
+
create: (pm2, parent, children) => {
|
|
199
|
+
return pm2[parent]({}, ...children);
|
|
200
|
+
}
|
|
197
201
|
}),
|
|
198
202
|
createGeneratorConfig({
|
|
199
203
|
parents: { type: "text", names: ["text"] },
|
|
200
|
-
|
|
201
|
-
create: (_parent) => {
|
|
204
|
+
create: () => {
|
|
202
205
|
return createPsuedoSentence();
|
|
203
206
|
}
|
|
204
207
|
})
|
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
import type { Node } from "@tiptap/pm/model";
|
|
2
2
|
import type { builders } from "prosemirror-test-builder";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Generates a random doc using faker js.
|
|
7
|
-
*
|
|
8
|
-
* A config describing how to create the doc is required. One is available under `pm/generator`.
|
|
9
|
-
*
|
|
10
|
-
* @experimental
|
|
11
|
-
*/
|
|
12
|
-
export declare function generateRandomDoc<TBuilder extends ReturnType<typeof builders>, TData extends string>(builder: TBuilder, config?: GeneratorConfigEntry<any, any, any, any>[], treeOptions?: Parameters<typeof generateRandomTree>[1], { checkAfterNodeCreation }?: {
|
|
13
|
-
/**
|
|
14
|
-
* Checks if every returned node is valid for debugging invalid generator configs.
|
|
15
|
-
*
|
|
16
|
-
* A check is always done on the root node at the end regardless of this option.
|
|
17
|
-
*
|
|
18
|
-
* It is very slow (each check, rechecks children).
|
|
19
|
-
*
|
|
20
|
-
* @default false
|
|
21
|
-
*/
|
|
22
|
-
checkAfterNodeCreation?: boolean;
|
|
23
|
-
}): Node;
|
|
3
|
+
import type { GeneratorConfigEntry } from "./generator/createGeneratorConfig.js";
|
|
4
|
+
export declare function generateRandomDoc<TBuilder extends ReturnType<typeof builders>>(pm: TBuilder, config?: GeneratorConfigEntry<any, any, any, any>[]): Node;
|
|
5
|
+
export declare function pickWeightedChild(options: [string, number][]): string | undefined;
|
|
@@ -1,83 +1,42 @@
|
|
|
1
|
-
import { unreachable } from "@alanscodelog/utils/unreachable";
|
|
2
1
|
import { faker } from "@faker-js/faker";
|
|
3
|
-
import { generateRandomTree } from "./generateRandomTree.js";
|
|
4
2
|
import { generatorConfig } from "../generator.js";
|
|
5
|
-
export function generateRandomDoc(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const map = {};
|
|
10
|
-
function schemaFilter(name) {
|
|
11
|
-
return name !== "text" && name !== schema.topNodeType.name;
|
|
12
|
-
}
|
|
13
|
-
for (const entry of config) {
|
|
14
|
-
for (const node of entry.parents.names) {
|
|
15
|
-
if (node === "") throw new Error(`Empty node name ""`);
|
|
16
|
-
const type = entry.parents.type === "node" ? schema.nodes[node] : schema.marks[node];
|
|
17
|
-
if (type === void 0 && node !== "text") {
|
|
18
|
-
throw new Error(`${node} (on entry of type ${entry.parents.type}) not found in schema. Valid names are ${Object.keys(entry.parents.type === "node" ? schema.nodes : schema.marks)}`);
|
|
19
|
-
}
|
|
20
|
-
for (const node2 of entry.parents.names) {
|
|
21
|
-
const subEntry = { ...entry };
|
|
22
|
-
if (entry.ignoreValidation === void 0 || entry.ignoreValidation !== true) {
|
|
23
|
-
const childrenToValidate = (entry.children.names ?? []).filter((_) => !Array.isArray(entry.ignoreValidation) || !entry.ignoreValidation.includes(_));
|
|
24
|
-
for (const child of childrenToValidate) {
|
|
25
|
-
if (child === "") throw new Error(`Empty node name ""`);
|
|
26
|
-
if (entry.children.type === "node") {
|
|
27
|
-
const childType = schema.nodes[child];
|
|
28
|
-
const possibleNames = [childType.name, ...(childType.spec.group ?? "").split(" ").filter((e) => e !== "")];
|
|
29
|
-
const isAllowedChild = type.spec.content && possibleNames.some((n) => type.spec.content.includes(n));
|
|
30
|
-
if (!(isAllowedChild && schemaFilter(childType.name))) {
|
|
31
|
-
throw new Error(`Node ${node2} cannot contain child of type ${child}`);
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
const childType = schema.marks[child];
|
|
35
|
-
if (entry.parents.type === "node") {
|
|
36
|
-
} else {
|
|
37
|
-
const possibleNames = [childType.name, ...(childType.spec.group ?? "").split(" ").filter((e) => e !== "")];
|
|
38
|
-
const t = type;
|
|
39
|
-
const isExcluded = t.spec.excludes !== void 0 && possibleNames.some((n) => {
|
|
40
|
-
return t.spec.excludes.includes(n) || t.spec.excludes.includes("_");
|
|
41
|
-
});
|
|
42
|
-
if (isExcluded) {
|
|
43
|
-
throw new Error(`Mark ${node2} cannot contain mark child of type ${child}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
map[node2] = { ...subEntry };
|
|
50
|
-
}
|
|
3
|
+
export function generateRandomDoc(pm, config = generatorConfig) {
|
|
4
|
+
function generateNode(pm2, nodeConfig, parentType, depth = 0) {
|
|
5
|
+
if (!nodeConfig.parents.names.includes(parentType)) {
|
|
6
|
+
throw new Error(`Node config ${nodeConfig.parents.names.join(", ")} does not include parent type ${parentType}`);
|
|
51
7
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
8
|
+
const nodes = [];
|
|
9
|
+
if ("count" in nodeConfig) {
|
|
10
|
+
const childrenCount = nodeConfig.count(depth);
|
|
11
|
+
for (let i = 0; i < childrenCount; i++) {
|
|
12
|
+
const type = pickWeightedChild(nodeConfig.children.names);
|
|
13
|
+
if (type === void 0) continue;
|
|
14
|
+
if (nodeConfig?.skipChild?.(parentType, type, depth)) continue;
|
|
15
|
+
const childConfig = config.find((c) => {
|
|
16
|
+
return c.parents.names.includes(type);
|
|
17
|
+
});
|
|
18
|
+
if (!childConfig) continue;
|
|
19
|
+
const child = generateNode(pm2, childConfig, type, depth + 1);
|
|
20
|
+
if (child === void 0) continue;
|
|
21
|
+
nodes.push(child);
|
|
62
22
|
}
|
|
63
|
-
},
|
|
64
|
-
createNode: (children2, _isLeaf, data) => {
|
|
65
|
-
if (data === "") return void 0;
|
|
66
|
-
if (!data) unreachable();
|
|
67
|
-
const type = schema.nodes[data];
|
|
68
|
-
if (!type) return void 0;
|
|
69
|
-
const parent = map[data]?.create?.(data, children2) ?? builder[data]({}, ...children2);
|
|
70
|
-
if (checkAfterNodeCreation) {
|
|
71
|
-
;
|
|
72
|
-
parent?.check?.();
|
|
73
|
-
}
|
|
74
|
-
return parent;
|
|
75
23
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
24
|
+
return nodeConfig.create(pm2, parentType, nodes);
|
|
25
|
+
}
|
|
26
|
+
const firstEntry = config[0];
|
|
27
|
+
if (firstEntry === void 0) throw new Error("No config entries found.");
|
|
28
|
+
if (!("children" in firstEntry)) throw new Error("No children found in the first config entry. The first entry must have children.");
|
|
29
|
+
const startingType = pickWeightedChild(firstEntry.parents.names.map((name) => [name, 1]));
|
|
30
|
+
if (startingType === void 0) throw new Error("No starting type found.");
|
|
31
|
+
return generateNode(pm, config[0], startingType);
|
|
32
|
+
}
|
|
33
|
+
export function pickWeightedChild(options) {
|
|
34
|
+
const totalWeight = options.reduce((sum, [, weight]) => sum + weight, 0);
|
|
35
|
+
if (totalWeight === 0) return void 0;
|
|
36
|
+
let random = faker.number.float({ min: 0, max: totalWeight });
|
|
37
|
+
for (const [name, weight] of options) {
|
|
38
|
+
if (random < weight) return name;
|
|
39
|
+
random -= weight;
|
|
40
|
+
}
|
|
41
|
+
return options[0][0];
|
|
83
42
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Mark, Node } from "@tiptap/pm/model";
|
|
2
|
+
import type { builders } from "prosemirror-test-builder";
|
|
3
|
+
export declare function createGeneratorConfig<TBuilder extends ReturnType<typeof builders>, TChildType extends "node" | "text", TParentType extends "node" | "text", TChildNodeType extends TChildType extends "node" ? Node : (Mark | string), TParentNodeType extends TParentType extends "node" ? Node : (Mark | string)>(config: GeneratorConfigEntry<TBuilder, TChildType, TParentType, TChildNodeType, TParentNodeType>): GeneratorConfigEntry<TBuilder, TChildType, TParentType, TChildNodeType, TParentNodeType>;
|
|
4
|
+
export type GeneratorConfigEntry<TBuilder extends ReturnType<typeof builders>, TChildType extends "node" | "text" = "node" | "text", TParentType extends "node" | "text" = "node" | "text", TChildNodeType extends TChildType extends "node" ? Node : (Mark | string) = TChildType extends "node" ? Node : (Mark | string), TParentNodeType extends TParentType extends "node" ? Node : (Mark | string) = TParentType extends "node" ? Node : (Mark | string)> = {
|
|
5
|
+
/**
|
|
6
|
+
* Creates the node. Can return undefined to "terminate" the branch being created, the node will be filtered out of the nodes passed to it's parent.
|
|
7
|
+
*
|
|
8
|
+
* Note also, it is not required to use the children. You can ignore them or use a subset or create different ones if needed (some node types *require* text and if count returns 0 children will be empty, which can cause issues).
|
|
9
|
+
*/
|
|
10
|
+
create: (pm: TBuilder, parentType: string, children: TChildNodeType[]) => TParentNodeType | undefined;
|
|
11
|
+
parents: {
|
|
12
|
+
/**
|
|
13
|
+
* The type of the parent (node or "text") where "text" is a string or mark.
|
|
14
|
+
* Determines the call signature of the create function.
|
|
15
|
+
*/
|
|
16
|
+
type: TParentType;
|
|
17
|
+
/** Possible parent nodes that can have the given children. The children need not be direct descendants or real prosemirror nodes since `create` is what determines how they're created. */
|
|
18
|
+
names: string[];
|
|
19
|
+
};
|
|
20
|
+
} & ({} | {
|
|
21
|
+
skipChild?: (parentType: string, childType: string, depth: number) => boolean;
|
|
22
|
+
children: {
|
|
23
|
+
/** The type of children (node or "text") where "text" is a string or mark. */
|
|
24
|
+
type: TChildType;
|
|
25
|
+
names: [name: string, weight: number][];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* How many children to generate, is passed the depth so you can make the tree "slimmer" as it does deeper.
|
|
29
|
+
*
|
|
30
|
+
* See the `sometimesZero`, `influenceWithDepth` and `createRandomChildCountGenerator` helpers to make this easier to control.
|
|
31
|
+
*/
|
|
32
|
+
count: (depth: number) => number;
|
|
33
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
export function createPsuedoSentence({ min = 0, max = 10 } = {}) {
|
|
3
|
+
const sentenceLength = faker.number.int({ min, max });
|
|
4
|
+
const sentence = Array.from(
|
|
5
|
+
{ length: sentenceLength },
|
|
6
|
+
() => {
|
|
7
|
+
const doLorem = faker.number.float() < 0.5;
|
|
8
|
+
if (doLorem) {
|
|
9
|
+
return faker.lorem.word();
|
|
10
|
+
} else {
|
|
11
|
+
return faker.string.sample({ min: 1, max: 10 });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
).join(" ");
|
|
15
|
+
return sentence;
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combines `sometimesZero` and `influenceWithDepth` to create a function that returns a random number to pass to `count`.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* count: createRandomChildCountGenerator({ max: 10, depthInfluence: 0.5 })
|
|
6
|
+
* // or
|
|
7
|
+
* count: (depth: number) => createRandomChildCountGenerator({ max: 10, depthInfluence: 0.5 })(depth)
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare function createRandomChildCountGenerator({ max, zeroChance, depthInfluence }: {
|
|
11
|
+
max: number;
|
|
12
|
+
zeroChance?: number;
|
|
13
|
+
depthInfluence?: number;
|
|
14
|
+
}): (depth: number) => number;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { influenceWithDepth } from "./influenceWithDepth.js";
|
|
3
|
+
import { sometimesZero } from "./sometimesZero.js";
|
|
4
|
+
export function createRandomChildCountGenerator({
|
|
5
|
+
max = 10,
|
|
6
|
+
zeroChance = 0.05,
|
|
7
|
+
depthInfluence = 1
|
|
8
|
+
}) {
|
|
9
|
+
return (depth) => {
|
|
10
|
+
depth++;
|
|
11
|
+
return sometimesZero(
|
|
12
|
+
faker.number.int({ min: 1, max: influenceWithDepth(max, depth, depthInfluence) || 1 }),
|
|
13
|
+
zeroChance
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function getTextOrMarkLength(textOrMark) {
|
|
2
|
+
if (typeof textOrMark === "string") {
|
|
3
|
+
return textOrMark.length;
|
|
4
|
+
}
|
|
5
|
+
const textNodes = textOrMark.flat.map((_) => "text" in _ ? _.text.length : getTextOrMarkLength(_));
|
|
6
|
+
return textNodes.reduce((a, b) => a + b, 0);
|
|
7
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decreases the given number by dividing it by the depth + 1 (so it it's not zero). Returns a floored *int*.
|
|
3
|
+
*
|
|
4
|
+
* Intended to help decrease the number of nodes as the depth increases. Can be adjusted by the strength parameter, to, for example, decrease the adjustment for nodes that tend to be deeper.
|
|
5
|
+
*/
|
|
6
|
+
export declare function influenceWithDepth(num: number, depth: number, strength?: number): number;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns 0 instead of the given number depending on the chance passed (0.05 by default).
|
|
3
|
+
*
|
|
4
|
+
* This is useful to avoid too many empty nodes without having to increase the max a lot.
|
|
5
|
+
*
|
|
6
|
+
* You can pass chance 0 to always return the given number.
|
|
7
|
+
*/
|
|
8
|
+
export declare function sometimesZero(num: number, chance?: number, getRandom?: (options?: number | {
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
fractionDigits?: number;
|
|
12
|
+
multipleOf?: number;
|
|
13
|
+
}) => number): number;
|