vitest-prosemirror 0.2.2 → 0.3.1

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.
@@ -8,6 +8,13 @@ export declare interface CustomMatchers<R = unknown> {
8
8
  toEqualProseMirrorNode(expected: Node_2): R;
9
9
  }
10
10
 
11
+ export declare interface KeyboardModifiers {
12
+ altKey?: boolean;
13
+ ctrlKey?: boolean;
14
+ metaKey?: boolean;
15
+ shiftKey?: boolean;
16
+ }
17
+
11
18
  export declare interface Options {
12
19
  plugins: Array<Plugin_2>;
13
20
  }
@@ -17,9 +24,8 @@ export declare class ProseMirrorTester {
17
24
  get schema(): Schema;
18
25
  private readonly view;
19
26
  constructor(documentRoot: Node_2, options?: Partial<Options>);
20
- insertText(text: string): void;
27
+ insertText(text: string, modifiers?: KeyboardModifiers): void;
21
28
  selectText(selection: TesterSelection): void;
22
- shortcut(text: string): void;
23
29
  private getSelection;
24
30
  }
25
31
 
@@ -28,11 +34,6 @@ export declare type TesterSelection = "all" | "end" | "start" | {
28
34
  to: number;
29
35
  } | Selection_2 | number;
30
36
 
31
- /**
32
- * @public
33
- */
34
- export declare function trimProseMirrorNode(node: Node_2): Node_2;
35
-
36
37
  export { }
37
38
 
38
39
 
@@ -2,8 +2,6 @@ import { expect } from "vitest";
2
2
  import stringifyObject from "stringify-object";
3
3
  import { EditorState, AllSelection, TextSelection } from "prosemirror-state";
4
4
  import { EditorView } from "prosemirror-view";
5
- import { Keyboard } from "test-keyboard";
6
- import { Fragment } from "prosemirror-model";
7
5
  function getMarks(marks, origContent) {
8
6
  let content = `'${origContent}'`;
9
7
  for (const mark of [...marks].reverse()) {
@@ -28,33 +26,116 @@ const renamedTypes = {
28
26
  paragraph: "p"
29
27
  };
30
28
  function stringifyProseMirrorNode(node, indentation = "") {
31
- var _a;
32
- const nextIndentation = `${indentation} `;
33
29
  if (node.type.name === "text") {
34
30
  return `${indentation}${getMarks(node.marks, node.text ?? "")}`;
35
31
  }
36
32
  const type = renamedTypes[node.type.name] ?? node.type.name;
37
33
  const content = [];
38
- const hasAttrs = Object.keys(node.attrs).length > 0;
39
- if (hasAttrs) {
34
+ const nextIndentation = `${indentation} `;
35
+ if (Object.keys(node.attrs).length > 0) {
40
36
  content.push(
41
- stringifyObject(node.attrs, { indent: " ", inlineCharacterLimit: 1e3 })
37
+ `${nextIndentation}${stringifyObject(node.attrs, { indent: " ", inlineCharacterLimit: 1e3 })},`
42
38
  );
43
39
  }
44
40
  node.content.forEach((item) => {
45
- content.push(stringifyProseMirrorNode(item, nextIndentation));
41
+ content.push(`${stringifyProseMirrorNode(item, nextIndentation)},`);
46
42
  });
47
- if (!hasAttrs && content.length === 1 && ((_a = node.content.firstChild) == null ? void 0 : _a.type.name) === "text") {
43
+ if (content.length === 0) {
44
+ return `${indentation}${type}()`;
45
+ }
46
+ if (content.length === 1 && node.content.firstChild?.type.name === "text") {
48
47
  return `${indentation}${type}(${stringifyProseMirrorNode(node.content.firstChild, "")})`;
49
48
  }
50
- const joiner = `,
51
- `;
52
- const prefix = hasAttrs ? `
53
- ${nextIndentation}` : content.length > 0 ? "\n" : "";
54
- const postfix = content.length > 0 ? `
55
- ${indentation}` : "";
56
- return `${indentation}${type}(${prefix}${content.join(joiner)}${postfix})`;
49
+ return `${indentation}${type}(
50
+ ${content.join("\n")}
51
+ ${indentation})`;
52
+ }
53
+ function tokenizeKeyboardInput(input) {
54
+ const output = [];
55
+ let currentGroupOpener = null;
56
+ let group = "";
57
+ for (const char of input) {
58
+ if (currentGroupOpener !== null) {
59
+ if (["]", "}"].includes(char)) {
60
+ if (group.endsWith("\\") && char === matchingBrace(currentGroupOpener)) {
61
+ group = group.slice(0, -2) + char;
62
+ } else if (char === matchingBrace(currentGroupOpener)) {
63
+ if (group.length === 4 && group.startsWith("Key")) {
64
+ output.push(group.slice(3).toLowerCase());
65
+ } else {
66
+ output.push(group);
67
+ }
68
+ currentGroupOpener = null;
69
+ group = "";
70
+ } else {
71
+ group += char;
72
+ }
73
+ } else if (group === "" && currentGroupOpener === char) {
74
+ output.push(char);
75
+ currentGroupOpener = null;
76
+ group = "";
77
+ } else {
78
+ group += char;
79
+ }
80
+ } else if (["[", "{"].includes(char)) {
81
+ currentGroupOpener = char;
82
+ } else {
83
+ output.push(char);
84
+ }
85
+ }
86
+ output.forEach(assertSupported);
87
+ return output;
57
88
  }
89
+ function assertSupported(character) {
90
+ if (/^\/.+/u.exec(character) || /.+>[\d]*\/?$/u.exec(character)) {
91
+ throw new Error("Unsupported keyboard input");
92
+ }
93
+ }
94
+ function matchingBrace(opener) {
95
+ return opener === "{" ? "}" : "]";
96
+ }
97
+ class KeyboardEventMock extends KeyboardEvent {
98
+ constructor(onPreventDefault, type, eventInitDict) {
99
+ super(type, eventInitDict);
100
+ this.onPreventDefault = onPreventDefault;
101
+ }
102
+ preventDefault() {
103
+ super.preventDefault();
104
+ this.onPreventDefault();
105
+ }
106
+ }
107
+ const _MutationObserverMock = class _MutationObserverMock {
108
+ constructor(callback) {
109
+ this.callback = callback;
110
+ this.target = void 0;
111
+ }
112
+ static createMutation(target, mutationRecords) {
113
+ const observer = _MutationObserverMock.activeObservers.get(target);
114
+ if (observer === void 0) {
115
+ return;
116
+ }
117
+ observer.callback(
118
+ mutationRecords,
119
+ observer
120
+ );
121
+ }
122
+ disconnect() {
123
+ if (this.target !== void 0) {
124
+ _MutationObserverMock.activeObservers.delete(this.target);
125
+ }
126
+ this.target = void 0;
127
+ }
128
+ observe(target) {
129
+ this.target = target;
130
+ _MutationObserverMock.activeObservers.set(target, this);
131
+ }
132
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this -- Mocking another method
133
+ takeRecords() {
134
+ return [];
135
+ }
136
+ };
137
+ _MutationObserverMock.activeObservers = /* @__PURE__ */ new Map();
138
+ let MutationObserverMock = _MutationObserverMock;
58
139
  class ProseMirrorTester {
59
140
  get doc() {
60
141
  return this.view.state.doc;
@@ -72,49 +153,109 @@ class ProseMirrorTester {
72
153
  doc: documentRoot,
73
154
  plugins: options.plugins ?? []
74
155
  });
156
+ global.MutationObserver = MutationObserverMock;
75
157
  this.view = new EditorView(element, {
76
158
  state
77
159
  });
78
160
  }
79
- insertText(text) {
80
- const keys = Keyboard.create({
81
- target: this.view.dom
82
- }).start();
83
- for (const character of text) {
84
- keys.char({ text: character, typing: true });
85
- if (this.view.someProp(
86
- "handleTextInput",
87
- (f) => f(
88
- this.view,
89
- this.view.state.selection.from,
90
- this.view.state.selection.from,
91
- character
161
+ insertText(text, modifiers) {
162
+ for (const key of tokenizeKeyboardInput(text)) {
163
+ const character = keyToChar(key);
164
+ let keydownPrevented = false;
165
+ this.view.dispatchEvent(
166
+ new KeyboardEventMock(
167
+ () => {
168
+ keydownPrevented = true;
169
+ },
170
+ "keydown",
171
+ {
172
+ bubbles: true,
173
+ charCode: character.charCodeAt(0),
174
+ key,
175
+ ...modifiers
176
+ }
92
177
  )
93
- ) !== true) {
94
- this.view.dispatch(
95
- this.view.state.tr.insertText(
96
- character,
97
- this.view.state.selection.from,
98
- this.view.state.selection.from
99
- )
100
- );
178
+ );
179
+ if (keydownPrevented) {
180
+ continue;
181
+ }
182
+ this.view.dispatchEvent(
183
+ new KeyboardEvent("keypress", {
184
+ bubbles: true,
185
+ charCode: character.charCodeAt(0),
186
+ key,
187
+ keyCode: character.charCodeAt(0),
188
+ ...modifiers
189
+ })
190
+ );
191
+ const domNode = this.view.domAtPos(this.view.state.selection.from).node;
192
+ if (domNode.childNodes.length === 1 && domNode.firstChild instanceof HTMLBRElement && domNode.firstChild.classList.contains("ProseMirror-trailingBreak")) {
193
+ const brNode = domNode.firstChild;
194
+ const textNode = new Text(character);
195
+ domNode.removeChild(brNode);
196
+ domNode.appendChild(textNode);
197
+ MutationObserverMock.createMutation(this.view.dom, [
198
+ {
199
+ addedNodes: [textNode],
200
+ attributeName: null,
201
+ attributeNamespace: null,
202
+ nextSibling: brNode,
203
+ oldValue: null,
204
+ previousSibling: null,
205
+ removedNodes: [],
206
+ target: domNode,
207
+ type: "childList"
208
+ },
209
+ {
210
+ addedNodes: [],
211
+ attributeName: null,
212
+ attributeNamespace: null,
213
+ nextSibling: null,
214
+ oldValue: null,
215
+ previousSibling: textNode,
216
+ removedNodes: [brNode],
217
+ target: domNode,
218
+ type: "childList"
219
+ }
220
+ ]);
221
+ } else {
222
+ const target = findLastCharacterDataNode(domNode);
223
+ if (target === null) {
224
+ continue;
225
+ }
226
+ const oldValue = target.data;
227
+ const domOffset = this.view.state.selection.from - this.view.posAtDOM(target, 0);
228
+ target.data = target.data.slice(0, domOffset) + character + target.data.slice(domOffset);
229
+ MutationObserverMock.createMutation(this.view.dom, [
230
+ {
231
+ addedNodes: [],
232
+ attributeName: null,
233
+ attributeNamespace: null,
234
+ nextSibling: null,
235
+ oldValue,
236
+ previousSibling: null,
237
+ removedNodes: [],
238
+ target,
239
+ type: "characterData"
240
+ }
241
+ ]);
101
242
  }
243
+ this.view.dispatchEvent(
244
+ new KeyboardEvent("keyup", {
245
+ bubbles: true,
246
+ charCode: character.charCodeAt(0),
247
+ key,
248
+ keyCode: character.charCodeAt(0),
249
+ ...modifiers
250
+ })
251
+ );
102
252
  }
103
- keys.end();
104
253
  }
105
254
  selectText(selection) {
106
255
  this.view.dispatch(
107
256
  this.view.state.tr.setSelection(this.getSelection(selection))
108
257
  );
109
258
  }
110
- shortcut(text) {
111
- Keyboard.create({
112
- batch: true,
113
- target: this.view.dom
114
- }).start().mod({ text: text.replace(/Enter$/u, "\n") }).forEach(({ event }) => {
115
- this.view.dispatchEvent(event);
116
- }).end();
117
- }
118
259
  getSelection(selection) {
119
260
  if (selection === "all") {
120
261
  return new AllSelection(this.doc);
@@ -139,24 +280,26 @@ class ProseMirrorTester {
139
280
  return TextSelection.near(this.doc.resolve(pos));
140
281
  }
141
282
  }
142
- function trimProseMirrorNode(node) {
143
- let start = 0;
144
- let end = node.children.length;
145
- for (const child of node.children) {
146
- if (child.type.name === "paragraph" && ["", "\n"].includes(child.textContent)) {
147
- start++;
148
- } else {
149
- break;
150
- }
283
+ function findLastCharacterDataNode(node) {
284
+ if (node instanceof CharacterData) {
285
+ return node;
151
286
  }
152
- for (const child of node.children.slice().reverse()) {
153
- if (child.type.name === "paragraph" && ["", "\n"].includes(child.textContent)) {
154
- end--;
155
- } else {
156
- break;
287
+ for (const child of Array.from(node.childNodes).reverse()) {
288
+ const textNode = findLastCharacterDataNode(child);
289
+ if (textNode !== null) {
290
+ return textNode;
157
291
  }
158
292
  }
159
- return node.copy(Fragment.from(node.children.slice(start, end)));
293
+ return null;
294
+ }
295
+ function keyToChar(key) {
296
+ if (key === "Enter") {
297
+ return "\n";
298
+ }
299
+ if (key === "Tab") {
300
+ return " ";
301
+ }
302
+ return key;
160
303
  }
161
304
  expect.extend({
162
305
  toEqualProseMirrorNode(received, expected) {
@@ -194,7 +337,6 @@ ${diffString}` : ""}`;
194
337
  }
195
338
  });
196
339
  export {
197
- ProseMirrorTester,
198
- trimProseMirrorNode
340
+ ProseMirrorTester
199
341
  };
200
342
  //# sourceMappingURL=vitest-prosemirror.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vitest-prosemirror.js","sources":["../src/stringifyProseMirrorNode.ts","../src/ProseMirrorTester.ts","../src/trimProseMirrorNode.ts","../src/index.ts"],"sourcesContent":["import type { Mark, Node } from \"prosemirror-model\";\n\nimport stringifyObject from \"stringify-object\";\n\nfunction getMarks(marks: ReadonlyArray<Mark>, origContent: string): string {\n let content = `'${origContent}'`;\n\n for (const mark of [...marks].reverse()) {\n const hasAttrs = Object.keys(mark.attrs).length > 0;\n const items: Array<string> = [content];\n\n if (hasAttrs) {\n items.unshift(\n stringifyObject(mark.attrs, {\n indent: \" \",\n inlineCharacterLimit: 1000,\n }),\n );\n }\n\n content = `${mark.type.name}(${items.join(\", \")})`;\n }\n\n return content;\n}\n\nconst renamedTypes: Record<string, string> = {\n hardBreak: \"br\",\n heading: \"h\",\n horizontalRule: \"hr\",\n paragraph: \"p\",\n};\n\nexport function stringifyProseMirrorNode(node: Node, indentation = \"\"): string {\n const nextIndentation = `${indentation} `;\n\n if (node.type.name === \"text\") {\n return `${indentation}${getMarks(node.marks, node.text ?? \"\")}`;\n }\n\n const type = renamedTypes[node.type.name] ?? node.type.name;\n const content: Array<string> = [];\n const hasAttrs = Object.keys(node.attrs).length > 0;\n\n if (hasAttrs) {\n content.push(\n stringifyObject(node.attrs, { indent: \" \", inlineCharacterLimit: 1000 }),\n );\n }\n\n node.content.forEach((item) => {\n content.push(stringifyProseMirrorNode(item, nextIndentation));\n });\n\n if (\n !hasAttrs &&\n content.length === 1 &&\n node.content.firstChild?.type.name === \"text\"\n ) {\n return `${indentation}${type}(${stringifyProseMirrorNode(node.content.firstChild, \"\")})`;\n }\n\n const joiner = `,\\n`;\n const prefix = hasAttrs\n ? `\\n${nextIndentation}`\n : content.length > 0\n ? \"\\n\"\n : \"\";\n const postfix = content.length > 0 ? `\\n${indentation}` : \"\";\n\n return `${indentation}${type}(${prefix}${content.join(joiner)}${postfix})`;\n}\n","import type { Node, Schema } from \"prosemirror-model\";\n\nimport {\n AllSelection,\n EditorState,\n type Plugin,\n type Selection,\n TextSelection,\n} from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\nimport { Keyboard } from \"test-keyboard\";\n\nexport interface Options {\n plugins: Array<Plugin>;\n}\n\nexport type TesterSelection =\n | \"all\"\n | \"end\"\n | \"start\"\n | { from: number; to: number }\n | Selection\n | number;\n\nexport class ProseMirrorTester {\n public get doc(): Node {\n return this.view.state.doc;\n }\n\n public get schema(): Schema {\n return this.view.state.schema;\n }\n\n private readonly view: EditorView;\n\n public constructor(documentRoot: Node, options: Partial<Options> = {}) {\n if (typeof document === \"undefined\") {\n throw new Error(\"TODO\");\n }\n\n const element = document.createElement(\"div\");\n document.body.append(element);\n\n const state = EditorState.create({\n doc: documentRoot,\n plugins: options.plugins ?? [],\n });\n this.view = new EditorView(element, {\n state,\n });\n }\n\n public insertText(text: string): void {\n const keys = Keyboard.create({\n target: this.view.dom,\n }).start();\n\n for (const character of text) {\n keys.char({ text: character, typing: true });\n\n if (\n this.view.someProp(\"handleTextInput\", (f) =>\n f(\n this.view,\n this.view.state.selection.from,\n this.view.state.selection.from,\n character,\n ),\n ) !== true\n ) {\n this.view.dispatch(\n this.view.state.tr.insertText(\n character,\n this.view.state.selection.from,\n this.view.state.selection.from,\n ),\n );\n }\n }\n keys.end();\n }\n\n public selectText(selection: TesterSelection): void {\n this.view.dispatch(\n this.view.state.tr.setSelection(this.getSelection(selection)),\n );\n }\n\n public shortcut(text: string): void {\n Keyboard.create({\n batch: true,\n target: this.view.dom,\n })\n .start()\n .mod({ text: text.replace(/Enter$/u, \"\\n\") })\n .forEach(({ event }) => {\n this.view.dispatchEvent(event);\n })\n .end();\n }\n\n private getSelection(selection: TesterSelection): Selection {\n if (selection === \"all\") {\n return new AllSelection(this.doc);\n }\n\n if (\n typeof selection === \"object\" &&\n \"$anchor\" in selection &&\n \"$head\" in selection\n ) {\n return selection;\n }\n\n if (\n typeof selection === \"object\" &&\n \"from\" in selection &&\n \"to\" in selection\n ) {\n return TextSelection.between(\n this.doc.resolve(selection.from),\n this.doc.resolve(selection.to),\n );\n }\n\n let pos = 0;\n if (selection === \"start\") {\n pos = 0;\n } else if (selection === \"end\") {\n pos = this.doc.nodeSize - 2;\n } else {\n pos = selection;\n }\n\n return TextSelection.near(this.doc.resolve(pos));\n }\n}\n","import { Fragment, type Node } from \"prosemirror-model\";\n\n/**\n * @public\n */\nexport function trimProseMirrorNode(node: Node): Node {\n let start = 0;\n let end = node.children.length;\n for (const child of node.children) {\n if (\n child.type.name === \"paragraph\" &&\n [\"\", \"\\n\"].includes(child.textContent)\n ) {\n start++;\n } else {\n break;\n }\n }\n for (const child of node.children.slice().reverse()) {\n if (\n child.type.name === \"paragraph\" &&\n [\"\", \"\\n\"].includes(child.textContent)\n ) {\n end--;\n } else {\n break;\n }\n }\n return node.copy(Fragment.from(node.children.slice(start, end)));\n}\n","import type { Node } from \"prosemirror-model\";\n\nimport { expect } from \"vitest\";\n\nimport { stringifyProseMirrorNode } from \"./stringifyProseMirrorNode\";\n\nexport {\n type Options,\n ProseMirrorTester,\n type TesterSelection,\n} from \"./ProseMirrorTester\";\nexport { trimProseMirrorNode } from \"./trimProseMirrorNode\";\n\nexport interface CustomMatchers<R = unknown> {\n toEqualProseMirrorNode(expected: Node): R;\n}\n\n/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-explicit-any -- These are overridest for vitest matchers */\n\ndeclare module \"vitest\" {\n interface Assertion<T = any> extends CustomMatchers<T> {}\n interface AsymmetricMatchersContaining extends CustomMatchers {}\n}\n\n/* eslint-enable */\n\nexpect.extend({\n toEqualProseMirrorNode(received: Node, expected: Node) {\n const receivedDoc = `\\n${stringifyProseMirrorNode(received)}\\n`;\n const expectedDoc = `\\n${stringifyProseMirrorNode(expected)}\\n`;\n const pass = this.equals(receivedDoc, expectedDoc);\n const message = pass\n ? (): string =>\n `${this.utils.matcherHint(\".not.toEqualProsemirrorNode\")}\\n\\n` +\n `Expected value of document to not equal:\\n ${this.utils.printExpected(expectedDoc)}\\n` +\n `Actual:\\n ${this.utils.printReceived(receivedDoc)}`\n : (): string => {\n const diffString = this.utils.diff(expectedDoc, receivedDoc, {\n expand: this.expand ?? false,\n });\n return `${this.utils.matcherHint(\".toEqualProsemirrorNode\")}\\n\\nExpected value of document to equal:\\n${this.utils.printExpected(expectedDoc)}\\nActual:\\n${this.utils.printReceived(receivedDoc)}${diffString !== undefined ? `\\n\\nDifference:\\n\\n${diffString}` : \"\"}`;\n };\n return {\n message,\n pass,\n };\n },\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vitest-prosemirror.js","sources":["../src/stringifyProseMirrorNode.ts","../src/utils/keyboardInput.ts","../src/ProseMirrorTester.ts","../src/index.ts"],"sourcesContent":["import type { Mark, Node } from \"prosemirror-model\";\n\nimport stringifyObject from \"stringify-object\";\n\nfunction getMarks(marks: ReadonlyArray<Mark>, origContent: string): string {\n let content = `'${origContent}'`;\n\n for (const mark of [...marks].reverse()) {\n const hasAttrs = Object.keys(mark.attrs).length > 0;\n const items: Array<string> = [content];\n\n if (hasAttrs) {\n items.unshift(\n stringifyObject(mark.attrs, {\n indent: \" \",\n inlineCharacterLimit: 1000,\n }),\n );\n }\n\n content = `${mark.type.name}(${items.join(\", \")})`;\n }\n\n return content;\n}\n\nconst renamedTypes: Record<string, string> = {\n hardBreak: \"br\",\n heading: \"h\",\n horizontalRule: \"hr\",\n paragraph: \"p\",\n};\n\nexport function stringifyProseMirrorNode(node: Node, indentation = \"\"): string {\n if (node.type.name === \"text\") {\n return `${indentation}${getMarks(node.marks, node.text ?? \"\")}`;\n }\n\n const type = renamedTypes[node.type.name] ?? node.type.name;\n const content: Array<string> = [];\n const nextIndentation = `${indentation} `;\n\n if (Object.keys(node.attrs).length > 0) {\n content.push(\n `${nextIndentation}${stringifyObject(node.attrs, { indent: \" \", inlineCharacterLimit: 1000 })},`,\n );\n }\n\n node.content.forEach((item) => {\n content.push(`${stringifyProseMirrorNode(item, nextIndentation)},`);\n });\n\n if (content.length === 0) {\n return `${indentation}${type}()`;\n }\n\n if (content.length === 1 && node.content.firstChild?.type.name === \"text\") {\n return `${indentation}${type}(${stringifyProseMirrorNode(node.content.firstChild, \"\")})`;\n }\n\n return `${indentation}${type}(\\n${content.join(\"\\n\")}\\n${indentation})`;\n}\n","export function tokenizeKeyboardInput(input: string): Array<string> {\n const output = [];\n\n let currentGroupOpener: \"[\" | \"{\" | null = null;\n let group = \"\";\n for (const char of input) {\n if (currentGroupOpener !== null) {\n if ([\"]\", \"}\"].includes(char)) {\n if (\n group.endsWith(\"\\\\\") &&\n char === matchingBrace(currentGroupOpener)\n ) {\n group = group.slice(0, -2) + char;\n } else if (char === matchingBrace(currentGroupOpener)) {\n if (group.length === 4 && group.startsWith(\"Key\")) {\n output.push(group.slice(3).toLowerCase());\n } else {\n output.push(group);\n }\n currentGroupOpener = null;\n group = \"\";\n } else {\n group += char;\n }\n } else if (group === \"\" && currentGroupOpener === char) {\n output.push(char);\n currentGroupOpener = null;\n group = \"\";\n } else {\n group += char;\n }\n } else if ([\"[\", \"{\"].includes(char)) {\n currentGroupOpener = char as \"[\" | \"{\";\n } else {\n output.push(char);\n }\n }\n\n output.forEach(assertSupported);\n return output;\n}\n\nfunction assertSupported(character: string): never | void {\n if (/^\\/.+/u.exec(character) || /.+>[\\d]*\\/?$/u.exec(character)) {\n throw new Error(\"Unsupported keyboard input\");\n }\n}\n\nfunction matchingBrace(opener: \"[\" | \"{\"): \"]\" | \"}\" {\n return opener === \"{\" ? \"}\" : \"]\";\n}\n","import type { Node as ProseMirrorNode, Schema } from \"prosemirror-model\";\n\nimport {\n AllSelection,\n EditorState,\n type Plugin,\n type Selection,\n TextSelection,\n} from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport { tokenizeKeyboardInput } from \"./utils/keyboardInput\";\n\nexport interface KeyboardModifiers {\n altKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n}\n\nexport interface Options {\n plugins: Array<Plugin>;\n}\n\nexport type TesterSelection =\n | \"all\"\n | \"end\"\n | \"start\"\n | { from: number; to: number }\n | Selection\n | number;\n\ntype UsableMutationRecord = Omit<\n MutationRecord,\n \"addedNodes\" | \"removedNodes\"\n> & {\n addedNodes: Array<Node>;\n removedNodes: Array<Node>;\n};\n\nclass KeyboardEventMock extends KeyboardEvent {\n private readonly onPreventDefault: () => void;\n\n public constructor(\n onPreventDefault: () => void,\n type: string,\n eventInitDict?: KeyboardEventInit,\n ) {\n super(type, eventInitDict);\n this.onPreventDefault = onPreventDefault;\n }\n public override preventDefault(): void {\n super.preventDefault();\n this.onPreventDefault();\n }\n}\n\nclass MutationObserverMock {\n private static readonly activeObservers: Map<Node, MutationObserverMock> =\n new Map<Node, MutationObserverMock>();\n\n private readonly callback: MutationCallback;\n private target: Node | undefined;\n\n public constructor(callback: MutationCallback) {\n this.callback = callback;\n this.target = undefined;\n }\n\n public static createMutation(\n target: Node,\n mutationRecords: Array<UsableMutationRecord>,\n ): void {\n const observer = MutationObserverMock.activeObservers.get(target);\n if (observer === undefined) {\n return;\n }\n observer.callback(\n mutationRecords as unknown as Array<MutationRecord>,\n observer,\n );\n }\n\n public disconnect(): void {\n if (this.target !== undefined) {\n MutationObserverMock.activeObservers.delete(this.target);\n }\n this.target = undefined;\n }\n\n public observe(target: Node): void {\n this.target = target;\n MutationObserverMock.activeObservers.set(target, this);\n }\n\n // eslint-disable-next-line @typescript-eslint/class-methods-use-this -- Mocking another method\n public takeRecords(): Array<MutationRecord> {\n return [];\n }\n}\n\nexport class ProseMirrorTester {\n public get doc(): ProseMirrorNode {\n return this.view.state.doc;\n }\n\n public get schema(): Schema {\n return this.view.state.schema;\n }\n\n private readonly view: EditorView;\n\n public constructor(\n documentRoot: ProseMirrorNode,\n options: Partial<Options> = {},\n ) {\n if (typeof document === \"undefined\") {\n throw new Error(\"TODO\");\n }\n\n const element = document.createElement(\"div\");\n document.body.append(element);\n\n const state = EditorState.create({\n doc: documentRoot,\n plugins: options.plugins ?? [],\n });\n\n global.MutationObserver = MutationObserverMock;\n\n this.view = new EditorView(element, {\n state,\n });\n }\n\n public insertText(text: string, modifiers?: KeyboardModifiers): void {\n for (const key of tokenizeKeyboardInput(text)) {\n const character = keyToChar(key);\n\n let keydownPrevented = false;\n this.view.dispatchEvent(\n new KeyboardEventMock(\n () => {\n keydownPrevented = true;\n },\n \"keydown\",\n {\n bubbles: true,\n charCode: character.charCodeAt(0),\n key,\n ...modifiers,\n },\n ),\n );\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- False positive due to the value being set in a callback\n if (keydownPrevented) {\n continue;\n }\n\n this.view.dispatchEvent(\n new KeyboardEvent(\"keypress\", {\n bubbles: true,\n charCode: character.charCodeAt(0),\n key,\n keyCode: character.charCodeAt(0),\n ...modifiers,\n }),\n );\n\n const domNode = this.view.domAtPos(this.view.state.selection.from).node;\n if (\n domNode.childNodes.length === 1 &&\n domNode.firstChild instanceof HTMLBRElement &&\n domNode.firstChild.classList.contains(\"ProseMirror-trailingBreak\")\n ) {\n const brNode = domNode.firstChild;\n const textNode = new Text(character);\n domNode.removeChild(brNode);\n domNode.appendChild(textNode);\n MutationObserverMock.createMutation(this.view.dom, [\n {\n addedNodes: [textNode],\n attributeName: null,\n attributeNamespace: null,\n nextSibling: brNode,\n oldValue: null,\n previousSibling: null,\n removedNodes: [],\n target: domNode,\n type: \"childList\",\n },\n {\n addedNodes: [],\n attributeName: null,\n attributeNamespace: null,\n nextSibling: null,\n oldValue: null,\n previousSibling: textNode,\n removedNodes: [brNode],\n target: domNode,\n type: \"childList\",\n },\n ]);\n } else {\n const target = findLastCharacterDataNode(domNode);\n if (target === null) {\n continue;\n }\n const oldValue = target.data;\n const domOffset =\n this.view.state.selection.from - this.view.posAtDOM(target, 0);\n target.data =\n target.data.slice(0, domOffset) +\n character +\n target.data.slice(domOffset);\n MutationObserverMock.createMutation(this.view.dom, [\n {\n addedNodes: [],\n attributeName: null,\n attributeNamespace: null,\n nextSibling: null,\n oldValue,\n previousSibling: null,\n removedNodes: [],\n target,\n type: \"characterData\",\n },\n ]);\n }\n\n this.view.dispatchEvent(\n new KeyboardEvent(\"keyup\", {\n bubbles: true,\n charCode: character.charCodeAt(0),\n key,\n keyCode: character.charCodeAt(0),\n ...modifiers,\n }),\n );\n }\n }\n\n public selectText(selection: TesterSelection): void {\n this.view.dispatch(\n this.view.state.tr.setSelection(this.getSelection(selection)),\n );\n }\n\n private getSelection(selection: TesterSelection): Selection {\n if (selection === \"all\") {\n return new AllSelection(this.doc);\n }\n\n if (\n typeof selection === \"object\" &&\n \"$anchor\" in selection &&\n \"$head\" in selection\n ) {\n return selection;\n }\n\n if (\n typeof selection === \"object\" &&\n \"from\" in selection &&\n \"to\" in selection\n ) {\n return TextSelection.between(\n this.doc.resolve(selection.from),\n this.doc.resolve(selection.to),\n );\n }\n\n let pos = 0;\n if (selection === \"start\") {\n pos = 0;\n } else if (selection === \"end\") {\n pos = this.doc.nodeSize - 2;\n } else {\n pos = selection;\n }\n\n return TextSelection.near(this.doc.resolve(pos));\n }\n}\n\nfunction findLastCharacterDataNode(node: Node): CharacterData | null {\n if (node instanceof CharacterData) {\n return node;\n }\n for (const child of Array.from(node.childNodes).reverse()) {\n const textNode = findLastCharacterDataNode(child);\n if (textNode !== null) {\n return textNode;\n }\n }\n return null;\n}\n\nfunction keyToChar(key: string): string {\n if (key === \"Enter\") {\n return \"\\n\";\n }\n if (key === \"Tab\") {\n return \"\\t\";\n }\n return key;\n}\n","import type { Node } from \"prosemirror-model\";\n\nimport { expect } from \"vitest\";\n\nimport { stringifyProseMirrorNode } from \"./stringifyProseMirrorNode\";\n\nexport {\n type KeyboardModifiers,\n type Options,\n ProseMirrorTester,\n type TesterSelection,\n} from \"./ProseMirrorTester\";\n\nexport interface CustomMatchers<R = unknown> {\n toEqualProseMirrorNode(expected: Node): R;\n}\n\n/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-explicit-any -- These are overridest for vitest matchers */\n\ndeclare module \"vitest\" {\n interface Assertion<T = any> extends CustomMatchers<T> {}\n interface AsymmetricMatchersContaining extends CustomMatchers {}\n}\n\n/* eslint-enable */\n\nexpect.extend({\n toEqualProseMirrorNode(received: Node, expected: Node) {\n const receivedDoc = `\\n${stringifyProseMirrorNode(received)}\\n`;\n const expectedDoc = `\\n${stringifyProseMirrorNode(expected)}\\n`;\n const pass = this.equals(receivedDoc, expectedDoc);\n const message = pass\n ? (): string =>\n `${this.utils.matcherHint(\".not.toEqualProsemirrorNode\")}\\n\\n` +\n `Expected value of document to not equal:\\n ${this.utils.printExpected(expectedDoc)}\\n` +\n `Actual:\\n ${this.utils.printReceived(receivedDoc)}`\n : (): string => {\n const diffString = this.utils.diff(expectedDoc, receivedDoc, {\n expand: this.expand ?? false,\n });\n return `${this.utils.matcherHint(\".toEqualProsemirrorNode\")}\\n\\nExpected value of document to equal:\\n${this.utils.printExpected(expectedDoc)}\\nActual:\\n${this.utils.printReceived(receivedDoc)}${diffString !== undefined ? `\\n\\nDifference:\\n\\n${diffString}` : \"\"}`;\n };\n return {\n message,\n pass,\n };\n },\n});\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitest-prosemirror",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "A plugin for Vitest that enables you to write tests using the ProseMirror editor",
5
5
  "keywords": [
6
6
  "vitest",
@@ -11,69 +11,72 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/marekdedic/vitest-prosemirror/issues"
13
13
  },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/marekdedic/vitest-prosemirror.git"
17
+ },
14
18
  "license": "MIT",
15
19
  "author": "Marek Dědič",
20
+ "sideEffects": true,
16
21
  "type": "module",
17
- "module": "dist/vitest-prosemirror.js",
18
- "types": "dist/vitest-prosemirror.d.ts",
19
22
  "exports": {
20
23
  ".": {
21
24
  "import": "./dist/vitest-prosemirror.js"
22
25
  }
23
26
  },
24
- "sideEffects": true,
27
+ "module": "dist/vitest-prosemirror.js",
28
+ "types": "dist/vitest-prosemirror.d.ts",
25
29
  "files": [
26
- "dist",
27
- "LICENSE",
28
- "README.md"
30
+ "dist"
29
31
  ],
30
- "repository": {
31
- "type": "git",
32
- "url": "git+https://github.com/marekdedic/vitest-prosemirror.git"
33
- },
34
32
  "scripts": {
35
- "clean": "rimraf dist/*",
36
33
  "prebuild": "npm run clean",
37
34
  "build": "vite build",
35
+ "clean": "rimraf dist/*",
36
+ "lint": "eslint",
38
37
  "start": "vite build --watch",
39
- "lint": "eslint --color 'src/**/*.ts' 'tests/**/*.ts' '*.config.{js,ts}'",
40
38
  "test": "vitest",
41
39
  "test-coverage": "vitest run --coverage"
42
40
  },
43
- "peerDependencies": {
44
- "vitest": "^2.1.9 || ^3.0.7"
45
- },
46
- "peerDependenciesMeta": {
47
- "vitest": {
48
- "optional": true
49
- }
50
- },
51
41
  "dependencies": {
52
42
  "prosemirror-model": "^1.24.1",
53
43
  "prosemirror-state": "^1.4.3",
54
44
  "prosemirror-view": "^1.38.0",
55
- "stringify-object": "^5.0.0",
56
- "test-keyboard": "^2.0.7"
45
+ "stringify-object": "^6.0.0"
57
46
  },
58
47
  "devDependencies": {
59
48
  "@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
60
49
  "@eslint/js": "^9.9.1",
61
- "@types/node": "^22.13.8",
50
+ "@eslint/json": "^0.13.0",
51
+ "@eslint/markdown": "^7.0.0",
52
+ "@types/node": "^24.0.2",
62
53
  "@types/stringify-object": "^4.0.5",
63
- "@vitest/coverage-v8": "^3.0.7 <3.0.8",
64
- "@vitest/eslint-plugin": "^1.1.36",
54
+ "@vitest/coverage-v8": "^4.0.4",
55
+ "@vitest/eslint-plugin": "^1.3.26",
65
56
  "eslint": "^9.9.0",
66
57
  "eslint-config-prettier": "^10.0.1",
58
+ "eslint-plugin-package-json": "^0.59.0",
67
59
  "eslint-plugin-perfectionist": "^4.1.2",
68
- "eslint-plugin-prefer-arrow-functions": "^3.4.0 <3.7",
60
+ "eslint-plugin-prefer-arrow-functions": "^3.9.1",
69
61
  "eslint-plugin-prettier": "^5.1.3",
70
- "jsdom": "^26.0.0",
62
+ "jsdom": "^27.0.0",
71
63
  "prettier": "^3.3.0",
64
+ "prosemirror-commands": "^1.7.1",
65
+ "prosemirror-inputrules": "^1.5.0",
66
+ "prosemirror-keymap": "^1.2.3",
72
67
  "prosemirror-schema-basic": "^1.2.3",
73
68
  "rimraf": "^6.0.1",
74
69
  "typescript": "^5.3.3",
75
70
  "typescript-eslint": "^8.2.0",
76
- "vite": "^6.0.2",
71
+ "vite": "^7.0.0",
77
72
  "vite-plugin-dts": "^4.5.1"
73
+ },
74
+ "peerDependencies": {
75
+ "vitest": "^2.1.9 || ^3.0.7 || ^4.0.4"
76
+ },
77
+ "peerDependenciesMeta": {
78
+ "vitest": {
79
+ "optional": true
80
+ }
78
81
  }
79
82
  }