@pixerate/editor 0.23.0 → 0.25.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 +167 -2
- package/THIRD_PARTY_NOTICES.md +80 -0
- package/dist/agent/index.cjs +10 -8
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +4 -3
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +4 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +4437 -411
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +934 -4
- package/dist/canvas/index.d.ts +934 -4
- package/dist/canvas/index.js +4309 -283
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-4BVP64JJ.cjs +1406 -0
- package/dist/chunk-4BVP64JJ.cjs.map +1 -0
- package/dist/chunk-664LQYFJ.js +115 -0
- package/dist/chunk-664LQYFJ.js.map +1 -0
- package/dist/chunk-7WISYZFO.cjs +740 -0
- package/dist/chunk-7WISYZFO.cjs.map +1 -0
- package/dist/chunk-AL6JMGWW.cjs +783 -0
- package/dist/chunk-AL6JMGWW.cjs.map +1 -0
- package/dist/chunk-BVP3TSLH.cjs +69 -0
- package/dist/chunk-BVP3TSLH.cjs.map +1 -0
- package/dist/{chunk-RIKBJLS2.cjs → chunk-C7P22VIP.cjs} +2001 -279
- package/dist/chunk-C7P22VIP.cjs.map +1 -0
- package/dist/chunk-D6FH2YAX.cjs +131 -0
- package/dist/chunk-D6FH2YAX.cjs.map +1 -0
- package/dist/chunk-ECCCYKGL.js +740 -0
- package/dist/chunk-ECCCYKGL.js.map +1 -0
- package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
- package/dist/chunk-FD4LPFAE.cjs.map +1 -0
- package/dist/{chunk-QBJ22YZR.js → chunk-FH6F67DN.js} +1999 -277
- package/dist/chunk-FH6F67DN.js.map +1 -0
- package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
- package/dist/chunk-FPENXAEJ.js.map +1 -0
- package/dist/chunk-HLIMTC6N.js +1 -0
- package/dist/chunk-HLIMTC6N.js.map +1 -0
- package/dist/chunk-HRMEDT2L.js +1406 -0
- package/dist/chunk-HRMEDT2L.js.map +1 -0
- package/dist/{chunk-QGHGJ56O.js → chunk-IXHSYOVY.js} +2518 -122
- package/dist/chunk-IXHSYOVY.js.map +1 -0
- package/dist/chunk-MKA3AHLV.cjs +256 -0
- package/dist/chunk-MKA3AHLV.cjs.map +1 -0
- package/dist/chunk-NAXVVS5I.js +783 -0
- package/dist/chunk-NAXVVS5I.js.map +1 -0
- package/dist/chunk-O5RYH2PG.js +69 -0
- package/dist/chunk-O5RYH2PG.js.map +1 -0
- package/dist/chunk-OXSV64JX.js +689 -0
- package/dist/chunk-OXSV64JX.js.map +1 -0
- package/dist/chunk-P3RQ5UJE.cjs +689 -0
- package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
- package/dist/chunk-P6ODPZ4W.js +256 -0
- package/dist/chunk-P6ODPZ4W.js.map +1 -0
- package/dist/chunk-PL4JB3BF.cjs +1 -0
- package/dist/chunk-PL4JB3BF.cjs.map +1 -0
- package/dist/{chunk-GVSMRPHB.cjs → chunk-PO6A6QQH.cjs} +2607 -211
- package/dist/chunk-PO6A6QQH.cjs.map +1 -0
- package/dist/{chunk-JJDLPEWL.js → chunk-QGYDWPRM.js} +2 -2
- package/dist/chunk-RR7F5GUM.js +5726 -0
- package/dist/chunk-RR7F5GUM.js.map +1 -0
- package/dist/chunk-TNNJXF46.cjs +115 -0
- package/dist/chunk-TNNJXF46.cjs.map +1 -0
- package/dist/chunk-U5HZSFCS.js +131 -0
- package/dist/chunk-U5HZSFCS.js.map +1 -0
- package/dist/{chunk-MJZBNWG7.js → chunk-UAKDG62Z.js} +309 -581
- package/dist/chunk-UAKDG62Z.js.map +1 -0
- package/dist/{chunk-CL37JGFW.cjs → chunk-V3CHHWOE.cjs} +4 -4
- package/dist/{chunk-CL37JGFW.cjs.map → chunk-V3CHHWOE.cjs.map} +1 -1
- package/dist/chunk-WSQKHXW7.cjs +5726 -0
- package/dist/chunk-WSQKHXW7.cjs.map +1 -0
- package/dist/{chunk-AA4ZEVCC.cjs → chunk-X4N4WUKB.cjs} +336 -608
- package/dist/chunk-X4N4WUKB.cjs.map +1 -0
- package/dist/commands/index.cjs +74 -1
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.d.cts +38 -353
- package/dist/commands/index.d.ts +38 -353
- package/dist/commands/index.js +73 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/comment-store-BEMgVlAA.d.cts +135 -0
- package/dist/comment-store-BEMgVlAA.d.ts +135 -0
- package/dist/compare/index.cjs +15 -0
- package/dist/compare/index.cjs.map +1 -0
- package/dist/compare/index.d.cts +58 -0
- package/dist/compare/index.d.ts +58 -0
- package/dist/compare/index.js +15 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/controller-BIJiNoVs.d.cts +1842 -0
- package/dist/controller-BIJiNoVs.d.ts +1842 -0
- package/dist/documents-CHT1U5Vs.d.ts +86 -0
- package/dist/documents-Gp7wb0Me.d.cts +86 -0
- package/dist/extensions/index.cjs +100 -5
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +16 -4
- package/dist/extensions/index.d.ts +16 -4
- package/dist/extensions/index.js +100 -5
- package/dist/generation/index.cjs +2317 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +1015 -0
- package/dist/generation/index.d.ts +1015 -0
- package/dist/generation/index.js +2317 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/grammar/index.cjs +48 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +322 -100
- package/dist/grammar/index.d.ts +322 -100
- package/dist/grammar/index.js +54 -9
- package/dist/image-editor/index.cjs +4392 -481
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +1249 -97
- package/dist/image-editor/index.d.ts +1249 -97
- package/dist/image-editor/index.js +4281 -370
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index-7a6bHTLy.d.ts +1754 -0
- package/dist/index-Csd5qI8u.d.cts +1754 -0
- package/dist/index.cjs +1682 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -21
- package/dist/index.d.ts +118 -21
- package/dist/index.js +1630 -47
- package/dist/index.js.map +1 -1
- package/dist/mention-text-CDnCFd3c.d.cts +53 -0
- package/dist/mention-text-CDnCFd3c.d.ts +53 -0
- package/dist/migrate-iTlm3a8h.d.cts +112 -0
- package/dist/migrate-iTlm3a8h.d.ts +112 -0
- package/dist/model-C1zApQM8.d.cts +219 -0
- package/dist/model-C1zApQM8.d.ts +219 -0
- package/dist/persistence/index.cjs +676 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +230 -0
- package/dist/persistence/index.d.ts +230 -0
- package/dist/persistence/index.js +676 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
- package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.cts} +12 -1
- package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.ts} +12 -1
- package/dist/registry-D32LpIc4.d.cts +354 -0
- package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
- package/dist/registry-evKTP4ls.d.ts +354 -0
- package/dist/schema-DYDGdYL9.d.cts +41 -0
- package/dist/schema-DYDGdYL9.d.ts +41 -0
- package/dist/serializers/index.cjs +12 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +40 -12
- package/dist/serializers/index.d.ts +40 -12
- package/dist/serializers/index.js +12 -3
- package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
- package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
- package/dist/spreadsheet/index.cjs +161 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +611 -20
- package/dist/spreadsheet/index.d.ts +611 -20
- package/dist/spreadsheet/index.js +168 -10
- package/dist/storage-BpFfspHm.d.cts +120 -0
- package/dist/storage-BpFfspHm.d.ts +120 -0
- package/dist/tokens/index.cjs +115 -0
- package/dist/tokens/index.cjs.map +1 -0
- package/dist/tokens/index.d.cts +212 -0
- package/dist/tokens/index.d.ts +212 -0
- package/dist/tokens/index.js +115 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
- package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
- package/dist/{track-changes-BSF58RK0.d.cts → track-changes-D_VAPELi.d.cts} +110 -144
- package/dist/{track-changes-BSF58RK0.d.ts → track-changes-Db_fGEvx.d.ts} +110 -144
- package/package.json +21 -1
- package/dist/chunk-4SUNJZWB.cjs.map +0 -1
- package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
- package/dist/chunk-AXV2ZW34.cjs +0 -118
- package/dist/chunk-AXV2ZW34.cjs.map +0 -1
- package/dist/chunk-B2ZRLN4S.js +0 -118
- package/dist/chunk-B2ZRLN4S.js.map +0 -1
- package/dist/chunk-GVSMRPHB.cjs.map +0 -1
- package/dist/chunk-K3R5NG2D.js +0 -3100
- package/dist/chunk-K3R5NG2D.js.map +0 -1
- package/dist/chunk-MJZBNWG7.js.map +0 -1
- package/dist/chunk-OYXSKQFR.js.map +0 -1
- package/dist/chunk-QBJ22YZR.js.map +0 -1
- package/dist/chunk-QGHGJ56O.js.map +0 -1
- package/dist/chunk-RIKBJLS2.cjs.map +0 -1
- package/dist/chunk-XDMXXC4Z.cjs +0 -3100
- package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
- package/dist/controller-pePCJLT1.d.cts +0 -959
- package/dist/controller-pePCJLT1.d.ts +0 -959
- package/dist/index-CCr_z9kF.d.cts +0 -899
- package/dist/index-Ck6ajwXh.d.ts +0 -899
- /package/dist/{chunk-JJDLPEWL.js.map → chunk-QGYDWPRM.js.map} +0 -0
|
@@ -5,6 +5,7 @@ import { MentionOptions as MentionOptions$1 } from '@tiptap/extension-mention';
|
|
|
5
5
|
import { SuggestionOptions } from '@tiptap/suggestion';
|
|
6
6
|
import { EditorState, PluginKey } from '@tiptap/pm/state';
|
|
7
7
|
import { Node } from '@tiptap/pm/model';
|
|
8
|
+
import { R as ReviewAuthor } from './comment-store-BEMgVlAA.js';
|
|
8
9
|
|
|
9
10
|
interface MentionEntity {
|
|
10
11
|
id: string;
|
|
@@ -27,144 +28,30 @@ interface MentionOptions extends Partial<MentionOptions$1> {
|
|
|
27
28
|
* Creates atomic inline <span data-type="mention"> nodes with full suggestion support.
|
|
28
29
|
*/
|
|
29
30
|
declare const Mention: _tiptap_core.Node<MentionOptions$1<any, _tiptap_extension_mention.MentionNodeAttrs>, any>;
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
declare function createMentionExtension(options?: Partial<MentionOptions>): _tiptap_core.Node<MentionOptions$1<any, _tiptap_extension_mention.MentionNodeAttrs>, any>;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Who made a comment, reply or tracked change.
|
|
37
|
-
*/
|
|
38
|
-
interface ReviewAuthor {
|
|
31
|
+
/** Mention nodes in a document, with their positions (for role pickers). */
|
|
32
|
+
interface MentionNodeInfo {
|
|
33
|
+
pos: number;
|
|
39
34
|
id: string;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Where a comment thread is attached in the document. `from`/`to` are
|
|
46
|
-
* ProseMirror positions and `quote` is the commented text at the time the
|
|
47
|
-
* anchor was last synced. Positions are only meaningful for the current
|
|
48
|
-
* document; the `comment` mark in the document is the source of truth.
|
|
49
|
-
*/
|
|
50
|
-
interface CommentAnchor {
|
|
51
|
-
from: number;
|
|
52
|
-
to: number;
|
|
53
|
-
quote: string;
|
|
54
|
-
}
|
|
55
|
-
interface CommentReply {
|
|
56
|
-
id: string;
|
|
57
|
-
author: ReviewAuthor;
|
|
58
|
-
body: string;
|
|
59
|
-
createdAt: number;
|
|
60
|
-
editedAt?: number;
|
|
61
|
-
}
|
|
62
|
-
interface CommentThread {
|
|
63
|
-
id: string;
|
|
64
|
-
/** `null` while the thread has no text in the document (see `orphaned`). */
|
|
65
|
-
anchor: CommentAnchor | null;
|
|
66
|
-
author: ReviewAuthor;
|
|
67
|
-
createdAt: number;
|
|
68
|
-
/** An empty body marks a draft that has not been posted yet. */
|
|
69
|
-
body: string;
|
|
70
|
-
editedAt?: number;
|
|
71
|
-
replies: CommentReply[];
|
|
72
|
-
resolved: boolean;
|
|
73
|
-
resolvedAt?: number;
|
|
74
|
-
resolvedBy?: ReviewAuthor;
|
|
75
|
-
/**
|
|
76
|
-
* True when the commented text was deleted from the document. Undoing the
|
|
77
|
-
* deletion re-attaches the thread.
|
|
78
|
-
*/
|
|
79
|
-
orphaned: boolean;
|
|
80
|
-
/** The quote the thread had before it was orphaned. */
|
|
81
|
-
lastQuote?: string;
|
|
82
|
-
}
|
|
83
|
-
interface CommentStoreSnapshot {
|
|
84
|
-
/** Threads in document order (anchored first), then orphaned threads. */
|
|
85
|
-
threads: readonly CommentThread[];
|
|
86
|
-
activeThreadId: string | null;
|
|
87
|
-
}
|
|
88
|
-
/** JSON shape produced by `CommentStore.toJSON()`. */
|
|
89
|
-
interface SerializedComments {
|
|
90
|
-
version: 1;
|
|
91
|
-
threads: CommentThread[];
|
|
92
|
-
}
|
|
93
|
-
interface CommentStoreOptions {
|
|
94
|
-
threads?: CommentThread[] | SerializedComments;
|
|
95
|
-
generateId?: () => string;
|
|
96
|
-
now?: () => number;
|
|
97
|
-
}
|
|
98
|
-
interface CreateThreadInput {
|
|
99
|
-
id?: string;
|
|
100
|
-
body: string;
|
|
101
|
-
author: ReviewAuthor;
|
|
102
|
-
anchor?: CommentAnchor | null;
|
|
103
|
-
createdAt?: number;
|
|
35
|
+
label: string;
|
|
36
|
+
type?: string;
|
|
37
|
+
role?: string;
|
|
104
38
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
39
|
+
/** Every mention node of an editor's document, in document order. */
|
|
40
|
+
declare function getMentionNodes(editor: {
|
|
41
|
+
state: {
|
|
42
|
+
doc: any;
|
|
43
|
+
};
|
|
44
|
+
}): MentionNodeInfo[];
|
|
110
45
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* back via `new CommentStore({ threads })` or `load()`. Snapshots are
|
|
115
|
-
* immutable and only replaced when something changes, so `getSnapshot` is safe
|
|
116
|
-
* to use with React's `useSyncExternalStore`. `subscribe` calls the listener
|
|
117
|
-
* immediately (Svelte store contract).
|
|
46
|
+
* Sets (or with `null` clears) the role of the mention node at `pos`, as one
|
|
47
|
+
* undoable step. Returns `false` when there is no mention at `pos` or the role
|
|
48
|
+
* name is invalid.
|
|
118
49
|
*/
|
|
119
|
-
declare
|
|
120
|
-
private threads;
|
|
121
|
-
private activeThreadId;
|
|
122
|
-
private snapshot;
|
|
123
|
-
private listeners;
|
|
124
|
-
/** Deleted threads, kept so undoing a "Delete Comment" can restore them. */
|
|
125
|
-
private deleted;
|
|
126
|
-
private generateId;
|
|
127
|
-
private now;
|
|
128
|
-
constructor(options?: CommentStoreOptions);
|
|
129
|
-
/** Parses `toJSON()` output (or a plain thread array). */
|
|
130
|
-
static parse(json: string | CommentThread[] | SerializedComments): CommentThread[];
|
|
131
|
-
subscribe: (listener: CommentStoreListener) => (() => void);
|
|
132
|
-
getSnapshot: () => CommentStoreSnapshot;
|
|
133
|
-
getThread(id: string): CommentThread | undefined;
|
|
134
|
-
createThread(input: CreateThreadInput): CommentThread;
|
|
135
|
-
/** Edits the thread's body, or one of its replies when `replyId` is given. */
|
|
136
|
-
editComment(threadId: string, body: string, replyId?: string): boolean;
|
|
137
|
-
addReply(threadId: string, input: {
|
|
138
|
-
body: string;
|
|
139
|
-
author: ReviewAuthor;
|
|
140
|
-
id?: string;
|
|
141
|
-
}): CommentReply | null;
|
|
142
|
-
deleteReply(threadId: string, replyId: string): boolean;
|
|
143
|
-
resolveThread(id: string, resolved?: boolean, by?: ReviewAuthor): boolean;
|
|
144
|
-
deleteThread(id: string): boolean;
|
|
145
|
-
/** Deletes every thread whose text is no longer in the document. */
|
|
146
|
-
removeOrphanedThreads(): string[];
|
|
147
|
-
setActiveThread(id: string | null): void;
|
|
148
|
-
/**
|
|
149
|
-
* Updates anchors from the document. Threads missing from `anchors` become
|
|
150
|
-
* orphaned. Threads that were deleted but whose mark re-appeared (e.g. after
|
|
151
|
-
* undoing "Delete Comment") are restored. Returns true if anything changed.
|
|
152
|
-
*/
|
|
153
|
-
syncAnchors(anchors: Map<string, CommentAnchor>): boolean;
|
|
154
|
-
/** Replaces all threads, e.g. with data loaded from a server. */
|
|
155
|
-
load(json: string | CommentThread[] | SerializedComments): void;
|
|
156
|
-
clear(): void;
|
|
157
|
-
toJSON(): SerializedComments;
|
|
158
|
-
private updateThread;
|
|
159
|
-
private computeSnapshot;
|
|
160
|
-
private emit;
|
|
161
|
-
}
|
|
162
|
-
declare function createCommentStore(options?: CommentStoreOptions): CommentStore;
|
|
50
|
+
declare function setMentionRoleAt(editor: any, pos: number, role: string | null): boolean;
|
|
163
51
|
/**
|
|
164
|
-
*
|
|
165
|
-
* "3h ago", then a locale date). Shared by the React and Svelte components.
|
|
52
|
+
* Helper to configure the Mention extension with preset defaults.
|
|
166
53
|
*/
|
|
167
|
-
declare function
|
|
54
|
+
declare function createMentionExtension(options?: Partial<MentionOptions>): _tiptap_core.Node<MentionOptions$1<any, _tiptap_extension_mention.MentionNodeAttrs>, any>;
|
|
168
55
|
|
|
169
56
|
declare const INSERTION_MARK_NAME = "insertion";
|
|
170
57
|
declare const DELETION_MARK_NAME = "deletion";
|
|
@@ -172,12 +59,18 @@ declare const DELETION_MARK_NAME = "deletion";
|
|
|
172
59
|
declare const FORMAT_CHANGE_MARK_NAME = "formatChange";
|
|
173
60
|
/** Node attribute recording a tracked block change (type, attributes or wrapping). */
|
|
174
61
|
declare const BLOCK_CHANGE_ATTRIBUTE = "blockChange";
|
|
62
|
+
/**
|
|
63
|
+
* Attribute of the insertion and deletion marks linking the two ends of a
|
|
64
|
+
* tracked move: the deletion is where the text moved from, the insertion
|
|
65
|
+
* where it moved to. Serialized as `data-move-id`.
|
|
66
|
+
*/
|
|
67
|
+
declare const MOVE_ID_ATTRIBUTE = "moveId";
|
|
175
68
|
/**
|
|
176
69
|
* Set this transaction meta to `true` to apply a change without tracking it,
|
|
177
70
|
* e.g. `editor.chain().command(({ tr }) => { tr.setMeta(TRACK_CHANGES_SKIP_META, true); return true; }).setContent(…).run()`.
|
|
178
71
|
*/
|
|
179
72
|
declare const TRACK_CHANGES_SKIP_META = "trackChangesSkip";
|
|
180
|
-
type TrackedChangeType = "insertion" | "deletion" | "format" | "block";
|
|
73
|
+
type TrackedChangeType = "insertion" | "deletion" | "format" | "block" | "move";
|
|
181
74
|
/**
|
|
182
75
|
* How tracked content is rendered by serializers:
|
|
183
76
|
* - `accepted` (default): as if every change were accepted (deleted text is
|
|
@@ -192,6 +85,11 @@ interface TrackedChangeAttributes {
|
|
|
192
85
|
authorName: string;
|
|
193
86
|
authorColor: string | null;
|
|
194
87
|
createdAt: number;
|
|
88
|
+
/**
|
|
89
|
+
* Insertion/deletion marks only: links a deletion (moved from) and an
|
|
90
|
+
* insertion (moved to) into one tracked move.
|
|
91
|
+
*/
|
|
92
|
+
moveId?: string | null;
|
|
195
93
|
}
|
|
196
94
|
/** A serializable mark (`mark.toJSON()`). */
|
|
197
95
|
interface TrackedMark {
|
|
@@ -215,9 +113,16 @@ interface TrackedBlockSnapshot {
|
|
|
215
113
|
attrs: Record<string, any>;
|
|
216
114
|
}[];
|
|
217
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Whole-block operation of a `blockChange` record: the block was inserted
|
|
118
|
+
* (rejecting removes it) or deleted (accepting removes it). Produced by
|
|
119
|
+
* `compareDocuments`; absent for type/attribute/wrapping changes.
|
|
120
|
+
*/
|
|
121
|
+
type TrackedBlockOperation = "insert" | "delete";
|
|
218
122
|
/** Value of the `blockChange` node attribute. */
|
|
219
123
|
interface TrackedBlockChangeAttributes extends TrackedChangeAttributes {
|
|
220
124
|
previous: TrackedBlockSnapshot;
|
|
125
|
+
operation?: TrackedBlockOperation;
|
|
221
126
|
}
|
|
222
127
|
interface TrackedFormatSummary {
|
|
223
128
|
/** Labels of added formatting, e.g. `["Bold"]`. */
|
|
@@ -249,10 +154,32 @@ interface TrackedChange {
|
|
|
249
154
|
description: string;
|
|
250
155
|
/** Formatting changes (`type: "format"`). */
|
|
251
156
|
format?: TrackedFormatSummary;
|
|
252
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* Block changes (`type: "block"`): the first block's previous and current
|
|
159
|
+
* state, and the whole-block operation for inserted/deleted blocks.
|
|
160
|
+
*/
|
|
253
161
|
block?: {
|
|
254
162
|
previous: TrackedBlockSnapshot;
|
|
255
163
|
current: TrackedBlockSnapshot;
|
|
164
|
+
operation?: TrackedBlockOperation;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Moves (`type: "move"`): where the text was moved from (struck through
|
|
168
|
+
* until accepted) and where it was moved to. `ranges` holds both.
|
|
169
|
+
*/
|
|
170
|
+
move?: {
|
|
171
|
+
from: {
|
|
172
|
+
from: number;
|
|
173
|
+
to: number;
|
|
174
|
+
}[];
|
|
175
|
+
to: {
|
|
176
|
+
from: number;
|
|
177
|
+
to: number;
|
|
178
|
+
}[];
|
|
179
|
+
/** The moved text at its source. */
|
|
180
|
+
fromText: string;
|
|
181
|
+
/** The moved text at its destination. */
|
|
182
|
+
toText: string;
|
|
256
183
|
};
|
|
257
184
|
}
|
|
258
185
|
interface TrackChangesSnapshot {
|
|
@@ -275,6 +202,10 @@ interface TrackChangesOptions {
|
|
|
275
202
|
formatChangeHTMLAttributes: Record<string, any>;
|
|
276
203
|
/** Class added to blocks with a tracked block change (margin bar by default). */
|
|
277
204
|
blockChangeClass: string;
|
|
205
|
+
/** Extra class of wholly inserted blocks (`blockChange.operation: "insert"`, from comparisons). */
|
|
206
|
+
blockInsertedClass: string;
|
|
207
|
+
/** Extra class of wholly deleted blocks (`blockChange.operation: "delete"`, from comparisons). */
|
|
208
|
+
blockDeletedClass: string;
|
|
278
209
|
/** Track mark changes (bold, links, font size, …) on existing text. Default `true`. */
|
|
279
210
|
trackFormatting: boolean;
|
|
280
211
|
/** Track textblock type/attribute and wrapping (list, quote) changes. Default `true`. */
|
|
@@ -290,6 +221,19 @@ interface TrackChangesOptions {
|
|
|
290
221
|
ignoredMarks: string[];
|
|
291
222
|
/** Node attributes ignored when comparing blocks (e.g. generated ids). */
|
|
292
223
|
ignoredBlockAttributes: string[];
|
|
224
|
+
/**
|
|
225
|
+
* Record a cut and paste (or a drag) of the same text as one tracked move
|
|
226
|
+
* instead of a deletion and an insertion. Default `true`.
|
|
227
|
+
*/
|
|
228
|
+
trackMoves: boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Decides whether moved text is big enough to be a move. Default
|
|
231
|
+
* `isMoveSized` (a paragraph, or at least a sentence of two words, as in
|
|
232
|
+
* Word); pass `() => true` to record every cut/paste or drag as a move.
|
|
233
|
+
*/
|
|
234
|
+
isMove: (text: string) => boolean;
|
|
235
|
+
/** HTML attributes (e.g. `class`) of moved text, at both ends. Replaces the default green double line. */
|
|
236
|
+
moveHTMLAttributes: Record<string, any>;
|
|
293
237
|
}
|
|
294
238
|
/**
|
|
295
239
|
* External store over the editor's tracked-change state. Snapshots only
|
|
@@ -325,27 +269,39 @@ declare module "@tiptap/core" {
|
|
|
325
269
|
/** Rejects one change (single undo step). */
|
|
326
270
|
rejectChange: (id: string) => ReturnType;
|
|
327
271
|
acceptAllChanges: () => ReturnType;
|
|
272
|
+
/** Accepts a tracked move: removes the source, keeps the destination. */
|
|
273
|
+
acceptMove: (id: string) => ReturnType;
|
|
274
|
+
/** Rejects a tracked move: restores the source, removes the destination. */
|
|
275
|
+
rejectMove: (id: string) => ReturnType;
|
|
328
276
|
rejectAllChanges: () => ReturnType;
|
|
329
277
|
/** Selects the next change after the selection, wrapping around. */
|
|
330
278
|
selectNextChange: () => ReturnType;
|
|
331
279
|
/** Selects the previous change before the selection, wrapping around. */
|
|
332
280
|
selectPreviousChange: () => ReturnType;
|
|
281
|
+
/** Selects a change (a move's destination, a block change's content). */
|
|
282
|
+
selectChange: (id: string) => ReturnType;
|
|
333
283
|
};
|
|
334
284
|
}
|
|
335
285
|
}
|
|
286
|
+
interface TrackedMarkOptions {
|
|
287
|
+
HTMLAttributes: Record<string, any>;
|
|
288
|
+
/** Attributes used instead of `HTMLAttributes` when the mark is one end of a move. */
|
|
289
|
+
moveHTMLAttributes: Record<string, any>;
|
|
290
|
+
}
|
|
291
|
+
/** Default classes of moved text: green double underline (destination) / strike (source), as in Word. */
|
|
292
|
+
declare const MOVE_TO_CLASS = "pixerate-move-to underline decoration-double decoration-emerald-600 text-emerald-700 dark:text-emerald-400";
|
|
293
|
+
declare const MOVE_FROM_CLASS = "pixerate-move-from line-through decoration-double decoration-emerald-600 text-emerald-700 dark:text-emerald-400";
|
|
336
294
|
/**
|
|
337
|
-
* Text inserted while tracking was on. Rendered as `<ins>`.
|
|
295
|
+
* Text inserted while tracking was on. Rendered as `<ins>`. With a `moveId`
|
|
296
|
+
* it is the destination of a tracked move.
|
|
338
297
|
*/
|
|
339
|
-
declare const TrackedInsertion: Mark<
|
|
340
|
-
HTMLAttributes: Record<string, any>;
|
|
341
|
-
}, any>;
|
|
298
|
+
declare const TrackedInsertion: Mark<TrackedMarkOptions, any>;
|
|
342
299
|
/**
|
|
343
300
|
* Text deleted while tracking was on. The text stays in the document until
|
|
344
|
-
* the change is accepted. Rendered as `<del>` (struck through).
|
|
301
|
+
* the change is accepted. Rendered as `<del>` (struck through). With a
|
|
302
|
+
* `moveId` it is the source of a tracked move.
|
|
345
303
|
*/
|
|
346
|
-
declare const TrackedDeletion: Mark<
|
|
347
|
-
HTMLAttributes: Record<string, any>;
|
|
348
|
-
}, any>;
|
|
304
|
+
declare const TrackedDeletion: Mark<TrackedMarkOptions, any>;
|
|
349
305
|
/**
|
|
350
306
|
* Existing text whose formatting changed while tracking was on. Stores the
|
|
351
307
|
* formatting before and after the change, rendered as
|
|
@@ -358,6 +314,8 @@ declare const TrackedFormatChange: Mark<{
|
|
|
358
314
|
declare function describeFormatChange(summary: TrackedFormatSummary): string;
|
|
359
315
|
/** Describes a block change, e.g. `Changed Paragraph to Heading 2`. */
|
|
360
316
|
declare function describeBlockChange(previous: TrackedBlockSnapshot, current: TrackedBlockSnapshot, ignoredAttributes?: readonly string[]): string;
|
|
317
|
+
/** Short label of a change's type for review UIs (`Moved` for a move). */
|
|
318
|
+
declare function trackedChangeLabel(change: Pick<TrackedChange, "type">): string;
|
|
361
319
|
/**
|
|
362
320
|
* Lists tracked changes in document order. Accepts an editor, an editor
|
|
363
321
|
* state or a ProseMirror document.
|
|
@@ -373,17 +331,25 @@ declare function getTrackChangesStore(editor: Editor | null | undefined): TrackC
|
|
|
373
331
|
* (`accepted` by default). The input document is not modified.
|
|
374
332
|
*/
|
|
375
333
|
declare function resolveTrackedChanges(doc: Node, view?: TrackedChangesView): Node;
|
|
334
|
+
/**
|
|
335
|
+
* Whether moved text is big enough to be recorded as a move rather than a
|
|
336
|
+
* deletion and an insertion, as in Word: a paragraph (the text holds a
|
|
337
|
+
* paragraph break) or at least a sentence of two or more words.
|
|
338
|
+
*/
|
|
339
|
+
declare function isMoveSized(text: string): boolean;
|
|
376
340
|
/**
|
|
377
341
|
* Suggestion mode / track changes. When enabled, typed and pasted content is
|
|
378
342
|
* marked as an insertion and deleted content is kept but marked as a
|
|
379
343
|
* deletion (struck through) until the change is accepted or rejected.
|
|
380
344
|
* Formatting changes on existing text are recorded with the `formatChange`
|
|
381
345
|
* mark, and textblock type/attribute/wrapping changes with the `blockChange`
|
|
382
|
-
* node attribute.
|
|
346
|
+
* node attribute. A cut and paste (or a drag) of a sentence or paragraph is
|
|
347
|
+
* recorded as a move: a deletion and an insertion linked by `moveId`, listed
|
|
348
|
+
* as one change and accepted or rejected together.
|
|
383
349
|
*
|
|
384
350
|
* Deleting your own insertion really deletes it. Paragraph splits and joins
|
|
385
351
|
* are not tracked. IME composition is tracked once the composition ends.
|
|
386
352
|
*/
|
|
387
353
|
declare const TrackChanges: Extension<TrackChangesOptions, TrackChangesStorage>;
|
|
388
354
|
|
|
389
|
-
export {
|
|
355
|
+
export { describeFormatChange as A, BLOCK_CHANGE_ATTRIBUTE as B, getMentionNodes as C, DELETION_MARK_NAME as D, getTrackChangesStore as E, FORMAT_CHANGE_MARK_NAME as F, getTrackedChangeAt as G, getTrackedChanges as H, INSERTION_MARK_NAME as I, isMoveSized as J, isTrackChangesEnabled as K, resolveTrackedChanges as L, MOVE_FROM_CLASS as M, setMentionRoleAt as N, trackChangesPluginKey as O, trackedChangeLabel as P, TRACK_CHANGES_SKIP_META as T, MOVE_ID_ATTRIBUTE as a, MOVE_TO_CLASS as b, Mention as c, type MentionEntity as d, type MentionNodeInfo as e, type MentionOptions as f, TrackChanges as g, type TrackChangesOptions as h, type TrackChangesSnapshot as i, type TrackChangesStorage as j, TrackChangesStore as k, type TrackedBlockChangeAttributes as l, type TrackedBlockOperation as m, type TrackedBlockSnapshot as n, type TrackedChange as o, type TrackedChangeAttributes as p, type TrackedChangeType as q, type TrackedChangesView as r, TrackedDeletion as s, TrackedFormatChange as t, type TrackedFormatChangeAttributes as u, type TrackedFormatSummary as v, TrackedInsertion as w, type TrackedMark as x, createMentionExtension as y, describeBlockChange as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "UI-agnostic rich text and media editing core library",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -63,6 +63,26 @@
|
|
|
63
63
|
"types": "./dist/commands/index.d.ts",
|
|
64
64
|
"import": "./dist/commands/index.js",
|
|
65
65
|
"require": "./dist/commands/index.cjs"
|
|
66
|
+
},
|
|
67
|
+
"./persistence": {
|
|
68
|
+
"types": "./dist/persistence/index.d.ts",
|
|
69
|
+
"import": "./dist/persistence/index.js",
|
|
70
|
+
"require": "./dist/persistence/index.cjs"
|
|
71
|
+
},
|
|
72
|
+
"./generation": {
|
|
73
|
+
"types": "./dist/generation/index.d.ts",
|
|
74
|
+
"import": "./dist/generation/index.js",
|
|
75
|
+
"require": "./dist/generation/index.cjs"
|
|
76
|
+
},
|
|
77
|
+
"./compare": {
|
|
78
|
+
"types": "./dist/compare/index.d.ts",
|
|
79
|
+
"import": "./dist/compare/index.js",
|
|
80
|
+
"require": "./dist/compare/index.cjs"
|
|
81
|
+
},
|
|
82
|
+
"./tokens": {
|
|
83
|
+
"types": "./dist/tokens/index.d.ts",
|
|
84
|
+
"import": "./dist/tokens/index.js",
|
|
85
|
+
"require": "./dist/tokens/index.cjs"
|
|
66
86
|
}
|
|
67
87
|
},
|
|
68
88
|
"files": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-4SUNJZWB.cjs","../src/grammar/tokenizer.ts","../src/grammar/engine.ts","../src/grammar/resolver.ts","../src/grammar/sourcemap.ts","../src/grammar/fields.ts"],"names":["out"],"mappings":"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EAAA;AACO,EAAA;AACT;AJ6UmB;AACA;AKtaH;AAIR,EAAA;AACA,EAAA;AACK,IAAA;AACX,EAAA;AACiB,EAAA;AAEA,EAAA;AACX,IAAA;AACC,IAAA;AACU,MAAA;AACX,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACW,QAAA;AACb,MAAA;AACY,MAAA;AACd,IAAA;AACW,IAAA;AACP,IAAA;AACS,MAAA;AACb,IAAA;AACO,IAAA;AACT,EAAA;AAGE,EAAA;AAKW,IAAA;AACC,MAAA;AACF,QAAA;AACK,QAAA;AACP,QAAA;AACF,UAAA;AACF,QAAA;AACI,QAAA;AACF,UAAA;AACF,QAAA;AACS,MAAA;AACA,QAAA;AACA,MAAA;AACH,QAAA;AACD,QAAA;AACH,UAAA;AACF,QAAA;AACM,QAAA;AACF,QAAA;AACE,QAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AAEgB,EAAA;AACH,EAAA;AACf;AA0BgB;AAIP,EAAA;AACU,IAAA;AACR,IAAA;AACM,IAAA;AACA,IAAA;AAGA,IAAA;AAGH,IAAA;AACK,IAAA;AACf,EAAA;AACJ;AAMgB;AAGgB,EAAA;AAClB,EAAA;AACI,IAAA;AACD,MAAA;AACb,IAAA;AACF,EAAA;AACO,EAAA;AACT;ALsXmB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-4SUNJZWB.cjs","sourcesContent":[null,"import {\n TEMPLATE_REGEX,\n VARIABLE_REGEX,\n INSTRUCTION_REGEX,\n Token,\n PromptDiagnostic,\n} from \"./tokens\";\nimport { matchConditionalTags, parseVariableBody } from \"./variables\";\n\ntype RawMatch = Token & { type: \"template\" | \"variable\" | \"instruction\" | \"conditional\" };\n\nexport interface TokenizeResult {\n tokens: Token[];\n /** Unbalanced conditional tags, which were emitted as text. */\n diagnostics: PromptDiagnostic[];\n}\n\n/**\n * Parses any prompt string into an array of typed tokens in linear order.\n * Plain text between tokens is preserved as `{ type: 'text' }`.\n *\n * Conditional section tags (`{?name}`, `{!name}`, `{/name}`) are only emitted\n * as `conditional` tokens when balanced; unbalanced tags become text. Use\n * `tokenizePromptWithDiagnostics` to find out which tags were rejected.\n */\nexport function tokenizePrompt(text: string): Token[] {\n return tokenizePromptWithDiagnostics(text).tokens;\n}\n\n/**\n * Returns the diagnostics `tokenizePrompt` would report for `text`.\n */\nexport function getPromptDiagnostics(text: string): PromptDiagnostic[] {\n return tokenizePromptWithDiagnostics(text).diagnostics;\n}\n\n/**\n * Like `tokenizePrompt`, but also reports unbalanced conditional tags.\n */\nexport function tokenizePromptWithDiagnostics(text: string): TokenizeResult {\n if (!text) {\n return { tokens: [], diagnostics: [] };\n }\n\n const rawMatches: RawMatch[] = [];\n\n // Match {{template}}\n const tmplRegex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = tmplRegex.exec(text)) !== null) {\n rawMatches.push({\n type: \"template\",\n raw: match[0],\n value: match[1].trim(),\n start: match.index,\n end: match.index + match[0].length,\n });\n }\n\n // Match {variable}\n const varRegex = new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags);\n while ((match = varRegex.exec(text)) !== null) {\n // Avoid double matching if overlapping with template\n const start = match.index;\n const end = start + match[0].length;\n const overlaps = rawMatches.some(\n (m) => !(end <= m.start || start >= m.end),\n );\n if (!overlaps) {\n const parsed = parseVariableBody(match[1]);\n if (parsed.kind === \"conditional\") {\n rawMatches.push({\n type: \"conditional\",\n raw: match[0],\n value: parsed.name,\n start,\n end,\n conditional: parsed.conditional,\n });\n } else {\n const token: RawMatch = {\n type: \"variable\",\n raw: match[0],\n value: parsed.name,\n start,\n end,\n };\n if (parsed.defaultValue !== undefined) {\n token.defaultValue = parsed.defaultValue;\n }\n if (parsed.description !== undefined) {\n token.description = parsed.description;\n }\n rawMatches.push(token);\n }\n }\n }\n\n // Match __instruction__\n const instRegex = new RegExp(\n INSTRUCTION_REGEX.source,\n INSTRUCTION_REGEX.flags,\n );\n while ((match = instRegex.exec(text)) !== null) {\n const start = match.index;\n const end = start + match[0].length;\n const overlaps = rawMatches.some(\n (m) => !(end <= m.start || start >= m.end),\n );\n if (!overlaps) {\n rawMatches.push({\n type: \"instruction\",\n raw: match[0],\n value: match[1].trim(),\n start,\n end,\n });\n }\n }\n\n // Sort matches by start index\n rawMatches.sort((a, b) => a.start - b.start);\n\n // Pair conditional tags; unbalanced ones are demoted to text below.\n const diagnostics: PromptDiagnostic[] = [];\n const literal = new Set<RawMatch>();\n const conditionals = rawMatches.filter(\n (m): m is RawMatch & Required<Pick<Token, \"conditional\">> =>\n m.type === \"conditional\",\n );\n matchConditionalTags(\n conditionals.map((m) => ({ conditional: m.conditional, name: m.value })),\n ).forEach((result, i) => {\n if (!result.error) return;\n const tag = conditionals[i];\n literal.add(tag);\n diagnostics.push({\n code: result.error,\n message:\n result.error === \"unclosed-section\"\n ? `Section \"${tag.raw}\" is never closed with \"{/${tag.value}}\"`\n : `\"${tag.raw}\" does not close any open section`,\n name: tag.value,\n start: tag.start,\n end: tag.end,\n });\n });\n\n const tokens: Token[] = [];\n let currentIdx = 0;\n\n const pushText = (start: number, end: number) => {\n const previous = tokens[tokens.length - 1];\n if (previous?.type === \"text\" && previous.end === start) {\n // Merge with text produced by a demoted conditional tag.\n previous.raw = previous.value = text.slice(previous.start, end);\n previous.end = end;\n return;\n }\n const textChunk = text.slice(start, end);\n tokens.push({\n type: \"text\",\n raw: textChunk,\n value: textChunk,\n start,\n end,\n });\n };\n\n for (const m of rawMatches) {\n if (m.start > currentIdx) {\n pushText(currentIdx, m.start);\n }\n if (literal.has(m)) {\n pushText(m.start, m.end);\n } else {\n tokens.push({ ...m });\n }\n currentIdx = m.end;\n }\n\n if (currentIdx < text.length) {\n pushText(currentIdx, text.length);\n }\n\n return { tokens, diagnostics };\n}\n","import type {\n PromptDiagnostic,\n PromptValues,\n Template,\n TemplateVersion,\n Token,\n} from \"./tokens\";\nimport type { SourceMapSegment } from \"./sourcemap\";\nimport { tokenizePromptWithDiagnostics } from \"./tokenizer\";\nimport { evaluateCondition, getSuppliedValue } from \"./variables\";\n\n/**\n * Finds the latest version of a template based on `latestVersion` or last version entry.\n */\nexport function getLatestVersion(\n template: Template,\n): TemplateVersion | undefined {\n if (!template.versions || template.versions.length === 0) {\n if (template.body !== undefined) {\n return {\n id: template.id || \"default\",\n version: \"1.0\",\n body: template.body,\n };\n }\n return undefined;\n }\n if (template.latestVersion) {\n const found = template.versions.find(\n (v) => v.version === template.latestVersion,\n );\n if (found) return found;\n }\n return template.versions[template.versions.length - 1];\n}\n\n/** Marker substituted for a template tag that would recurse into itself. */\nexport const TEMPLATE_LOOP_ERROR = \"[Template loop detected]\";\n/** Marker substituted for a template tag nested deeper than `maxDepth`. */\nexport const TEMPLATE_DEPTH_ERROR = \"[Template max depth exceeded]\";\n\n/**\n * Returns the body a template tag resolves to, honoring version bindings.\n */\nexport function getTemplateBody(\n template: Template,\n bindings?: Record<string, string>,\n): string | undefined {\n const boundVersionId = bindings?.[template.name];\n if (boundVersionId && template.versions) {\n const boundVersion = template.versions.find(\n (v) => v.id === boundVersionId || v.version === boundVersionId,\n );\n return boundVersion?.body;\n }\n return getLatestVersion(template)?.body ?? template.body;\n}\n\nexport interface ResolvePromptOptions {\n /** Template version bindings (`{ templateName: versionIdOrVersion }`). */\n bindings?: Record<string, string>;\n /** Maximum template nesting depth (default 10). */\n maxDepth?: number;\n /**\n * Values for `{variable}` slots and `{?variable}` / `{!variable}` sections.\n * When omitted, variables and section tags are left exactly as written.\n */\n values?: PromptValues;\n}\n\nexport interface ResolvePromptResult {\n text: string;\n map: SourceMapSegment[];\n diagnostics: PromptDiagnostic[];\n}\n\ntype Segment = SourceMapSegment & { locked?: boolean };\n\n/** Accumulates resolved text and, at the top level, source map segments. */\nclass Output {\n text = \"\";\n constructor(readonly segments: Segment[] | null) {}\n\n /** Text copied verbatim from the raw input. Locked segments never merge. */\n raw(rawStart: number, rawEnd: number, value: string, locked = false) {\n const resolvedStart = this.text.length;\n this.text += value;\n if (!this.segments) return;\n const last = this.segments[this.segments.length - 1];\n if (\n !locked &&\n last &&\n last.source === \"raw\" &&\n !last.locked &&\n last.rawEnd === rawStart &&\n last.resolvedEnd === resolvedStart\n ) {\n last.rawEnd = rawEnd;\n last.resolvedEnd = this.text.length;\n return;\n }\n this.segments.push({\n resolvedStart,\n resolvedEnd: this.text.length,\n source: \"raw\",\n rawStart,\n rawEnd,\n ...(locked ? { locked } : {}),\n });\n }\n\n /** Text that replaces a raw range (template body, value, removed section). */\n replaced(\n rawStart: number,\n rawEnd: number,\n value: string,\n extra: Pick<\n SourceMapSegment,\n \"source\" | \"templateName\" | \"variableName\" | \"valueSource\"\n >,\n ) {\n const resolvedStart = this.text.length;\n this.text += value;\n this.segments?.push({\n resolvedStart,\n resolvedEnd: this.text.length,\n rawStart,\n rawEnd,\n ...extra,\n });\n }\n}\n\n/** Pairs balanced conditional tokens (the tokenizer guarantees nesting). */\nfunction pairSections(tokens: Token[]): Map<number, number> {\n const pairs = new Map<number, number>();\n const stack: number[] = [];\n tokens.forEach((token, index) => {\n if (token.type !== \"conditional\") return;\n if (token.conditional === \"end\") {\n const open = stack.pop();\n if (open !== undefined) pairs.set(open, index);\n } else {\n stack.push(index);\n }\n });\n return pairs;\n}\n\n/**\n * Resolves a prompt: expands `{{templates}}` recursively (with loop and depth\n * protection), and, when `values` are given, substitutes `{variables}` (falling\n * back to their `|default`) and keeps or removes `{?name}…{/name}` sections.\n *\n * Template bodies are parsed on their own, so a section must open and close\n * within the same body. Templates inside a removed section are never expanded\n * and cannot trigger loop or depth errors. Unbalanced section tags are kept as\n * literal text and reported in `diagnostics`.\n *\n * Returns the resolved text, a source map from resolved to raw offsets, and\n * diagnostics. With no `values` the text matches the original template-only\n * resolver exactly.\n */\nexport function resolvePrompt(\n text: string,\n templates: Template[] = [],\n options: ResolvePromptOptions = {},\n): ResolvePromptResult {\n const templateMap = new Map<string, Template>();\n for (const t of templates) {\n templateMap.set(t.name, t);\n }\n const maxDepth = options.maxDepth ?? 10;\n const values = options.values;\n const diagnostics: PromptDiagnostic[] = [];\n const reported = new Set<string>();\n\n function resolveInto(\n source: string,\n out: Output,\n visited: Set<string>,\n depth: number,\n templateName: string | undefined,\n ): void {\n const { tokens, diagnostics: found } =\n tokenizePromptWithDiagnostics(source);\n for (const diagnostic of found) {\n const key = `${templateName ?? \"\"}\\u0000${diagnostic.start}\\u0000${diagnostic.code}`;\n if (reported.has(key)) continue;\n reported.add(key);\n diagnostics.push(\n templateName === undefined ? diagnostic : { ...diagnostic, templateName },\n );\n }\n const pairs = values ? pairSections(tokens) : null;\n\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n\n if (token.type === \"template\") {\n const name = token.value;\n if (visited.has(name)) {\n out.replaced(token.start, token.end, TEMPLATE_LOOP_ERROR, {\n source: \"template\",\n templateName: name,\n });\n continue;\n }\n const template = templateMap.get(name);\n const body = template\n ? getTemplateBody(template, options.bindings)\n : undefined;\n if (body === undefined) {\n out.raw(token.start, token.end, token.raw, true);\n continue;\n }\n if (depth + 1 > maxDepth) {\n out.replaced(token.start, token.end, TEMPLATE_DEPTH_ERROR, {\n source: \"template\",\n templateName: name,\n });\n continue;\n }\n const nested = new Output(null);\n const nextVisited = new Set(visited);\n nextVisited.add(name);\n resolveInto(body, nested, nextVisited, depth + 1, name);\n out.replaced(token.start, token.end, nested.text, {\n source: \"template\",\n templateName: name,\n });\n continue;\n }\n\n if (values && token.type === \"variable\") {\n const supplied = getSuppliedValue(values, token.value);\n const value = supplied ?? token.defaultValue;\n if (value !== undefined) {\n out.replaced(token.start, token.end, value, {\n source: \"variable\",\n variableName: token.value,\n valueSource: supplied !== undefined ? \"value\" : \"default\",\n });\n continue;\n }\n }\n\n if (values && token.type === \"conditional\" && token.conditional) {\n const tagInfo = {\n source: \"conditional\" as const,\n variableName: token.value,\n };\n if (token.conditional !== \"end\") {\n const close = pairs!.get(i)!;\n if (!evaluateCondition(token.conditional, token.value, values)) {\n // Drop the whole section, tags included.\n out.replaced(token.start, tokens[close].end, \"\", tagInfo);\n i = close;\n continue;\n }\n }\n out.replaced(token.start, token.end, \"\", tagInfo);\n continue;\n }\n\n out.raw(token.start, token.end, token.raw);\n }\n }\n\n const out = new Output([]);\n resolveInto(text, out, new Set(), 0, undefined);\n\n const map: SourceMapSegment[] = out.segments!.map(\n ({ locked: _locked, ...segment }) => segment,\n );\n if (map.length === 0) {\n map.push({\n resolvedStart: 0,\n resolvedEnd: 0,\n source: \"raw\",\n rawStart: 0,\n rawEnd: 0,\n });\n }\n return { text: out.text, map, diagnostics };\n}\n\n/** A token annotated with the value it resolves to. */\nexport interface EvaluatedToken extends Token {\n /** Variables only, when values were given: the substituted text. */\n resolvedValue?: string;\n /** Variables only: whether `resolvedValue` came from `values` or the default. */\n valueSource?: \"value\" | \"default\";\n}\n\n/**\n * Tokenizes a prompt for display. Without `values` this is `tokenizePrompt`.\n * With `values`, sections whose condition fails are removed (tags included),\n * the tags of kept sections are dropped, and each variable that has a value or\n * a default carries it in `resolvedValue`. Templates are not expanded; resolve\n * them first (without values) if the display should show their bodies.\n */\nexport function evaluatePromptTokens(\n text: string,\n values?: PromptValues,\n): EvaluatedToken[] {\n const tokens = tokenizePromptWithDiagnostics(text).tokens;\n if (!values) return tokens;\n\n const pairs = pairSections(tokens);\n const result: EvaluatedToken[] = [];\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (token.type === \"conditional\") {\n if (\n token.conditional !== \"end\" &&\n !evaluateCondition(token.conditional!, token.value, values)\n ) {\n i = pairs.get(i)!;\n }\n continue;\n }\n if (token.type === \"variable\") {\n const supplied = getSuppliedValue(values, token.value);\n const value = supplied ?? token.defaultValue;\n if (value !== undefined) {\n result.push({\n ...token,\n resolvedValue: value,\n valueSource: supplied !== undefined ? \"value\" : \"default\",\n });\n continue;\n }\n }\n result.push(token);\n }\n return result;\n}\n","import {\n TEMPLATE_REGEX,\n VARIABLE_REGEX,\n INSTRUCTION_REGEX,\n Template,\n PromptValues,\n} from \"./tokens\";\nimport { resolvePrompt } from \"./engine\";\nimport { parseVariableBody } from \"./variables\";\n\nexport interface ResolveTemplatesOptions {\n bindings?: Record<string, string>;\n maxDepth?: number;\n /**\n * Values for `{variable}` slots and `{?variable}` sections. When omitted,\n * variables, defaults and section tags are left exactly as written.\n */\n values?: PromptValues;\n}\n\n/**\n * Recursively resolves template tags `{{template_name}}` in a given text.\n * A tag that would recurse into itself is replaced with `TEMPLATE_LOOP_ERROR`,\n * and a tag nested deeper than `maxDepth` with `TEMPLATE_DEPTH_ERROR`; the rest\n * of the text still resolves normally.\n *\n * Pass `options.values` to also fill variables (falling back to their\n * `{name|default}`) and evaluate `{?name}…{/name}` / `{!name}…{/name}`\n * sections, including those inside template bodies. See `resolvePrompt` for\n * the source map and diagnostics.\n */\nexport function resolveTemplates(\n text: string,\n templates: Template[] = [],\n options?: ResolveTemplatesOptions,\n): string {\n return resolvePrompt(text, templates, options).text;\n}\n\n/**\n * Replaces `{variableName}` with values from a dictionary, falling back to a\n * `{variableName|default}` when no value is supplied, and evaluates\n * `{?name}…{/name}` / `{!name}…{/name}` sections. Variables with neither a\n * value nor a default are left as written. Templates are not expanded.\n */\nexport function resolveVariables(\n text: string,\n values: PromptValues,\n): string {\n if (!text) return \"\";\n return resolvePrompt(text, [], { values }).text;\n}\n\n/**\n * Extracts unique template names referenced in text.\n */\nexport function extractTemplateNames(text: string): string[] {\n if (!text) return [];\n const set = new Set<string>();\n const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n set.add(match[1].trim());\n }\n return Array.from(set);\n}\n\n/**\n * Extracts unique variable names referenced in text, including names used by\n * conditional section tags. Defaults and descriptions are stripped.\n */\nexport function extractVariableNames(text: string): string[] {\n if (!text) return [];\n const set = new Set<string>();\n const regex = new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n set.add(parseVariableBody(match[1]).name);\n }\n return Array.from(set);\n}\n\n/**\n * Extracts unique instruction names referenced in text.\n */\nexport function extractInstructionNames(text: string): string[] {\n if (!text) return [];\n const set = new Set<string>();\n const regex = new RegExp(INSTRUCTION_REGEX.source, INSTRUCTION_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n set.add(match[1].trim());\n }\n return Array.from(set);\n}\n","import type { PromptDiagnostic, Template } from \"./tokens\";\nimport type { ResolveTemplatesOptions } from \"./resolver\";\nimport { resolvePrompt } from \"./engine\";\nimport { getPromptDiagnostics } from \"./tokenizer\";\n\n/**\n * One contiguous piece of resolved output and the raw range it came from.\n *\n * - `raw`: copied verbatim; offsets map character by character.\n * - `template`: the expansion of a `{{template}}` tag.\n * - `variable`: a substituted value or `|default` for a `{variable}` tag.\n * - `conditional`: a section tag, or a whole removed section. These segments\n * are empty in the resolved text (`resolvedStart === resolvedEnd`).\n *\n * Offsets inside non-raw segments map to the start of their raw range.\n */\nexport interface SourceMapSegment {\n resolvedStart: number;\n resolvedEnd: number;\n source: \"raw\" | \"template\" | \"variable\" | \"conditional\";\n rawStart: number;\n rawEnd: number;\n templateName?: string;\n /** Variable substituted (`variable`) or tested (`conditional`). */\n variableName?: string;\n /** For `variable` segments: whether a supplied value or the default was used. */\n valueSource?: \"value\" | \"default\";\n}\n\n/**\n * Resolves templates in text while tracking character offset mapping\n * between the raw input and the fully resolved output.\n *\n * Pass `options.values` to also substitute variables and evaluate conditional\n * sections (see `resolvePrompt`); without it the output is unchanged from the\n * template-only behavior.\n */\nexport function resolveTemplatesWithMapping(\n text: string,\n templates: Template[] = [],\n templateBindings?: Record<string, string>,\n options?: Pick<ResolveTemplatesOptions, \"maxDepth\" | \"values\">,\n): { text: string; map: SourceMapSegment[]; diagnostics: PromptDiagnostic[] } {\n if (\n options?.values === undefined &&\n (!templates || templates.length === 0 || !text.includes(\"{{\"))\n ) {\n return {\n diagnostics: getPromptDiagnostics(text),\n text,\n map: [\n {\n resolvedStart: 0,\n resolvedEnd: text.length,\n source: \"raw\",\n rawStart: 0,\n rawEnd: text.length,\n },\n ],\n };\n }\n\n return resolvePrompt(text, templates, {\n bindings: templateBindings,\n maxDepth: options?.maxDepth,\n values: options?.values,\n });\n}\n\n/**\n * Maps an offset in resolved text back to the corresponding offset in raw text.\n */\nexport function mapResolvedOffsetToRaw(\n resolvedOffset: number,\n map: SourceMapSegment[],\n): number {\n for (let i = 0; i < map.length; i++) {\n const seg = map[i];\n const isLast = i === map.length - 1;\n const inRange = isLast\n ? resolvedOffset >= seg.resolvedStart && resolvedOffset <= seg.resolvedEnd\n : resolvedOffset >= seg.resolvedStart && resolvedOffset < seg.resolvedEnd;\n\n if (inRange) {\n if (seg.source === \"raw\") {\n return seg.rawStart + (resolvedOffset - seg.resolvedStart);\n }\n // The end of the text maps to the end of the tag; anywhere inside a\n // resolved template maps to the start of its tag.\n if (resolvedOffset === seg.resolvedEnd) {\n return seg.rawEnd;\n }\n return seg.rawStart;\n }\n }\n return resolvedOffset;\n}\n\n/**\n * Maps an offset in raw text to the corresponding offset in resolved text.\n */\nexport function mapRawOffsetToResolved(\n rawOffset: number,\n map: SourceMapSegment[],\n): number {\n for (let i = 0; i < map.length; i++) {\n const seg = map[i];\n const isLast = i === map.length - 1;\n const inRange = isLast\n ? rawOffset >= seg.rawStart && rawOffset <= seg.rawEnd\n : rawOffset >= seg.rawStart && rawOffset < seg.rawEnd;\n\n if (inRange) {\n if (seg.source === \"raw\") {\n return seg.resolvedStart + (rawOffset - seg.rawStart);\n }\n if (rawOffset === seg.rawEnd) {\n return seg.resolvedEnd;\n }\n return seg.resolvedStart;\n }\n }\n return rawOffset;\n}\n","import type { PromptValues, Template } from \"./tokens\";\nimport { tokenizePrompt } from \"./tokenizer\";\nimport { getTemplateBody } from \"./engine\";\n\n/** Everything a prompt (and, optionally, its templates) says about one variable. */\nexport interface VariableDescriptor {\n name: string;\n /** First `{name|default}` found. */\n defaultValue?: string;\n /** First `{name|default|description}` found. */\n description?: string;\n /** Appears as a `{name}` slot. */\n usedAsValue: boolean;\n /** Appears in a `{?name}` / `{!name}` condition. */\n usedInCondition: boolean;\n /** Number of `{name…}` slots and condition tags (closing tags excluded). */\n occurrences: number;\n /** Templates whose bodies mention the variable, in discovery order. */\n templates: string[];\n}\n\nexport interface ExtractVariablesOptions {\n /** Templates to search recursively for further variables. */\n templates?: Template[];\n bindings?: Record<string, string>;\n /** Maximum template nesting depth to search (default 10). */\n maxDepth?: number;\n}\n\n/**\n * Lists every variable a prompt uses, in order of first appearance, with its\n * default and description. Templates referenced by the prompt are searched\n * recursively when `options.templates` is given (loops are skipped). All\n * sections are searched, whatever their condition would evaluate to.\n */\nexport function extractVariables(\n text: string,\n options: ExtractVariablesOptions = {},\n): VariableDescriptor[] {\n const descriptors = new Map<string, VariableDescriptor>();\n const templateMap = new Map(\n (options.templates ?? []).map((t) => [t.name, t] as const),\n );\n const maxDepth = options.maxDepth ?? 10;\n\n const describe = (name: string, templateName?: string) => {\n let descriptor = descriptors.get(name);\n if (!descriptor) {\n descriptor = {\n name,\n usedAsValue: false,\n usedInCondition: false,\n occurrences: 0,\n templates: [],\n };\n descriptors.set(name, descriptor);\n }\n descriptor.occurrences++;\n if (templateName && !descriptor.templates.includes(templateName)) {\n descriptor.templates.push(templateName);\n }\n return descriptor;\n };\n\n const visit = (\n source: string,\n visited: Set<string>,\n depth: number,\n templateName?: string,\n ) => {\n for (const token of tokenizePrompt(source)) {\n if (token.type === \"variable\") {\n const descriptor = describe(token.value, templateName);\n descriptor.usedAsValue = true;\n if (descriptor.defaultValue === undefined && token.defaultValue !== undefined) {\n descriptor.defaultValue = token.defaultValue;\n }\n if (descriptor.description === undefined && token.description !== undefined) {\n descriptor.description = token.description;\n }\n } else if (token.type === \"conditional\" && token.conditional !== \"end\") {\n describe(token.value, templateName).usedInCondition = true;\n } else if (token.type === \"template\") {\n const template = templateMap.get(token.value);\n if (!template || visited.has(token.value) || depth + 1 > maxDepth) {\n continue;\n }\n const body = getTemplateBody(template, options.bindings);\n if (body === undefined) continue;\n visit(body, new Set(visited).add(token.value), depth + 1, token.value);\n }\n }\n };\n\n if (text) visit(text, new Set(), 0);\n return Array.from(descriptors.values());\n}\n\n/** A headless description of one input in a variable fill-in form. */\nexport interface VariableFormField {\n name: string;\n /** The variable's description, or its name. */\n label: string;\n /** The variable's default, or an empty string. */\n placeholder: string;\n defaultValue?: string;\n description?: string;\n /**\n * The variable is used as a slot and has no default, so leaving it blank\n * leaves the `{name}` placeholder in the resolved prompt.\n */\n required: boolean;\n /** Only used by `{?name}` / `{!name}` conditions, never substituted. */\n conditionOnly: boolean;\n}\n\n/**\n * Builds field descriptors for a fill-in form (Word's FILLIN analogue): one\n * per variable, labelled with its description and using its default as the\n * placeholder. Feed the entered text through `compactVariableValues` before\n * resolving so blank inputs fall back to defaults.\n */\nexport function getVariableFormFields(\n text: string,\n options: ExtractVariablesOptions = {},\n): VariableFormField[] {\n return extractVariables(text, options).map((variable) => ({\n name: variable.name,\n label: variable.description || variable.name,\n placeholder: variable.defaultValue ?? \"\",\n ...(variable.defaultValue !== undefined\n ? { defaultValue: variable.defaultValue }\n : {}),\n ...(variable.description !== undefined\n ? { description: variable.description }\n : {}),\n required: variable.usedAsValue && variable.defaultValue === undefined,\n conditionOnly: !variable.usedAsValue,\n }));\n}\n\n/**\n * Drops blank entries from form input so the resolver falls back to each\n * variable's default (an explicit `\"\"` value would otherwise render as empty).\n */\nexport function compactVariableValues(\n input: Record<string, string | null | undefined>,\n): PromptValues {\n const values: PromptValues = {};\n for (const [name, value] of Object.entries(input)) {\n if (value !== null && value !== undefined && value.trim() !== \"\") {\n values[name] = value;\n }\n }\n return values;\n}\n"]}
|