"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.language = void 0;
const M = __importStar(require(".."));
const P = __importStar(require("./core"));
const util_1 = require("./util");
const regex_1 = __importDefault(require("@twemoji/parser/dist/lib/regex"));
const space = P.difference(P.regexp(/\s/), P.newline);
const alphaAndNum = P.regexp(/\p{Letter}|\p{Number}/iu);
const newLine = P.alt([P.crlf, P.cr, P.lf]);
function seqOrText(parsers) {
return new P.Parser((input, index, state) => {
const accum = [];
let latestIndex = index;
for (let i = 0; i < parsers.length; i++) {
const result = parsers[i].handler(input, latestIndex, state);
if (!result.success) {
if (latestIndex === index) {
return P.failure();
}
else {
return P.success(latestIndex, input.slice(index, latestIndex));
}
}
accum.push(result.value);
latestIndex = result.index;
}
return P.success(latestIndex, accum);
});
}
const notLinkLabel = new P.Parser((_input, index, state) => {
return (!state.linkLabel)
? P.success(index, null)
: P.failure();
});
const nestable = new P.Parser((_input, index, state) => {
return (state.depth < state.nestLimit)
? P.success(index, null)
: P.failure();
});
function nest(parser, fallback) {
const inner = P.alt([
P.seq([nestable, parser], 1),
(fallback != null) ? fallback : P.char,
]);
return new P.Parser((input, index, state) => {
state.depth++;
const result = inner.handler(input, index, state);
state.depth--;
return result;
});
}
exports.language = P.createLanguage({
fullParser: r => {
return r.full.many(0);
},
simpleParser: r => {
return r.simple.many(0);
},
full: r => {
return P.alt([
r.unicodeEmoji,
r.centerTag,
r.smallTag,
r.plainTag,
r.boldTag,
r.italicTag,
r.strikeTag,
r.urlAlt,
r.big,
r.boldAsta,
r.italicAsta,
r.boldUnder,
r.italicUnder,
r.codeBlock,
r.inlineCode,
r.quote,
r.mathBlock,
r.mathInline,
r.strikeWave,
r.fn,
r.mention,
r.hashtag,
r.emojiCode,
r.link,
r.url,
r.search,
r.text,
]);
},
simple: r => {
return P.alt([
r.unicodeEmoji,
r.emojiCode,
r.text,
]);
},
inline: r => {
return P.alt([
r.unicodeEmoji,
r.smallTag,
r.plainTag,
r.boldTag,
r.italicTag,
r.strikeTag,
r.urlAlt,
r.big,
r.boldAsta,
r.italicAsta,
r.boldUnder,
r.italicUnder,
r.inlineCode,
r.mathInline,
r.strikeWave,
r.fn,
r.mention,
r.hashtag,
r.emojiCode,
r.link,
r.url,
r.text,
]);
},
quote: r => {
const lines = P.seq([
P.str('>'),
space.option(),
P.seq([P.notMatch(newLine), P.char], 1).many(0).text(),
], 2).sep(newLine, 1);
const parser = P.seq([
newLine.option(),
newLine.option(),
P.lineBegin,
lines,
newLine.option(),
newLine.option(),
], 3);
return new P.Parser((input, index, state) => {
let result;
result = parser.handler(input, index, state);
if (!result.success) {
return result;
}
const contents = result.value;
const quoteIndex = result.index;
if (contents.length === 1 && contents[0].length === 0) {
return P.failure();
}
const contentParser = nest(r.fullParser).many(0);
result = contentParser.handler(contents.join('\n'), 0, state);
if (!result.success) {
return result;
}
return P.success(quoteIndex, M.QUOTE((0, util_1.mergeText)(result.value)));
});
},
codeBlock: r => {
const mark = P.str('```');
return P.seq([
newLine.option(),
P.lineBegin,
mark,
P.seq([P.notMatch(newLine), P.char], 1).many(0),
newLine,
P.seq([P.notMatch(P.seq([newLine, mark, P.lineEnd])), P.char], 1).many(1),
newLine,
mark,
P.lineEnd,
newLine.option(),
]).map(result => {
const lang = result[3].join('').trim();
const code = result[5].join('');
return M.CODE_BLOCK(code, (lang.length > 0 ? lang : null));
});
},
mathBlock: r => {
const open = P.str('\\[');
const close = P.str('\\]');
return P.seq([
newLine.option(),
open,
newLine.option(),
P.seq([P.notMatch(P.seq([newLine.option(), close])), P.char], 1).many(1),
newLine.option(),
close,
newLine.option(),
]).map(result => {
const formula = result[3].join('');
return M.MATH_BLOCK(formula);
});
},
centerTag: r => {
const open = P.str('
');
const close = P.str('');
return P.seq([
newLine.option(),
P.lineBegin,
open,
newLine.option(),
P.seq([P.notMatch(P.seq([newLine.option(), close])), nest(r.inline)], 1).many(1),
newLine.option(),
close,
P.lineEnd,
newLine.option(),
]).map(result => {
return M.CENTER((0, util_1.mergeText)(result[4]));
});
},
big: r => {
const mark = P.str('***');
return seqOrText([
mark,
P.seq([P.notMatch(mark), nest(r.inline)], 1).many(1),
mark,
]).map(result => {
if (typeof result === 'string')
return result;
return M.FN('tada', {}, (0, util_1.mergeText)(result[1]));
});
},
boldAsta: r => {
const mark = P.str('**');
return seqOrText([
mark,
P.seq([P.notMatch(mark), nest(r.inline)], 1).many(1),
mark,
]).map(result => {
if (typeof result === 'string')
return result;
return M.BOLD((0, util_1.mergeText)(result[1]));
});
},
boldTag: r => {
const open = P.str('');
const close = P.str('');
return seqOrText([
open,
P.seq([P.notMatch(close), nest(r.inline)], 1).many(1),
close,
]).map(result => {
if (typeof result === 'string')
return result;
return M.BOLD((0, util_1.mergeText)(result[1]));
});
},
boldUnder: r => {
const mark = P.str('__');
return P.seq([
mark,
P.alt([alphaAndNum, space]).many(1),
mark,
]).map(result => M.BOLD((0, util_1.mergeText)(result[1])));
},
smallTag: r => {
const open = P.str('');
const close = P.str('');
return seqOrText([
open,
P.seq([P.notMatch(close), nest(r.inline)], 1).many(1),
close,
]).map(result => {
if (typeof result === 'string')
return result;
return M.SMALL((0, util_1.mergeText)(result[1]));
});
},
italicTag: r => {
const open = P.str('');
const close = P.str('');
return seqOrText([
open,
P.seq([P.notMatch(close), nest(r.inline)], 1).many(1),
close,
]).map(result => {
if (typeof result === 'string')
return result;
return M.ITALIC((0, util_1.mergeText)(result[1]));
});
},
italicAsta: r => {
const mark = P.str('*');
const parser = P.seq([
mark,
P.alt([alphaAndNum, space]).many(1),
mark,
]);
return new P.Parser((input, index, state) => {
const result = parser.handler(input, index, state);
if (!result.success) {
return P.failure();
}
const beforeStr = input.slice(0, index);
if (/[a-z0-9]$/i.test(beforeStr)) {
return P.failure();
}
return P.success(result.index, M.ITALIC((0, util_1.mergeText)(result.value[1])));
});
},
italicUnder: r => {
const mark = P.str('_');
const parser = P.seq([
mark,
P.alt([alphaAndNum, space]).many(1),
mark,
]);
return new P.Parser((input, index, state) => {
const result = parser.handler(input, index, state);
if (!result.success) {
return P.failure();
}
const beforeStr = input.slice(0, index);
if (/[a-z0-9]$/i.test(beforeStr)) {
return P.failure();
}
return P.success(result.index, M.ITALIC((0, util_1.mergeText)(result.value[1])));
});
},
strikeTag: r => {
const open = P.str('');
const close = P.str('');
return seqOrText([
open,
P.seq([P.notMatch(close), nest(r.inline)], 1).many(1),
close,
]).map(result => {
if (typeof result === 'string')
return result;
return M.STRIKE((0, util_1.mergeText)(result[1]));
});
},
strikeWave: r => {
const mark = P.str('~~');
return seqOrText([
mark,
P.seq([P.notMatch(P.alt([mark, newLine])), nest(r.inline)], 1).many(1),
mark,
]).map(result => {
if (typeof result === 'string')
return result;
return M.STRIKE((0, util_1.mergeText)(result[1]));
});
},
unicodeEmoji: r => {
const emoji = RegExp(regex_1.default.source);
return P.regexp(emoji).map(content => M.UNI_EMOJI(content));
},
plainTag: r => {
const open = P.str('');
const close = P.str('');
return P.seq([
open,
newLine.option(),
P.seq([
P.notMatch(P.seq([newLine.option(), close])),
P.char,
], 1).many(1).text(),
newLine.option(),
close,
], 2).map(result => M.PLAIN(result));
},
fn: r => {
const fnName = new P.Parser((input, index, state) => {
const result = P.regexp(/[a-z0-9_]+/i).handler(input, index, state);
if (!result.success) {
return result;
}
return P.success(result.index, result.value);
});
const arg = P.seq([
P.regexp(/[a-z0-9_]+/i),
P.seq([
P.str('='),
P.regexp(/[a-z0-9_.-]+/i),
], 1).option(),
]).map(result => {
return {
k: result[0],
v: (result[1] != null) ? result[1] : true,
};
});
const args = P.seq([
P.str('.'),
arg.sep(P.str(','), 1),
], 1).map(pairs => {
const result = {};
for (const pair of pairs) {
result[pair.k] = pair.v;
}
return result;
});
const fnClose = P.str(']');
return seqOrText([
P.str('$['),
fnName,
args.option(),
P.str(' '),
P.seq([P.notMatch(fnClose), nest(r.inline)], 1).many(1),
fnClose,
]).map(result => {
if (typeof result === 'string')
return result;
const name = result[1];
const args = result[2] || {};
const content = result[4];
return M.FN(name, args, (0, util_1.mergeText)(content));
});
},
inlineCode: r => {
const mark = P.str('`');
return P.seq([
mark,
P.seq([
P.notMatch(P.alt([mark, P.str('´'), newLine])),
P.char,
], 1).many(1),
mark,
]).map(result => M.INLINE_CODE(result[1].join('')));
},
mathInline: r => {
const open = P.str('\\(');
const close = P.str('\\)');
return P.seq([
open,
P.seq([
P.notMatch(P.alt([close, newLine])),
P.char,
], 1).many(1),
close,
]).map(result => M.MATH_INLINE(result[1].join('')));
},
mention: r => {
const parser = P.seq([
notLinkLabel,
P.str('@'),
P.regexp(/[a-z0-9_.-]+/i),
P.seq([
P.str('@'),
P.regexp(/[a-z0-9_.-]+/i),
], 1).option(),
]);
return new P.Parser((input, index, state) => {
let result;
result = parser.handler(input, index, state);
if (!result.success) {
return P.failure();
}
const beforeStr = input.slice(0, index);
if (/[a-z0-9]$/i.test(beforeStr)) {
return P.failure();
}
let invalidMention = false;
const resultIndex = result.index;
const username = result.value[2];
const hostname = result.value[3];
let modifiedHost = hostname;
if (hostname != null) {
result = /[.-]+$/.exec(hostname);
if (result != null) {
modifiedHost = hostname.slice(0, (-1 * result[0].length));
if (modifiedHost.length === 0) {
invalidMention = true;
modifiedHost = null;
}
}
}
let modifiedName = username;
result = /-+$/.exec(username);
if (result != null) {
if (modifiedHost == null) {
modifiedName = username.slice(0, (-1 * result[0].length));
}
else {
invalidMention = true;
}
}
if (modifiedName.length === 0 || modifiedName[0] === '-') {
invalidMention = true;
}
if (modifiedHost != null && /^[.-]/.test(modifiedHost)) {
invalidMention = true;
}
if (invalidMention) {
return P.success(resultIndex, input.slice(index, resultIndex));
}
const acct = modifiedHost != null ? `@${modifiedName}@${modifiedHost}` : `@${modifiedName}`;
return P.success(index + acct.length, M.MENTION(modifiedName, modifiedHost, acct));
});
},
hashtag: r => {
const mark = P.str('#');
const hashTagChar = P.seq([
P.notMatch(P.regexp(/[\s.,\u2063!?'"#:/[\]【】()「」()<>]/u)),
P.char,
], 1);
const innerItem = P.lazy(() => P.alt([
P.seq([
P.str('('), nest(innerItem, hashTagChar).many(0), P.str(')'),
]),
P.seq([
P.str('['), nest(innerItem, hashTagChar).many(0), P.str(']'),
]),
P.seq([
P.str('「'), nest(innerItem, hashTagChar).many(0), P.str('」'),
]),
P.seq([
P.str('('), nest(innerItem, hashTagChar).many(0), P.str(')'),
]),
hashTagChar,
]));
const parser = P.seq([
notLinkLabel,
mark,
innerItem.many(1).text(),
], 2);
return new P.Parser((input, index, state) => {
const result = parser.handler(input, index, state);
if (!result.success) {
return P.failure();
}
const beforeStr = input.slice(0, index);
if (/[a-z0-9]$/i.test(beforeStr)) {
return P.failure();
}
const resultIndex = result.index;
const resultValue = result.value;
if (/^[0-9]+$/.test(resultValue)) {
return P.failure();
}
return P.success(resultIndex, M.HASHTAG(resultValue));
});
},
emojiCode: r => {
const side = P.notMatch(P.regexp(/[a-z0-9]/i));
const mark = P.str(':');
return P.seq([
P.alt([P.lineBegin, side]),
mark,
P.regexp(/[\p{Letter}\p{Number}\p{Mark}_+-]+/iu),
mark,
P.alt([P.lineEnd, side]),
], 2).map(name => M.EMOJI_CODE(name.normalize('NFC')));
},
link: r => {
const labelInline = new P.Parser((input, index, state) => {
state.linkLabel = true;
const result = r.inline.handler(input, index, state);
state.linkLabel = false;
return result;
});
const closeLabel = P.str(']');
return P.seq([
notLinkLabel,
P.alt([P.str('?['), P.str('[')]),
P.seq([
P.notMatch(P.alt([closeLabel, newLine])),
nest(labelInline),
], 1).many(1),
closeLabel,
P.str('('),
P.alt([r.urlAlt, r.url]),
P.str(')'),
]).map(result => {
const silent = (result[1] === '?[');
const label = result[2];
const url = result[5];
return M.LINK(silent, url.props.url, (0, util_1.mergeText)(label));
});
},
url: r => {
const urlChar = P.regexp(/[.,a-z0-9_/:%#@$&?!~=+-]/i);
const innerItem = P.lazy(() => P.alt([
P.seq([
P.str('('), nest(innerItem, urlChar).many(0), P.str(')'),
]),
P.seq([
P.str('['), nest(innerItem, urlChar).many(0), P.str(']'),
]),
urlChar,
]));
const parser = P.seq([
notLinkLabel,
P.regexp(/https?:\/\//),
innerItem.many(1).text(),
]);
return new P.Parser((input, index, state) => {
let result;
result = parser.handler(input, index, state);
if (!result.success) {
return P.failure();
}
const resultIndex = result.index;
let modifiedIndex = resultIndex;
const schema = result.value[1];
let content = result.value[2];
result = /[.,]+$/.exec(content);
if (result != null) {
modifiedIndex -= result[0].length;
content = content.slice(0, (-1 * result[0].length));
if (content.length === 0) {
return P.success(resultIndex, input.slice(index, resultIndex));
}
}
return P.success(modifiedIndex, M.N_URL(schema + content, false));
});
},
urlAlt: r => {
const open = P.str('<');
const close = P.str('>');
const parser = P.seq([
notLinkLabel,
open,
P.regexp(/https?:\/\//),
P.seq([P.notMatch(P.alt([close, space])), P.char], 1).many(1),
close,
]).text();
return new P.Parser((input, index, state) => {
const result = parser.handler(input, index, state);
if (!result.success) {
return P.failure();
}
const text = result.value.slice(1, (result.value.length - 1));
return P.success(result.index, M.N_URL(text, true));
});
},
search: r => {
const button = P.alt([
P.regexp(/\[(検索|search)\]/i),
]);
return P.seq([
newLine.option(),
P.lineBegin,
P.seq([
P.notMatch(P.alt([
newLine,
P.seq([space, button, P.lineEnd]),
])),
P.char,
], 1).many(1),
space,
button,
P.lineEnd,
newLine.option(),
]).map(result => {
const query = result[2].join('');
return M.SEARCH(query, `${query}${result[3]}${result[4]}`);
});
},
text: r => P.char,
});