diff --git a/index.js b/index.js
index 0fb6c27..d04a823 100644
--- a/index.js
+++ b/index.js
@@ -12,7 +12,7 @@ class EntityMessage {
// validate params
if (!text || typeof text !== "string" || !entities || !entities.length) {
throw new Error(
- `Expected string in field text - got ${typeof text}, array/object in field entities - got ${typeof entities}`
+ `Expected string in field text - got ${typeof text}, array/object in field entities - got ${typeof entities}`
);
}
this.text = text;
@@ -24,19 +24,7 @@ class EntityMessage {
* @return {string} HTML formatted text
*/
get html() {
- let content = this.text;
- let totalOffset = 0;
- for (let entity of this.entities) {
- let replacement = formatEntity(this.text, entity, "html");
- content = spliceString(
- content,
- totalOffset + entity.offset,
- entity.length,
- replacement
- );
- totalOffset += replacement.length - entity.length;
- }
- return content;
+ return applyEntity(this.text, this.entities, "html");
}
/**
@@ -44,108 +32,138 @@ class EntityMessage {
* @return {string} Markdown formatted text
*/
get markdown() {
- let content = this.text;
- let totalOffset = 0;
- for (let entity of this.entities) {
- let replacement = formatEntity(this.text, entity, "markdown");
- content = spliceString(
- content,
- entity.offset,
- entity.length,
- replacement
- );
- totalOffset += replacement.length - entity.length;
- }
- return content;
+ return applyEntity(this.text, this.entities, "markdown");
}
}
// Helper functions
-function formatEntity(text, entity, format) {
- let entityText = text.substring(entity.offset, entity.offset + entity.length);
- let options = {};
- switch (entity.type) {
- case "text_link":
- options.url = entity.url;
- break;
- case "text_mention":
- options.user = entity.user;
- break;
- case "pre":
- options.language = entity.language;
- break;
- case "custom_emoji":
- options.custom_emoji_id = entity.custom_emoji_id;
- break;
+function applyEntity(mainText = "", entities, markupType = "html") {
+ if (markupType !== "html" || markupType !== "markdown") return mainText;
+ if (!entities.length) return mainText;
+ if (!mainText.length) return mainText;
+
+ let content = mainText;
+ const addedTags = [];
+ for (let entity of entities) {
+ const {
+ type,
+ offset,
+ length,
+ url,
+ user,
+ language,
+ custom_emoji_id
+ } = entity;
+ const text = mainText.slice(offset, offset + length);
+ const [opening, closing] = (entityTypes(text, {
+ url,
+ userId: user?.id,
+ custom_emoji_id,
+ language
+ })[type][markupType] || ["", ""]);
+
+ if (opening !== "" || closing !== "") {
+ const {start: beforeStart, end: beforeEnd} = addedTags.reduce((t, {startAt, tag}) => {
+ let {start, end} = t;
+ if (startAt <= offset) {
+ start += tag.length;
+ }
+ if (startAt < (offset + length)) {
+ end += tag.length
+ }
+ return {start, end};
+ }, {
+ start: 0, end: 0
+ })
+
+ const start = offset + beforeStart;
+ const end = offset + length + beforeEnd;
+ addedTags.push({startAt: offset, tag: opening});
+ addedTags.push({startAt: offset + length, tag: closing});
+ content = content.slice(0, start) + opening + content.slice(start, end) + closing + content.slice(end);
+ }
}
- return entityTypes[entity.type][format](entityText, options);
+ return content;
}
-const entityTypes = {
- mention: { html: (text) => text, markdown: (text) => text },
-
- hashtag: { html: (text) => text, markdown: (text) => text },
-
- cashtag: { html: (text) => text, markdown: (text) => text },
-
- bot_command: { html: (text) => text, markdown: (text) => text },
-
- url: { html: (text) => text, markdown: (text) => text },
-
- email: { html: (text) => text, markdown: (text) => text },
-
- phone_number: { html: (text) => text, markdown: (text) => text },
-
- bold: { html: (text) => `${text}`, markdown: (text) => `**${text}**` },
+const entityTypes = (text, {url, userId, custom_emoji_id}) => {
- italic: { html: (text) => `${text}`, markdown: (text) => `*${text}*` },
-
- underline: { html: (text) => `${text}`, markdown: (text) => text },
-
- strikethrough: {
- html: (text) => `${text}`,
- markdown: (text) => text,
- },
-
- spoiler: { html: (text) => text, markdown: (text) => text },
-
- code: {
- html: (text) => `${text}
`,
- markdown: (text) => `\`${text}\``,
- },
-
- pre: {
- html: (text, { language }) => `
${text}`, - markdown: (text, { language }) => `\`\`\`${text}\`\`\``, - }, - - text_link: { - html: (text, { url }) => `${text}`, - markdown: (text, { url }) => `[${text}](${url})`, - }, - - text_mention: { - html: (text, { user }) => text, - markdown: (text, { user }) => text, - }, - - custom_emoji: { - html: (text, { custom_emoji_id }) => "", - markdown: (text, { custom_emoji_id }) => "", - }, -}; - -// Utility function -function spliceString(str, index, count, add) { - // We cannot pass negative indexes directly to the 2nd slicing operation. - if (index < 0) { - index = str.length + index; - if (index < 0) { - index = 0; - } + /** + * [markUpType]: { + * [markUpName]: [openingTag, closingTag], + * }, + * */ + + return { + mention: { + html: [``, ``], + markdown: [`[`, `](https://t.me/${text.slice(1)})`], + }, + hashtag: { + html: [``, ``], + markdown: [``, ``], + }, + cashtag: { + html: [``, ``], + markdown: [``, ``], + }, + bot_command: { + html: [``, ``], + markdown: [``, ``], + }, + url: { + html: [``, ``], + markdown: [`[`, `](${text})`], + }, + email: { + html: [``, ``], + markdown: [`[`, `](mailto:${text})`], + }, + phone_number: { + html: [``, ``], + markdown: [`[`, `](tel:${text})`], + }, + bold: { + html: [``, ``], + markdown: [`**`, `**`], + }, + italic: { + html: [``, ``], + markdown: [`*`, `*`], + }, + underline: { + html: [``, ``], + markdown: [``, ``], + }, + strikethrough: { + html: [`
`, `
`],
+ markdown: [``, ``],
+ },
+ pre: {
+ html: [``, ``], + markdown: [`\`\`\``, `\`\`\``], + }, + text_link: { + html: [``, ``], + markdown: [`[`, `](${url})`], + }, + text_mention: { + html: [``, ``], + markdown: [`[`, `](tg://user?id=${userId})`], + }, + custom_emoji: { + html: [``, ``], + markdown: [``, ``], + }, } - - return str.slice(0, index) + (add || "") + str.slice(index + count); } -module.exports = { EntityMessage }; +module.exports = {EntityMessage};