@pixerate/editor 0.44.0 → 0.46.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/README.md +29 -3
- package/dist/agent/index.cjs +548 -45
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +47 -17
- package/dist/agent/index.d.ts +47 -17
- package/dist/agent/index.js +536 -33
- package/dist/agent/index.js.map +1 -1
- package/dist/{builtins-BLud97fC.d.cts → builtins-CZW-aYKS.d.cts} +1 -1
- package/dist/{builtins-D0BDyAgw.d.ts → builtins-DghNQbT-.d.ts} +1 -1
- package/dist/chart/index.cjs +1984 -0
- package/dist/chart/index.cjs.map +1 -0
- package/dist/chart/index.d.cts +646 -0
- package/dist/chart/index.d.ts +646 -0
- package/dist/chart/index.js +1984 -0
- package/dist/chart/index.js.map +1 -0
- package/dist/{chunk-I6BZB5ZH.cjs → chunk-EFDCLENW.cjs} +73 -6
- package/dist/chunk-EFDCLENW.cjs.map +1 -0
- package/dist/chunk-HHQ4XJWT.js +826 -0
- package/dist/chunk-HHQ4XJWT.js.map +1 -0
- package/dist/chunk-J3R2OWOE.cjs +1465 -0
- package/dist/chunk-J3R2OWOE.cjs.map +1 -0
- package/dist/chunk-K2LVZ4FA.cjs +826 -0
- package/dist/chunk-K2LVZ4FA.cjs.map +1 -0
- package/dist/{chunk-6MDQKHRH.cjs → chunk-N4MLNJPO.cjs} +21 -899
- package/dist/chunk-N4MLNJPO.cjs.map +1 -0
- package/dist/chunk-PQM5W7ZN.js +168 -0
- package/dist/chunk-PQM5W7ZN.js.map +1 -0
- package/dist/{chunk-DDADOHJW.js → chunk-Q25ZS4F7.js} +5 -883
- package/dist/chunk-Q25ZS4F7.js.map +1 -0
- package/dist/chunk-TK2XZK6Z.js +1465 -0
- package/dist/chunk-TK2XZK6Z.js.map +1 -0
- package/dist/commands/index.cjs +3 -2
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.d.cts +5 -5
- package/dist/commands/index.d.ts +5 -5
- package/dist/commands/index.js +2 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/extensions/index.cjs +4 -4
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +3 -3
- package/dist/extensions/index.d.ts +3 -3
- package/dist/extensions/index.js +12 -12
- package/dist/generation/index.cjs +2 -2
- package/dist/generation/index.d.cts +4 -4
- package/dist/generation/index.d.ts +4 -4
- package/dist/generation/index.js +1 -1
- package/dist/image-editor/index.cjs +24 -24
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +2 -2
- package/dist/image-editor/index.d.ts +2 -2
- package/dist/image-editor/index.js +24 -24
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-C6gaQRH0.d.cts → index-CfOQf70b.d.cts} +1 -1
- package/dist/{index-DXAv_R08.d.ts → index-jwJ_onWf.d.ts} +1 -1
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +12 -12
- package/dist/parameters/index.d.cts +2 -2
- package/dist/parameters/index.d.ts +2 -2
- package/dist/{registry-DnzpgY27.d.cts → registry-B4l-lYts.d.cts} +1 -1
- package/dist/{registry-DhVUZioj.d.ts → registry-BfVD-vVg.d.ts} +1 -1
- package/dist/{registry-BDe-vlv3.d.ts → registry-CSlH4iUn.d.ts} +1 -1
- package/dist/{registry-D0GADKc7.d.cts → registry-vz6HOiiy.d.cts} +1 -1
- package/dist/{schema-DYDGdYL9.d.cts → schema-Di0CS6Pe.d.cts} +26 -2
- package/dist/{schema-DYDGdYL9.d.ts → schema-Di0CS6Pe.d.ts} +26 -2
- package/dist/tools/index.cjs +37 -3
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.d.cts +871 -11
- package/dist/tools/index.d.ts +871 -11
- package/dist/tools/index.js +36 -2
- package/dist/vector/index.d.cts +2 -2
- package/dist/vector/index.d.ts +2 -2
- package/package.json +6 -1
- package/dist/chunk-36BLROHV.js +0 -438
- package/dist/chunk-36BLROHV.js.map +0 -1
- package/dist/chunk-5H2OPMXZ.js +0 -586
- package/dist/chunk-5H2OPMXZ.js.map +0 -1
- package/dist/chunk-6MDQKHRH.cjs.map +0 -1
- package/dist/chunk-D6S5M7HV.js +0 -101
- package/dist/chunk-D6S5M7HV.js.map +0 -1
- package/dist/chunk-DDADOHJW.js.map +0 -1
- package/dist/chunk-I6BZB5ZH.cjs.map +0 -1
- package/dist/chunk-MC2LQN5S.cjs +0 -586
- package/dist/chunk-MC2LQN5S.cjs.map +0 -1
- package/dist/chunk-V7CC7RZ6.cjs +0 -438
- package/dist/chunk-V7CC7RZ6.cjs.map +0 -1
|
@@ -0,0 +1,1465 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isTrackChangesEnabled
|
|
3
|
+
} from "./chunk-SWE3NPOU.js";
|
|
4
|
+
|
|
5
|
+
// src/extensions/table/nesting.ts
|
|
6
|
+
import { Fragment, Slice } from "@tiptap/pm/model";
|
|
7
|
+
import { Plugin, PluginKey, Selection } from "@tiptap/pm/state";
|
|
8
|
+
import {
|
|
9
|
+
CellSelection,
|
|
10
|
+
__pastedCells,
|
|
11
|
+
handlePaste as handleTablePaste
|
|
12
|
+
} from "@tiptap/pm/tables";
|
|
13
|
+
var ALLOW_NESTED_TABLES_META = "allowNestedTables";
|
|
14
|
+
var tableNestingPluginKey = new PluginKey("tableNesting");
|
|
15
|
+
var roleOf = (node) => node.type.spec.tableRole;
|
|
16
|
+
var isTableNode = (node) => roleOf(node) === "table";
|
|
17
|
+
function outermostTableDepth($pos) {
|
|
18
|
+
for (let d = 1; d <= $pos.depth; d++) if (isTableNode($pos.node(d))) return d;
|
|
19
|
+
return -1;
|
|
20
|
+
}
|
|
21
|
+
function isInTableCell($pos) {
|
|
22
|
+
for (let d = $pos.depth; d > 0; d--) {
|
|
23
|
+
const role = roleOf($pos.node(d));
|
|
24
|
+
if (role === "cell" || role === "header_cell") return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
function sliceContainsTable(content) {
|
|
29
|
+
const fragment = content instanceof Slice ? content.content : content;
|
|
30
|
+
let found = false;
|
|
31
|
+
fragment.descendants((node) => {
|
|
32
|
+
if (found) return false;
|
|
33
|
+
if (isTableNode(node)) found = true;
|
|
34
|
+
return !found;
|
|
35
|
+
});
|
|
36
|
+
return found;
|
|
37
|
+
}
|
|
38
|
+
function insertSliceAfterTable(tr, from, to, slice) {
|
|
39
|
+
const $from = tr.doc.resolve(from);
|
|
40
|
+
const depth = outermostTableDepth($from);
|
|
41
|
+
if (depth < 0) return null;
|
|
42
|
+
const tableStart = $from.before(depth);
|
|
43
|
+
const tableEnd = $from.after(depth);
|
|
44
|
+
if (to > from && to < tableEnd) {
|
|
45
|
+
if (tr.selection instanceof CellSelection && tr.selection.from === from && tr.selection.to === to) {
|
|
46
|
+
tr.deleteSelection();
|
|
47
|
+
} else {
|
|
48
|
+
tr.delete(from, to);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const table = tr.doc.nodeAt(tableStart);
|
|
52
|
+
if (!table) return null;
|
|
53
|
+
const after = tableStart + table.nodeSize;
|
|
54
|
+
const before = tr.doc.content.size;
|
|
55
|
+
tr.replace(after, after, new Slice(slice.content, 0, 0));
|
|
56
|
+
return after + (tr.doc.content.size - before);
|
|
57
|
+
}
|
|
58
|
+
function handleTablePasteWithoutNesting(view, event, slice) {
|
|
59
|
+
const { state } = view;
|
|
60
|
+
const { selection } = state;
|
|
61
|
+
if (outermostTableDepth(selection.$from) < 0) return false;
|
|
62
|
+
if (selection instanceof CellSelection || __pastedCells(slice)) {
|
|
63
|
+
if (handleTablePaste(view, event, slice)) return true;
|
|
64
|
+
}
|
|
65
|
+
if (!sliceContainsTable(slice)) return false;
|
|
66
|
+
const tr = state.tr;
|
|
67
|
+
const end = insertSliceAfterTable(tr, selection.from, selection.to, slice);
|
|
68
|
+
if (end === null) return false;
|
|
69
|
+
tr.setSelection(Selection.near(tr.doc.resolve(end), -1));
|
|
70
|
+
view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function changedRanges(transactions, skip2) {
|
|
74
|
+
let ranges = [];
|
|
75
|
+
for (const tr of transactions) {
|
|
76
|
+
const skipped = skip2(tr);
|
|
77
|
+
for (const step of tr.steps) {
|
|
78
|
+
const map = step.getMap();
|
|
79
|
+
ranges = ranges.map(([from, to]) => [map.map(from, 1), map.map(to, -1)]).filter(([from, to]) => to > from);
|
|
80
|
+
if (skipped) continue;
|
|
81
|
+
map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
|
|
82
|
+
if (newEnd > newStart) ranges.push([newStart, newEnd]);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return ranges;
|
|
87
|
+
}
|
|
88
|
+
function findNestedTables(doc, ranges) {
|
|
89
|
+
const found = /* @__PURE__ */ new Set();
|
|
90
|
+
for (const [from, to] of ranges) {
|
|
91
|
+
doc.nodesBetween(from, to, (node, pos) => {
|
|
92
|
+
if (!isTableNode(node) || pos < from) return true;
|
|
93
|
+
if (isInTableCell(doc.resolve(pos))) {
|
|
94
|
+
found.add(pos);
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const sorted = [...found].sort((a, b) => a - b);
|
|
101
|
+
const outer = [];
|
|
102
|
+
for (const pos of sorted) {
|
|
103
|
+
const last = outer[outer.length - 1];
|
|
104
|
+
if (last === void 0 || pos >= last + doc.nodeAt(last).nodeSize) outer.push(pos);
|
|
105
|
+
}
|
|
106
|
+
return outer;
|
|
107
|
+
}
|
|
108
|
+
function unnestTables(tr, ranges) {
|
|
109
|
+
let changed = false;
|
|
110
|
+
for (let round = 0; round < 32 && ranges.length; round++) {
|
|
111
|
+
const nested = findNestedTables(tr.doc, ranges);
|
|
112
|
+
if (!nested.length) break;
|
|
113
|
+
const groups = /* @__PURE__ */ new Map();
|
|
114
|
+
for (const pos of nested) {
|
|
115
|
+
const $pos = tr.doc.resolve(pos);
|
|
116
|
+
const outer = $pos.before(outermostTableDepth($pos));
|
|
117
|
+
groups.set(outer, [...groups.get(outer) ?? [], pos]);
|
|
118
|
+
}
|
|
119
|
+
const next = [];
|
|
120
|
+
for (const outer of [...groups.keys()].sort((a, b) => b - a)) {
|
|
121
|
+
const positions = groups.get(outer);
|
|
122
|
+
const nodes = positions.map((pos) => tr.doc.nodeAt(pos));
|
|
123
|
+
for (let i = positions.length - 1; i >= 0; i--) {
|
|
124
|
+
const pos = positions[i];
|
|
125
|
+
const node = nodes[i];
|
|
126
|
+
const $pos = tr.doc.resolve(pos);
|
|
127
|
+
const parent = $pos.parent;
|
|
128
|
+
const filler = parent.childCount === 1 ? parent.type.contentMatch.defaultType?.createAndFill() : null;
|
|
129
|
+
if (filler) tr.replaceWith(pos, pos + node.nodeSize, filler);
|
|
130
|
+
else tr.delete(pos, pos + node.nodeSize);
|
|
131
|
+
}
|
|
132
|
+
const table = tr.doc.nodeAt(outer);
|
|
133
|
+
const after = outer + table.nodeSize;
|
|
134
|
+
const fragment = Fragment.fromArray(nodes);
|
|
135
|
+
tr.insert(after, fragment);
|
|
136
|
+
next.push([after, after + fragment.size]);
|
|
137
|
+
changed = true;
|
|
138
|
+
}
|
|
139
|
+
ranges = next;
|
|
140
|
+
}
|
|
141
|
+
return changed;
|
|
142
|
+
}
|
|
143
|
+
function replacesDocument(tr) {
|
|
144
|
+
return tr.steps.some((step, i) => {
|
|
145
|
+
const { from, to } = step;
|
|
146
|
+
return from === 0 && to !== void 0 && to >= tr.docs[i].content.size;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
var skip = (tr) => !tr.docChanged || tr.getMeta(ALLOW_NESTED_TABLES_META) === true || // Undo/redo and remote collaborative changes restore what was there.
|
|
150
|
+
!!tr.getMeta("history$") || !!tr.getMeta("y-sync$") || // Other plugins' housekeeping, e.g. Track Changes putting a deleted
|
|
151
|
+
// (nested) table back so the deletion can be reviewed.
|
|
152
|
+
!!tr.getMeta("appendedTransaction") || replacesDocument(tr);
|
|
153
|
+
function createTableNestingPlugin() {
|
|
154
|
+
return new Plugin({
|
|
155
|
+
key: tableNestingPluginKey,
|
|
156
|
+
props: {
|
|
157
|
+
handlePaste: (view, event, slice) => handleTablePasteWithoutNesting(view, event, slice)
|
|
158
|
+
},
|
|
159
|
+
appendTransaction(transactions, _oldState, newState) {
|
|
160
|
+
if (transactions.every(skip)) return null;
|
|
161
|
+
const ranges = changedRanges(transactions, skip);
|
|
162
|
+
if (!ranges.length) return null;
|
|
163
|
+
const tr = newState.tr;
|
|
164
|
+
if (!unnestTables(tr, ranges)) return null;
|
|
165
|
+
return tr;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/extensions/find-replace/pattern.ts
|
|
171
|
+
var FIND_PARAGRAPH_MARK = "\r";
|
|
172
|
+
var MAX_FIND_PATTERN_LENGTH = 1024;
|
|
173
|
+
var MAX_COUNT = 1e3;
|
|
174
|
+
var MAX_PROGRAM_SIZE = 2e4;
|
|
175
|
+
var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
176
|
+
function createSearchBudget(options = {}) {
|
|
177
|
+
return {
|
|
178
|
+
deadline: now() + (options.timeLimitMs ?? 250),
|
|
179
|
+
steps: options.maxSteps ?? 5e7,
|
|
180
|
+
exhausted: false
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
var PARA = 13;
|
|
184
|
+
var ANY = (cp) => cp !== PARA;
|
|
185
|
+
var LETTER = /\p{L}/u;
|
|
186
|
+
var PUNCT = /\p{P}/u;
|
|
187
|
+
var WORD = /[\p{L}\p{M}\p{Nd}\p{Pc}]/u;
|
|
188
|
+
var foldCache = /* @__PURE__ */ new Map();
|
|
189
|
+
function foldCodePoint(cp) {
|
|
190
|
+
if (cp < 128) return cp >= 65 && cp <= 90 ? cp + 32 : cp;
|
|
191
|
+
const cached = foldCache.get(cp);
|
|
192
|
+
if (cached !== void 0) return cached;
|
|
193
|
+
const lower = String.fromCodePoint(cp).toLowerCase();
|
|
194
|
+
const folded = [...lower].length === 1 ? lower.codePointAt(0) : cp;
|
|
195
|
+
if (foldCache.size < 4096) foldCache.set(cp, folded);
|
|
196
|
+
return folded;
|
|
197
|
+
}
|
|
198
|
+
function isWordChar(cp) {
|
|
199
|
+
if (cp < 0) return false;
|
|
200
|
+
if (cp < 128) {
|
|
201
|
+
return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 95;
|
|
202
|
+
}
|
|
203
|
+
return WORD.test(String.fromCodePoint(cp));
|
|
204
|
+
}
|
|
205
|
+
var isLetter = (cp) => cp < 128 ? cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 : LETTER.test(String.fromCodePoint(cp));
|
|
206
|
+
function isPunct(cp) {
|
|
207
|
+
if (cp < 128) {
|
|
208
|
+
return cp >= 33 && cp <= 47 || cp >= 58 && cp <= 64 || cp >= 91 && cp <= 96 || cp >= 123 && cp <= 126;
|
|
209
|
+
}
|
|
210
|
+
return cp >= 8208 && cp <= 8231 || cp === 161 || cp === 191 || cp === 171 || cp === 187 || PUNCT.test(String.fromCodePoint(cp));
|
|
211
|
+
}
|
|
212
|
+
var isSpace = (cp) => cp === 32 || cp === 9 || cp === 160;
|
|
213
|
+
function cpBefore(hay, pos) {
|
|
214
|
+
if (pos <= 0) return -1;
|
|
215
|
+
const low = hay.charCodeAt(pos - 1);
|
|
216
|
+
if (low >= 56320 && low <= 57343 && pos >= 2) {
|
|
217
|
+
const high = hay.charCodeAt(pos - 2);
|
|
218
|
+
if (high >= 55296 && high <= 56319) return hay.codePointAt(pos - 2);
|
|
219
|
+
}
|
|
220
|
+
return low;
|
|
221
|
+
}
|
|
222
|
+
var cpAt = (hay, pos) => pos < hay.length ? hay.codePointAt(pos) : -1;
|
|
223
|
+
var PatternError = class extends Error {
|
|
224
|
+
constructor(code, message) {
|
|
225
|
+
super(message);
|
|
226
|
+
this.code = code;
|
|
227
|
+
}
|
|
228
|
+
code;
|
|
229
|
+
};
|
|
230
|
+
var charNode = (test) => ({ k: "char", test });
|
|
231
|
+
var exact = (cp) => charNode((c) => c === cp);
|
|
232
|
+
var literalNode = (cp, caseInsensitive) => {
|
|
233
|
+
if (!caseInsensitive) return exact(cp);
|
|
234
|
+
const f = foldCodePoint(cp);
|
|
235
|
+
return charNode((_c, folded) => folded === f);
|
|
236
|
+
};
|
|
237
|
+
var star = (body, lazy) => ({ k: "rep", body, min: 0, max: -1, lazy });
|
|
238
|
+
function findCode(c) {
|
|
239
|
+
switch (c) {
|
|
240
|
+
case "p":
|
|
241
|
+
return exact(PARA);
|
|
242
|
+
case "t":
|
|
243
|
+
return exact(9);
|
|
244
|
+
case "?":
|
|
245
|
+
return charNode(ANY);
|
|
246
|
+
case "#":
|
|
247
|
+
return charNode((cp) => cp >= 48 && cp <= 57);
|
|
248
|
+
case "$":
|
|
249
|
+
return charNode((cp) => isLetter(cp));
|
|
250
|
+
case "^":
|
|
251
|
+
return exact(94);
|
|
252
|
+
case "l":
|
|
253
|
+
return exact(10);
|
|
254
|
+
case "m":
|
|
255
|
+
return exact(12);
|
|
256
|
+
case "n":
|
|
257
|
+
return exact(14);
|
|
258
|
+
case "+":
|
|
259
|
+
return exact(8212);
|
|
260
|
+
case "=":
|
|
261
|
+
return exact(8211);
|
|
262
|
+
case "s":
|
|
263
|
+
return exact(160);
|
|
264
|
+
case "~":
|
|
265
|
+
return exact(8209);
|
|
266
|
+
case "-":
|
|
267
|
+
return exact(173);
|
|
268
|
+
case "w":
|
|
269
|
+
return { k: "rep", body: charNode((cp) => isSpace(cp)), min: 1, max: -1, lazy: false };
|
|
270
|
+
case "g":
|
|
271
|
+
return exact(65532);
|
|
272
|
+
case "%":
|
|
273
|
+
return exact(167);
|
|
274
|
+
case "v":
|
|
275
|
+
return exact(182);
|
|
276
|
+
default:
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function replaceCode(c) {
|
|
281
|
+
switch (c) {
|
|
282
|
+
case "p":
|
|
283
|
+
return FIND_PARAGRAPH_MARK;
|
|
284
|
+
case "t":
|
|
285
|
+
return " ";
|
|
286
|
+
case "^":
|
|
287
|
+
return "^";
|
|
288
|
+
case "l":
|
|
289
|
+
return "\n";
|
|
290
|
+
case "m":
|
|
291
|
+
return "\f";
|
|
292
|
+
case "n":
|
|
293
|
+
return "";
|
|
294
|
+
case "+":
|
|
295
|
+
return "\u2014";
|
|
296
|
+
case "=":
|
|
297
|
+
return "\u2013";
|
|
298
|
+
case "s":
|
|
299
|
+
return "\xA0";
|
|
300
|
+
case "~":
|
|
301
|
+
return "\u2011";
|
|
302
|
+
case "-":
|
|
303
|
+
return "\xAD";
|
|
304
|
+
case "%":
|
|
305
|
+
return "\xA7";
|
|
306
|
+
case "v":
|
|
307
|
+
return "\xB6";
|
|
308
|
+
default:
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function codeChar(n) {
|
|
313
|
+
switch (n) {
|
|
314
|
+
case 13:
|
|
315
|
+
return PARA;
|
|
316
|
+
case 11:
|
|
317
|
+
return 10;
|
|
318
|
+
case 12:
|
|
319
|
+
return 12;
|
|
320
|
+
case 14:
|
|
321
|
+
return 14;
|
|
322
|
+
case 30:
|
|
323
|
+
return 8209;
|
|
324
|
+
case 31:
|
|
325
|
+
return 173;
|
|
326
|
+
}
|
|
327
|
+
if (n > 1114111 || n >= 55296 && n <= 57343) return null;
|
|
328
|
+
if (n < 32 && n !== 9 || n >= 127 && n < 160) return null;
|
|
329
|
+
return n;
|
|
330
|
+
}
|
|
331
|
+
function numericCode(chars, i) {
|
|
332
|
+
const unicode = chars[i] === "u";
|
|
333
|
+
const start = unicode ? i + 1 : i;
|
|
334
|
+
const max = unicode ? 5 : 4;
|
|
335
|
+
let digits = "";
|
|
336
|
+
for (let j = start; j < chars.length && digits.length < max && /[0-9]/.test(chars[j]); j++) digits += chars[j];
|
|
337
|
+
if (!digits) return null;
|
|
338
|
+
const cp = codeChar(parseInt(digits, 10));
|
|
339
|
+
return cp === null ? null : { cp, used: start - i + digits.length };
|
|
340
|
+
}
|
|
341
|
+
var toChars = (s) => Array.from(s);
|
|
342
|
+
var cpOf = (ch) => ch.codePointAt(0);
|
|
343
|
+
function parseSpecial(query, o, caseInsensitive) {
|
|
344
|
+
const chars = toChars(query);
|
|
345
|
+
const atoms = [];
|
|
346
|
+
let spans = false;
|
|
347
|
+
let i = 0;
|
|
348
|
+
while (i < chars.length) {
|
|
349
|
+
const c = chars[i++];
|
|
350
|
+
if (c === "^" && !o.literal && i < chars.length) {
|
|
351
|
+
const n = chars[i];
|
|
352
|
+
const code = findCode(n);
|
|
353
|
+
if (code) {
|
|
354
|
+
if (n === "p") spans = true;
|
|
355
|
+
atoms.push(code);
|
|
356
|
+
i++;
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const num = numericCode(chars, i);
|
|
360
|
+
if (num) {
|
|
361
|
+
if (num.cp === PARA) spans = true;
|
|
362
|
+
atoms.push(literalNode(num.cp, caseInsensitive));
|
|
363
|
+
i += num.used;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const cp = cpOf(c);
|
|
368
|
+
if (o.ignorePunctuation && isPunct(cp) || o.ignoreWhitespace && isSpace(cp)) continue;
|
|
369
|
+
atoms.push(literalNode(cp, caseInsensitive));
|
|
370
|
+
}
|
|
371
|
+
const filler = o.ignorePunctuation && o.ignoreWhitespace ? (cp) => isPunct(cp) || isSpace(cp) : o.ignorePunctuation ? (cp) => isPunct(cp) : o.ignoreWhitespace ? (cp) => isSpace(cp) : null;
|
|
372
|
+
const items = [];
|
|
373
|
+
atoms.forEach((atom, index) => {
|
|
374
|
+
if (index > 0 && filler) items.push(star(charNode(filler), false));
|
|
375
|
+
items.push(atom);
|
|
376
|
+
});
|
|
377
|
+
return { node: { k: "cat", items }, spans };
|
|
378
|
+
}
|
|
379
|
+
function parseCount(body) {
|
|
380
|
+
const bad = () => new PatternError("invalid_pattern", `{${body}} is not a valid count`);
|
|
381
|
+
const num = (s) => {
|
|
382
|
+
const t = s.trim();
|
|
383
|
+
if (!t) return null;
|
|
384
|
+
if (!/^[0-9]+$/.test(t)) throw bad();
|
|
385
|
+
const n = parseInt(t, 10);
|
|
386
|
+
if (n > MAX_COUNT) throw new PatternError("invalid_pattern", `counts go up to ${MAX_COUNT}`);
|
|
387
|
+
return n;
|
|
388
|
+
};
|
|
389
|
+
const sep = body.search(/[,;]/);
|
|
390
|
+
if (sep < 0) {
|
|
391
|
+
const n = num(body);
|
|
392
|
+
if (n === null) throw bad();
|
|
393
|
+
return { min: n, max: n };
|
|
394
|
+
}
|
|
395
|
+
const a = num(body.slice(0, sep)) ?? 0;
|
|
396
|
+
const b = num(body.slice(sep + 1));
|
|
397
|
+
if (b !== null && b < a) throw bad();
|
|
398
|
+
return { min: a, max: b ?? -1 };
|
|
399
|
+
}
|
|
400
|
+
function parseClass(inner) {
|
|
401
|
+
let negated = false;
|
|
402
|
+
if (inner[0] === "!") {
|
|
403
|
+
negated = true;
|
|
404
|
+
inner = inner.slice(1);
|
|
405
|
+
}
|
|
406
|
+
if (inner.length === 0) throw new PatternError("invalid_pattern", "[ ] needs at least one character");
|
|
407
|
+
const singles = /* @__PURE__ */ new Set();
|
|
408
|
+
const ranges = [];
|
|
409
|
+
let i = 0;
|
|
410
|
+
while (i < inner.length) {
|
|
411
|
+
let c = inner[i];
|
|
412
|
+
if (c === "\\" && i + 1 < inner.length) c = inner[++i];
|
|
413
|
+
i++;
|
|
414
|
+
if (inner[i] === "-" && i + 1 < inner.length) {
|
|
415
|
+
const hi = inner[i + 1];
|
|
416
|
+
if (cpOf(hi) < cpOf(c)) throw new PatternError("invalid_pattern", `[${c}-${hi}] is not in ascending order`);
|
|
417
|
+
ranges.push([cpOf(c), cpOf(hi)]);
|
|
418
|
+
i += 2;
|
|
419
|
+
} else {
|
|
420
|
+
singles.add(cpOf(c));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const inSet = (cp) => singles.has(cp) || ranges.some(([lo, hi]) => cp >= lo && cp <= hi);
|
|
424
|
+
return negated ? (cp) => cp !== PARA && !inSet(cp) : (cp) => inSet(cp);
|
|
425
|
+
}
|
|
426
|
+
function parseWildcards(query) {
|
|
427
|
+
const chars = toChars(query);
|
|
428
|
+
const stack = [{ items: [], group: 0 }];
|
|
429
|
+
let groups = 0;
|
|
430
|
+
let spans = false;
|
|
431
|
+
const top = () => stack[stack.length - 1].items;
|
|
432
|
+
const quantify = (min, max, what) => {
|
|
433
|
+
const items = top();
|
|
434
|
+
const last = items[items.length - 1];
|
|
435
|
+
if (!last || last.k === "assert" || last.k === "rep") {
|
|
436
|
+
throw new PatternError("invalid_pattern", `${what} needs something to repeat before it`);
|
|
437
|
+
}
|
|
438
|
+
items[items.length - 1] = { k: "rep", body: last, min, max, lazy: false };
|
|
439
|
+
};
|
|
440
|
+
let i = 0;
|
|
441
|
+
while (i < chars.length) {
|
|
442
|
+
const c = chars[i++];
|
|
443
|
+
switch (c) {
|
|
444
|
+
case "?":
|
|
445
|
+
top().push(charNode(ANY));
|
|
446
|
+
break;
|
|
447
|
+
case "*":
|
|
448
|
+
top().push(star(charNode(ANY), true));
|
|
449
|
+
break;
|
|
450
|
+
case "@":
|
|
451
|
+
quantify(1, -1, "@");
|
|
452
|
+
break;
|
|
453
|
+
case "<":
|
|
454
|
+
top().push({ k: "assert", kind: "wordStart" });
|
|
455
|
+
break;
|
|
456
|
+
case ">":
|
|
457
|
+
top().push({ k: "assert", kind: "wordEnd" });
|
|
458
|
+
break;
|
|
459
|
+
case "(":
|
|
460
|
+
stack.push({ items: [], group: ++groups });
|
|
461
|
+
break;
|
|
462
|
+
case ")": {
|
|
463
|
+
if (stack.length === 1) throw new PatternError("invalid_pattern", "a ) has no opening (");
|
|
464
|
+
const frame = stack.pop();
|
|
465
|
+
top().push({ k: "group", index: frame.group, body: { k: "cat", items: frame.items } });
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
case "{": {
|
|
469
|
+
const end = chars.indexOf("}", i);
|
|
470
|
+
if (end < 0) throw new PatternError("invalid_pattern", "a { needs a closing }");
|
|
471
|
+
const { min, max } = parseCount(chars.slice(i, end).join(""));
|
|
472
|
+
quantify(min, max, `{${chars.slice(i, end).join("")}}`);
|
|
473
|
+
i = end + 1;
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
case "[": {
|
|
477
|
+
const end = chars.indexOf("]", i);
|
|
478
|
+
if (end < 0) throw new PatternError("invalid_pattern", "a [ needs a closing ]");
|
|
479
|
+
top().push(charNode(parseClass(chars.slice(i, end))));
|
|
480
|
+
i = end + 1;
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
case "\\": {
|
|
484
|
+
if (i >= chars.length) {
|
|
485
|
+
top().push(exact(92));
|
|
486
|
+
} else if (/[0-9]/.test(chars[i])) {
|
|
487
|
+
throw new PatternError("invalid_pattern", "back-references (\\1) work in Replace with, not in Find what");
|
|
488
|
+
} else {
|
|
489
|
+
top().push(exact(cpOf(chars[i++])));
|
|
490
|
+
}
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
case "^": {
|
|
494
|
+
if (i >= chars.length) {
|
|
495
|
+
top().push(exact(94));
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
const n = chars[i];
|
|
499
|
+
const code = findCode(n);
|
|
500
|
+
if (code) {
|
|
501
|
+
if (n === "p") spans = true;
|
|
502
|
+
top().push(code);
|
|
503
|
+
i++;
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
const num = numericCode(chars, i);
|
|
507
|
+
if (num) {
|
|
508
|
+
if (num.cp === PARA) spans = true;
|
|
509
|
+
top().push(exact(num.cp));
|
|
510
|
+
i += num.used;
|
|
511
|
+
} else {
|
|
512
|
+
top().push(exact(94));
|
|
513
|
+
}
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
default:
|
|
517
|
+
top().push(exact(cpOf(c)));
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (stack.length > 1) throw new PatternError("invalid_pattern", "a ( needs a closing )");
|
|
521
|
+
return { node: { k: "cat", items: stack[0].items }, spans, groups };
|
|
522
|
+
}
|
|
523
|
+
function compileProgram(node) {
|
|
524
|
+
const prog = [];
|
|
525
|
+
const push = (inst) => {
|
|
526
|
+
if (prog.length >= MAX_PROGRAM_SIZE) {
|
|
527
|
+
throw new PatternError("too_complex", "the pattern is too complex (too many repeats)");
|
|
528
|
+
}
|
|
529
|
+
prog.push(inst);
|
|
530
|
+
return prog.length - 1;
|
|
531
|
+
};
|
|
532
|
+
const emit = (n) => {
|
|
533
|
+
switch (n.k) {
|
|
534
|
+
case "char":
|
|
535
|
+
push({ op: 0 /* Char */, test: n.test });
|
|
536
|
+
return;
|
|
537
|
+
case "cat":
|
|
538
|
+
n.items.forEach(emit);
|
|
539
|
+
return;
|
|
540
|
+
case "group":
|
|
541
|
+
push({ op: 3 /* Save */, n: 2 * n.index });
|
|
542
|
+
emit(n.body);
|
|
543
|
+
push({ op: 3 /* Save */, n: 2 * n.index + 1 });
|
|
544
|
+
return;
|
|
545
|
+
case "assert":
|
|
546
|
+
push({ op: 4 /* Assert */, kind: n.kind });
|
|
547
|
+
return;
|
|
548
|
+
case "rep": {
|
|
549
|
+
for (let k = 0; k < n.min; k++) emit(n.body);
|
|
550
|
+
if (n.max < 0) {
|
|
551
|
+
const split = push({ op: 1 /* Split */, x: 0, y: 0 });
|
|
552
|
+
emit(n.body);
|
|
553
|
+
push({ op: 2 /* Jmp */, x: split });
|
|
554
|
+
const exit2 = prog.length;
|
|
555
|
+
const inst = prog[split];
|
|
556
|
+
inst.x = n.lazy ? exit2 : split + 1;
|
|
557
|
+
inst.y = n.lazy ? split + 1 : exit2;
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const splits = [];
|
|
561
|
+
for (let k = n.min; k < n.max; k++) {
|
|
562
|
+
splits.push(push({ op: 1 /* Split */, x: 0, y: 0 }));
|
|
563
|
+
emit(n.body);
|
|
564
|
+
}
|
|
565
|
+
const exit = prog.length;
|
|
566
|
+
for (const s of splits) {
|
|
567
|
+
const inst = prog[s];
|
|
568
|
+
inst.x = n.lazy ? exit : s + 1;
|
|
569
|
+
inst.y = n.lazy ? s + 1 : exit;
|
|
570
|
+
}
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
push({ op: 3 /* Save */, n: 0 });
|
|
576
|
+
emit(node);
|
|
577
|
+
push({ op: 3 /* Save */, n: 1 });
|
|
578
|
+
push({ op: 5 /* Match */ });
|
|
579
|
+
return prog;
|
|
580
|
+
}
|
|
581
|
+
function checkAssert(kind, hay, pos) {
|
|
582
|
+
const before = isWordChar(cpBefore(hay, pos));
|
|
583
|
+
const after = isWordChar(cpAt(hay, pos));
|
|
584
|
+
switch (kind) {
|
|
585
|
+
case "boundary":
|
|
586
|
+
return before !== after;
|
|
587
|
+
case "wordStart":
|
|
588
|
+
return !before && after;
|
|
589
|
+
case "wordEnd":
|
|
590
|
+
return before && !after;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
function pikeExec(prog, groupCount, caseInsensitive, hay, start, end, budget) {
|
|
594
|
+
const ncap = 2 * (groupCount + 1);
|
|
595
|
+
const mark = new Int32Array(prog.length);
|
|
596
|
+
let gen = 1;
|
|
597
|
+
let clistPc = [];
|
|
598
|
+
let clistCaps = [];
|
|
599
|
+
let nlistPc = [];
|
|
600
|
+
let nlistCaps = [];
|
|
601
|
+
const stackPc = [];
|
|
602
|
+
const stackCaps = [];
|
|
603
|
+
let matched = null;
|
|
604
|
+
const initial = new Int32Array(ncap).fill(-1);
|
|
605
|
+
const add = (listPc, listCaps, pc0, caps0, pos) => {
|
|
606
|
+
stackPc.push(pc0);
|
|
607
|
+
stackCaps.push(caps0);
|
|
608
|
+
while (stackPc.length) {
|
|
609
|
+
const pc = stackPc.pop();
|
|
610
|
+
const caps = stackCaps.pop();
|
|
611
|
+
if (mark[pc] === gen) continue;
|
|
612
|
+
mark[pc] = gen;
|
|
613
|
+
const inst = prog[pc];
|
|
614
|
+
switch (inst.op) {
|
|
615
|
+
case 2 /* Jmp */:
|
|
616
|
+
stackPc.push(inst.x);
|
|
617
|
+
stackCaps.push(caps);
|
|
618
|
+
break;
|
|
619
|
+
case 1 /* Split */:
|
|
620
|
+
stackPc.push(inst.y, inst.x);
|
|
621
|
+
stackCaps.push(caps, caps);
|
|
622
|
+
break;
|
|
623
|
+
case 3 /* Save */: {
|
|
624
|
+
const next = caps.slice();
|
|
625
|
+
next[inst.n] = pos;
|
|
626
|
+
stackPc.push(pc + 1);
|
|
627
|
+
stackCaps.push(next);
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
case 4 /* Assert */:
|
|
631
|
+
if (checkAssert(inst.kind, hay, pos)) {
|
|
632
|
+
stackPc.push(pc + 1);
|
|
633
|
+
stackCaps.push(caps);
|
|
634
|
+
}
|
|
635
|
+
break;
|
|
636
|
+
default:
|
|
637
|
+
listPc.push(pc);
|
|
638
|
+
listCaps.push(caps);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
let i = start;
|
|
643
|
+
if (budget.steps <= 0 || now() > budget.deadline) {
|
|
644
|
+
budget.exhausted = true;
|
|
645
|
+
return "budget";
|
|
646
|
+
}
|
|
647
|
+
let steps = 0;
|
|
648
|
+
for (; ; ) {
|
|
649
|
+
if (!matched) add(clistPc, clistCaps, 0, initial, i);
|
|
650
|
+
const cp = i < end ? hay.codePointAt(i) : -1;
|
|
651
|
+
const width = cp > 65535 ? 2 : 1;
|
|
652
|
+
if (clistPc.length === 0) {
|
|
653
|
+
if (matched || i >= end) break;
|
|
654
|
+
gen++;
|
|
655
|
+
i += width;
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
const folded = cp >= 0 && caseInsensitive ? foldCodePoint(cp) : cp;
|
|
659
|
+
gen++;
|
|
660
|
+
nlistPc = [];
|
|
661
|
+
nlistCaps = [];
|
|
662
|
+
for (let t = 0; t < clistPc.length; t++) {
|
|
663
|
+
if (++steps >= 4096) {
|
|
664
|
+
budget.steps -= steps;
|
|
665
|
+
steps = 0;
|
|
666
|
+
if (budget.steps <= 0 || now() > budget.deadline) {
|
|
667
|
+
budget.exhausted = true;
|
|
668
|
+
return "budget";
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
const inst = prog[clistPc[t]];
|
|
672
|
+
if (inst.op === 0 /* Char */) {
|
|
673
|
+
if (cp >= 0 && inst.test(cp, folded)) add(nlistPc, nlistCaps, clistPc[t] + 1, clistCaps[t], i + width);
|
|
674
|
+
} else if (inst.op === 5 /* Match */) {
|
|
675
|
+
matched = clistCaps[t];
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
clistPc = nlistPc;
|
|
680
|
+
clistCaps = nlistCaps;
|
|
681
|
+
if (i >= end) break;
|
|
682
|
+
i += width;
|
|
683
|
+
}
|
|
684
|
+
budget.steps -= steps;
|
|
685
|
+
if (!matched) return null;
|
|
686
|
+
const groups = [];
|
|
687
|
+
for (let g = 0; g <= groupCount; g++) {
|
|
688
|
+
const a = matched[2 * g];
|
|
689
|
+
const b = matched[2 * g + 1];
|
|
690
|
+
groups.push(a >= 0 && b >= 0 ? hay.slice(a, b) : void 0);
|
|
691
|
+
}
|
|
692
|
+
return { start: matched[0], end: matched[1], groups };
|
|
693
|
+
}
|
|
694
|
+
var WORD_CLASS = "[\\p{L}\\p{M}\\p{Nd}\\p{Pc}]";
|
|
695
|
+
var REGEX_BOUNDARY = `(?:(?<=${WORD_CLASS})(?!${WORD_CLASS})|(?<!${WORD_CLASS})(?=${WORD_CLASS}))`;
|
|
696
|
+
function hasNestedRepeat(source) {
|
|
697
|
+
const quantifierAt = (i) => {
|
|
698
|
+
const c = source[i];
|
|
699
|
+
if (c === "*" || c === "+") return { repeats: true, many: true };
|
|
700
|
+
if (c === "{") {
|
|
701
|
+
const m = /^\{(\d*)(,?)(\d*)\}/.exec(source.slice(i));
|
|
702
|
+
if (m) {
|
|
703
|
+
const max = m[2] ? m[3] ? Number(m[3]) : Infinity : Number(m[1]);
|
|
704
|
+
return { repeats: max > 1, many: max > 1 };
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return { repeats: false, many: false };
|
|
708
|
+
};
|
|
709
|
+
const stack = [];
|
|
710
|
+
let inClass = false;
|
|
711
|
+
for (let i = 0; i < source.length; i++) {
|
|
712
|
+
const c = source[i];
|
|
713
|
+
if (c === "\\") {
|
|
714
|
+
i++;
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
if (inClass) {
|
|
718
|
+
if (c === "]") inClass = false;
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
if (c === "[") {
|
|
722
|
+
inClass = true;
|
|
723
|
+
} else if (c === "(") {
|
|
724
|
+
stack.push(false);
|
|
725
|
+
} else if (c === ")") {
|
|
726
|
+
const inner = stack.pop() ?? false;
|
|
727
|
+
const q = quantifierAt(i + 1);
|
|
728
|
+
if (inner && q.many) return true;
|
|
729
|
+
if (stack.length && (inner || q.repeats)) stack[stack.length - 1] = true;
|
|
730
|
+
} else if (stack.length && quantifierAt(i).repeats) {
|
|
731
|
+
stack[stack.length - 1] = true;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
function compileRegex(query, o) {
|
|
737
|
+
if (hasNestedRepeat(query)) {
|
|
738
|
+
throw new PatternError(
|
|
739
|
+
"too_complex",
|
|
740
|
+
"a repeated group containing a repeat, like (a+)+, can take exponential time; rewrite it without nesting"
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
let source = query;
|
|
744
|
+
if (o.wholeWord || o.matchPrefix && o.matchSuffix) source = `${REGEX_BOUNDARY}(?:${query})${REGEX_BOUNDARY}`;
|
|
745
|
+
else if (o.matchPrefix) source = `${REGEX_BOUNDARY}(?:${query})`;
|
|
746
|
+
else if (o.matchSuffix) source = `(?:${query})${REGEX_BOUNDARY}`;
|
|
747
|
+
let re;
|
|
748
|
+
try {
|
|
749
|
+
re = new RegExp(source, o.matchCase ? "gu" : "giu");
|
|
750
|
+
} catch (error) {
|
|
751
|
+
throw new PatternError("invalid_pattern", `bad pattern: ${error instanceof Error ? error.message : String(error)}`);
|
|
752
|
+
}
|
|
753
|
+
let slicedFor = null;
|
|
754
|
+
return {
|
|
755
|
+
mode: "regex",
|
|
756
|
+
spansParagraphs: false,
|
|
757
|
+
caseInsensitive: !o.matchCase,
|
|
758
|
+
groupCount: 0,
|
|
759
|
+
exec(hay, start, end, budget) {
|
|
760
|
+
if (now() > budget.deadline) {
|
|
761
|
+
budget.exhausted = true;
|
|
762
|
+
return "budget";
|
|
763
|
+
}
|
|
764
|
+
let text = hay;
|
|
765
|
+
if (end < hay.length) {
|
|
766
|
+
if (!slicedFor || slicedFor.hay !== hay || slicedFor.end !== end) {
|
|
767
|
+
slicedFor = { hay, end, text: hay.slice(0, end) };
|
|
768
|
+
}
|
|
769
|
+
text = slicedFor.text;
|
|
770
|
+
}
|
|
771
|
+
re.lastIndex = start;
|
|
772
|
+
const m = re.exec(text);
|
|
773
|
+
if (!m) return null;
|
|
774
|
+
return { start: m.index, end: m.index + m[0].length, groups: Array.from(m) };
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function compileFindPattern(query, options = {}) {
|
|
779
|
+
try {
|
|
780
|
+
if (Array.from(query).length > MAX_FIND_PATTERN_LENGTH) {
|
|
781
|
+
throw new PatternError("too_long", `the Find what text is longer than ${MAX_FIND_PATTERN_LENGTH} characters`);
|
|
782
|
+
}
|
|
783
|
+
if (options.regex) return { ok: true, pattern: compileRegex(query, options) };
|
|
784
|
+
const wildcards = !!options.wildcards && !options.literal;
|
|
785
|
+
const caseInsensitive = !options.matchCase && !wildcards;
|
|
786
|
+
let node;
|
|
787
|
+
let spans;
|
|
788
|
+
let groups = 0;
|
|
789
|
+
if (wildcards) {
|
|
790
|
+
({ node, spans, groups } = parseWildcards(query));
|
|
791
|
+
} else {
|
|
792
|
+
({ node, spans } = parseSpecial(query, options, caseInsensitive));
|
|
793
|
+
const before = options.wholeWord || options.matchPrefix;
|
|
794
|
+
const after = options.wholeWord || options.matchSuffix;
|
|
795
|
+
if (before || after) {
|
|
796
|
+
const items = [];
|
|
797
|
+
if (before) items.push({ k: "assert", kind: "boundary" });
|
|
798
|
+
items.push(node);
|
|
799
|
+
if (after) items.push({ k: "assert", kind: "boundary" });
|
|
800
|
+
node = { k: "cat", items };
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const prog = compileProgram(node);
|
|
804
|
+
return {
|
|
805
|
+
ok: true,
|
|
806
|
+
pattern: {
|
|
807
|
+
mode: wildcards ? "wildcards" : "special",
|
|
808
|
+
spansParagraphs: spans,
|
|
809
|
+
caseInsensitive,
|
|
810
|
+
groupCount: groups,
|
|
811
|
+
exec: (hay, start, end, budget) => pikeExec(prog, groups, caseInsensitive, hay, start, end, budget)
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
} catch (error) {
|
|
815
|
+
if (error instanceof PatternError) return { ok: false, error: { code: error.code, message: error.message } };
|
|
816
|
+
return { ok: false, error: { code: "invalid_pattern", message: error instanceof Error ? error.message : String(error) } };
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
function findAllMatches(pattern, hay, options = {}) {
|
|
820
|
+
const budget = options.budget ?? createSearchBudget();
|
|
821
|
+
const maxMatches = options.maxMatches ?? 1e4;
|
|
822
|
+
const cuts = [...options.cuts ?? [], hay.length].sort((a, b) => a - b);
|
|
823
|
+
const matches = [];
|
|
824
|
+
let from = 0;
|
|
825
|
+
for (const cut of cuts) {
|
|
826
|
+
if (cut <= from) continue;
|
|
827
|
+
let pos = from;
|
|
828
|
+
from = cut;
|
|
829
|
+
for (; ; ) {
|
|
830
|
+
const m = pattern.exec(hay, pos, cut, budget);
|
|
831
|
+
if (m === "budget") return { matches, truncated: true };
|
|
832
|
+
if (!m) break;
|
|
833
|
+
const empty = m.end === m.start;
|
|
834
|
+
const next = empty ? m.end + (cpAt(hay, m.end) > 65535 ? 2 : 1) : m.end;
|
|
835
|
+
if (next > cut) break;
|
|
836
|
+
pos = next;
|
|
837
|
+
if (empty) continue;
|
|
838
|
+
matches.push(m);
|
|
839
|
+
if (matches.length >= maxMatches) return { matches, truncated: true };
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return { matches, truncated: false };
|
|
843
|
+
}
|
|
844
|
+
function parseReplacement(replacement, options = {}) {
|
|
845
|
+
if (options.literal || options.regex) return replacement ? [{ type: "text", text: replacement }] : [];
|
|
846
|
+
const chars = toChars(replacement);
|
|
847
|
+
const out = [];
|
|
848
|
+
let cur = "";
|
|
849
|
+
const flush = () => {
|
|
850
|
+
if (cur) out.push({ type: "text", text: cur });
|
|
851
|
+
cur = "";
|
|
852
|
+
};
|
|
853
|
+
let i = 0;
|
|
854
|
+
while (i < chars.length) {
|
|
855
|
+
const c = chars[i++];
|
|
856
|
+
if (c === "\\" && options.wildcards && i < chars.length) {
|
|
857
|
+
const d = chars[i];
|
|
858
|
+
if (/[1-9]/.test(d)) {
|
|
859
|
+
flush();
|
|
860
|
+
out.push({ type: "group", index: Number(d) });
|
|
861
|
+
} else {
|
|
862
|
+
cur += d;
|
|
863
|
+
}
|
|
864
|
+
i++;
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
if (c === "^" && i < chars.length) {
|
|
868
|
+
const n = chars[i];
|
|
869
|
+
if (n === "&" || n === "c") {
|
|
870
|
+
flush();
|
|
871
|
+
out.push(n === "&" ? { type: "found" } : { type: "clipboard" });
|
|
872
|
+
i++;
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
const code = replaceCode(n);
|
|
876
|
+
if (code !== null) {
|
|
877
|
+
cur += code;
|
|
878
|
+
i++;
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
const num = numericCode(chars, i);
|
|
882
|
+
if (num) {
|
|
883
|
+
cur += String.fromCodePoint(num.cp);
|
|
884
|
+
i += num.used;
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
cur += c;
|
|
889
|
+
}
|
|
890
|
+
flush();
|
|
891
|
+
return out;
|
|
892
|
+
}
|
|
893
|
+
function expandReplacement(pieces, match, clipboardText = "") {
|
|
894
|
+
let out = "";
|
|
895
|
+
for (const piece of pieces) {
|
|
896
|
+
switch (piece.type) {
|
|
897
|
+
case "text":
|
|
898
|
+
out += piece.text;
|
|
899
|
+
break;
|
|
900
|
+
case "found":
|
|
901
|
+
out += match.groups[0] ?? "";
|
|
902
|
+
break;
|
|
903
|
+
case "group":
|
|
904
|
+
out += match.groups[piece.index] ?? "";
|
|
905
|
+
break;
|
|
906
|
+
case "clipboard":
|
|
907
|
+
out += clipboardText.replace(/\r\n/g, "\r").replace(/\n/g, "\r");
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return out;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// src/extensions/find-replace/search.ts
|
|
915
|
+
var DELETION_MARK = "deletion";
|
|
916
|
+
var DROPPED_REPLACEMENT_MARKS = /* @__PURE__ */ new Set([DELETION_MARK, "formatChange"]);
|
|
917
|
+
var OBJECT_CHAR = "\uFFFC";
|
|
918
|
+
function searchDocument(doc, query, options = {}, searchOptions = {}) {
|
|
919
|
+
if (!query) return { matches: [], truncated: false, error: null };
|
|
920
|
+
const compiled = compileFindPattern(query, options);
|
|
921
|
+
if (!compiled.ok) return { matches: [], truncated: false, error: compiled.error };
|
|
922
|
+
const pattern = compiled.pattern;
|
|
923
|
+
const pieces = parseReplacement(searchOptions.replacement ?? "", options);
|
|
924
|
+
const budget = createSearchBudget({ timeLimitMs: searchOptions.timeLimitMs });
|
|
925
|
+
const maxMatches = searchOptions.maxMatches ?? 1e4;
|
|
926
|
+
const blocks = [];
|
|
927
|
+
doc.descendants((node, pos, parent, index) => {
|
|
928
|
+
if (!node.isTextblock) return true;
|
|
929
|
+
blocks.push({ node, pos, parent, index });
|
|
930
|
+
return false;
|
|
931
|
+
});
|
|
932
|
+
const chunks = [];
|
|
933
|
+
blocks.forEach((block, i) => {
|
|
934
|
+
const prev = blocks[i - 1];
|
|
935
|
+
const joins = pattern.spansParagraphs && prev && prev.parent === block.parent && prev.index + 1 === block.index;
|
|
936
|
+
if (joins) chunks[chunks.length - 1].push(block);
|
|
937
|
+
else chunks.push([block]);
|
|
938
|
+
});
|
|
939
|
+
const matches = [];
|
|
940
|
+
let truncated = false;
|
|
941
|
+
for (const chunk of chunks) {
|
|
942
|
+
let hay = "";
|
|
943
|
+
const posOf = [];
|
|
944
|
+
const endOf = [];
|
|
945
|
+
const cuts = [];
|
|
946
|
+
chunk.forEach((block, k) => {
|
|
947
|
+
const contentStart = block.pos + 1;
|
|
948
|
+
block.node.forEach((child, offset) => {
|
|
949
|
+
const at = contentStart + offset;
|
|
950
|
+
if (child.marks.some((m) => m.type.name === DELETION_MARK)) {
|
|
951
|
+
if (cuts[cuts.length - 1] !== hay.length) cuts.push(hay.length);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
if (child.isText) {
|
|
955
|
+
const text = child.text ?? "";
|
|
956
|
+
for (let j = 0; j < text.length; j++) {
|
|
957
|
+
posOf.push(at + j);
|
|
958
|
+
endOf.push(at + j + 1);
|
|
959
|
+
}
|
|
960
|
+
hay += text;
|
|
961
|
+
} else {
|
|
962
|
+
posOf.push(at);
|
|
963
|
+
endOf.push(at + child.nodeSize);
|
|
964
|
+
hay += child.type.name === "hardBreak" ? "\n" : OBJECT_CHAR;
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
const next = chunk[k + 1];
|
|
968
|
+
if (next) {
|
|
969
|
+
posOf.push(contentStart + block.node.content.size);
|
|
970
|
+
endOf.push(next.pos + 1);
|
|
971
|
+
hay += FIND_PARAGRAPH_MARK;
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
if (!hay) continue;
|
|
975
|
+
const result = findAllMatches(pattern, hay, {
|
|
976
|
+
cuts,
|
|
977
|
+
budget,
|
|
978
|
+
maxMatches: maxMatches - matches.length
|
|
979
|
+
});
|
|
980
|
+
for (const m of result.matches) {
|
|
981
|
+
matches.push({
|
|
982
|
+
from: posOf[m.start],
|
|
983
|
+
to: endOf[m.end - 1],
|
|
984
|
+
text: m.groups[0] ?? hay.slice(m.start, m.end),
|
|
985
|
+
replacement: expandReplacement(pieces, m, searchOptions.clipboardText ?? "")
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
if (result.truncated) {
|
|
989
|
+
truncated = true;
|
|
990
|
+
break;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
return { matches, truncated, error: null };
|
|
994
|
+
}
|
|
995
|
+
function replacementMarks(doc, from, to) {
|
|
996
|
+
const $from = doc.resolve(from);
|
|
997
|
+
const node = from < to ? $from.nodeAfter : null;
|
|
998
|
+
const marks = node ? node.marks : $from.marks();
|
|
999
|
+
return marks.filter((m) => !DROPPED_REPLACEMENT_MARKS.has(m.type.name));
|
|
1000
|
+
}
|
|
1001
|
+
function inlineContent(schema, text, marks) {
|
|
1002
|
+
const nodes = [];
|
|
1003
|
+
const hardBreak = schema.nodes.hardBreak;
|
|
1004
|
+
const parts = hardBreak ? text.split("\n") : [text];
|
|
1005
|
+
parts.forEach((part, i) => {
|
|
1006
|
+
if (i > 0) nodes.push(hardBreak.create(null, null, marks));
|
|
1007
|
+
if (part) nodes.push(schema.text(part, marks));
|
|
1008
|
+
});
|
|
1009
|
+
return nodes;
|
|
1010
|
+
}
|
|
1011
|
+
function applyReplacements(tr, matches) {
|
|
1012
|
+
const ends = new Array(matches.length);
|
|
1013
|
+
const schema = tr.doc.type.schema;
|
|
1014
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
1015
|
+
const { from, to, replacement } = matches[i];
|
|
1016
|
+
const marks = replacementMarks(tr.doc, from, to);
|
|
1017
|
+
const parts = replacement.split(/[\r\u2029]/);
|
|
1018
|
+
const stepsBefore = tr.steps.length;
|
|
1019
|
+
const first = inlineContent(schema, parts[0], marks);
|
|
1020
|
+
if (first.length) tr.replaceWith(from, to, first);
|
|
1021
|
+
else if (to > from) tr.delete(from, to);
|
|
1022
|
+
let pos = tr.mapping.slice(stepsBefore).map(to, 1);
|
|
1023
|
+
for (let k = 1; k < parts.length; k++) {
|
|
1024
|
+
tr.split(pos);
|
|
1025
|
+
pos += 2;
|
|
1026
|
+
const content = inlineContent(schema, parts[k], marks);
|
|
1027
|
+
if (content.length) {
|
|
1028
|
+
tr.insert(pos, content);
|
|
1029
|
+
pos += content.reduce((size, node) => size + node.nodeSize, 0);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const map = tr.mapping.slice(stepsBefore);
|
|
1033
|
+
for (let j = i + 1; j < matches.length; j++) ends[j] = map.map(ends[j], 1);
|
|
1034
|
+
ends[i] = pos;
|
|
1035
|
+
}
|
|
1036
|
+
return ends;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// src/extensions/table/extension.ts
|
|
1040
|
+
import { getHTMLFromFragment } from "@tiptap/core";
|
|
1041
|
+
import { Fragment as Fragment2 } from "@tiptap/pm/model";
|
|
1042
|
+
import * as _Table from "@tiptap/extension-table";
|
|
1043
|
+
import * as _TableRow from "@tiptap/extension-table-row";
|
|
1044
|
+
import * as _TableHeader from "@tiptap/extension-table-header";
|
|
1045
|
+
import * as _TableCell from "@tiptap/extension-table-cell";
|
|
1046
|
+
var resolveExt = (mod, name) => mod?.[name] || mod?.default?.[name] || mod?.default?.default || mod?.default || mod;
|
|
1047
|
+
var BaseTable = resolveExt(_Table, "Table");
|
|
1048
|
+
var BaseTableRow = resolveExt(_TableRow, "TableRow");
|
|
1049
|
+
var BaseTableHeader = resolveExt(_TableHeader, "TableHeader");
|
|
1050
|
+
var BaseTableCell = resolveExt(_TableCell, "TableCell");
|
|
1051
|
+
var ALIGNMENTS = /* @__PURE__ */ new Set(["left", "center", "right", "justify"]);
|
|
1052
|
+
function normalizeTableCellAlignment(value) {
|
|
1053
|
+
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
1054
|
+
return ALIGNMENTS.has(v) ? v : null;
|
|
1055
|
+
}
|
|
1056
|
+
var COLOR_REGEX = /^(?:#[0-9a-f]{3,8}|(?:rgb|rgba|hsl|hsla)\(\s*[-0-9.%\s,/deg]+\)|[a-z]{3,20})$/i;
|
|
1057
|
+
function normalizeTableCellColor(value) {
|
|
1058
|
+
const v = typeof value === "string" ? value.trim() : "";
|
|
1059
|
+
if (!v || v.length > 64 || !COLOR_REGEX.test(v)) return null;
|
|
1060
|
+
if (/^(?:inherit|initial|unset|revert|transparent)$/i.test(v)) return null;
|
|
1061
|
+
return v;
|
|
1062
|
+
}
|
|
1063
|
+
var cellAttributes = () => ({
|
|
1064
|
+
align: {
|
|
1065
|
+
default: null,
|
|
1066
|
+
parseHTML: (element) => normalizeTableCellAlignment(element.style?.textAlign || element.getAttribute("align")),
|
|
1067
|
+
renderHTML: (attrs) => {
|
|
1068
|
+
const align = normalizeTableCellAlignment(attrs.align);
|
|
1069
|
+
return align ? { style: `text-align: ${align}` } : {};
|
|
1070
|
+
}
|
|
1071
|
+
},
|
|
1072
|
+
backgroundColor: {
|
|
1073
|
+
default: null,
|
|
1074
|
+
parseHTML: (element) => normalizeTableCellColor(
|
|
1075
|
+
element.getAttribute("data-background-color") || element.style?.backgroundColor || element.getAttribute("bgcolor")
|
|
1076
|
+
),
|
|
1077
|
+
renderHTML: (attrs) => {
|
|
1078
|
+
const color = normalizeTableCellColor(attrs.backgroundColor);
|
|
1079
|
+
return color ? { style: `background-color: ${color}`, "data-background-color": color } : {};
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
var children = (node) => {
|
|
1084
|
+
const list = [];
|
|
1085
|
+
node.forEach((child) => list.push(child));
|
|
1086
|
+
return list;
|
|
1087
|
+
};
|
|
1088
|
+
var hasSpan = (cell) => (cell.attrs.colspan ?? 1) > 1 || (cell.attrs.rowspan ?? 1) > 1;
|
|
1089
|
+
function isGfmTable(node) {
|
|
1090
|
+
const rows = children(node);
|
|
1091
|
+
if (rows.length === 0) return false;
|
|
1092
|
+
const width = rows[0].childCount;
|
|
1093
|
+
return rows.every(
|
|
1094
|
+
(row, r) => row.childCount === width && children(row).every(
|
|
1095
|
+
(cell) => (r === 0 ? cell.type.name === "tableHeader" : cell.type.name === "tableCell") && !hasSpan(cell) && cell.childCount === 1 && cell.firstChild.type.name === "paragraph"
|
|
1096
|
+
)
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
var DELIMITERS = { left: ":---", center: ":---:", right: "---:" };
|
|
1100
|
+
function serializeTableMarkdown(state, node) {
|
|
1101
|
+
if (!isGfmTable(node)) {
|
|
1102
|
+
const html = getHTMLFromFragment(Fragment2.from(node), node.type.schema);
|
|
1103
|
+
state.write(html.replace(/\n{2,}/g, "\n"));
|
|
1104
|
+
state.closeBlock(node);
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
const previous = state.inTable;
|
|
1108
|
+
state.inTable = true;
|
|
1109
|
+
children(node).forEach((row, r) => {
|
|
1110
|
+
if (r) state.ensureNewLine();
|
|
1111
|
+
state.write("| ");
|
|
1112
|
+
children(row).forEach((cell, c) => {
|
|
1113
|
+
if (c) state.write(" | ");
|
|
1114
|
+
const paragraph = cell.firstChild;
|
|
1115
|
+
const start = state.out.length;
|
|
1116
|
+
if (paragraph.childCount) state.renderInline(paragraph);
|
|
1117
|
+
const text = state.out.slice(start);
|
|
1118
|
+
state.out = state.out.slice(0, start) + text.replace(/\n/g, " ").replace(/\|/g, "\\|");
|
|
1119
|
+
});
|
|
1120
|
+
state.write(" |");
|
|
1121
|
+
if (r === 0) {
|
|
1122
|
+
const delimiter = children(row).map((cell) => DELIMITERS[cell.attrs.align] ?? "---");
|
|
1123
|
+
state.ensureNewLine();
|
|
1124
|
+
state.write(`| ${delimiter.join(" | ")} |`);
|
|
1125
|
+
}
|
|
1126
|
+
});
|
|
1127
|
+
state.inTable = previous;
|
|
1128
|
+
state.closeBlock(node);
|
|
1129
|
+
}
|
|
1130
|
+
var DEFAULT_TABLE_OPTIONS = {
|
|
1131
|
+
resizable: true,
|
|
1132
|
+
handleWidth: 5,
|
|
1133
|
+
cellMinWidth: 25,
|
|
1134
|
+
lastColumnResizable: true,
|
|
1135
|
+
allowTableNodeSelection: true,
|
|
1136
|
+
HTMLAttributes: { class: "pixerate-table" },
|
|
1137
|
+
cellHTMLAttributes: {},
|
|
1138
|
+
headerHTMLAttributes: {},
|
|
1139
|
+
rowHTMLAttributes: {}
|
|
1140
|
+
};
|
|
1141
|
+
var Table = BaseTable.extend({
|
|
1142
|
+
addStorage() {
|
|
1143
|
+
return { markdown: { serialize: serializeTableMarkdown } };
|
|
1144
|
+
},
|
|
1145
|
+
addProseMirrorPlugins() {
|
|
1146
|
+
return [...this.parent?.() ?? [], createTableNestingPlugin()];
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
var TableRow = BaseTableRow;
|
|
1150
|
+
var TableCell = BaseTableCell.extend({
|
|
1151
|
+
addAttributes() {
|
|
1152
|
+
return { ...this.parent?.(), ...cellAttributes() };
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1155
|
+
var TableHeader = BaseTableHeader.extend({
|
|
1156
|
+
addAttributes() {
|
|
1157
|
+
return { ...this.parent?.(), ...cellAttributes() };
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
function createTableExtensions(options = {}) {
|
|
1161
|
+
const o = { ...DEFAULT_TABLE_OPTIONS, ...options };
|
|
1162
|
+
return [
|
|
1163
|
+
Table.configure({
|
|
1164
|
+
resizable: o.resizable,
|
|
1165
|
+
handleWidth: o.handleWidth,
|
|
1166
|
+
cellMinWidth: o.cellMinWidth,
|
|
1167
|
+
lastColumnResizable: o.lastColumnResizable,
|
|
1168
|
+
allowTableNodeSelection: o.allowTableNodeSelection,
|
|
1169
|
+
HTMLAttributes: o.HTMLAttributes
|
|
1170
|
+
}),
|
|
1171
|
+
TableRow.configure({ HTMLAttributes: o.rowHTMLAttributes }),
|
|
1172
|
+
TableHeader.configure({ HTMLAttributes: o.headerHTMLAttributes }),
|
|
1173
|
+
TableCell.configure({ HTMLAttributes: o.cellHTMLAttributes })
|
|
1174
|
+
];
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// src/extensions/table/actions.ts
|
|
1178
|
+
import { CellSelection as CellSelection2, isInTable, selectedRect } from "@tiptap/pm/tables";
|
|
1179
|
+
var TABLE_ACTIONS = [
|
|
1180
|
+
{ action: "insertTable", label: "Insert Table", description: "Inserts a table (rows, cols, withHeaderRow) at the cursor.", keywords: ["table", "grid", "new"] },
|
|
1181
|
+
{ action: "addRowBefore", label: "Insert Row Above", description: "Adds a row above the current row.", keywords: ["row", "add", "above"] },
|
|
1182
|
+
{ action: "addRowAfter", label: "Insert Row Below", description: "Adds a row below the current row.", keywords: ["row", "add", "below"] },
|
|
1183
|
+
{ action: "deleteRow", label: "Delete Row", description: "Deletes the selected rows.", keywords: ["row", "remove"] },
|
|
1184
|
+
{ action: "addColumnBefore", label: "Insert Column Left", description: "Adds a column left of the current column.", keywords: ["column", "add", "left", "before"] },
|
|
1185
|
+
{ action: "addColumnAfter", label: "Insert Column Right", description: "Adds a column right of the current column.", keywords: ["column", "add", "right", "after"] },
|
|
1186
|
+
{ action: "deleteColumn", label: "Delete Column", description: "Deletes the selected columns.", keywords: ["column", "remove"] },
|
|
1187
|
+
{ action: "deleteTable", label: "Delete Table", description: "Deletes the table around the cursor.", keywords: ["table", "remove"] },
|
|
1188
|
+
{ action: "mergeCells", label: "Merge Cells", description: "Merges the selected cells into one.", keywords: ["combine", "join", "span"] },
|
|
1189
|
+
{ action: "splitCell", label: "Split Cell", description: "Splits a merged cell back into single cells.", keywords: ["unmerge", "span"] },
|
|
1190
|
+
{ action: "toggleHeaderRow", label: "Toggle Header Row", description: "Turns the first row into header cells, or back.", keywords: ["header", "row", "th"] },
|
|
1191
|
+
{ action: "toggleHeaderColumn", label: "Toggle Header Column", description: "Turns the first column into header cells, or back.", keywords: ["header", "column", "th"] },
|
|
1192
|
+
{ action: "toggleHeaderCell", label: "Toggle Header Cell", description: "Turns the selected cells into header cells, or back.", keywords: ["header", "cell", "th"] },
|
|
1193
|
+
{ action: "goToNextCell", label: "Next Cell", description: "Moves the cursor to the next cell.", keywords: ["tab", "navigate"] },
|
|
1194
|
+
{ action: "goToPreviousCell", label: "Previous Cell", description: "Moves the cursor to the previous cell.", keywords: ["shift tab", "navigate"] },
|
|
1195
|
+
{ action: "setCellAlignment", label: "Align Cells\u2026", description: "Sets the horizontal alignment (align: left | center | right | justify | null) of the selected cells.", keywords: ["align", "left", "center", "right"] },
|
|
1196
|
+
{ action: "setCellBackground", label: "Cell Background\u2026", description: "Sets the background color (color: CSS color or null) of the selected cells.", keywords: ["shading", "fill", "color"] }
|
|
1197
|
+
];
|
|
1198
|
+
var DEFAULT_TABLE_TOOLBAR = [
|
|
1199
|
+
{ id: "addRowBefore", action: "addRowBefore", label: "+ Row \u2191", title: "Insert row above", group: "rows" },
|
|
1200
|
+
{ id: "addRowAfter", action: "addRowAfter", label: "+ Row \u2193", title: "Insert row below", group: "rows" },
|
|
1201
|
+
{ id: "deleteRow", action: "deleteRow", label: "\u2212 Row", title: "Delete row", group: "rows" },
|
|
1202
|
+
{ id: "addColumnBefore", action: "addColumnBefore", label: "+ Col \u2190", title: "Insert column left", group: "columns" },
|
|
1203
|
+
{ id: "addColumnAfter", action: "addColumnAfter", label: "+ Col \u2192", title: "Insert column right", group: "columns" },
|
|
1204
|
+
{ id: "deleteColumn", action: "deleteColumn", label: "\u2212 Col", title: "Delete column", group: "columns" },
|
|
1205
|
+
{ id: "mergeCells", action: "mergeCells", label: "Merge", title: "Merge cells", group: "cells" },
|
|
1206
|
+
{ id: "splitCell", action: "splitCell", label: "Split", title: "Split cell", group: "cells" },
|
|
1207
|
+
{ id: "toggleHeaderRow", action: "toggleHeaderRow", label: "Header row", title: "Toggle header row", group: "headers", active: (s) => s.headerRow },
|
|
1208
|
+
{ id: "toggleHeaderColumn", action: "toggleHeaderColumn", label: "Header col", title: "Toggle header column", group: "headers", active: (s) => s.headerColumn },
|
|
1209
|
+
{ id: "toggleHeaderCell", action: "toggleHeaderCell", label: "Header cell", title: "Toggle header cell", group: "headers", active: (s) => s.headerCell },
|
|
1210
|
+
{ id: "alignLeft", action: "setCellAlignment", params: { align: "left" }, label: "Left", title: "Align cell left", group: "align", active: (s) => s.cellAlignment === "left" },
|
|
1211
|
+
{ id: "alignCenter", action: "setCellAlignment", params: { align: "center" }, label: "Center", title: "Align cell center", group: "align", active: (s) => s.cellAlignment === "center" },
|
|
1212
|
+
{ id: "alignRight", action: "setCellAlignment", params: { align: "right" }, label: "Right", title: "Align cell right", group: "align", active: (s) => s.cellAlignment === "right" },
|
|
1213
|
+
{ id: "deleteTable", action: "deleteTable", label: "Delete table", title: "Delete table", group: "table" }
|
|
1214
|
+
];
|
|
1215
|
+
var MAX_TABLE_ROWS = 100;
|
|
1216
|
+
var MAX_TABLE_COLUMNS = 50;
|
|
1217
|
+
var live = (editor) => !!editor && !editor.isDestroyed;
|
|
1218
|
+
function isTableEnabled(editor) {
|
|
1219
|
+
return live(editor) && !!editor.schema.nodes.table && !!editor.schema.nodes.tableRow;
|
|
1220
|
+
}
|
|
1221
|
+
function isSelectionInTable(state) {
|
|
1222
|
+
if (!state.schema.nodes.table) return false;
|
|
1223
|
+
return state.selection instanceof CellSelection2 || isInTable(state);
|
|
1224
|
+
}
|
|
1225
|
+
function shouldShowTableBubbleMenu({ editor, state }) {
|
|
1226
|
+
return editor.isEditable && isSelectionInTable(state);
|
|
1227
|
+
}
|
|
1228
|
+
var isInt = (value, min, max) => typeof value === "number" && Number.isInteger(value) && value >= min && value <= max;
|
|
1229
|
+
var can = (editor, run) => {
|
|
1230
|
+
try {
|
|
1231
|
+
return !!run(editor.can().chain()).run();
|
|
1232
|
+
} catch {
|
|
1233
|
+
return false;
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
function getTableActionState(editor, action, params = {}) {
|
|
1237
|
+
if (!live(editor)) return "The editor is not available.";
|
|
1238
|
+
if (!isTableEnabled(editor)) return "Tables are not enabled in this editor.";
|
|
1239
|
+
if (!editor.isEditable) return "The editor is read-only.";
|
|
1240
|
+
const state = editor.state;
|
|
1241
|
+
const inTable = isSelectionInTable(state);
|
|
1242
|
+
if (action === "insertTable") {
|
|
1243
|
+
if (inTable) return "Tables cannot be nested: move the cursor out of the table first.";
|
|
1244
|
+
if (params.rows !== void 0 && !isInt(params.rows, 1, MAX_TABLE_ROWS)) {
|
|
1245
|
+
return `Rows must be a whole number from 1 to ${MAX_TABLE_ROWS}.`;
|
|
1246
|
+
}
|
|
1247
|
+
if (params.cols !== void 0 && !isInt(params.cols, 1, MAX_TABLE_COLUMNS)) {
|
|
1248
|
+
return `Columns must be a whole number from 1 to ${MAX_TABLE_COLUMNS}.`;
|
|
1249
|
+
}
|
|
1250
|
+
return can(editor, (c) => c.insertTable({ rows: 1, cols: 1 })) ? true : "A table cannot be inserted here.";
|
|
1251
|
+
}
|
|
1252
|
+
if (!inTable) return "Place the cursor in a table first.";
|
|
1253
|
+
switch (action) {
|
|
1254
|
+
case "mergeCells":
|
|
1255
|
+
case "splitCell": {
|
|
1256
|
+
if (isTrackChangesEnabled(editor)) {
|
|
1257
|
+
return `${action === "mergeCells" ? "Merging" : "Splitting"} cells cannot be tracked: turn off Track Changes first.`;
|
|
1258
|
+
}
|
|
1259
|
+
if (action === "mergeCells") {
|
|
1260
|
+
return can(editor, (c) => c.mergeCells()) ? true : "Select two or more adjacent cells to merge.";
|
|
1261
|
+
}
|
|
1262
|
+
return can(editor, (c) => c.splitCell()) ? true : "Only a merged cell can be split.";
|
|
1263
|
+
}
|
|
1264
|
+
case "deleteRow":
|
|
1265
|
+
case "deleteColumn": {
|
|
1266
|
+
const rect = selectedRect(state);
|
|
1267
|
+
const all = action === "deleteRow" ? rect.top === 0 && rect.bottom === rect.map.height : rect.left === 0 && rect.right === rect.map.width;
|
|
1268
|
+
const what = action === "deleteRow" ? "rows" : "columns";
|
|
1269
|
+
if (all || !can(editor, (c) => c[action]())) return `These are all the ${what}: delete the table instead.`;
|
|
1270
|
+
return true;
|
|
1271
|
+
}
|
|
1272
|
+
case "goToNextCell":
|
|
1273
|
+
return can(editor, (c) => c.goToNextCell()) ? true : "This is the last cell.";
|
|
1274
|
+
case "goToPreviousCell":
|
|
1275
|
+
return can(editor, (c) => c.goToPreviousCell()) ? true : "This is the first cell.";
|
|
1276
|
+
case "setCellAlignment":
|
|
1277
|
+
if (params.align !== void 0 && params.align !== null && !normalizeTableCellAlignment(params.align)) {
|
|
1278
|
+
return 'Alignment must be "left", "center", "right", "justify" or null.';
|
|
1279
|
+
}
|
|
1280
|
+
if (!editor.schema.nodes.tableCell?.spec.attrs?.align) return "Cell alignment is not supported by this schema.";
|
|
1281
|
+
return true;
|
|
1282
|
+
case "setCellBackground":
|
|
1283
|
+
if (params.color !== void 0 && params.color !== null && !normalizeTableCellColor(params.color)) {
|
|
1284
|
+
return "Color must be a CSS color such as #fde68a, rgb(\u2026) or a color name, or null.";
|
|
1285
|
+
}
|
|
1286
|
+
if (!editor.schema.nodes.tableCell?.spec.attrs?.backgroundColor) return "Cell backgrounds are not supported by this schema.";
|
|
1287
|
+
return true;
|
|
1288
|
+
default:
|
|
1289
|
+
return can(editor, (c) => c[action]()) ? true : "This table action is not available here.";
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
function runTableAction(editor, action, params = {}, options = {}) {
|
|
1293
|
+
if (getTableActionState(editor, action, params) !== true) return false;
|
|
1294
|
+
const ed = editor;
|
|
1295
|
+
let chain = ed.chain();
|
|
1296
|
+
if (options.focus) chain = chain.focus();
|
|
1297
|
+
switch (action) {
|
|
1298
|
+
case "insertTable":
|
|
1299
|
+
chain = chain.insertTable({
|
|
1300
|
+
rows: params.rows ?? 3,
|
|
1301
|
+
cols: params.cols ?? 3,
|
|
1302
|
+
withHeaderRow: params.withHeaderRow ?? true
|
|
1303
|
+
});
|
|
1304
|
+
break;
|
|
1305
|
+
case "setCellAlignment":
|
|
1306
|
+
chain = chain.setCellAttribute("align", normalizeTableCellAlignment(params.align));
|
|
1307
|
+
break;
|
|
1308
|
+
case "setCellBackground":
|
|
1309
|
+
chain = chain.setCellAttribute("backgroundColor", normalizeTableCellColor(params.color));
|
|
1310
|
+
break;
|
|
1311
|
+
default:
|
|
1312
|
+
chain = chain[action]();
|
|
1313
|
+
}
|
|
1314
|
+
return !!chain.run();
|
|
1315
|
+
}
|
|
1316
|
+
var NO_ACTIONS = Object.fromEntries(
|
|
1317
|
+
TABLE_ACTIONS.map(({ action }) => [action, { enabled: false, reason: "The editor is not available." }])
|
|
1318
|
+
);
|
|
1319
|
+
var EMPTY_TABLE_STATE = Object.freeze({
|
|
1320
|
+
enabled: false,
|
|
1321
|
+
inTable: false,
|
|
1322
|
+
cellSelection: false,
|
|
1323
|
+
rows: 0,
|
|
1324
|
+
columns: 0,
|
|
1325
|
+
row: -1,
|
|
1326
|
+
column: -1,
|
|
1327
|
+
headerRow: false,
|
|
1328
|
+
headerColumn: false,
|
|
1329
|
+
headerCell: false,
|
|
1330
|
+
cellAlignment: null,
|
|
1331
|
+
cellBackground: null,
|
|
1332
|
+
actions: NO_ACTIONS
|
|
1333
|
+
});
|
|
1334
|
+
function getTableState(editor) {
|
|
1335
|
+
if (!live(editor)) return EMPTY_TABLE_STATE;
|
|
1336
|
+
const actions = Object.fromEntries(
|
|
1337
|
+
TABLE_ACTIONS.map(({ action }) => {
|
|
1338
|
+
const result = getTableActionState(editor, action);
|
|
1339
|
+
return [action, result === true ? { enabled: true } : { enabled: false, reason: result }];
|
|
1340
|
+
})
|
|
1341
|
+
);
|
|
1342
|
+
const state = editor.state;
|
|
1343
|
+
const base = { ...EMPTY_TABLE_STATE, enabled: isTableEnabled(editor), actions };
|
|
1344
|
+
if (!base.enabled || !isSelectionInTable(state)) return base;
|
|
1345
|
+
try {
|
|
1346
|
+
const rect = selectedRect(state);
|
|
1347
|
+
const { map, table } = rect;
|
|
1348
|
+
const cellAt = (row, col) => table.nodeAt(map.map[row * map.width + col]);
|
|
1349
|
+
const allHeaders = (positions) => positions.length > 0 && positions.every((pos) => table.nodeAt(pos)?.type.name === "tableHeader");
|
|
1350
|
+
const firstRow = map.cellsInRect({ left: 0, right: map.width, top: 0, bottom: 1 });
|
|
1351
|
+
const firstColumn = map.cellsInRect({ left: 0, right: 1, top: 0, bottom: map.height });
|
|
1352
|
+
const cell = cellAt(rect.top, rect.left);
|
|
1353
|
+
return {
|
|
1354
|
+
...base,
|
|
1355
|
+
inTable: true,
|
|
1356
|
+
cellSelection: state.selection instanceof CellSelection2,
|
|
1357
|
+
rows: map.height,
|
|
1358
|
+
columns: map.width,
|
|
1359
|
+
row: rect.top,
|
|
1360
|
+
column: rect.left,
|
|
1361
|
+
headerRow: allHeaders(firstRow),
|
|
1362
|
+
headerColumn: allHeaders(firstColumn),
|
|
1363
|
+
headerCell: cell?.type.name === "tableHeader",
|
|
1364
|
+
cellAlignment: normalizeTableCellAlignment(cell?.attrs.align),
|
|
1365
|
+
cellBackground: normalizeTableCellColor(cell?.attrs.backgroundColor)
|
|
1366
|
+
};
|
|
1367
|
+
} catch {
|
|
1368
|
+
return { ...base, inTable: true };
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
var stateKey = (state) => JSON.stringify(state);
|
|
1372
|
+
function createTableStore(editor) {
|
|
1373
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1374
|
+
let snapshot = getTableState(editor);
|
|
1375
|
+
let key = stateKey(snapshot);
|
|
1376
|
+
const update = () => {
|
|
1377
|
+
const next = getTableState(editor);
|
|
1378
|
+
const nextKey = stateKey(next);
|
|
1379
|
+
if (nextKey === key) return;
|
|
1380
|
+
snapshot = next;
|
|
1381
|
+
key = nextKey;
|
|
1382
|
+
listeners.forEach((listener) => listener());
|
|
1383
|
+
};
|
|
1384
|
+
const detach = () => {
|
|
1385
|
+
editor?.off("transaction", update);
|
|
1386
|
+
editor?.off("update", update);
|
|
1387
|
+
editor?.off("focus", update);
|
|
1388
|
+
editor?.off("destroy", update);
|
|
1389
|
+
};
|
|
1390
|
+
return {
|
|
1391
|
+
getSnapshot: () => {
|
|
1392
|
+
if (!listeners.size) {
|
|
1393
|
+
const next = getTableState(editor);
|
|
1394
|
+
const nextKey = stateKey(next);
|
|
1395
|
+
if (nextKey !== key) {
|
|
1396
|
+
snapshot = next;
|
|
1397
|
+
key = nextKey;
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return snapshot;
|
|
1401
|
+
},
|
|
1402
|
+
subscribe(listener) {
|
|
1403
|
+
if (!listeners.size && editor) {
|
|
1404
|
+
update();
|
|
1405
|
+
editor.on("transaction", update);
|
|
1406
|
+
editor.on("update", update);
|
|
1407
|
+
editor.on("focus", update);
|
|
1408
|
+
editor.on("destroy", update);
|
|
1409
|
+
}
|
|
1410
|
+
listeners.add(listener);
|
|
1411
|
+
return () => {
|
|
1412
|
+
listeners.delete(listener);
|
|
1413
|
+
if (!listeners.size) detach();
|
|
1414
|
+
};
|
|
1415
|
+
},
|
|
1416
|
+
destroy() {
|
|
1417
|
+
detach();
|
|
1418
|
+
listeners.clear();
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
export {
|
|
1424
|
+
ALLOW_NESTED_TABLES_META,
|
|
1425
|
+
tableNestingPluginKey,
|
|
1426
|
+
outermostTableDepth,
|
|
1427
|
+
isInTableCell,
|
|
1428
|
+
sliceContainsTable,
|
|
1429
|
+
insertSliceAfterTable,
|
|
1430
|
+
handleTablePasteWithoutNesting,
|
|
1431
|
+
unnestTables,
|
|
1432
|
+
createTableNestingPlugin,
|
|
1433
|
+
FIND_PARAGRAPH_MARK,
|
|
1434
|
+
MAX_FIND_PATTERN_LENGTH,
|
|
1435
|
+
createSearchBudget,
|
|
1436
|
+
foldCodePoint,
|
|
1437
|
+
compileFindPattern,
|
|
1438
|
+
findAllMatches,
|
|
1439
|
+
parseReplacement,
|
|
1440
|
+
expandReplacement,
|
|
1441
|
+
searchDocument,
|
|
1442
|
+
applyReplacements,
|
|
1443
|
+
normalizeTableCellAlignment,
|
|
1444
|
+
normalizeTableCellColor,
|
|
1445
|
+
isGfmTable,
|
|
1446
|
+
DEFAULT_TABLE_OPTIONS,
|
|
1447
|
+
Table,
|
|
1448
|
+
TableRow,
|
|
1449
|
+
TableCell,
|
|
1450
|
+
TableHeader,
|
|
1451
|
+
createTableExtensions,
|
|
1452
|
+
TABLE_ACTIONS,
|
|
1453
|
+
DEFAULT_TABLE_TOOLBAR,
|
|
1454
|
+
MAX_TABLE_ROWS,
|
|
1455
|
+
MAX_TABLE_COLUMNS,
|
|
1456
|
+
isTableEnabled,
|
|
1457
|
+
isSelectionInTable,
|
|
1458
|
+
shouldShowTableBubbleMenu,
|
|
1459
|
+
getTableActionState,
|
|
1460
|
+
runTableAction,
|
|
1461
|
+
EMPTY_TABLE_STATE,
|
|
1462
|
+
getTableState,
|
|
1463
|
+
createTableStore
|
|
1464
|
+
};
|
|
1465
|
+
//# sourceMappingURL=chunk-TK2XZK6Z.js.map
|