@gramio/format
Version:
Library for formatting text for Telegram Bot API
493 lines (488 loc) • 19.1 kB
JavaScript
;
class FormattableString {
/** Text of FormattableString (auto covert to it if entities is unsupported)*/
text;
/** Entities of FormattableString */
entities;
/** Create new FormattableString */
constructor(text, entities) {
this.text = text;
this.entities = entities;
}
/** Create new FormattableString */
static from(text, entities) {
return new FormattableString(text, entities);
}
toString() {
return this.text;
}
toJSON() {
return this.text;
}
// ![INFO] - https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-3.html#instanceof-narrowing-through-symbolhasinstance
static [Symbol.hasInstance](value) {
return !!value && typeof value === "object" && "text" in value && "entities" in value;
}
}
function getFormattable(str) {
if (str instanceof FormattableString) return str;
return new FormattableString(str.toString(), []);
}
const FormattableMap = {
sendMessage: (params) => {
if (params.text instanceof FormattableString) {
params.entities = params.text.entities;
params.text = params.text.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
copyMessage: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendPhoto: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendAudio: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendDocument: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendVideo: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendAnimation: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendVoice: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendVideoNote: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendMediaGroup: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
if (params.media.length)
params.media = params.media.map(
(x) => "caption" in x && x.caption instanceof FormattableString ? {
...x,
caption: x.caption.text,
caption_entities: x.caption.entities
} : x
);
return params;
},
sendLocation: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendVenue: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendContact: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendPoll: (params) => {
if (params.question instanceof FormattableString) {
params.question_entities = params.question.entities;
params.question = params.question.text;
}
if (params.explanation instanceof FormattableString) {
params.explanation_entities = params.explanation.entities;
params.explanation = params.explanation.text;
}
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
if (params.options.length)
params.options = params.options.map(
(x) => "text" in x && x.text instanceof FormattableString ? { ...x, text: x.text.text, text_entities: x.text.entities } : x
);
return params;
},
sendDice: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
editMessageText: (params) => {
if (params.text instanceof FormattableString) {
params.entities = params.text.entities;
params.text = params.text.text;
}
return params;
},
editMessageCaption: (params) => {
if (params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
return params;
},
editMessageMedia: (params) => {
if (params.media !== void 0 && "caption" in params.media && params.media.caption instanceof FormattableString) {
params.media.caption_entities = params.media.caption.entities;
params.media.caption = params.media.caption.text;
}
return params;
},
sendSticker: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
// TODO: fix
answerInlineQuery: (params) => {
if (params.results?.length)
params.results = params.results.map(
(x) => "caption" in x && x.caption instanceof FormattableString ? {
...x,
caption: x.caption.text,
caption_entities: x.caption.entities
} : x
);
if (params.results?.length)
params.results = params.results.map(
(x) => "input_message_content" in x && x.input_message_content && "message_text" in x.input_message_content && x.input_message_content.message_text instanceof FormattableString ? {
...x,
input_message_content: {
...x.input_message_content,
message_text: x.input_message_content.message_text.text,
entities: x.input_message_content.message_text.entities
}
} : x
);
return params;
},
savePreparedInlineMessage: (params) => {
if ("caption" in params.result && params.result.caption instanceof FormattableString) {
params.result.caption_entities = params.result.caption.entities;
params.result.caption = params.result.caption.text;
}
if ("input_message_content" in params.result && params.result.input_message_content && "message_text" in params.result.input_message_content && params.result.input_message_content.message_text instanceof FormattableString) {
params.result = {
...params.result,
input_message_content: {
...params.result.input_message_content,
message_text: params.result.input_message_content.message_text.text,
entities: params.result.input_message_content.message_text.entities
}
};
}
return params;
},
sendGift: (params) => {
if (params.text instanceof FormattableString) {
params.text_entities = params.text.entities;
params.text = params.text.text;
}
return params;
},
answerWebAppQuery: (params) => {
if (params.result !== void 0 && "caption" in params.result && params.result.caption instanceof FormattableString) {
params.result.caption_entities = params.result.caption.entities;
params.result.caption = params.result.caption.text;
}
if ("input_message_content" in params.result && params.result.input_message_content !== void 0 && "message_text" in params.result.input_message_content && params.result.input_message_content.message_text instanceof FormattableString) {
params.result.input_message_content.entities = params.result.input_message_content.message_text.entities;
params.result.input_message_content.message_text = params.result.input_message_content.message_text.text;
}
return params;
},
sendInvoice: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
sendGame: (params) => {
if (params.reply_parameters !== void 0 && "quote" in params.reply_parameters && params.reply_parameters.quote instanceof FormattableString) {
params.reply_parameters.quote_entities = params.reply_parameters.quote.entities;
params.reply_parameters.quote = params.reply_parameters.quote.text;
}
return params;
},
giftPremiumSubscription: (params) => {
if (params.text && params.text instanceof FormattableString) {
params.text_entities = params.text.entities;
params.text = params.text.text;
}
return params;
},
postStory: (params) => {
if (params.caption && params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
return params;
},
editStory: (params) => {
if (params.caption && params.caption instanceof FormattableString) {
params.caption_entities = params.caption.entities;
params.caption = params.caption.text;
}
return params;
},
editMessageChecklist: (params) => {
if (params.checklist.title instanceof FormattableString) {
params.checklist.title_entities = params.checklist.title.entities;
params.checklist.title = params.checklist.title.text;
}
if (params.checklist.tasks.length) {
params.checklist.tasks = params.checklist.tasks.map((x) => {
if (x.text instanceof FormattableString) {
x.text_entities = x.text.entities;
x.text = x.text.text;
}
return x;
});
}
return params;
},
sendChecklist: (params) => {
if (params.checklist.title instanceof FormattableString) {
params.checklist.title_entities = params.checklist.title.entities;
params.checklist.title = params.checklist.title.text;
}
if (params.checklist.tasks.length) {
params.checklist.tasks = params.checklist.tasks.map((x) => {
if (x.text instanceof FormattableString) {
x.text_entities = x.text.entities;
x.text = x.text.text;
}
return x;
});
}
return params;
}
};
function buildFormatter(type) {
function formatter(first, ...rest) {
if (Array.isArray(first) && Object.hasOwn(first, "raw")) {
return formatter(
format(first, ...rest)
);
}
const formattable = getFormattable(first);
return new FormattableString(formattable.text, [
{
type,
offset: 0,
length: formattable.text.length
},
...formattable.entities
]);
}
return formatter;
}
function buildFormatterWithArgs(type, ...keys) {
return (str, ...args) => {
const formattable = getFormattable(str);
const formattableArgs = Object.fromEntries(
keys.map((key, i) => [key, args[i]])
);
return new FormattableString(formattable.text, [
{
type,
offset: 0,
length: formattable.text.length,
...formattableArgs
},
...formattable.entities
]);
};
}
const bold = buildFormatter("bold");
const italic = buildFormatter("italic");
const underline = buildFormatter("underline");
const strikethrough = buildFormatter("strikethrough");
const spoiler = buildFormatter("spoiler");
const blockquote = buildFormatter("blockquote");
const expandableBlockquote = buildFormatter("expandable_blockquote");
const code = buildFormatter("code");
const pre = buildFormatterWithArgs(
"pre",
"language"
);
const link = buildFormatterWithArgs("text_link", "url");
const mention = buildFormatterWithArgs(
"text_mention",
// @ts-expect-error wrong typings.... but it's works fine
"user"
);
const customEmoji = buildFormatterWithArgs(
"custom_emoji",
"custom_emoji_id"
);
function join(array, iterator, separator = ", ") {
let text = "";
const entities = [];
for (const [index, str] of array.map(iterator).entries()) {
if (str instanceof FormattableString)
entities.push(
...str.entities.map((e) => ({
...e,
offset: e.offset + text.length
}))
);
if (typeof str !== "undefined" && str !== null && str !== false)
text += str.toString() + (index === array.length - 1 ? "" : separator);
}
return new FormattableString(text, entities);
}
function processDeeperFormat(offset, strings) {
let text = "";
const entities = [];
for (const str of strings) {
if (Array.isArray(str)) {
const [newText, newEntities] = processDeeperFormat(text.length, str);
text += newText;
entities.push(...newEntities);
continue;
}
if (str instanceof FormattableString)
entities.push(
...str.entities.map((e) => ({
...e,
offset: e.offset + text.length + offset
}))
);
text += str.toString();
}
return [text, entities];
}
function processRawFormat(stringParts, strings) {
const entities = [];
let text = "";
const length = Math.max(stringParts.length, strings.length);
for (let index = 0; index < length; index++) {
for (const str of [stringParts[index], strings[index]]) {
if (Array.isArray(str)) {
const [newText, newEntities] = processDeeperFormat(text.length, str);
text += newText;
entities.push(...newEntities);
continue;
}
if (str instanceof FormattableString)
entities.push(
...str.entities.map((e) => ({
...e,
offset: e.offset + text.length
}))
);
if (typeof str !== "undefined") text += str.toString();
}
}
return new FormattableString(text, entities);
}
function format(stringParts, ...strings) {
return processRawFormat(
stringParts.map((x) => x.replace(/(?!\n\s+\n)\n(?!\n)\s+/g, "\n")),
strings
);
}
function formatSaveIndents(stringParts, ...strings) {
return processRawFormat([...stringParts], strings);
}
exports.FormattableMap = FormattableMap;
exports.FormattableString = FormattableString;
exports.blockquote = blockquote;
exports.bold = bold;
exports.code = code;
exports.customEmoji = customEmoji;
exports.expandableBlockquote = expandableBlockquote;
exports.format = format;
exports.formatSaveIndents = formatSaveIndents;
exports.getFormattable = getFormattable;
exports.italic = italic;
exports.join = join;
exports.link = link;
exports.mention = mention;
exports.pre = pre;
exports.spoiler = spoiler;
exports.strikethrough = strikethrough;
exports.underline = underline;