@sunafterrainwm/telegram-entities-builder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,385 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ EntityBuilder: () => EntityBuilder,
24
+ EntityBuilderProxy: () => EntityBuilderProxy,
25
+ LazyEntityBuilder: () => LazyEntityBuilder,
26
+ MessageComposer: () => MessageComposer,
27
+ escapeTag: () => escapeTag
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var EntityBuilder = class _EntityBuilder {
31
+ #text = "";
32
+ #entities = [];
33
+ #parent;
34
+ addText(text) {
35
+ this.#text += text;
36
+ return this;
37
+ }
38
+ addTextEntity(text, entity) {
39
+ text = String(text);
40
+ if (text.length > 0) {
41
+ this.#entities.push({
42
+ ...entity,
43
+ offset: this.#text.length,
44
+ length: text.length
45
+ });
46
+ this.#text += text;
47
+ }
48
+ return this;
49
+ }
50
+ addTextEntities(text, entities) {
51
+ for (const entity of entities) {
52
+ this.#entities.push({
53
+ ...entity,
54
+ offset: this.#text.length,
55
+ length: text.length
56
+ });
57
+ }
58
+ this.#text += text;
59
+ return this;
60
+ }
61
+ addTextSegmentList(segments) {
62
+ for (const segment of segments) {
63
+ if (segment.entity) {
64
+ this.addTextEntity(segment.text, segment.entity);
65
+ } else if (segment.entities) {
66
+ this.addTextEntities(segment.text, segment.entities);
67
+ } else {
68
+ this.#text += segment.text;
69
+ }
70
+ }
71
+ return this;
72
+ }
73
+ buildTextPayload() {
74
+ return {
75
+ text: this.#text,
76
+ entities: this.#entities
77
+ };
78
+ }
79
+ buildCaptionPayload() {
80
+ return {
81
+ caption: this.#text,
82
+ caption_entities: this.#entities
83
+ };
84
+ }
85
+ buildInlinePayload() {
86
+ return {
87
+ message_text: this.#text,
88
+ entities: this.#entities
89
+ };
90
+ }
91
+ sortEntities() {
92
+ this.#entities.sort((a, b) => a.offset - b.offset || a.length - b.length);
93
+ return this;
94
+ }
95
+ sliceInplace(start, end) {
96
+ if (!start && !end) {
97
+ return this;
98
+ }
99
+ const len = this.#text.length;
100
+ const s = start === void 0 ? 0 : start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
101
+ const e = end === void 0 ? len : end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
102
+ if (s >= e) {
103
+ this.#text = "";
104
+ this.#entities = [];
105
+ return this;
106
+ }
107
+ this.#text = this.#text.slice(s, e);
108
+ this.#entities = this.#entities.flatMap((entity) => {
109
+ const overlapStart = Math.max(s, entity.offset);
110
+ const overlapEnd = Math.min(e, entity.offset + entity.length);
111
+ if (overlapStart < overlapEnd) {
112
+ return [
113
+ {
114
+ ...entity,
115
+ offset: overlapStart - s,
116
+ length: overlapEnd - overlapStart
117
+ }
118
+ ];
119
+ }
120
+ return [];
121
+ });
122
+ return this;
123
+ }
124
+ slice(start, end) {
125
+ return this.clone().sliceInplace(start, end);
126
+ }
127
+ trimStart() {
128
+ const trimmedLength = this.#text.trimStart().length;
129
+ const diff = this.#text.length - trimmedLength;
130
+ if (diff > 0) {
131
+ this.sliceInplace(diff);
132
+ }
133
+ return this;
134
+ }
135
+ trimEnd() {
136
+ const trimmedLength = this.#text.trimEnd().length;
137
+ if (trimmedLength < this.#text.length) {
138
+ this.sliceInplace(0, trimmedLength);
139
+ }
140
+ return this;
141
+ }
142
+ trim() {
143
+ const originalLength = this.#text.length;
144
+ const startOffset = originalLength - this.#text.trimStart().length;
145
+ const endOffset = this.#text.trimEnd().length;
146
+ if (startOffset > 0 || endOffset < originalLength) {
147
+ this.sliceInplace(startOffset, endOffset);
148
+ }
149
+ return this;
150
+ }
151
+ clone() {
152
+ const instance = new _EntityBuilder();
153
+ instance.#text = this.#text;
154
+ instance.#entities = structuredClone(this.#entities);
155
+ return instance;
156
+ }
157
+ fork() {
158
+ const instance = new _EntityBuilder();
159
+ instance.#parent = this;
160
+ return instance;
161
+ }
162
+ /**
163
+ * Merges a payload text and its entities into this builder, optionally wrapping them with additional entities.
164
+ */
165
+ mergePayload(text, entities, wrappers = []) {
166
+ const startOffset = this.#text.length;
167
+ this.#text += text;
168
+ this.#entities.push(
169
+ ...wrappers.map(
170
+ (w) => ({
171
+ ...w,
172
+ offset: startOffset,
173
+ length: text.length
174
+ })
175
+ ),
176
+ ...entities.map((e) => ({
177
+ ...e,
178
+ offset: e.offset + startOffset
179
+ }))
180
+ );
181
+ }
182
+ merge(wrapperEntities = []) {
183
+ if (!this.#parent) {
184
+ throw new Error("Cannot merge: This builder is not a fork or has already been merged.");
185
+ }
186
+ this.#parent.mergePayload(this.#text, this.#entities, wrapperEntities);
187
+ this.#parent = void 0;
188
+ }
189
+ };
190
+ var LazyEntityBuilder = class _LazyEntityBuilder {
191
+ #segments = [];
192
+ #parent;
193
+ /**
194
+ * Flattens the lazy segments into a new EntityBuilder instance.
195
+ */
196
+ flatten() {
197
+ const builder = new EntityBuilder();
198
+ builder.addTextSegmentList(this.#segments);
199
+ return builder;
200
+ }
201
+ addText(text) {
202
+ this.#segments.push({ text });
203
+ return this;
204
+ }
205
+ addTextEntity(text, entity) {
206
+ this.#segments.push({ text, entity });
207
+ return this;
208
+ }
209
+ addTextEntities(text, entities) {
210
+ this.#segments.push({ text, entities });
211
+ return this;
212
+ }
213
+ addTextSegmentList(segments) {
214
+ this.#segments.push(...segments);
215
+ return this;
216
+ }
217
+ clone() {
218
+ const instance = new _LazyEntityBuilder();
219
+ instance.#segments = structuredClone(this.#segments);
220
+ return instance;
221
+ }
222
+ fork() {
223
+ const instance = new _LazyEntityBuilder();
224
+ instance.#parent = this;
225
+ return instance;
226
+ }
227
+ merge(wrapperEntities = []) {
228
+ if (!this.#parent) {
229
+ throw new Error("Cannot merge: This builder is not a fork or has already been merged.");
230
+ }
231
+ const wrappedSegments = this.#segments.map((seg) => {
232
+ if (seg.text.length === 0) {
233
+ return seg;
234
+ }
235
+ const existing = seg.entities ? [...seg.entities] : seg.entity ? [seg.entity] : [];
236
+ return {
237
+ text: seg.text,
238
+ entities: [...existing, ...wrapperEntities]
239
+ };
240
+ });
241
+ this.#parent.addTextSegmentList(wrappedSegments);
242
+ this.#parent = void 0;
243
+ }
244
+ };
245
+ var EntityBuilderProxy = class {
246
+ constructor(_entities) {
247
+ this._entities = _entities;
248
+ }
249
+ _entities;
250
+ get entities() {
251
+ return this._entities;
252
+ }
253
+ addText(...args) {
254
+ this._entities.addText(...args);
255
+ return this;
256
+ }
257
+ addTextEntity(...args) {
258
+ this._entities.addTextEntity(...args);
259
+ return this;
260
+ }
261
+ addTextEntities(...args) {
262
+ this._entities.addTextEntities(...args);
263
+ return this;
264
+ }
265
+ addTextSegmentList(...args) {
266
+ this._entities.addTextSegmentList(...args);
267
+ return this;
268
+ }
269
+ sliceInplace(...args) {
270
+ this._entities.sliceInplace(...args);
271
+ return this;
272
+ }
273
+ slice(...args) {
274
+ return this.fork().sliceInplace(...args);
275
+ }
276
+ trim() {
277
+ this._entities.trim();
278
+ return this;
279
+ }
280
+ trimStart() {
281
+ this._entities.trimStart();
282
+ return this;
283
+ }
284
+ trimEnd() {
285
+ this._entities.trimEnd();
286
+ return this;
287
+ }
288
+ sortEntities() {
289
+ this._entities.sortEntities();
290
+ return this;
291
+ }
292
+ clone() {
293
+ const newInstance = Object.create(this.constructor.prototype);
294
+ newInstance._entities.clone();
295
+ return newInstance;
296
+ }
297
+ fork() {
298
+ return this._entities.fork();
299
+ }
300
+ merge(...args) {
301
+ this._entities.merge(...args);
302
+ }
303
+ buildTextPayload() {
304
+ return this._entities.buildTextPayload();
305
+ }
306
+ buildCaptionPayload() {
307
+ const { text, entities } = this.buildTextPayload();
308
+ return {
309
+ caption: text,
310
+ caption_entities: entities
311
+ };
312
+ }
313
+ buildInlinePayload() {
314
+ const { text, entities, link_preview_options } = this.buildTextPayload();
315
+ return {
316
+ message_text: text,
317
+ entities,
318
+ link_preview_options
319
+ };
320
+ }
321
+ };
322
+ function upperFirst(input) {
323
+ return input.slice(0, 1).toUpperCase() + input.slice(1);
324
+ }
325
+ function escapeTag(input) {
326
+ return input.replaceAll(/["'′]/g, "").split(/[^\p{L}\p{N}_]/gu).map((s) => upperFirst(s)).join("");
327
+ }
328
+ var SymbolMessageComposer = /* @__PURE__ */ Symbol("MessageComposer");
329
+ var MessageComposer = class extends EntityBuilderProxy {
330
+ [SymbolMessageComposer] = true;
331
+ #upperTags = /* @__PURE__ */ new Set();
332
+ #tags = [];
333
+ /**
334
+ * Options for link preview generation.
335
+ */
336
+ linkPreviewOptions;
337
+ constructor(entities) {
338
+ if (entities && SymbolMessageComposer in entities) {
339
+ throw new Error("Cannot nest MessageComposer inside MessageComposer");
340
+ }
341
+ super(entities ?? new EntityBuilder());
342
+ }
343
+ /**
344
+ * Gets the current list of tags.
345
+ */
346
+ get tags() {
347
+ return [...this.#tags];
348
+ }
349
+ /**
350
+ * Adds one or more tags, escaping them and avoiding duplicates.
351
+ */
352
+ addTags(...tags) {
353
+ for (let tag of tags) {
354
+ tag = escapeTag(tag);
355
+ const upperTag = tag.toUpperCase();
356
+ if (this.#upperTags.has(upperTag)) {
357
+ continue;
358
+ }
359
+ this.#upperTags.add(upperTag);
360
+ this.#tags.push(tag);
361
+ }
362
+ return this;
363
+ }
364
+ buildTextPayload() {
365
+ const entities = this.entities.clone();
366
+ entities.trimEnd().addText("\n\n");
367
+ for (const tag of this.tags) {
368
+ entities.addTextEntity(`#${tag}`, { type: "hashtag" }).addText(" ");
369
+ }
370
+ entities.trimEnd();
371
+ return {
372
+ ...entities.buildTextPayload(),
373
+ link_preview_options: this.linkPreviewOptions
374
+ };
375
+ }
376
+ };
377
+ // Annotate the CommonJS export names for ESM import in node:
378
+ 0 && (module.exports = {
379
+ EntityBuilder,
380
+ EntityBuilderProxy,
381
+ LazyEntityBuilder,
382
+ MessageComposer,
383
+ escapeTag
384
+ });
385
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type * as TT from '@grammyjs/types';\n\ntype Telegram = TT.ApiMethods<never>;\ntype ApiParameters<T extends keyof Telegram> = Parameters<Telegram[T]>[0];\n\n/**\n * Represents a Telegram MessageEntity without the offset and length properties.\n */\nexport type PartialEntity<E extends TT.MessageEntity = TT.MessageEntity> = Omit<E, 'offset' | 'length'>;\n/**\n * Represents any draft entity that can be used before calculating the final offset and length.\n */\nexport type AnyDraftEntity =\n\t| PartialEntity<TT.MessageEntity.CommonMessageEntity>\n\t| PartialEntity<TT.MessageEntity.CustomEmojiMessageEntity>\n\t| PartialEntity<TT.MessageEntity.PreMessageEntity>\n\t| PartialEntity<TT.MessageEntity.TextLinkMessageEntity>\n\t| PartialEntity<TT.MessageEntity.TextMentionMessageEntity>;\n\n/**\n * Represents a segment of text which may contain one or multiple entities.\n */\nexport type TextSegment = TextSegment.SingleTextSegment | TextSegment.MultiTextSegment;\n\n/**\n * Namespace for TextSegment types.\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport declare namespace TextSegment {\n\tinterface SingleTextSegment {\n\t\ttext: string;\n\t\tentity?: AnyDraftEntity;\n\t\tentities?: never;\n\t}\n\n\tinterface MultiTextSegment {\n\t\ttext: string;\n\t\tentity?: never;\n\t\tentities: AnyDraftEntity[];\n\t}\n}\n\ntype PartialRequired<T, REQUIRED extends keyof T, OPTIONAL extends keyof T> = Required<Pick<T, REQUIRED>> &\n\tPick<T, OPTIONAL>;\n\n/**\n * Base interface for entity builders, providing fundamental operations for appending text and managing builder state.\n */\nexport interface IEntityBuilderBase {\n\t/**\n\t * Appends plain text.\n\t */\n\taddText(text: string): this;\n\t/**\n\t * Appends text with a single entity.\n\t */\n\taddTextEntity(text: string, entity: AnyDraftEntity): this;\n\t/**\n\t * Appends text with multiple entities.\n\t */\n\taddTextEntities(text: string, entities: AnyDraftEntity[]): this;\n\t/**\n\t * Appends a list of text segments.\n\t */\n\taddTextSegmentList(segments: TextSegment[]): this;\n\n\t/**\n\t * Creates a deep clone of this builder.\n\t */\n\tclone(): IEntityBuilderBase;\n\t/**\n\t * Creates a child builder that forks from this instance.\n\t */\n\tfork(): IEntityBuilderBase;\n\t/**\n\t * Merges a forked builder back into its parent.\n\t */\n\tmerge(wrapperEntities?: AnyDraftEntity[]): void;\n}\n\n/**\n * Advanced entity builder interface supporting string manipulation, entity sorting, and payload generation.\n */\nexport interface IEntityBuilder extends IEntityBuilderBase {\n\t/**\n\t * Trims or slices the string in-place, and automatically recalculates, filters, or truncates the affected entities.\n\t */\n\tsliceInplace(start?: number, end?: number): this;\n\t/**\n\t * Returns a new sliced instance.\n\t */\n\tslice(start?: number, end?: number): IEntityBuilder;\n\t/**\n\t * Removes leading whitespace in-place.\n\t */\n\ttrimStart(): this;\n\t/**\n\t * Removes trailing whitespace in-place.\n\t */\n\ttrimEnd(): this;\n\t/**\n\t * Removes leading and trailing whitespace in-place.\n\t */\n\ttrim(): this;\n\n\t/**\n\t * Sorts the entities based on their offset and length.\n\t */\n\tsortEntities(): this;\n\n\t/**\n\t * Builds the payload for sending a text message.\n\t */\n\tbuildTextPayload(): PartialRequired<ApiParameters<'sendMessage'>, 'text', 'entities' | 'link_preview_options'>;\n\t/**\n\t * Builds the payload for sending a document with a caption.\n\t */\n\tbuildCaptionPayload(): PartialRequired<ApiParameters<'sendDocument'>, 'caption', 'caption_entities'>;\n\t/**\n\t * Builds the payload for inline query results.\n\t */\n\tbuildInlinePayload(): PartialRequired<\n\t\tTT.InputTextMessageContent,\n\t\t'message_text',\n\t\t'entities' | 'link_preview_options'\n\t>;\n\n\tclone(): IEntityBuilder;\n\tfork(): IEntityBuilder;\n}\n\n/**\n * Main implementation of IEntityBuilder that eagerly evaluates and stores entities.\n */\nexport class EntityBuilder implements IEntityBuilder {\n\t#text = '';\n\t#entities: TT.MessageEntity[] = [];\n\t#parent?: EntityBuilder;\n\n\tpublic addText(text: string): this {\n\t\tthis.#text += text;\n\t\treturn this;\n\t}\n\n\tpublic addTextEntity(text: string, entity: AnyDraftEntity): this {\n\t\ttext = String(text);\n\t\tif (text.length > 0) {\n\t\t\tthis.#entities.push({\n\t\t\t\t...entity,\n\t\t\t\toffset: this.#text.length,\n\t\t\t\tlength: text.length,\n\t\t\t});\n\t\t\tthis.#text += text;\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic addTextEntities(text: string, entities: AnyDraftEntity[]): this {\n\t\tfor (const entity of entities) {\n\t\t\tthis.#entities.push({\n\t\t\t\t...entity,\n\t\t\t\toffset: this.#text.length,\n\t\t\t\tlength: text.length,\n\t\t\t} as TT.MessageEntity);\n\t\t}\n\t\tthis.#text += text;\n\t\treturn this;\n\t}\n\n\tpublic addTextSegmentList(segments: TextSegment[]): this {\n\t\tfor (const segment of segments) {\n\t\t\tif (segment.entity) {\n\t\t\t\tthis.addTextEntity(segment.text, segment.entity);\n\t\t\t} else if (segment.entities) {\n\t\t\t\tthis.addTextEntities(segment.text, segment.entities);\n\t\t\t} else {\n\t\t\t\tthis.#text += segment.text;\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic buildTextPayload() {\n\t\treturn {\n\t\t\ttext: this.#text,\n\t\t\tentities: this.#entities,\n\t\t};\n\t}\n\n\tpublic buildCaptionPayload() {\n\t\treturn {\n\t\t\tcaption: this.#text,\n\t\t\tcaption_entities: this.#entities as TT.MessageEntity[],\n\t\t};\n\t}\n\n\tpublic buildInlinePayload() {\n\t\treturn {\n\t\t\tmessage_text: this.#text,\n\t\t\tentities: this.#entities,\n\t\t};\n\t}\n\n\tpublic sortEntities() {\n\t\tthis.#entities.sort((a, b) => a.offset - b.offset || a.length - b.length);\n\t\treturn this;\n\t}\n\n\tpublic sliceInplace(start?: number, end?: number): this {\n\t\tif (!start && !end) {\n\t\t\treturn this;\n\t\t}\n\n\t\tconst len = this.#text.length;\n\n\t\tconst s = start === undefined ? 0 : start < 0 ? Math.max(len + start, 0) : Math.min(start, len);\n\t\tconst e = end === undefined ? len : end < 0 ? Math.max(len + end, 0) : Math.min(end, len);\n\n\t\tif (s >= e) {\n\t\t\tthis.#text = '';\n\t\t\tthis.#entities = [];\n\t\t\treturn this;\n\t\t}\n\n\t\tthis.#text = this.#text.slice(s, e);\n\t\tthis.#entities = this.#entities.flatMap<TT.MessageEntity>((entity) => {\n\t\t\t// 計算 Entity 區間與保留文字區間 [s, e) 的交集\n\t\t\tconst overlapStart = Math.max(s, entity.offset);\n\t\t\tconst overlapEnd = Math.min(e, entity.offset + entity.length);\n\n\t\t\t// 若交集長度大於 0,代表此 Entity 仍有部分存活於新字串中\n\t\t\tif (overlapStart < overlapEnd) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\t...entity,\n\t\t\t\t\t\toffset: overlapStart - s,\n\t\t\t\t\t\tlength: overlapEnd - overlapStart,\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\n\t\t\t// 剔除沒有交集的 Entity\n\t\t\treturn [];\n\t\t});\n\n\t\treturn this;\n\t}\n\n\tpublic slice(start?: number, end?: number): EntityBuilder {\n\t\treturn this.clone().sliceInplace(start, end);\n\t}\n\n\tpublic trimStart(): this {\n\t\tconst trimmedLength = this.#text.trimStart().length;\n\t\tconst diff = this.#text.length - trimmedLength;\n\t\tif (diff > 0) {\n\t\t\tthis.sliceInplace(diff);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic trimEnd(): this {\n\t\tconst trimmedLength = this.#text.trimEnd().length;\n\t\tif (trimmedLength < this.#text.length) {\n\t\t\tthis.sliceInplace(0, trimmedLength);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic trim(): this {\n\t\tconst originalLength = this.#text.length;\n\n\t\t// Calculate the number of leading whitespace characters\n\t\tconst startOffset = originalLength - this.#text.trimStart().length;\n\t\t// Calculate the effective length of the string after removing trailing whitespace (i.e., end index)\n\t\tconst endOffset = this.#text.trimEnd().length;\n\n\t\tif (startOffset > 0 || endOffset < originalLength) {\n\t\t\tthis.sliceInplace(startOffset, endOffset);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic clone(): EntityBuilder {\n\t\tconst instance = new EntityBuilder();\n\t\tinstance.#text = this.#text;\n\t\tinstance.#entities = structuredClone(this.#entities);\n\t\treturn instance;\n\t}\n\n\tpublic fork(): EntityBuilder {\n\t\tconst instance = new EntityBuilder();\n\t\tinstance.#parent = this;\n\t\treturn instance;\n\t}\n\n\t/**\n\t * Merges a payload text and its entities into this builder, optionally wrapping them with additional entities.\n\t */\n\tpublic mergePayload(text: string, entities: TT.MessageEntity[], wrappers: AnyDraftEntity[] = []): void {\n\t\tconst startOffset = this.#text.length;\n\t\tthis.#text += text;\n\n\t\tthis.#entities.push(\n\t\t\t// 1. Mount Wrapper (length covers the entire sub-block)\n\t\t\t...wrappers.map(\n\t\t\t\t(w) =>\n\t\t\t\t\t({\n\t\t\t\t\t\t...w,\n\t\t\t\t\t\toffset: startOffset,\n\t\t\t\t\t\tlength: text.length,\n\t\t\t\t\t}) as TT.MessageEntity,\n\t\t\t),\n\t\t\t// 2. Offset the entities of the child node itself\n\t\t\t...entities.map((e) => ({\n\t\t\t\t...e,\n\t\t\t\toffset: e.offset + startOffset,\n\t\t\t})),\n\t\t);\n\t}\n\n\tpublic merge(wrapperEntities: AnyDraftEntity[] = []): void {\n\t\tif (!this.#parent) {\n\t\t\tthrow new Error('Cannot merge: This builder is not a fork or has already been merged.');\n\t\t}\n\t\tthis.#parent.mergePayload(this.#text, this.#entities, wrapperEntities);\n\t\tthis.#parent = undefined;\n\t}\n}\n\n/**\n * A lazy implementation of IEntityBuilderBase that stores segments and flattens them into an EntityBuilder only when needed.\n */\nexport class LazyEntityBuilder implements IEntityBuilderBase {\n\t#segments: TextSegment[] = [];\n\t#parent?: LazyEntityBuilder;\n\n\t/**\n\t * Flattens the lazy segments into a new EntityBuilder instance.\n\t */\n\tpublic flatten(): EntityBuilder {\n\t\tconst builder = new EntityBuilder();\n\t\tbuilder.addTextSegmentList(this.#segments);\n\t\treturn builder;\n\t}\n\n\tpublic addText(text: string): this {\n\t\tthis.#segments.push({ text });\n\t\treturn this;\n\t}\n\n\tpublic addTextEntity(text: string, entity: AnyDraftEntity): this {\n\t\tthis.#segments.push({ text, entity });\n\t\treturn this;\n\t}\n\n\tpublic addTextEntities(text: string, entities: AnyDraftEntity[]): this {\n\t\tthis.#segments.push({ text, entities });\n\t\treturn this;\n\t}\n\n\tpublic addTextSegmentList(segments: TextSegment[]): this {\n\t\tthis.#segments.push(...segments);\n\t\treturn this;\n\t}\n\n\tpublic clone(): LazyEntityBuilder {\n\t\tconst instance = new LazyEntityBuilder();\n\t\tinstance.#segments = structuredClone(this.#segments);\n\t\treturn instance;\n\t}\n\n\tpublic fork(): LazyEntityBuilder {\n\t\tconst instance = new LazyEntityBuilder();\n\t\tinstance.#parent = this;\n\t\treturn instance;\n\t}\n\n\tpublic merge(wrapperEntities: AnyDraftEntity[] = []): void {\n\t\tif (!this.#parent) {\n\t\t\tthrow new Error('Cannot merge: This builder is not a fork or has already been merged.');\n\t\t}\n\n\t\tconst wrappedSegments: TextSegment[] = this.#segments.map((seg) => {\n\t\t\tif (seg.text.length === 0) {\n\t\t\t\t// Skip empty strings directly\n\t\t\t\treturn seg;\n\t\t\t}\n\n\t\t\t// Collect all original entities of this segment\n\t\t\tconst existing = seg.entities ? [...seg.entities] : seg.entity ? [seg.entity] : [];\n\n\t\t\treturn {\n\t\t\t\ttext: seg.text,\n\t\t\t\tentities: [...existing, ...wrapperEntities],\n\t\t\t};\n\t\t});\n\n\t\tthis.#parent.addTextSegmentList(wrappedSegments);\n\t\tthis.#parent = undefined;\n\t}\n}\n\n/**\n * Abstract proxy class that delegates all IEntityBuilder operations to an underlying builder instance.\n */\nexport abstract class EntityBuilderProxy<THIS extends IEntityBuilder = IEntityBuilder> implements IEntityBuilder {\n\tprotected constructor(protected _entities: IEntityBuilder) {}\n\n\tpublic get entities(): IEntityBuilder {\n\t\treturn this._entities;\n\t}\n\n\tpublic addText(...args: Parameters<IEntityBuilder['addText']>): this {\n\t\tthis._entities.addText(...args);\n\t\treturn this;\n\t}\n\n\tpublic addTextEntity(...args: Parameters<IEntityBuilder['addTextEntity']>): this {\n\t\tthis._entities.addTextEntity(...args);\n\t\treturn this;\n\t}\n\n\tpublic addTextEntities(...args: Parameters<IEntityBuilder['addTextEntities']>): this {\n\t\tthis._entities.addTextEntities(...args);\n\t\treturn this;\n\t}\n\n\tpublic addTextSegmentList(...args: Parameters<IEntityBuilder['addTextSegmentList']>): this {\n\t\tthis._entities.addTextSegmentList(...args);\n\t\treturn this;\n\t}\n\n\tpublic sliceInplace(...args: Parameters<IEntityBuilder['sliceInplace']>): this {\n\t\tthis._entities.sliceInplace(...args);\n\t\treturn this;\n\t}\n\n\tpublic slice(...args: Parameters<IEntityBuilder['slice']>): THIS {\n\t\treturn this.fork().sliceInplace(...args) as THIS;\n\t}\n\n\tpublic trim(): this {\n\t\tthis._entities.trim();\n\t\treturn this;\n\t}\n\n\tpublic trimStart(): this {\n\t\tthis._entities.trimStart();\n\t\treturn this;\n\t}\n\n\tpublic trimEnd(): this {\n\t\tthis._entities.trimEnd();\n\t\treturn this;\n\t}\n\n\tpublic sortEntities(): this {\n\t\tthis._entities.sortEntities();\n\t\treturn this;\n\t}\n\n\tpublic clone(): THIS {\n\t\tconst newInstance = Object.create(this.constructor.prototype) as EntityBuilderProxy;\n\t\tnewInstance._entities.clone();\n\t\treturn newInstance as IEntityBuilder as THIS;\n\t}\n\n\tpublic fork() {\n\t\treturn this._entities.fork();\n\t}\n\n\tpublic merge(...args: Parameters<IEntityBuilder['merge']>) {\n\t\tthis._entities.merge(...args);\n\t}\n\n\tpublic buildTextPayload() {\n\t\treturn this._entities.buildTextPayload();\n\t}\n\n\tpublic buildCaptionPayload() {\n\t\tconst { text, entities } = this.buildTextPayload();\n\t\treturn {\n\t\t\tcaption: text,\n\t\t\tcaption_entities: entities,\n\t\t};\n\t}\n\n\tpublic buildInlinePayload() {\n\t\tconst { text, entities, link_preview_options } = this.buildTextPayload();\n\t\treturn {\n\t\t\tmessage_text: text,\n\t\t\tentities: entities,\n\t\t\tlink_preview_options,\n\t\t};\n\t}\n}\n\nfunction upperFirst(input: string) {\n\treturn input.slice(0, 1).toUpperCase() + input.slice(1);\n}\n\n/**\n * Escapes a string to be used as a valid tag by removing or replacing invalid characters.\n */\nexport function escapeTag(input: string) {\n\t// return input.replace(/[^\\p{L}\\p{N}_]/gu, \"\");\n\treturn input\n\t\t.replaceAll(/[\"'′]/g, '') // It's => Its\n\t\t.split(/[^\\p{L}\\p{N}_]/gu)\n\t\t.map((s) => upperFirst(s))\n\t\t.join('');\n}\n\nconst SymbolMessageComposer = Symbol('MessageComposer');\n\n/**\n * A high-level composer that wraps an IEntityBuilder and provides additional features like tags and link preview options.\n */\nexport class MessageComposer extends EntityBuilderProxy<MessageComposer> {\n\tprotected [SymbolMessageComposer] = true as const;\n\n\t#upperTags = new Set<string>();\n\t#tags: string[] = [];\n\n\t/**\n\t * Options for link preview generation.\n\t */\n\tpublic linkPreviewOptions?: TT.LinkPreviewOptions;\n\n\tpublic constructor(entities?: IEntityBuilder & { [SymbolMessageComposer]?: never }) {\n\t\tif (entities && SymbolMessageComposer in entities) {\n\t\t\tthrow new Error('Cannot nest MessageComposer inside MessageComposer');\n\t\t}\n\t\tsuper(entities ?? new EntityBuilder());\n\t}\n\n\t/**\n\t * Gets the current list of tags.\n\t */\n\tpublic get tags(): string[] {\n\t\treturn [...this.#tags];\n\t}\n\n\t/**\n\t * Adds one or more tags, escaping them and avoiding duplicates.\n\t */\n\tpublic addTags(...tags: string[]) {\n\t\tfor (let tag of tags) {\n\t\t\ttag = escapeTag(tag);\n\t\t\tconst upperTag = tag.toUpperCase();\n\t\t\tif (this.#upperTags.has(upperTag)) {\n\t\t\t\t// Deduplicate\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.#upperTags.add(upperTag);\n\t\t\tthis.#tags.push(tag);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic override buildTextPayload() {\n\t\tconst entities = this.entities.clone();\n\n\t\tentities.trimEnd().addText('\\n\\n');\n\n\t\tfor (const tag of this.tags) {\n\t\t\tentities.addTextEntity(`#${tag}`, { type: 'hashtag' }).addText(' ');\n\t\t}\n\n\t\tentities.trimEnd();\n\n\t\treturn {\n\t\t\t...entities.buildTextPayload(),\n\t\t\tlink_preview_options: this.linkPreviewOptions,\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsIO,IAAM,gBAAN,MAAM,eAAwC;AAAA,EACpD,QAAQ;AAAA,EACR,YAAgC,CAAC;AAAA,EACjC;AAAA,EAEO,QAAQ,MAAoB;AAClC,SAAK,SAAS;AACd,WAAO;AAAA,EACR;AAAA,EAEO,cAAc,MAAc,QAA8B;AAChE,WAAO,OAAO,IAAI;AAClB,QAAI,KAAK,SAAS,GAAG;AACpB,WAAK,UAAU,KAAK;AAAA,QACnB,GAAG;AAAA,QACH,QAAQ,KAAK,MAAM;AAAA,QACnB,QAAQ,KAAK;AAAA,MACd,CAAC;AACD,WAAK,SAAS;AAAA,IACf;AACA,WAAO;AAAA,EACR;AAAA,EAEO,gBAAgB,MAAc,UAAkC;AACtE,eAAW,UAAU,UAAU;AAC9B,WAAK,UAAU,KAAK;AAAA,QACnB,GAAG;AAAA,QACH,QAAQ,KAAK,MAAM;AAAA,QACnB,QAAQ,KAAK;AAAA,MACd,CAAqB;AAAA,IACtB;AACA,SAAK,SAAS;AACd,WAAO;AAAA,EACR;AAAA,EAEO,mBAAmB,UAA+B;AACxD,eAAW,WAAW,UAAU;AAC/B,UAAI,QAAQ,QAAQ;AACnB,aAAK,cAAc,QAAQ,MAAM,QAAQ,MAAM;AAAA,MAChD,WAAW,QAAQ,UAAU;AAC5B,aAAK,gBAAgB,QAAQ,MAAM,QAAQ,QAAQ;AAAA,MACpD,OAAO;AACN,aAAK,SAAS,QAAQ;AAAA,MACvB;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EAEO,mBAAmB;AACzB,WAAO;AAAA,MACN,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,IAChB;AAAA,EACD;AAAA,EAEO,sBAAsB;AAC5B,WAAO;AAAA,MACN,SAAS,KAAK;AAAA,MACd,kBAAkB,KAAK;AAAA,IACxB;AAAA,EACD;AAAA,EAEO,qBAAqB;AAC3B,WAAO;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,UAAU,KAAK;AAAA,IAChB;AAAA,EACD;AAAA,EAEO,eAAe;AACrB,SAAK,UAAU,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM;AACxE,WAAO;AAAA,EACR;AAAA,EAEO,aAAa,OAAgB,KAAoB;AACvD,QAAI,CAAC,SAAS,CAAC,KAAK;AACnB,aAAO;AAAA,IACR;AAEA,UAAM,MAAM,KAAK,MAAM;AAEvB,UAAM,IAAI,UAAU,SAAY,IAAI,QAAQ,IAAI,KAAK,IAAI,MAAM,OAAO,CAAC,IAAI,KAAK,IAAI,OAAO,GAAG;AAC9F,UAAM,IAAI,QAAQ,SAAY,MAAM,MAAM,IAAI,KAAK,IAAI,MAAM,KAAK,CAAC,IAAI,KAAK,IAAI,KAAK,GAAG;AAExF,QAAI,KAAK,GAAG;AACX,WAAK,QAAQ;AACb,WAAK,YAAY,CAAC;AAClB,aAAO;AAAA,IACR;AAEA,SAAK,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC;AAClC,SAAK,YAAY,KAAK,UAAU,QAA0B,CAAC,WAAW;AAErE,YAAM,eAAe,KAAK,IAAI,GAAG,OAAO,MAAM;AAC9C,YAAM,aAAa,KAAK,IAAI,GAAG,OAAO,SAAS,OAAO,MAAM;AAG5D,UAAI,eAAe,YAAY;AAC9B,eAAO;AAAA,UACN;AAAA,YACC,GAAG;AAAA,YACH,QAAQ,eAAe;AAAA,YACvB,QAAQ,aAAa;AAAA,UACtB;AAAA,QACD;AAAA,MACD;AAGA,aAAO,CAAC;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACR;AAAA,EAEO,MAAM,OAAgB,KAA6B;AACzD,WAAO,KAAK,MAAM,EAAE,aAAa,OAAO,GAAG;AAAA,EAC5C;AAAA,EAEO,YAAkB;AACxB,UAAM,gBAAgB,KAAK,MAAM,UAAU,EAAE;AAC7C,UAAM,OAAO,KAAK,MAAM,SAAS;AACjC,QAAI,OAAO,GAAG;AACb,WAAK,aAAa,IAAI;AAAA,IACvB;AAEA,WAAO;AAAA,EACR;AAAA,EAEO,UAAgB;AACtB,UAAM,gBAAgB,KAAK,MAAM,QAAQ,EAAE;AAC3C,QAAI,gBAAgB,KAAK,MAAM,QAAQ;AACtC,WAAK,aAAa,GAAG,aAAa;AAAA,IACnC;AAEA,WAAO;AAAA,EACR;AAAA,EAEO,OAAa;AACnB,UAAM,iBAAiB,KAAK,MAAM;AAGlC,UAAM,cAAc,iBAAiB,KAAK,MAAM,UAAU,EAAE;AAE5D,UAAM,YAAY,KAAK,MAAM,QAAQ,EAAE;AAEvC,QAAI,cAAc,KAAK,YAAY,gBAAgB;AAClD,WAAK,aAAa,aAAa,SAAS;AAAA,IACzC;AAEA,WAAO;AAAA,EACR;AAAA,EAEO,QAAuB;AAC7B,UAAM,WAAW,IAAI,eAAc;AACnC,aAAS,QAAQ,KAAK;AACtB,aAAS,YAAY,gBAAgB,KAAK,SAAS;AACnD,WAAO;AAAA,EACR;AAAA,EAEO,OAAsB;AAC5B,UAAM,WAAW,IAAI,eAAc;AACnC,aAAS,UAAU;AACnB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKO,aAAa,MAAc,UAA8B,WAA6B,CAAC,GAAS;AACtG,UAAM,cAAc,KAAK,MAAM;AAC/B,SAAK,SAAS;AAEd,SAAK,UAAU;AAAA,MAEd,GAAG,SAAS;AAAA,QACX,CAAC,OACC;AAAA,UACA,GAAG;AAAA,UACH,QAAQ;AAAA,UACR,QAAQ,KAAK;AAAA,QACd;AAAA,MACF;AAAA,MAEA,GAAG,SAAS,IAAI,CAAC,OAAO;AAAA,QACvB,GAAG;AAAA,QACH,QAAQ,EAAE,SAAS;AAAA,MACpB,EAAE;AAAA,IACH;AAAA,EACD;AAAA,EAEO,MAAM,kBAAoC,CAAC,GAAS;AAC1D,QAAI,CAAC,KAAK,SAAS;AAClB,YAAM,IAAI,MAAM,sEAAsE;AAAA,IACvF;AACA,SAAK,QAAQ,aAAa,KAAK,OAAO,KAAK,WAAW,eAAe;AACrE,SAAK,UAAU;AAAA,EAChB;AACD;AAKO,IAAM,oBAAN,MAAM,mBAAgD;AAAA,EAC5D,YAA2B,CAAC;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKO,UAAyB;AAC/B,UAAM,UAAU,IAAI,cAAc;AAClC,YAAQ,mBAAmB,KAAK,SAAS;AACzC,WAAO;AAAA,EACR;AAAA,EAEO,QAAQ,MAAoB;AAClC,SAAK,UAAU,KAAK,EAAE,KAAK,CAAC;AAC5B,WAAO;AAAA,EACR;AAAA,EAEO,cAAc,MAAc,QAA8B;AAChE,SAAK,UAAU,KAAK,EAAE,MAAM,OAAO,CAAC;AACpC,WAAO;AAAA,EACR;AAAA,EAEO,gBAAgB,MAAc,UAAkC;AACtE,SAAK,UAAU,KAAK,EAAE,MAAM,SAAS,CAAC;AACtC,WAAO;AAAA,EACR;AAAA,EAEO,mBAAmB,UAA+B;AACxD,SAAK,UAAU,KAAK,GAAG,QAAQ;AAC/B,WAAO;AAAA,EACR;AAAA,EAEO,QAA2B;AACjC,UAAM,WAAW,IAAI,mBAAkB;AACvC,aAAS,YAAY,gBAAgB,KAAK,SAAS;AACnD,WAAO;AAAA,EACR;AAAA,EAEO,OAA0B;AAChC,UAAM,WAAW,IAAI,mBAAkB;AACvC,aAAS,UAAU;AACnB,WAAO;AAAA,EACR;AAAA,EAEO,MAAM,kBAAoC,CAAC,GAAS;AAC1D,QAAI,CAAC,KAAK,SAAS;AAClB,YAAM,IAAI,MAAM,sEAAsE;AAAA,IACvF;AAEA,UAAM,kBAAiC,KAAK,UAAU,IAAI,CAAC,QAAQ;AAClE,UAAI,IAAI,KAAK,WAAW,GAAG;AAE1B,eAAO;AAAA,MACR;AAGA,YAAM,WAAW,IAAI,WAAW,CAAC,GAAG,IAAI,QAAQ,IAAI,IAAI,SAAS,CAAC,IAAI,MAAM,IAAI,CAAC;AAEjF,aAAO;AAAA,QACN,MAAM,IAAI;AAAA,QACV,UAAU,CAAC,GAAG,UAAU,GAAG,eAAe;AAAA,MAC3C;AAAA,IACD,CAAC;AAED,SAAK,QAAQ,mBAAmB,eAAe;AAC/C,SAAK,UAAU;AAAA,EAChB;AACD;AAKO,IAAe,qBAAf,MAA0G;AAAA,EACtG,YAAsB,WAA2B;AAA3B;AAAA,EAA4B;AAAA,EAA5B;AAAA,EAEhC,IAAW,WAA2B;AACrC,WAAO,KAAK;AAAA,EACb;AAAA,EAEO,WAAW,MAAmD;AACpE,SAAK,UAAU,QAAQ,GAAG,IAAI;AAC9B,WAAO;AAAA,EACR;AAAA,EAEO,iBAAiB,MAAyD;AAChF,SAAK,UAAU,cAAc,GAAG,IAAI;AACpC,WAAO;AAAA,EACR;AAAA,EAEO,mBAAmB,MAA2D;AACpF,SAAK,UAAU,gBAAgB,GAAG,IAAI;AACtC,WAAO;AAAA,EACR;AAAA,EAEO,sBAAsB,MAA8D;AAC1F,SAAK,UAAU,mBAAmB,GAAG,IAAI;AACzC,WAAO;AAAA,EACR;AAAA,EAEO,gBAAgB,MAAwD;AAC9E,SAAK,UAAU,aAAa,GAAG,IAAI;AACnC,WAAO;AAAA,EACR;AAAA,EAEO,SAAS,MAAiD;AAChE,WAAO,KAAK,KAAK,EAAE,aAAa,GAAG,IAAI;AAAA,EACxC;AAAA,EAEO,OAAa;AACnB,SAAK,UAAU,KAAK;AACpB,WAAO;AAAA,EACR;AAAA,EAEO,YAAkB;AACxB,SAAK,UAAU,UAAU;AACzB,WAAO;AAAA,EACR;AAAA,EAEO,UAAgB;AACtB,SAAK,UAAU,QAAQ;AACvB,WAAO;AAAA,EACR;AAAA,EAEO,eAAqB;AAC3B,SAAK,UAAU,aAAa;AAC5B,WAAO;AAAA,EACR;AAAA,EAEO,QAAc;AACpB,UAAM,cAAc,OAAO,OAAO,KAAK,YAAY,SAAS;AAC5D,gBAAY,UAAU,MAAM;AAC5B,WAAO;AAAA,EACR;AAAA,EAEO,OAAO;AACb,WAAO,KAAK,UAAU,KAAK;AAAA,EAC5B;AAAA,EAEO,SAAS,MAA2C;AAC1D,SAAK,UAAU,MAAM,GAAG,IAAI;AAAA,EAC7B;AAAA,EAEO,mBAAmB;AACzB,WAAO,KAAK,UAAU,iBAAiB;AAAA,EACxC;AAAA,EAEO,sBAAsB;AAC5B,UAAM,EAAE,MAAM,SAAS,IAAI,KAAK,iBAAiB;AACjD,WAAO;AAAA,MACN,SAAS;AAAA,MACT,kBAAkB;AAAA,IACnB;AAAA,EACD;AAAA,EAEO,qBAAqB;AAC3B,UAAM,EAAE,MAAM,UAAU,qBAAqB,IAAI,KAAK,iBAAiB;AACvE,WAAO;AAAA,MACN,cAAc;AAAA,MACd;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;AAEA,SAAS,WAAW,OAAe;AAClC,SAAO,MAAM,MAAM,GAAG,CAAC,EAAE,YAAY,IAAI,MAAM,MAAM,CAAC;AACvD;AAKO,SAAS,UAAU,OAAe;AAExC,SAAO,MACL,WAAW,UAAU,EAAE,EACvB,MAAM,kBAAkB,EACxB,IAAI,CAAC,MAAM,WAAW,CAAC,CAAC,EACxB,KAAK,EAAE;AACV;AAEA,IAAM,wBAAwB,uBAAO,iBAAiB;AAK/C,IAAM,kBAAN,cAA8B,mBAAoC;AAAA,EACxE,CAAW,qBAAqB,IAAI;AAAA,EAEpC,aAAa,oBAAI,IAAY;AAAA,EAC7B,QAAkB,CAAC;AAAA;AAAA;AAAA;AAAA,EAKZ;AAAA,EAEA,YAAY,UAAiE;AACnF,QAAI,YAAY,yBAAyB,UAAU;AAClD,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACrE;AACA,UAAM,YAAY,IAAI,cAAc,CAAC;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,OAAiB;AAC3B,WAAO,CAAC,GAAG,KAAK,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKO,WAAW,MAAgB;AACjC,aAAS,OAAO,MAAM;AACrB,YAAM,UAAU,GAAG;AACnB,YAAM,WAAW,IAAI,YAAY;AACjC,UAAI,KAAK,WAAW,IAAI,QAAQ,GAAG;AAElC;AAAA,MACD;AACA,WAAK,WAAW,IAAI,QAAQ;AAC5B,WAAK,MAAM,KAAK,GAAG;AAAA,IACpB;AAEA,WAAO;AAAA,EACR;AAAA,EAEgB,mBAAmB;AAClC,UAAM,WAAW,KAAK,SAAS,MAAM;AAErC,aAAS,QAAQ,EAAE,QAAQ,MAAM;AAEjC,eAAW,OAAO,KAAK,MAAM;AAC5B,eAAS,cAAc,IAAI,GAAG,IAAI,EAAE,MAAM,UAAU,CAAC,EAAE,QAAQ,GAAG;AAAA,IACnE;AAEA,aAAS,QAAQ;AAEjB,WAAO;AAAA,MACN,GAAG,SAAS,iBAAiB;AAAA,MAC7B,sBAAsB,KAAK;AAAA,IAC5B;AAAA,EACD;AACD;","names":[]}