chore: move message-parser and peggy-loader to main repo (#31796)

This commit is contained in:
Guilherme Gazzo 2024-02-21 16:27:54 -03:00 committed by GitHub
parent be9dc386ac
commit f0bb6803b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
74 changed files with 4969 additions and 930 deletions

View File

@ -22,7 +22,7 @@
"@rocket.chat/core-services": "workspace:^",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/emitter": "~0.31.25",
"@rocket.chat/message-parser": "~0.31.28",
"@rocket.chat/message-parser": "workspace:^",
"@rocket.chat/model-typings": "workspace:^",
"@rocket.chat/models": "workspace:^",
"@rocket.chat/rest-typings": "workspace:^",

View File

@ -257,7 +257,7 @@
"@rocket.chat/logger": "workspace:^",
"@rocket.chat/logo": "^0.31.29",
"@rocket.chat/memo": "~0.31.25",
"@rocket.chat/message-parser": "~0.31.28",
"@rocket.chat/message-parser": "workspace:^",
"@rocket.chat/model-typings": "workspace:^",
"@rocket.chat/models": "workspace:^",
"@rocket.chat/mp3-encoder": "0.24.0",

View File

@ -16,6 +16,13 @@ COPY ./packages/core-typings/dist packages/core-typings/dist
COPY ./packages/rest-typings/package.json packages/rest-typings/package.json
COPY ./packages/rest-typings/dist packages/rest-typings/dist
COPY ./packages/message-parser/package.json packages/message-parser/package.json
COPY ./packages/message-parser/dist packages/message-parser/dist
COPY ./packages/message-parser/messageParser.js packages/message-parser/messageParser.js
COPY ./packages/peggy-loader/package.json packages/peggy-loader/package.json
COPY ./packages/peggy-loader/dist packages/peggy-loader/dist
COPY ./packages/model-typings/package.json packages/model-typings/package.json
COPY ./packages/model-typings/dist packages/model-typings/dist

View File

@ -16,6 +16,13 @@ COPY ./packages/core-typings/dist packages/core-typings/dist
COPY ./packages/rest-typings/package.json packages/rest-typings/package.json
COPY ./packages/rest-typings/dist packages/rest-typings/dist
COPY ./packages/message-parser/package.json packages/message-parser/package.json
COPY ./packages/message-parser/dist packages/message-parser/dist
COPY ./packages/message-parser/messageParser.js packages/message-parser/messageParser.js
COPY ./packages/peggy-loader/package.json packages/peggy-loader/package.json
COPY ./packages/peggy-loader/dist packages/peggy-loader/dist
COPY ./packages/model-typings/package.json packages/model-typings/package.json
COPY ./packages/model-typings/dist packages/model-typings/dist

View File

@ -16,6 +16,13 @@ COPY ./packages/core-typings/dist packages/core-typings/dist
COPY ./packages/rest-typings/package.json packages/rest-typings/package.json
COPY ./packages/rest-typings/dist packages/rest-typings/dist
COPY ./packages/message-parser/package.json packages/message-parser/package.json
COPY ./packages/message-parser/dist packages/message-parser/dist
COPY ./packages/message-parser/messageParser.js packages/message-parser/messageParser.js
COPY ./packages/peggy-loader/package.json packages/peggy-loader/package.json
COPY ./packages/peggy-loader/dist packages/peggy-loader/dist
COPY ./packages/password-policies/package.json packages/password-policies/package.json
COPY ./packages/password-policies/dist packages/password-policies/dist

View File

@ -16,6 +16,13 @@ COPY ./packages/core-typings/dist packages/core-typings/dist
COPY ./packages/rest-typings/package.json packages/rest-typings/package.json
COPY ./packages/rest-typings/dist packages/rest-typings/dist
COPY ./packages/message-parser/package.json packages/message-parser/package.json
COPY ./packages/message-parser/dist packages/message-parser/dist
COPY ./packages/message-parser/messageParser.js packages/message-parser/messageParser.js
COPY ./packages/peggy-loader/package.json packages/peggy-loader/package.json
COPY ./packages/peggy-loader/dist packages/peggy-loader/dist
COPY ./packages/model-typings/package.json packages/model-typings/package.json
COPY ./packages/model-typings/dist packages/model-typings/dist

View File

@ -19,6 +19,13 @@ COPY ./packages/core-typings/dist packages/core-typings/dist
COPY ./packages/rest-typings/package.json packages/rest-typings/package.json
COPY ./packages/rest-typings/dist packages/rest-typings/dist
COPY ./packages/message-parser/package.json packages/message-parser/package.json
COPY ./packages/message-parser/dist packages/message-parser/dist
COPY ./packages/message-parser/messageParser.js packages/message-parser/messageParser.js
COPY ./packages/peggy-loader/package.json packages/peggy-loader/package.json
COPY ./packages/peggy-loader/dist packages/peggy-loader/dist
COPY ./packages/model-typings/package.json packages/model-typings/package.json
COPY ./packages/model-typings/dist packages/model-typings/dist

View File

@ -16,6 +16,13 @@ COPY ./packages/core-typings/dist packages/core-typings/dist
COPY ./packages/rest-typings/package.json packages/rest-typings/package.json
COPY ./packages/rest-typings/dist packages/rest-typings/dist
COPY ./packages/message-parser/package.json packages/message-parser/package.json
COPY ./packages/message-parser/dist packages/message-parser/dist
COPY ./packages/message-parser/messageParser.js packages/message-parser/messageParser.js
COPY ./packages/peggy-loader/package.json packages/peggy-loader/package.json
COPY ./packages/peggy-loader/dist packages/peggy-loader/dist
COPY ./packages/model-typings/package.json packages/model-typings/package.json
COPY ./packages/model-typings/dist packages/model-typings/dist

View File

@ -16,6 +16,13 @@ COPY ./packages/core-typings/dist packages/core-typings/dist
COPY ./packages/rest-typings/package.json packages/rest-typings/package.json
COPY ./packages/rest-typings/dist packages/rest-typings/dist
COPY ./packages/message-parser/package.json packages/message-parser/package.json
COPY ./packages/message-parser/dist packages/message-parser/dist
COPY ./packages/message-parser/messageParser.js packages/message-parser/messageParser.js
COPY ./packages/peggy-loader/package.json packages/peggy-loader/package.json
COPY ./packages/peggy-loader/dist packages/peggy-loader/dist
COPY ./packages/model-typings/package.json packages/model-typings/package.json
COPY ./packages/model-typings/dist packages/model-typings/dist

View File

@ -12,7 +12,7 @@
"jest-environment-jsdom": "~29.6.4",
"jest-websocket-mock": "^2.4.0",
"ts-jest": "^29.1.2",
"typescript": "^5.3.3",
"typescript": "^5.3.2",
"ws": "^8.13.0"
},
"peerDependencies": {

View File

@ -37,7 +37,7 @@
"@rocket.chat/apps-engine": "1.41.0",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/icons": "^0.33.0",
"@rocket.chat/message-parser": "~0.31.28",
"@rocket.chat/message-parser": "workspace:^",
"@rocket.chat/models": "workspace:^",
"@rocket.chat/rest-typings": "workspace:^",
"@rocket.chat/ui-kit": "workspace:~",

View File

@ -25,7 +25,7 @@
"dependencies": {
"@rocket.chat/apps-engine": "1.41.0",
"@rocket.chat/icons": "^0.33.0",
"@rocket.chat/message-parser": "~0.31.28",
"@rocket.chat/message-parser": "workspace:^",
"@rocket.chat/ui-kit": "workspace:~"
},
"volta": {

View File

@ -8,7 +8,7 @@
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/fuselage": "^0.47.0",
"@rocket.chat/fuselage-tokens": "~0.32.0",
"@rocket.chat/message-parser": "~0.31.28",
"@rocket.chat/message-parser": "workspace:^",
"@rocket.chat/styled": "~0.31.25",
"@rocket.chat/ui-client": "workspace:^",
"@rocket.chat/ui-contexts": "workspace:^",

View File

@ -95,7 +95,7 @@
},
"dependencies": {
"@rocket.chat/gazzodown": "workspace:^",
"@rocket.chat/message-parser": "~0.31.28",
"@rocket.chat/message-parser": "workspace:^",
"@rocket.chat/random": "workspace:~",
"@rocket.chat/sdk": "^1.0.0-alpha.42",
"@rocket.chat/ui-kit": "workspace:~",

View File

@ -0,0 +1,2 @@
/node_modules
/dist

View File

@ -0,0 +1,12 @@
module.exports = {
extends: '@rocket.chat/eslint-config',
env: {
jest: true,
},
overrides: [
{
files: ['**/*.ts', '**/*.tsx'],
extends: '@rocket.chat/eslint-config',
},
],
};

2
packages/message-parser/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/node_modules
/dist

View File

@ -0,0 +1 @@
module.exports = require('@rocket.chat/prettier-config/fuselage');

View File

@ -0,0 +1,71 @@
# Change Log
## 0.31.28
### Patch Changes
- [`7fdfdb1b7`](https://github.com/RocketChat/fuselage/commit/7fdfdb1b7737808585b95cc62c4f9af2bc152b41) Thanks [@dougfabris](https://github.com/dougfabris)! - fix(message-parser): Made changes in grammar.pegjs for the strikedown approach
## 0.31.27
### Patch Changes
- [`a029dce78`](https://github.com/RocketChat/fuselage/commit/a029dce78935d8bba5cb5b09e251483fe8eabcb3) Thanks [@yash-rajpal](https://github.com/yash-rajpal)! - Stop accepting `[` in link titles
## 0.31.26
### Patch Changes
- [#1215](https://github.com/RocketChat/fuselage/pull/1215) [`684b73ca3`](https://github.com/RocketChat/fuselage/commit/684b73ca3b1e7c72f21f6dff23bfe46981ba472a) Thanks [@brf153](https://github.com/brf153)! - Added ChannelMention in the markup inside message-parser
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [0.31.0](https://github.com/RocketChat/fuselage/compare/v0.30.1...v0.31.0) (2021-12-28)
### Features
- New hooks for element size tracking ([#413](https://github.com/RocketChat/fuselage/issues/413)) ([8ca682c](https://github.com/RocketChat/fuselage/commit/8ca682c636d2e4813f7d346cb881513382be63cf))
# [0.30.0](https://github.com/RocketChat/fuselage/compare/v0.29.0...v0.30.0) (2021-10-06)
### Bug Fixes
- **jest:** Adjust jest and ts-jest dependencies ([#547](https://github.com/RocketChat/fuselage/issues/547)) ([91a4fa1](https://github.com/RocketChat/fuselage/commit/91a4fa1365394001afe1bd46480bda3bafed5505))
- **message-parser:** <https://domain.com|Test> ([#546](https://github.com/RocketChat/fuselage/issues/546)) ([faca16f](https://github.com/RocketChat/fuselage/commit/faca16febe517e411dd377cae294f888f1199d40))
- **message-parser:** Fix Url and Escaped Markdown ([#537](https://github.com/RocketChat/fuselage/issues/537)) ([bc0cbce](https://github.com/RocketChat/fuselage/commit/bc0cbce69589b9a056d797a03b78d7cd06423aaa))
# [0.29.0](https://github.com/RocketChat/fuselage/compare/v0.28.0...v0.29.0) (2021-08-31)
**Note:** Version bump only for package @rocket.chat/message-parser
# [0.28.0](https://github.com/RocketChat/fuselage/compare/v0.27.0...v0.28.0) (2021-07-30)
### Features
- **onboarding-ui:** Administrator information form and Organization information form ([#489](https://github.com/RocketChat/fuselage/issues/489)) ([b289f68](https://github.com/RocketChat/fuselage/commit/b289f68676954b91c792d8d97680314178bf2c60))
- styled API; monorepo grooming ([#482](https://github.com/RocketChat/fuselage/issues/482)) ([1b6b70c](https://github.com/RocketChat/fuselage/commit/1b6b70cf67ec16927b1566adc2350295a8927223))
# [0.27.0](https://github.com/RocketChat/fuselage/compare/v0.26.0...v0.27.0) (2021-06-28)
### Bug Fixes
- **eslint:** Add missing ESLint rule for TypeScript ([#470](https://github.com/RocketChat/fuselage/issues/470)) ([cc0d498](https://github.com/RocketChat/fuselage/commit/cc0d4989bf37f7602d1d58d051824f1dd6c096b3))
# [0.26.0](https://github.com/RocketChat/fuselage/compare/v0.25.0...v0.26.0) (2021-05-28)
**Note:** Version bump only for package @rocket.chat/message-parser
# [0.25.0](https://github.com/RocketChat/fuselage/compare/v0.24.0...v0.25.0) (2021-05-19)
### Bug Fixes
- **fuselage:** fix duplicated values on paginated multi select ([#456](https://github.com/RocketChat/fuselage/issues/456)) ([4518a4e](https://github.com/RocketChat/fuselage/commit/4518a4e661cb525d957f6140d59a641a50fc7b20))
- **message-parser:** Big emoji ([#451](https://github.com/RocketChat/fuselage/issues/451)) ([6d65343](https://github.com/RocketChat/fuselage/commit/6d653433d07edabaee821bd25ad07a5878b59a86))
- **message-parser:** URL issues ([#448](https://github.com/RocketChat/fuselage/issues/448)) ([8ce6b91](https://github.com/RocketChat/fuselage/commit/8ce6b9110547b5adf3633e87d6bc655114d4cfb4))
- message-parser Unordered List definition ([#445](https://github.com/RocketChat/fuselage/issues/445)) ([6c659b8](https://github.com/RocketChat/fuselage/commit/6c659b821fd6294eb8033dfe03e42db2dba1ca06))
### Features
- [@rocket](https://github.com/rocket).chat/message-parser ([#443](https://github.com/RocketChat/fuselage/issues/443)) ([4722cdf](https://github.com/RocketChat/fuselage/commit/4722cdff46f5987f335d989be59649c7652bb12a))
- Peggy loader ([#450](https://github.com/RocketChat/fuselage/issues/450)) ([0496cad](https://github.com/RocketChat/fuselage/commit/0496cad457d76f8a4d6a217209e4a55e315e8365))

View File

@ -0,0 +1,57 @@
<!--header-->
<p align="center">
<a href="https://rocket.chat" title="Rocket.Chat">
<img src="https://github.com/RocketChat/Rocket.Chat.Artwork/raw/master/Logos/2020/png/logo-horizontal-red.png" alt="Rocket.Chat" />
</a>
</p>
# `@rocket.chat/message-parser`
> Rocket.Chat parser for messages
---
[![npm@latest](https://img.shields.io/npm/v/@rocket.chat/message-parser/latest?style=flat-square)](https://www.npmjs.com/package/@rocket.chat/message-parser/v/latest) [![npm@next](https://img.shields.io/npm/v/@rocket.chat/message-parser/next?style=flat-square)](https://www.npmjs.com/package/@rocket.chat/message-parser/v/next) ![npm downloads](https://img.shields.io/npm/dw/@rocket.chat/message-parser?style=flat-square) ![License: MIT](https://img.shields.io/npm/l/@rocket.chat/message-parser?style=flat-square)
![deps](https://img.shields.io/librariesio/release/npm/@rocket.chat/message-parser?style=flat-square) ![npm bundle size](https://img.shields.io/bundlephobia/min/@rocket.chat/message-parser?style=flat-square)
<!--/header-->
## Description
Rocket.Chat grammar with the purpose of parsing the messages of the rocket chat, converting text to an AST tree.
The grammar provides support for markdown, mentions and emojis.
## Supported markup
- quotes
- bold/italic/strike
- ordered lists
- unordered lists
- task lists
- phone numbers
- mentions
- emoji
- colors
- URI's
- mentions users/channels
## Contributing
<!--contributing(msg)-->
Contributions, issues, and feature requests are welcome!<br />
Feel free to check the [issues](https://github.com/RocketChat/fuselage/issues).
<!--/contributing(msg)-->
Whenever you find a grammar-related bug, start by inserting the test case.
We are open to other tags/markups, as long as they don't generate unexpected behavior.
## Observations and known issues
- Nested lists are unsupported
- `URL` rule doesn't allow whitespace, `(`, or `)`

View File

@ -0,0 +1,18 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: [
'Chrome >= 59',
'FireFox >= 44',
'Safari >= 7',
'Explorer 11',
'last 4 Edge versions',
],
},
},
],
],
};

View File

@ -0,0 +1,12 @@
const path = require('path');
module.exports = {
coverageReporters: [],
transform: {
'\\.pegjs$': path.resolve(__dirname, './loaders/pegtransform.js'),
},
preset: 'ts-jest',
errorOnDeprecated: true,
testMatch: ['<rootDir>/tests/**/*.(spec|test).ts'],
moduleFileExtensions: ['js', 'ts', 'pegjs'],
};

View File

@ -0,0 +1,10 @@
const pegjs = require('peggy');
module.exports = {
process: (content) => ({
code: pegjs.generate(content, {
output: 'source',
format: 'commonjs',
}),
}),
};

View File

@ -0,0 +1,7 @@
/* eslint-disable import/no-unresolved */
if (process.env.NODE_ENV === 'production') {
module.exports = require('./dist/messageParser.production.js');
} else {
module.exports = require('./dist/messageParser.development.js');
}

View File

@ -0,0 +1,78 @@
{
"name": "@rocket.chat/message-parser",
"description": "Rocket.Chat parser for messages",
"version": "0.31.28",
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
},
"license": "MIT",
"homepage": "https://github.com/RocketChat/fuselage#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/RocketChat/fuselage.git",
"directory": "packages/message-parser"
},
"bugs": {
"url": "https://github.com/RocketChat/fuselage/issues"
},
"main": "messageParser.js",
"exports": {
".": {
"default": "./messageParser.js"
},
"./index": {
"default": "./messageParser.js"
}
},
"module": "dist/messageParser.mjs",
"unpkg": "dist/messageParser.umd.js",
"types": "dist/index.d.ts",
"files": [
"/dist",
"/messageParser.js"
],
"directories": {
"test": "test"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "run-s .:build:clean .:build:bundle",
".:build:clean": "rimraf dist",
".:build:bundle": "webpack",
"test": "jest --runInBand --coverage",
"watch": "jest --watch",
"lint": "eslint src",
"docs": "typedoc"
},
"devDependencies": {
"@babel/core": "~7.21.4",
"@babel/eslint-parser": "~7.21.3",
"@babel/preset-env": "~7.21.4",
"@rocket.chat/eslint-config": "workspace:^",
"@rocket.chat/peggy-loader": "workspace:~",
"@rocket.chat/prettier-config": "~0.31.25",
"@types/jest": "~29.5.7",
"@types/node": "~14.18.42",
"@typescript-eslint/parser": "~5.58.0",
"babel-loader": "~9.1.2",
"eslint": "~8.45.0",
"jest": "~29.6.4",
"npm-run-all": "^4.1.5",
"peggy": "3.0.2",
"prettier": "~2.8.7",
"prettier-plugin-pegjs": "~0.5.4",
"rimraf": "^3.0.2",
"ts-jest": "~29.1.0",
"ts-loader": "~9.4.2",
"typedoc": "~0.24.1",
"typescript": "~5.0.4",
"webpack": "~5.78.0",
"webpack-cli": "~5.0.1"
},
"dependencies": {
"tldts": "~5.7.112"
}
}

View File

@ -0,0 +1,249 @@
export type Blockquote = {
type: 'BLOCKQUOTE';
value: Paragraph[];
};
export type OrderedList = {
type: 'ORDERED_LIST';
value: ListItem[];
};
export type UnorderedList = {
type: 'UNORDERED_LIST';
value: ListItem[];
};
export type ListItem = {
type: 'LIST_ITEM';
value: Inlines[];
number?: number;
};
export type Tasks = {
type: 'TASKS';
value: Task[];
};
export type Task = {
type: 'TASK';
status: boolean;
value: Inlines[];
};
export type CodeLine = {
type: 'CODE_LINE';
value: Plain;
};
export type Color = {
type: 'COLOR';
value: {
r: number;
g: number;
b: number;
a: number;
};
};
export type BigEmoji = {
type: 'BIG_EMOJI';
value: [Emoji] | [Emoji, Emoji] | [Emoji, Emoji, Emoji];
};
export type Emoji =
| {
type: 'EMOJI';
value: Plain;
shortCode: string;
}
| {
type: 'EMOJI';
value: undefined;
unicode: string;
};
export type Code = {
type: 'CODE';
language: string | undefined;
value: CodeLine[];
};
export type InlineCode = {
type: 'INLINE_CODE';
value: Plain;
};
export type Heading = {
type: 'HEADING';
level: 1 | 2 | 3 | 4;
value: Plain[];
};
export type Quote = {
type: 'QUOTE';
value: Paragraph[];
};
export type Markup = Italic | Strike | Bold | Plain | ChannelMention;
export type MarkupExcluding<T extends Markup> = Exclude<Markup, T>;
export type Bold = {
type: 'BOLD';
value: Array<
| MarkupExcluding<Bold>
| Link
| Emoji
| UserMention
| ChannelMention
| InlineCode
>;
};
export type Italic = {
type: 'ITALIC';
value: Array<
| MarkupExcluding<Italic>
| Link
| Emoji
| UserMention
| ChannelMention
| InlineCode
>;
};
export type Strike = {
type: 'STRIKE';
value: Array<
| MarkupExcluding<Strike>
| Link
| Emoji
| UserMention
| ChannelMention
| InlineCode
| Italic
>;
};
export type Plain = {
type: 'PLAIN_TEXT';
value: string;
};
export type LineBreak = {
type: 'LINE_BREAK';
value: undefined;
};
export type KaTeX = {
type: 'KATEX';
value: string;
};
export type InlineKaTeX = {
type: 'INLINE_KATEX';
value: string;
};
export type Paragraph = {
type: 'PARAGRAPH';
value: Array<Exclude<Inlines, Paragraph>>;
};
export type Image = {
type: 'IMAGE';
value: {
src: Plain;
label: Markup;
};
};
export type Link = {
type: 'LINK';
value: {
src: Plain;
label: Markup | Markup[];
};
};
export type UserMention = {
type: 'MENTION_USER';
value: Plain;
};
export type ChannelMention = {
type: 'MENTION_CHANNEL';
value: Plain;
};
export type Types = {
BOLD: Bold;
PARAGRAPH: Paragraph;
PLAIN_TEXT: Plain;
ITALIC: Italic;
STRIKE: Strike;
CODE: Code;
CODE_LINE: CodeLine;
INLINE_CODE: InlineCode;
HEADING: Heading;
QUOTE: Quote;
LINK: Link;
MENTION_USER: UserMention;
MENTION_CHANNEL: ChannelMention;
EMOJI: Emoji;
BIG_EMOJI: BigEmoji;
COLOR: Color;
TASKS: Tasks;
TASK: Task;
UNORDERED_LIST: UnorderedList;
ORDERED_LIST: OrderedList;
LIST_ITEM: ListItem;
IMAGE: Image;
LINE_BREAK: LineBreak;
};
export type ASTNode =
| BigEmoji
| Bold
| Paragraph
| Plain
| Italic
| Strike
| Code
| CodeLine
| InlineCode
| Heading
| Quote
| Link
| UserMention
| ChannelMention
| Emoji
| Color
| Tasks;
export type TypesKeys = keyof Types;
export type Inlines =
| Bold
| Plain
| Italic
| Strike
| InlineCode
| Image
| Link
| UserMention
| ChannelMention
| Emoji
| Color
| InlineKaTeX;
export type Blocks =
| Code
| Heading
| Quote
| ListItem
| Tasks
| OrderedList
| UnorderedList
| LineBreak
| KaTeX;
export type Root = Array<Paragraph | Blocks> | [BigEmoji];

View File

@ -0,0 +1,705 @@
{{
const {
autoEmail,
autoLink,
bigEmoji,
bold,
code,
codeLine,
color,
emoji,
emojiUnicode,
emoticon,
heading,
image,
inlineCode,
inlineKatex,
italic,
katex,
lineBreak,
link,
listItem,
mentionChannel,
mentionUser,
orderedList,
paragraph,
phoneChecker,
plain,
quote,
reducePlainTexts,
strike,
task,
tasks,
unorderedList,
} = require('./utils');
}}
Start
= @BigEmoji !.
/ (Blocks / Paragraph / EndOfLine { return paragraph([plain('')]); })+
/**
*
* Blocks
*
*/
Blocks
= Blockquote
/ Code
/ Heading
/ Tasks
/ OrderedList
/ UnorderedList
/ Katex
/ LineBreak
/**
*
* Blockquote
* e.g: > This is a blockquote
*
*/
Blockquote = b:BlockquoteLine+ { return quote(b); }
BlockquoteLine = ">" [ \t]* @Paragraph
/**
*
* Code Chunk
* e.g:
* ```js
* console.log('hello world');
* ```
*/
Code = "```" language:CodeLanguage? EndOfLine lines:CodeLine+ EndOfLine "```" { return code(lines, language); }
CodeLanguage = $[a-zA-Z0-9 \_\-.]+
CodeLine
= chunk:CodeChunk { return codeLine(chunk); }
/ "\n" chunk:CodeChunk { return codeLine(chunk); }
/ "\n" !"```" { return codeLine(plain('')); }
CodeChunk = text:$(!EndOfLine !"```" .)+ { return plain(text); }
/**
*
* Heading: h1, h2, h3, h4
* e.g:
* # Heading 1
* ## Heading 2
* ### Heading 3
* #### Heading 4
*
*/
Heading = count:HeadingStart [ \t]+ text:HeadingChunk { return heading([text], count); }
HeadingStart = value:"#" |1..4| { return value.length; }
HeadingChunk = text:$(!EndOfLine .)+ { return plain(text); }
/**
*
* Tasks
* e.g:
* - [x] Task One (checked)
* - [ ] Task two
* - [x] Task three (checked)
*
*/
Tasks = items:Task+ { return tasks(items); }
Task = "- [" flag:TaskFlag "]" [ \t]+ text:Inline { return task(text, flag); }
TaskFlag = "x" { return true; } / " " { return false; }
/**
*
* Ordered List
* e.g:
* 1. Item One
* 2. Item Two
* 3. Item Three
*
*/
OrderedList = items:OrderedListItem+ { return orderedList(items); }
OrderedListItem = number:Digits "." [ \t]+ text:Inline { return listItem(text, parseInt(number, 10)); }
/**
*
* Unordered List
* e.g:
* - Item One
* - Item Two
* * Item Three
* * Item Four
*
*/
UnorderedList = items:(UnorderedListHyphenItem+ / UnorderedListAsteriskItem+) { return unorderedList(items); }
UnorderedListHyphenItem = "-" [ \t]+ text:Inline { return listItem(text); }
UnorderedListAsteriskItem = "*" [ \t]+ text:UnorderedListItemContent { return listItem(text); }
UnorderedListItemContent = value:UnorderedListItemContentItem+ !"*" EndOfLine? { return reducePlainTexts(value); }
UnorderedListItemContentItem = InlineItem / !"*" @Any
/**
*
* KaTex
* e.g: \[ KATEX_HERE \] OR $$ KATEX_HERE $$
* $$x = \begin{cases}
* a &\text{if } b \\
* c &\text{if } d
* \end{cases}$$
*
*/
Katex = KatexStart content:$(!KatexEnd .)* KatexEnd { return katex(content); }
KatexStart
= & { return options.katex?.parenthesisSyntax; } "\\["
/ & { return options.katex?.dollarSyntax; } "$$"
KatexEnd
= & { return options.katex?.parenthesisSyntax; } "\\]"
/ & { return options.katex?.dollarSyntax; } "$$"
KatexInline
= KatexInlineStart content:$(!KatexInlineEnd .)* KatexInlineEnd {
return inlineKatex(content);
}
KatexInlineStart
= & { return options.katex?.parenthesisSyntax; } "\\("
/ & { return options.katex?.dollarSyntax; } "$"
KatexInlineEnd
= & { return options.katex?.parenthesisSyntax; } "\\)"
/ & { return options.katex?.dollarSyntax; } "$"
/**
*
* LineBreak
* e.g: \n
*
*/
LineBreak = Space* EndOfLine { return lineBreak(); }
/**
*
* Paragraph
* e.g: This is a paragraph
*/
Paragraph = value:Inline { return paragraph(value); }
/**
*
* Inline
*
*/
Inline = value:(InlineItem / Any)+ EndOfLine? { return reducePlainTexts(value); }
InlineItem = Whitespace
/ References
/ AutolinkedPhone
/ AutolinkedEmail
/ AutolinkedURL
/ EmphasisWithWhitespace
/ Emphasis
/ UserMention
/ ChannelMention
/ Emoji
/ InlineCode
/ Image
/ Emoticon
/ Color
/ KatexInline
/ Escaped
/**
*
* URL
* e.g:
* Reference: [Rocket.Chat Website](https://rocket.chat), [](https://rocket.chat), <rocket.chat|Rocket.Chat Website>
* Image: ![](https://rocket.chat/logo.png)
*
*/
References
= "[" title:LinkTitle* "](" href:LinkRef ")" { return title.length ? link(href, reducePlainTexts(title)) : link(href); }
/ "<" href:LinkRef "|" title:LinkTitle2 ">" { return link(href, [plain(title)]); }
LinkTitle = (Whitespace / EmphasisForReferences) / anyTitle:$(!("](" .) .) { return plain(anyTitle) }
LinkTitle2 = $([\x20-\x3B\x3D\x3F-\x60\x61-\x7B\x7D-\xFF] / NonASCII)+
LinkRef = URL / FilePath / p:Phone { return 'tel:' + p.number; } // TODO: Accept parenthesis
FilePath = $(URLScheme URLBody+)
Image = "![" title:Line? "](" href:LinkRef ")" { return title ? image(href, title) : image(href); }
URL
= $(URLScheme URLAuthority URLBody*)
/ $(URLAuthorityHost URLBody*)
URLScheme = $([A-Za-z0-9+-] |1..32| ":")
URLBody
= (
!(Extra+ (Whitespace / EndOfLine) / Whitespace)
(AnyText / [*\[\/\]\^_`{}~(])
)+
URLAuthority = $("//" URLAuthorityUserInfo? URLAuthorityHost)
URLAuthorityUserInfo = $(URLAuthorityUser (":" URLAuthorityPassword)? "@")
URLAuthorityUser = $(AlphaDigit / ![@/] Safe)+
URLAuthorityPassword = $(AlphaDigit / ![@/] Safe)+
URLAuthorityHost = URLAuthorityHostName (":" URLAuthorityPort)?
URLAuthorityHostName
= DomainName
/ $(Digits |4, "."|) // TODO: IPv4 and IPv6
URLAuthorityPort
= Digits // TODO: from "0" to "65535"
DomainName
= "localhost"
/ $(DomainNameLabel ("." DomainChar DomainNameLabel*)+)
DomainNameLabel = $(DomainChar+ ("-" DomainChar+)*)
DomainChar = !Extra ([\__-] / !Safe) !EndOfLine !Space ![\\/|><%`] .
/**
*
* Phone
* e.g: 075-63546725
*
*/
Phone = "+" p:PhoneNumber { return { text: '+' + p.text, number: p.number }; }
PhoneNumber
= p:PhonePrefix "-" d:Digits {
return { text: p.text + '-' + d, number: p.number + d };
}
/ p:PhonePrefix d1:Digits "-" d2:Digits {
return { text: p.text + d1 + '-' + d2, number: p.number + d1 + d2 };
}
/ p:PhonePrefix d:Digits {
return { text: p.text + d, number: p.number + d };
}
/ d:Digits { return { text: d, number: d }; }
PhonePrefix
= d:Digits { return { text: d, number: d }; }
/ "(" d:Digits ")" { return { text: '(' + d + ')', number: d }; }
AutolinkedPhone = p:Phone { return phoneChecker(p.text, p.number); }
/**
*
* Email
* e.g: contact@rocket.chat
*
*/
Email = "mailto:"? @$(LocalPart "@" DomainName)
LocalPart = $(LocalPartChar+ ("." LocalPartChar+)*)
LocalPartChar = AlphaNumericOrMarkChar+ LocalPartSpecialChars*
LocalPartSpecialChars = [!#$%&'*+/=?^_\`{|}~-]
AutolinkedEmail = e:Email { return autoEmail(e); }
/**
*
* Auto Link URL
* e.g: rocket.chat, https://rocket.chat,
* with customDomains options as intranet: protocol://internaltool.intranet
*
*/
AutolinkedURL = u:AutoLinkURL { return autoLink(u, options.customDomains); }
AutoLinkURL
= $(URLScheme URLAuthority AutoLinkURLBody*)
/ $(URLAuthorityHost AutoLinkURLBody*)
AutoLinkURLBody = !(Extra* (Whitespace / EndOfLine)) .
/**
*
* Emphasis
*
*/
Emphasis = Bold / Italic / Strikethrough
/**
*
* Emphasis for References
*
*/
EmphasisForReferences = BoldForReferences / ItalicForReferences / StrikethroughForReferences
/**
*
* Italic, Bold and Strike
* e.g: __italic__, _italic_, **bold**, __*bold italic*__, ~~strikethrough~~
*
*/
/* Italic */
Italic
= value:$([a-zA-Z0-9]+ [\x5F] [\x5F]?) { return plain(value); }
/ [\x5F] [\x5F] i:ItalicContentItems [\x5F] [\x5F] t:$[a-zA-Z0-9]+ {
return reducePlainTexts([plain('__'), ...i, plain('__'), plain(t)])[0];
}
/ [\x5F] i:ItalicContentItems [\x5F] t:$[a-zA-Z]+ {
return reducePlainTexts([plain('_'), ...i, plain('_'), plain(t)])[0];
}
/ [\x5F] [\x5F] @ItalicContent [\x5F] [\x5F]
/ [\x5F] @ItalicContent [\x5F]
ItalicContent = text:ItalicContentItems { return italic(text); }
ItalicContentItems = text:ItalicContentItem+ { return reducePlainTexts(text); }
ItalicContentItem
= Whitespace
/ InlineCode
/ References
/ UserMention
/ ChannelMention
/ Bold
/ Strikethrough
/ Emoji
/ Emoticon
/ AnyItalic
/ Line
/* Bold */
Bold = [\x2A] [\x2A] @BoldContent [\x2A] [\x2A] / [\x2A] @BoldContent [\x2A]
BoldContent = text:BoldContentItem+ { return bold(reducePlainTexts(text)); }
BoldContentItem = Whitespace / InlineCode / References / UserMention / ChannelMention / Italic / Strikethrough / Emoji / Emoticon / AnyBold / Line
/* Strike */
Strikethrough = [\x7E] [\x7E] @StrikethroughContent [\x7E] [\x7E] / [\x7E] @StrikethroughContent [\x7E]
StrikethroughContent = text:(InlineCode / Whitespace / References / UserMention / ChannelMention / Italic / Bold / Emoji / Emoticon / AnyStrike / Line)+ {
return strike(reducePlainTexts(text));
}
/* Italic for References */
ItalicForReferences
= value:$([a-zA-Z0-9]+ [\x5F] [\x5F]?) { return plain(value); }
/ [\x5F] [\x5F] i:ItalicContentItemsForReferences [\x5F] [\x5F] t:$[a-zA-Z0-9]+ {
return reducePlainTexts([plain('__'), ...i, plain('__'), plain(t)])[0];
}
/ [\x5F] i:ItalicContentItemsForReferences [\x5F] t:$[a-zA-Z]+ {
return reducePlainTexts([plain('_'), ...i, plain('_'), plain(t)])[0];
}
/ [\x5F] [\x5F] @ItalicContentForReferences [\x5F] [\x5F]
/ [\x5F] @ItalicContentForReferences [\x5F]
ItalicContentForReferences = text:ItalicContentItemsForReferences { return italic(text); }
ItalicContentItemsForReferences = text:ItalicContentItemForReferences+ { return reducePlainTexts(text); }
ItalicContentItemForReferences
= Whitespace
/ UserMention
/ ChannelMention
/ BoldForReferences
/ StrikethroughForReferences
/ Emoji
/ Emoticon
/ AnyItalic
/ Line
/ InlineCode
/* Bold for References */
BoldForReferences = [\x2A] [\x2A] @BoldContentForReferences [\x2A] [\x2A] / [\x2A] @BoldContentForReferences [\x2A]
BoldContentForReferences = text:(Whitespace / UserMention / ChannelMention / ItalicForReferences / StrikethroughForReferences / Emoji / Emoticon / AnyBold / Line / InlineCode)+ { return bold(reducePlainTexts(text)); }
/* Strike for References */
StrikethroughForReferences = [\x7E] [\x7E] @StrikethroughContentForReferences [\x7E] [\x7E] / [\x7E] @StrikethroughContentForReferences [\x7E]
StrikethroughContentForReferences = text:(Whitespace / UserMention / ChannelMention / ItalicForReferences / BoldForReferences / Emoji / Emoticon / AnyStrike / Line / InlineCode)+ {
return strike(reducePlainTexts(text));
}
AnyBold = t:[^\x0a\* ] { return plain(t); }
AnyStrike = t:[^\x0a\~ ] { return plain(t); }
AnyItalic = t:[^\x0a\_ ] { return plain(t); }
/**
* Emphasis with only whitespaces return plain text
* e.g: __ __, _ _, ** **, * *, ** *, ~~ ~~
*/
EmphasisWithWhitespace = AsteriskWithWhitespace / UnderscoreWithWhitespace / TildeWithWhitespace
AsteriskWithWhitespace = first:Asterisk second:Whitespace third:Asterisk
{
return reducePlainTexts([first,second,third])[0];
}
UnderscoreWithWhitespace = first:Underscore second:Whitespace third:Underscore
{
return reducePlainTexts([first,second,third])[0];
}
TildeWithWhitespace = first:Tilde second:Whitespace third:Tilde
{
return reducePlainTexts([first,second,third])[0];
}
Asterisk = t:"*"+ {return plain(t.join(""))}
Underscore = t:"_"+ {return plain(t.join(""))}
Tilde = t:"~"+ {return plain(t.join(""))}
/**
*
* Mentions
* e.g: @user, #channel
*
*/
UserMention
= t:Text "@"+ user:AlphaNumericChar {
return reducePlainTexts([t, plain('@' + user)])[0];
}
/ "@"+ user:$(UTF8NamesValidation ([:@] UTF8NamesValidation)?) {
return mentionUser(user);
}
ChannelMention
= t:Text "#" channel:AlphaNumericChar {
return reducePlainTexts([t, plain('#' + channel)])[0];
}
/ "#" channel:UTF8NamesValidation { return mentionChannel(channel); }
/**
*
* EMOJIS
* e.g:
* BigEmoji (min: 1 | max: 3 without text) and ShortCode :smile: :+1: :heart:
* Unicode: 😀 🚀 🌈
* Emoticon: :D :P :( :/
*
*/
BigEmoji = (EndOfLine / Space)* es:(@(Emoji / Emoticon) (EndOfLine / Space)*) |1..3| { return [bigEmoji(es)]; }
Emoji = EmojiShortCode / ch:UnicodeEmoji { return emojiUnicode(ch); }
EmojiShortCode = ":" shortCode:EmojiShortCodeName ":" { return emoji(shortCode); }
EmojiShortCodeName = $[0-9a-zA-Z-_+.]+
/* Emoticons */
Emoticon = & { return options.emoticons; } @EmoticonPattern
EmoticonPattern
= e:$"<3" { return emoticon(e, 'heart'); }
/ e:$"</3" { return emoticon(e, 'broken_heart'); }
/ e:$(":D" / ":-D" / "=D") { return emoticon(e, 'smiley'); }
/ e:$(">:)" / ">;)" / ">:-)" / ">=)") { return emoticon(e, 'laughing'); }
/ e:$("':)" / "':-)" / "'=)" / "':D" / "':-D" / "'=D") {
return emoticon(e, 'sweat_smile');
}
/ e:$(":')" / ":'-)") { return emoticon(e, 'joy'); }
/ e:$(
"O:-)"
/ "0:-3"
/ "0:3"
/ "0:-)"
/ "0:)"
/ "0;^)"
/ "O:)"
/ "O;-)"
/ "O=)"
/ "0;-)"
/ "O:-3"
/ "O:3"
) { return emoticon(e, 'innocent'); }
/ e:$(":)" / ":-)" / "=]" / "=)" / ":]") {
return emoticon(e, 'slight_smile');
}
/ e:$(";)" / ";-)" / "*-)" / "*)" / ";-]" / ";]" / ";D" / ";^)") {
return emoticon(e, 'wink');
}
/ e:$(":*" / ":-*" / "=*" / ":^*") { return emoticon(e, 'kissing_heart'); }
/ e:$(":P" / ":-P" / "=P" / ":-\u00de" / ":\u00de" / ":-b" / ":b") {
return emoticon(e, 'stuck_out_tongue');
}
/ e:$(">:P" / "X-P") { return emoticon(e, 'stuck_out_tongue_winking_eye'); }
/ e:$("B-)" / "B)" / "8)" / "8-)" / "B-D" / "8-D") {
return emoticon(e, 'sunglasses');
}
/ e:$(">:[" / ":-(" / ":(" / ":-[" / ":[" / "=(") {
return emoticon(e, 'disappointed');
}
/ e:$(
">:\\"
/ ">:\/"
/ ":-\/"
/ ":-."
/ ":\/"
/ ":\\"
/ "=\/"
/ "=\\"
/ ":L"
/ "=L"
) { return emoticon(e, 'confused'); }
/ e:$">.<" { return emoticon(e, 'persevere'); }
/ e:$(":'(" / ":'-(" / ";(" / ";-(") { return emoticon(e, 'cry'); }
/ e:$(">:(" / ">:-(" / ":@") { return emoticon(e, 'angry'); }
/ e:$(":$" / "=$") { return emoticon(e, 'flushed'); }
/ e:$"D:" { return emoticon(e, 'fearful'); }
/ e:$("':(" / "':-(" / "'=(") { return emoticon(e, 'sweat'); }
/ e:$(":-X" / ":X" / ":-#" / ":#" / "=X" / "=#") {
return emoticon(e, 'no_mouth');
}
/ e:$("-_-" / "-__-" / "-___-") { return emoticon(e, 'expressionless'); }
/ e:$(":-O" / ":O" / "O_O" / ">:O") { return emoticon(e, 'open_mouth'); }
/ e:$("#-)" / "#)" / "%-)" / "%)" / "X)" / "X-)") {
return emoticon(e, 'dizzy_face');
}
/ e:$"(y)" { return emoticon(e, 'thumbsup'); }
/ e:$("*\\0\/*" / "\\0\/" / "*\\O\/*" / "\\O\/") {
return emoticon(e, 'person_gesturing_ok');
}
/* Unicode emojis */
UnicodeEmoji
= UnicodeEmojiEmoticon
/ $(
UnicodeEmojiSupplementalSymbolsAndPictographs
(
UnicodeEmojiMiscellaneousSymbolsAndPictographs
([\u200D] UnicodeEmojiMiscellaneousSymbolsAndPictographs)*
)?
)
/ $(
(
UnicodeEmojiMiscellaneousSymbolsAndPictographs
UnicodeEmojiMiscellaneousSymbolsAndPictographsFitzpatrickModifiers?
[\u200D]
)*
UnicodeEmojiMiscellaneousSymbolsAndPictographs
UnicodeEmojiMiscellaneousSymbolsAndPictographsFitzpatrickModifiers?
)
/ UnicodeEmojiTransportAndMapSymbols
/ UnicodeEmojiMiscellaneousTechnical
/ UnicodeEmojiMiscellaneousSymbols
/ UnicodeEmojiDingbats
/ UnicodeEmojiFlags
UnicodeEmojiEmoticon = $([\uD83D] [\uDE00-\uDE4F])
UnicodeEmojiSupplementalSymbolsAndPictographs = $([\uD83E] [\uDD00-\uDDFF])
UnicodeEmojiMiscellaneousSymbolsAndPictographs = $([\uD83C] [\uDF00-\uDFFF] [\uFE00-\uFE0F]?) / $([\uD83D] [\uDC00-\uDDFF] [\uFE00-\uFE0F]?)
UnicodeEmojiMiscellaneousSymbolsAndPictographsFitzpatrickModifiers = $([\uD83C] [\uDFFB-\uDFFF])
UnicodeEmojiTransportAndMapSymbols = $([\uD83D] [\uDE80-\uDEFA])
UnicodeEmojiMiscellaneousTechnical = $([\u2300-\u23FF] [\uFE00-\uFE0F]?)
UnicodeEmojiMiscellaneousSymbols = $([\u2600-\u26FF] [\uFE00-\uFE0F]?)
UnicodeEmojiDingbats = $([\u2700-\u27BF] [\uFE00-\uFE0F]?)
UnicodeEmojiFlags = $([\uD83C] [\uDD00-\uDDFF] [\uD83C] [\uDD00-\uDDFF])
/**
*
* Inline Code
* e.g: `console.log('hello world')`
*
*/
InlineCode = "`" text:$InlineCode__+ "`" { return inlineCode(plain(text)); }
InlineCode__ = $(!"`" !"\n" .)
/**
*
* Colors
* e.g: color:#ff0000 , color:#ff0
*
*/
Color = & { return options.colors; } "color:#" rgba:ColorRGBATuple !AnyText {
return color(...rgba);
}
ColorRGBATuple = HexByte|3..4| / HexNible|3..4|
/**
*
* Macros
*
*/
Whitespace = w:$Space+ { return plain(w); }
EndOfLine = "\r\n" / "\n" / "\r"
Space = " " / "\t"
Escaped = "\\" t:[*_~`#.] { return plain(t); }
Any = !EndOfLine t:. p:$AutolinkedPhone? u:$URL? { return plain(t + p + u); }
AnyText = [\x20-\x27\x2B-\x40\x41-\x5A\x61-\x7A] / NonASCII
Text = text:AnyText { return plain(text); }
Line = t:LineStructure { return plain(t); }
LineStructure = head:$Space* text:$AnyText+ tail:$Space* { return head + text + tail; }
UTF8NamesValidation = $([-_.] / AlphaNumericChar)+
NonASCII = [\x80-\uFFFF]
Unicode = "\\" Digits:$(HexDigit |1..6|) ("\r\n" / [ \t\r\n\f])? { return String.fromCharCode(parseInt(Digits, 16)); }
Digit = [0-9]
Digits = $Digit+
Safe = [$@&+\__#?-]
Extra = [.,!%~*\"':;()=~]
HexDigit = [0-9A-Fa-f]
HexNible = a:HexDigit { return parseInt(a + a, 16); }
HexByte = a:HexDigit b:HexDigit { return parseInt(a + b, 16); }
AlphaDigit = [a-zA-Z0-9]
AlphaNumericOrMarkChar = AlphaOrMarkChar / DecimalNumberChar
AlphaOrMarkChar = AlphaChar / EmojiChar / MarkChar
AlphaNumericChar = AlphaChar / DecimalNumberChar
AlphaChar = [A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]
DecimalNumberChar = [0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19]
EmojiChar = [\u2700-\u27bf\udde6-\uddff\ud800-\udbff\udc00-\udfff\ufe0e\ufe0f\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0\ud83c\udffb-\udfff\u200d\u3299\u3297\u303d\u3030\u24c2\ud83c\udd70-\udd71\udd7e-\udd7f\udd8e\udd91-\udd9a\udde6-\uddff\ude01-\ude02\ude1a\ude2f\ude32-\ude3a\ude50-\ude51\u203c\u2049\u25aa-\u25ab\u25b6\u25c0\u25fb-\u25fe\u00a9\u00ae\u2122\u2139\udc04\u2600-\u26FF\u2b05\u2b06\u2b07\u2b1b\u2b1c\u2b50\u2b55\u231a\u231b\u2328\u23cf\u23e9-\u23f3\u23f8-\u23fa\udccf\u2935\u2934\u2190-\u21ff]
MarkChar = [\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D4-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D01-\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF5\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]

View File

@ -0,0 +1,10 @@
import type { ASTNode } from './definitions';
export const isNodeOfType = <N extends ASTNode>(
value: unknown,
type: N['type']
): value is N =>
typeof value === 'object' &&
value !== null &&
'type' in value &&
(value as { type: unknown }).type === type;

View File

@ -0,0 +1,26 @@
import type { Root } from './definitions';
import * as grammar from './grammar.pegjs';
export * from './definitions';
export { isNodeOfType } from './guards';
export type Options = {
colors?: boolean;
emoticons?: boolean;
katex?: {
dollarSyntax?: boolean;
parenthesisSyntax?: boolean;
};
customDomains?: string[];
};
export const parse = (input: string, options?: Options): Root =>
grammar.parse(input, options);
export {
/** @deprecated */
parse as parser,
/** @deprecated */
Root as MarkdownAST,
};

View File

@ -0,0 +1,7 @@
declare module '*.pegjs' {
import type { ParserOptions } from 'peggy';
import type { ASTMessage } from '../definitions';
export const parse: (input: string, options?: ParserOptions) => ASTMessage;
}

View File

@ -0,0 +1,235 @@
import { parse as tldParse } from 'tldts';
import type {
BigEmoji,
Code,
Color,
Heading,
Markup,
Paragraph,
Types,
Task,
ListItem,
Inlines,
LineBreak,
Emoji,
KaTeX,
InlineKaTeX,
Link,
} from './definitions';
const generate =
<Type extends keyof Types>(type: Type) =>
(value: Types[Type]['value']): Types[Type] =>
({ type, value } as any);
export const paragraph = generate('PARAGRAPH');
export const bold = generate('BOLD');
export const color = (r: number, g: number, b: number, a = 255): Color => ({
type: 'COLOR',
value: { r, g, b, a },
});
export const heading = (
value: Heading['value'],
level: Heading['level'] = 1
): Heading => ({
type: 'HEADING',
level,
value,
});
export const code = (
value: Code['value'],
language?: Code['language']
): Code => ({
type: 'CODE',
language: language || 'none',
value,
});
export const bigEmoji = (value: BigEmoji['value']): BigEmoji => ({
type: 'BIG_EMOJI',
value,
});
export const task = (value: Task['value'], status: boolean): Task => ({
type: 'TASK',
status,
value,
});
export const inlineCode = generate('INLINE_CODE');
export const tasks = generate('TASKS');
export const italic = generate('ITALIC');
export const plain = generate('PLAIN_TEXT');
export const strike = generate('STRIKE');
export const codeLine = generate('CODE_LINE');
const isValidLink = (link: string) => {
try {
return Boolean(new URL(link));
} catch (error) {
return false;
}
};
export const link = (src: string, label?: Markup[]): Link => ({
type: 'LINK',
value: { src: plain(src), label: label ?? [plain(src)] },
});
export const autoLink = (src: string, customDomains?: string[]) => {
const validHosts = ['localhost', ...(customDomains ?? [])];
const { isIcann, isIp, isPrivate, domain } = tldParse(src, {
detectIp: false,
allowPrivateDomains: true,
validHosts,
});
if (
!(isIcann || isIp || isPrivate || (domain && validHosts.includes(domain)))
) {
return plain(src);
}
const href = isValidLink(src) || src.startsWith('//') ? src : `//${src}`;
return link(href, [plain(src)]);
};
export const autoEmail = (src: string) => {
const href = `mailto:${src}`;
const { isIcann, isIp, isPrivate } = tldParse(href, {
detectIp: false,
allowPrivateDomains: true,
});
if (!(isIcann || isIp || isPrivate)) {
return plain(src);
}
return link(href, [plain(src)]);
};
export const image = (() => {
const fn = generate('IMAGE');
return (src: string, label?: Markup) =>
fn({ src: plain(src), label: label || plain(src) });
})();
export const quote = generate('QUOTE');
export const mentionChannel = (() => {
const fn = generate('MENTION_CHANNEL');
return (value: string) => fn(plain(value));
})();
export const orderedList = generate('ORDERED_LIST');
export const unorderedList = generate('UNORDERED_LIST');
export const listItem = (text: Inlines[], number?: number): ListItem => ({
type: 'LIST_ITEM',
value: text,
...(number && { number }),
});
export const mentionUser = (() => {
const fn = generate('MENTION_USER');
return (value: string) => fn(plain(value));
})();
export const emoji = (shortCode: string): Emoji => ({
type: 'EMOJI',
value: plain(shortCode),
shortCode,
});
export const emojiUnicode = (unicode: string): Emoji => ({
type: 'EMOJI',
value: undefined,
unicode,
});
export const emoticon = (emoticon: string, shortCode: string): Emoji => ({
type: 'EMOJI',
value: plain(emoticon),
shortCode,
});
const joinEmoji = (
current: Inlines,
previous: Inlines | undefined,
next: Inlines | undefined
): Inlines => {
if (current.type !== 'EMOJI' || !current.value || (!previous && !next)) {
return current;
}
const hasEmojiAsNeighbor =
previous?.type === current.type || current.type === next?.type;
const hasPlainAsNeighbor =
(previous?.type === 'PLAIN_TEXT' && previous.value.trim() !== '') ||
(next?.type === 'PLAIN_TEXT' && next.value.trim() !== '');
const isEmoticon = current.shortCode !== current.value.value;
if (current.value && (hasEmojiAsNeighbor || hasPlainAsNeighbor)) {
if (isEmoticon) {
return current.value;
}
return {
...current.value,
value: `:${current.value.value}:`,
};
}
return current;
};
export const reducePlainTexts = (
values: Paragraph['value']
): Paragraph['value'] =>
values.reduce((result, item, index) => {
const next = values[index + 1];
const current = joinEmoji(item, values[index - 1], next);
const previous: Inlines = result[result.length - 1];
if (previous) {
if (current.type === 'PLAIN_TEXT' && current.type === previous.type) {
previous.value += current.value;
return result;
}
}
return [...result, current];
}, [] as Paragraph['value']);
export const lineBreak = (): LineBreak => ({
type: 'LINE_BREAK',
value: undefined,
});
export const katex = (content: string): KaTeX => ({
type: 'KATEX',
value: content,
});
export const inlineKatex = (content: string): InlineKaTeX => ({
type: 'INLINE_KATEX',
value: content,
});
export const phoneChecker = (text: string, number: string) => {
if (number.length < 5) {
return plain(text);
}
return link(`tel:${number}`, [plain(text)]);
};

View File

@ -0,0 +1,13 @@
import { parse } from '../src';
import { paragraph, plain } from '../src/utils';
test.each([
['free text', [paragraph([plain('free text')])]],
['free text, with comma', [paragraph([plain('free text, with comma')])]],
[
'free text with unxpected/unfinished blocks *bold_',
[paragraph([plain('free text with unxpected/unfinished blocks *bold_')])],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,40 @@
import { parse } from '../src';
import { paragraph, plain, quote, bold } from '../src/utils';
test.each([
[
`
As Rocket Cat said:
> meowww
> grr.
`.trim(),
[
paragraph([plain('As Rocket Cat said:')]),
quote([paragraph([plain('meowww')]), paragraph([plain('grr.')])]),
],
],
[
`
As Rocket Cat said:
> *meowww*
> grr.
`.trim(),
[
paragraph([plain('As Rocket Cat said:')]),
quote([paragraph([bold([plain('meowww')])]), paragraph([plain('grr.')])]),
],
],
[
`
As Rocket Cat said:
>meowww
>grr.
`.trim(),
[
paragraph([plain('As Rocket Cat said:')]),
quote([paragraph([plain('meowww')]), paragraph([plain('grr.')])]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,83 @@
import { parse } from '../src';
import { paragraph, plain, codeLine, code } from '../src/utils';
const multiply = <T>(a: number, element: T): Array<T> =>
Array.from({ length: a }, () => element);
test.each([
[
`\`\`\`
code
code
\`\`\``,
[
code([
codeLine(plain('code')),
...multiply(4, codeLine(plain(''))),
codeLine(plain('code')),
]),
],
],
[
`\`\`\`
code
\`\`\``,
[code([codeLine(plain('code')), ...multiply(2, codeLine(plain('')))])],
],
[
`\`\`\`
code
\`\`\``,
[code([codeLine(plain('code'))])],
],
[
`\`\`\`
var a = "teste";
\`\`\``,
[code([codeLine(plain('var a = "teste";'))])],
],
[
`\`\`\`javascript
code
\`\`\``,
[code([codeLine(plain('code'))], 'javascript')],
],
[
`\`\`\`bash c
code
\`\`\``,
[code([codeLine(plain('code'))], 'bash c')],
],
[
` \`\`\`
code
\`\`\``,
[
paragraph([plain(` \`\`\``)]),
paragraph([plain(`code`)]),
paragraph([plain(`\`\`\``)]),
],
],
[
`\`\`\`
code
code
\`\`\``,
[code([codeLine(plain(`code`)), codeLine(plain(`code`))])],
],
[
`\`\`\`
# code
**code**
\`\`\``,
[code([codeLine(plain(`# code`)), codeLine(plain(`**code**`))])],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,34 @@
import { parse } from '../src';
import { color, paragraph, plain } from '../src/utils';
test.each([
[
'color:#ccc',
[paragraph([color(0xcc, 0xcc, 0xcc)])],
[paragraph([plain('color:#ccc')])],
],
[
'color:#cccc',
[paragraph([color(0xcc, 0xcc, 0xcc, 0xcc)])],
[paragraph([plain('color:#cccc')])],
],
[
'color:#c7c7c7',
[paragraph([color(0xc7, 0xc7, 0xc7)])],
[paragraph([plain('color:#c7c7c7')])],
],
[
'color:#c7c7c7c7',
[paragraph([color(0xc7, 0xc7, 0xc7, 0xc7)])],
[paragraph([plain('color:#c7c7c7c7')])],
],
['color:#c7c7c7c7c7', [paragraph([plain('color:#c7c7c7c7c7')])], undefined],
['color:#c7', [paragraph([plain('color:#c7')])], undefined],
['color:#zzz', [paragraph([plain('color:#zzz')])], undefined],
])('parses %p', (input, output, disabledOutput) => {
expect(parse(input, { colors: true })).toMatchObject(output);
if (disabledOutput) {
expect(parse(input, { colors: false })).toMatchObject(disabledOutput);
}
});

View File

@ -0,0 +1,144 @@
import { parse } from '../src';
import { link, paragraph, plain } from '../src/utils';
test.each([
[
'joe@joe.com',
[paragraph([link('mailto:joe@joe.com', [plain('joe@joe.com')])])],
],
[
"joe@joe.com is Joe's email",
[
paragraph([
link('mailto:joe@joe.com', [plain('joe@joe.com')]),
plain(" is Joe's email"),
]),
],
],
[
"Joe's email is joe@joe.com because it is",
[
paragraph([
plain("Joe's email is "),
link('mailto:joe@joe.com', [plain('joe@joe.com')]),
plain(' because it is'),
]),
],
],
[
"Joe's email is joe@joe.com",
[
paragraph([
plain("Joe's email is "),
link('mailto:joe@joe.com', [plain('joe@joe.com')]),
]),
],
],
[
"Joe's email is joe@joe.com. Try emailing him",
[
paragraph([
plain("Joe's email is "),
link('mailto:joe@joe.com', [plain('joe@joe.com')]),
plain('. Try emailing him'),
]),
],
],
[
"Joe's email is joe.smith@joe.com",
[
paragraph([
plain("Joe's email is "),
link('mailto:joe.smith@joe.com', [plain('joe.smith@joe.com')]),
]),
],
],
[
"Joe's email is JOE@JOE.COM",
[
paragraph([
plain("Joe's email is "),
link('mailto:JOE@JOE.COM', [plain('JOE@JOE.COM')]),
]),
],
],
[
"Joe's email is (joe@joe.com)",
[
paragraph([
plain("Joe's email is ("),
link('mailto:joe@joe.com', [plain('joe@joe.com')]),
plain(')'),
]),
],
],
[
"Joe's email is (joe_roe@joe.com)",
[
paragraph([
plain("Joe's email is ("),
link('mailto:joe_roe@joe.com', [plain('joe_roe@joe.com')]),
plain(')'),
]),
],
],
[
"Joe's email is (joe'roe@joe.com)",
[
paragraph([
plain("Joe's email is ("),
link("mailto:joe'roe@joe.com", [plain("joe'roe@joe.com")]),
plain(')'),
]),
],
],
[
"Joe's email is mañana@mañana.com",
[
paragraph([
plain("Joe's email is "),
link('mailto:mañana@mañana.com', [plain('mañana@mañana.com')]),
]),
],
],
[
"Joe's email is Кириллица@Кириллица.com",
[
paragraph([
plain("Joe's email is "),
link('mailto:Кириллица@Кириллица.com', [
plain('Кириллица@Кириллица.com'),
]),
]),
],
],
['Hi there@stuff', [paragraph([plain('Hi there@stuff')])]],
[
'My email is busueng.kim@aaa.com',
[
paragraph([
plain('My email is '),
link('mailto:busueng.kim@aaa.com', [plain('busueng.kim@aaa.com')]),
]),
],
],
[
'My email is mailto:asdf@asdf.com',
[
paragraph([
plain('My email is '),
link('mailto:asdf@asdf.com', [plain('asdf@asdf.com')]),
]),
],
],
[
'My email is fake@gmail.c',
[paragraph([plain('My email is fake@gmail.c')])],
],
[
'My email is fake@gmail.comf',
[paragraph([plain('My email is fake@gmail.comf')])],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,90 @@
import { parse } from '../src';
import { emoji, bigEmoji, paragraph, plain, emojiUnicode } from '../src/utils';
test.each([
[':smile: asd', [paragraph([emoji('smile'), plain(' asd')])]],
['text:inner:outer', [paragraph([plain('text:inner:outer')])]],
['10:20:30', [paragraph([plain('10:20:30')])]],
['10:20:30:', [paragraph([plain('10:20:30:')])]],
['":smile:"', [paragraph([plain('":smile:"')])]],
['":smile: "', [paragraph([plain('":smile: "')])]],
['" :smile: "', [paragraph([plain('" '), emoji('smile'), plain(' "')])]],
[
`:smile:
:smile:
`,
[bigEmoji([emoji('smile'), emoji('smile')])],
],
[
'asdas :smile: asd',
[paragraph([plain('asdas '), emoji('smile'), plain(' asd')])],
],
[
'normal emojis :smile: :smile: :smile:',
[
paragraph([
plain('normal emojis '),
emoji('smile'),
plain(' '),
emoji('smile'),
plain(' '),
emoji('smile'),
]),
],
],
[
':smile::smile::smile:',
[bigEmoji([emoji('smile'), emoji('smile'), emoji('smile')])],
],
[
' :smile::smile::smile: ',
[bigEmoji([emoji('smile'), emoji('smile'), emoji('smile')])],
],
[
'\n :smile::smile::smile: \n',
[bigEmoji([emoji('smile'), emoji('smile'), emoji('smile')])],
],
[
':smile: :smile: :smile:',
[bigEmoji([emoji('smile'), emoji('smile'), emoji('smile')])],
],
[':smile::smile:', [bigEmoji([emoji('smile'), emoji('smile')])]],
[':smile:', [bigEmoji([emoji('smile')])]],
['Hi :+1:', [paragraph([plain('Hi '), emoji('+1')])]],
['Hi :+1_tone4:', [paragraph([plain('Hi '), emoji('+1_tone4')])]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});
// Tests for unicode emojis
test.each([
['😀', [bigEmoji([emojiUnicode('😀')])]],
['😃', [bigEmoji([emojiUnicode('😃')])]],
['🥵', [bigEmoji([emojiUnicode('🥵')])]],
['🧿', [bigEmoji([emojiUnicode('🧿')])]],
['🐶', [bigEmoji([emojiUnicode('🐶')])]],
['🍏', [bigEmoji([emojiUnicode('🍏')])]],
['⚽', [bigEmoji([emojiUnicode('⚽')])]],
['⚽️', [bigEmoji([emojiUnicode('⚽️')])]],
['👨‍👩‍👧‍👦', [bigEmoji([emojiUnicode('👨‍👩‍👧‍👦')])]],
['🚗', [bigEmoji([emojiUnicode('🚗')])]],
['⌚️', [bigEmoji([emojiUnicode('⌚️')])]],
['❤️', [bigEmoji([emojiUnicode('❤️')])]],
['🏳️', [bigEmoji([emojiUnicode('🏳️')])]],
['🧑🏾‍💻', [bigEmoji([emojiUnicode('🧑🏾‍💻')])]],
['🧑🏾‍💻🧑🏾‍💻', [bigEmoji([emojiUnicode('🧑🏾‍💻'), emojiUnicode('🧑🏾‍💻')])]],
[
'🧑🏾‍💻🧑🏾‍💻🧑🏾‍💻',
[bigEmoji([emojiUnicode('🧑🏾‍💻'), emojiUnicode('🧑🏾‍💻'), emojiUnicode('🧑🏾‍💻')])],
],
['👆🏽', [bigEmoji([emojiUnicode('👆🏽')])]],
['👆🏽👆🏽', [bigEmoji([emojiUnicode('👆🏽'), emojiUnicode('👆🏽')])]],
[
'👆🏽👆🏽👆🏽',
[bigEmoji([emojiUnicode('👆🏽'), emojiUnicode('👆🏽'), emojiUnicode('👆🏽')])],
],
['👆🏺', [bigEmoji([emojiUnicode('👆'), emojiUnicode('🏺')])]],
['Hi 👍', [paragraph([plain('Hi '), emojiUnicode('👍')])]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,148 @@
import { parse } from '../src';
import { bigEmoji, paragraph, plain, emoticon } from '../src/utils';
test.each([
// Should render normal Emojis
[
`test
:) test`,
[
paragraph([plain('test')]),
paragraph([
plain(' '),
emoticon(':)', 'slight_smile'),
plain(' test'),
]),
],
],
[':) asd', [paragraph([emoticon(':)', 'slight_smile'), plain(' asd')])]],
[':) asd', [paragraph([emoticon(':)', 'slight_smile'), plain(' asd')])]],
[
' :) asd',
[paragraph([plain(' '), emoticon(':)', 'slight_smile'), plain(' asd')])],
],
['Hi :)', [paragraph([plain('Hi '), emoticon(':)', 'slight_smile')])]],
[
'asdas :) asd',
[
paragraph([
plain('asdas '),
emoticon(':)', 'slight_smile'),
plain(' asd'),
]),
],
],
[
':) :) :) :)',
[
paragraph([
emoticon(':)', 'slight_smile'),
plain(' '),
emoticon(':)', 'slight_smile'),
plain(' '),
emoticon(':)', 'slight_smile'),
plain(' '),
emoticon(':)', 'slight_smile'),
]),
],
],
// Should render BigEmojis
[
`:)
:)
`,
[
bigEmoji([
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
]),
],
],
[
':):):)',
[
bigEmoji([
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
]),
],
],
[
' :):):) ',
[
bigEmoji([
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
]),
],
],
[
'\n :):):) \n',
[
bigEmoji([
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
]),
],
],
[
':) :) :)',
[
bigEmoji([
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
]),
],
],
[
':) :)',
[
bigEmoji([
emoticon(':)', 'slight_smile'),
emoticon(':)', 'slight_smile'),
]),
],
],
[':)', [bigEmoji([emoticon(':)', 'slight_smile')])]],
[' :)', [bigEmoji([emoticon(':)', 'slight_smile')])]],
[':) ', [bigEmoji([emoticon(':)', 'slight_smile')])]],
[' :) ', [bigEmoji([emoticon(':)', 'slight_smile')])]],
['D:', [bigEmoji([emoticon('D:', 'fearful')])]],
['D: D:', [bigEmoji([emoticon('D:', 'fearful'), emoticon('D:', 'fearful')])]],
[
' D: D: D: ',
[
bigEmoji([
emoticon('D:', 'fearful'),
emoticon('D:', 'fearful'),
emoticon('D:', 'fearful'),
]),
],
],
['Hi D:', [paragraph([plain('Hi '), emoticon('D:', 'fearful')])]],
// Should not render Emojis or BigEmojis if they are not surrounded by spaces
['normal emojis :):):)', [paragraph([plain('normal emojis :):):)')])]],
[':)10:30', [paragraph([plain(':)10:30')])]],
[':smile::)text', [paragraph([plain(':smile::)text')])]],
['text:):smile:', [paragraph([plain('text:):smile:')])]],
['text:):)', [paragraph([plain('text:):)')])]],
[':):):) normal emojis', [paragraph([plain(':):):) normal emojis')])]],
[':):):):)', [paragraph([plain(':):):):)')])]],
['10:30', [paragraph([plain('10:30')])]],
['he:)llo', [paragraph([plain('he:)llo')])]],
[':)Hi', [paragraph([plain(':)Hi')])]],
['Hi:) Hi', [paragraph([plain('Hi:) Hi')])]],
['Hi:)', [paragraph([plain('Hi:)')])]],
['@#@#! :)@!@', [paragraph([plain('@#@#! :)@!@')])]],
])('parses %p', (input, output) => {
expect(parse(input, { emoticons: true })).toMatchObject(output);
});

View File

@ -0,0 +1,174 @@
import { parse } from '../src';
import {
italic,
paragraph,
plain,
strike,
bold,
emoji,
link,
bigEmoji,
emojiUnicode,
mentionChannel,
mentionUser,
} from '../src/utils';
test.each([
['_:smile:_', [paragraph([italic([emoji('smile')])])]],
['_:slight_smile:_', [paragraph([italic([emoji('slight_smile')])])]],
[
'_test :smile: test_',
[paragraph([italic([plain('test '), emoji('smile'), plain(' test')])])],
],
[
'_test :slight_smile: test_',
[
paragraph([
italic([plain('test '), emoji('slight_smile'), plain(' test')]),
]),
],
],
['_😀_', [paragraph([italic([emojiUnicode('😀')])])]],
['_test 😀_', [paragraph([italic([plain('test '), emojiUnicode('😀')])])]],
[
'_test @guilherme.gazzo test_',
[
paragraph([
italic([
plain('test '),
mentionUser('guilherme.gazzo'),
plain(' test'),
]),
]),
],
],
[
'_test #GENERAL test_',
[
paragraph([
italic([plain('test '), mentionChannel('GENERAL'), plain(' test')]),
]),
],
],
[
'_[A brand new Gist](https://gist.github.com/24dddfa97bef58f46ac2ce0f80c58ba4)_',
[
paragraph([
italic([
link('https://gist.github.com/24dddfa97bef58f46ac2ce0f80c58ba4', [
plain('A brand new Gist'),
]),
]),
]),
],
],
['__italic__', [paragraph([italic([plain('italic')])])]],
['__italic__non', [paragraph([plain('__italic__non')])]],
['__test__test__', [paragraph([plain('__test__test__')])]],
['pre__italic__post', [paragraph([plain('pre__italic__post')])]],
[' pre__italic__post', [paragraph([plain(' pre__italic__post')])]],
[
' pre__**~~boldstrikeitalic~~**__post ',
[
paragraph([
plain(' pre__'),
bold([strike([plain('boldstrikeitalic')])]),
plain('__post '),
]),
],
],
['__', [paragraph([plain('__')])]],
['_ _', [paragraph([plain('_ _')])]],
['__ _', [paragraph([plain('__ _')])]],
['__ __', [paragraph([plain('__ __')])]],
['_ Hello_', [paragraph([italic([plain(' Hello')])])]],
['_Hello _', [paragraph([italic([plain('Hello ')])])]],
[':custom_emoji_case:', [bigEmoji([emoji('custom_emoji_case')])]],
['_Hel lo_', [paragraph([italic([plain('Hel lo')])])]],
['_Hello_', [paragraph([italic([plain('Hello')])])]],
['__Hello__', [paragraph([italic([plain('Hello')])])]],
['__Hello_', [paragraph([plain('_'), italic([plain('Hello')])])]],
['_Hello__', [paragraph([italic([plain('Hello')]), plain('_')])]],
['_Hello', [paragraph([plain('_Hello')])]],
['Hello_', [paragraph([plain('Hello_')])]],
['He_llo', [paragraph([plain('He_llo')])]],
[
'___Hello___',
[paragraph([plain('_'), italic([plain('Hello')]), plain('_')])],
],
['___Hello__', [paragraph([plain('_'), italic([plain('Hello')])])]],
[
'_Hello_ this is dog',
[paragraph([italic([plain('Hello')]), plain(` this is dog`)])],
],
[
'Rocket cat says _Hello_',
[paragraph([plain(`Rocket cat says `), italic([plain('Hello')])])],
],
[
'He said _Hello_ to her',
[
paragraph([
plain(`He said `),
italic([plain('Hello')]),
plain(` to her`),
]),
],
],
[
'__Hello__ this is dog',
[paragraph([italic([plain('Hello')]), plain(` this is dog`)])],
],
[
'Rocket cat says __Hello__',
[paragraph([plain(`Rocket cat says `), italic([plain('Hello')])])],
],
[
'He said __Hello__ to her',
[
paragraph([
plain(`He said `),
italic([plain('Hello')]),
plain(` to her`),
]),
],
],
['text_hello_text', [paragraph([plain('text_hello_text')])]],
['_hello_text', [paragraph([plain('_hello_text')])]],
['text_hello_', [paragraph([plain('text_hello_')])]],
['_italic@test_', [paragraph([italic([plain('italic@test')])])]],
['_italic#test_', [paragraph([italic([plain('italic#test')])])]],
['paragraph@test__', [paragraph([plain('paragraph@test__')])]],
[
'_ @guilherme_gazzo_ _',
[
paragraph([
italic([plain(' '), mentionUser('guilherme_gazzo_'), plain(' ')]),
]),
],
],
[
'_ @guilherme.gazzo _',
[
paragraph([
italic([plain(' '), mentionUser('guilherme.gazzo'), plain(' ')]),
]),
],
],
[
'**reference link inside [emphasis with more [references](https://rocket.chat)](https://rocket.chat)**',
[
paragraph([
bold([
plain('reference link inside '),
link('https://rocket.chat', [
plain('emphasis with more [references'),
]),
plain('](https://rocket.chat)'),
]),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,38 @@
import { parse } from '../src';
import { paragraph, plain, bold } from '../src/utils';
test.each([
['¯\\\\_(ツ)_/¯', [paragraph([plain('¯\\_(ツ)_/¯')])]],
[
'\\*escaped as*bold*escaped*',
[
paragraph([
plain('*escaped as'),
bold([plain('bold')]),
plain('escaped*'),
]),
],
],
['\\*not bold*', [paragraph([plain('*not bold*')])]],
['*_~`#.'.split('').join('\\'), [paragraph([plain('*_~`#.')])]],
['\\*not emphasized*', [paragraph([plain('*not emphasized*')])]],
['\\<br/> tag plain text', [paragraph([plain('\\<br/> tag plain text')])]],
[
'\\[it is not a link](/foo)',
[paragraph([plain('\\[it is not a link](/foo)')])],
],
['\\`not code`', [paragraph([plain('`not code`')])]],
['1\\. not a list', [paragraph([plain('1. not a list')])]],
['\\* not a list', [paragraph([plain('* not a list')])]],
['\\# not a heading', [paragraph([plain('# not a heading')])]],
[
'\\[foo]: /url "not a reference"',
[paragraph([plain('\\[foo]: /url "not a reference"')])],
],
[
'\\&ouml; not a character entity',
[paragraph([plain('\\&ouml; not a character entity')])],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,58 @@
import { parse } from '../src';
import {
heading,
lineBreak,
mentionChannel,
paragraph,
plain,
} from '../src/utils';
test.each([
['# h1', [heading([plain('h1')], 1)]],
['# Hello', [heading([plain('Hello')], 1)]],
['# Rocket.Cat', [heading([plain('Rocket.Cat')], 1)]],
['# Hi', [heading([plain('Hi')], 1)]],
['# Hello this is dog', [heading([plain('Hello this is dog')], 1)]],
['# Rocket cat says Hello', [heading([plain('Rocket cat says Hello')], 1)]],
['# He said Hello to her', [heading([plain('He said Hello to her')], 1)]],
['#Hello', [paragraph([mentionChannel('Hello')])]],
['#Hello#', [paragraph([mentionChannel('Hello'), plain('#')])]],
['He#llo', [paragraph([plain('He#llo')])]],
['## Hello', [heading([plain('Hello')], 2)]],
['## Rocket.Cat', [heading([plain('Rocket.Cat')], 2)]],
['## Hi', [heading([plain('Hi')], 2)]],
['## Hello this is dog', [heading([plain('Hello this is dog')], 2)]],
['## Rocket cat says Hello', [heading([plain('Rocket cat says Hello')], 2)]],
['## He said Hello to her', [heading([plain('He said Hello to her')], 2)]],
['##Hello', [paragraph([plain('##Hello')])]],
['##Hello##', [paragraph([plain('##Hello##')])]],
['He##llo', [paragraph([plain('He##llo')])]],
['### Hello', [heading([plain('Hello')], 3)]],
['### Rocket.Cat', [heading([plain('Rocket.Cat')], 3)]],
['### Hi', [heading([plain('Hi')], 3)]],
['### Hello this is dog', [heading([plain('Hello this is dog')], 3)]],
['### Rocket cat says Hello', [heading([plain('Rocket cat says Hello')], 3)]],
['### He said Hello to her', [heading([plain('He said Hello to her')], 3)]],
['###Hello', [paragraph([plain('###Hello')])]],
['###Hello###', [paragraph([plain('###Hello###')])]],
['He###llo', [paragraph([plain('He###llo')])]],
['#### Hello', [heading([plain('Hello')], 4)]],
['#### Rocket.Cat', [heading([plain('Rocket.Cat')], 4)]],
['#### Hi', [heading([plain('Hi')], 4)]],
['#### Hello this is dog', [heading([plain('Hello this is dog')], 4)]],
[
'#### Rocket cat says Hello',
[heading([plain('Rocket cat says Hello')], 4)],
],
['#### He said Hello to her', [heading([plain('He said Hello to her')], 4)]],
['####Hello', [paragraph([plain('####Hello')])]],
['####Hello####', [paragraph([plain('####Hello####')])]],
['He####llo', [paragraph([plain('He####llo')])]],
['# Hello\n', [heading([plain('Hello')], 1), lineBreak()]],
['# # Hello\n', [heading([plain('# Hello')], 1), lineBreak()]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,19 @@
import { parse } from '../src';
import { image, paragraph, plain } from '../src/utils';
test.each([
[
'![image](https://rocket.chat/assets/img/header/logo.svg)',
[
paragraph([
image('https://rocket.chat/assets/img/header/logo.svg', plain('image')),
]),
],
],
[
'![](https://rocket.chat/assets/img/header/logo.svg)',
[paragraph([image('https://rocket.chat/assets/img/header/logo.svg')])],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,27 @@
import { parse } from '../src';
import { inlineCode, paragraph, plain } from '../src/utils';
test.each([
[
'`[asd](https://localhost)`',
[paragraph([inlineCode(plain('[asd](https://localhost)'))])],
],
[`\`code\``, [paragraph([inlineCode(plain('code'))])]],
[
`File extension (\`.mov\`)`,
[
paragraph([
plain('File extension ('),
inlineCode(plain('.mov')),
plain(')'),
]),
],
],
['`@rocket.chat`', [paragraph([inlineCode(plain('@rocket.chat'))])]],
[
'`@rocket.chat/message-parser`',
[paragraph([inlineCode(plain('@rocket.chat/message-parser'))])],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,46 @@
import { parse } from '../src';
import {
bold,
inlineCode,
italic,
paragraph,
plain,
strike,
} from '../src/utils';
test.each([
[
'~~`Striking Inline Code`~~',
[paragraph([strike([inlineCode(plain('Striking Inline Code'))])])],
],
[
'~~_`Striking Inline Code with Italics`_~~',
[
paragraph([
strike([
italic([inlineCode(plain('Striking Inline Code with Italics'))]),
]),
]),
],
],
[
'~~**`Striking Inline Code with Bold`**~~',
[
paragraph([
strike([bold([inlineCode(plain('Striking Inline Code with Bold'))])]),
]),
],
],
[
'~~__*`Striking Inline Code with Bold`*__~~',
[
paragraph([
strike([
italic([bold([inlineCode(plain('Striking Inline Code with Bold'))])]),
]),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,33 @@
import { parse } from '../src';
import { inlineKatex, katex, paragraph, plain } from '../src/utils';
test.each([
[
`\\[
\\f\\relax{x} = \\int_{-\\infty}^\\infty
\\f\\hat\\xi\\,e^{2 \\pi i \\xi x}
\\,d\\xi
\\]`,
[
katex(`
\\f\\relax{x} = \\int_{-\\infty}^\\infty
\\f\\hat\\xi\\,e^{2 \\pi i \\xi x}
\\,d\\xi
`),
],
],
[
'Easy as \\(E = mc^2\\), right?',
[
paragraph([
plain('Easy as '),
inlineKatex('E = mc^2'),
plain(', right?'),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input, { katex: { parenthesisSyntax: true } })).toMatchObject(
output
);
});

View File

@ -0,0 +1,35 @@
import { parse } from '../src';
import { lineBreak, paragraph, plain } from '../src/utils';
test.each([
[
`test
test2`,
[paragraph([plain('test')]), lineBreak(), paragraph([plain('test2')])],
],
[
`test
test2
`,
[paragraph([plain('test')]), lineBreak(), paragraph([plain('test2')])],
],
[
`test
test2
`,
[
paragraph([plain('test')]),
lineBreak(),
lineBreak(),
lineBreak(),
paragraph([plain('test2')]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,589 @@
import { parse } from '../src';
import {
link,
paragraph,
plain,
bold,
strike,
italic,
quote,
lineBreak,
unorderedList,
listItem,
orderedList,
} from '../src/utils';
test.each([
[
'<https://domain.com|Test>',
[paragraph([link('https://domain.com', [plain('Test')])])],
],
[
`<https://domain.com|Test
>`,
[paragraph([plain('<https://domain.com|Test')]), paragraph([plain('>')])],
],
[
`<https://domain.com|Test
> quote here`,
[
paragraph([plain('<https://domain.com|Test')]),
quote([paragraph([plain('quote here')])]),
],
],
[
'[Link](https://domain.com/link?a=%28node_filesystem_avail_bytes%29)',
[
paragraph([
link('https://domain.com/link?a=%28node_filesystem_avail_bytes%29', [
plain('Link'),
]),
]),
],
],
['[](https://rocket.chat)', [paragraph([link('https://rocket.chat')])]],
[
'[ ](https://rocket.chat)',
[paragraph([link('https://rocket.chat', [plain(' ')])])],
],
[
'[ test](https://rocket.chat)',
[paragraph([link('https://rocket.chat', [plain(' test')])])],
],
[
'[ test ](https://rocket.chat)',
[paragraph([link('https://rocket.chat', [plain(' test ')])])],
],
[
'[title](https://rocket.chat)',
[paragraph([link('https://rocket.chat', [plain('title')])])],
],
[
'[title](http://localhost)',
[paragraph([link('http://localhost', [plain('title')])])],
],
[
'[title](http://localhost?testing=true)',
[paragraph([link('http://localhost?testing=true', [plain('title')])])],
],
[
'[**title**](https://rocket.chat)',
[paragraph([link('https://rocket.chat', [bold([plain('title')])])])],
],
[
'[~~title~~](https://rocket.chat)',
[paragraph([link('https://rocket.chat', [strike([plain('title')])])])],
],
[
'[__title__](https://rocket.chat)',
[paragraph([link('https://rocket.chat', [italic([plain('title')])])])],
],
[
'[__**~~title~~**__](https://rocket.chat)',
[
paragraph([
link('https://rocket.chat', [
italic([bold([strike([plain('title')])])]),
]),
]),
],
],
[
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351'
),
]),
],
],
[
'<https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351|Test>',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[plain('Test')]
),
]),
],
],
[
'[title](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[plain('title')]
),
]),
],
],
[
'[**title**](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[bold([plain('title')])]
),
]),
],
],
[
'[~~title~~](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[strike([plain('title')])]
),
]),
],
],
[
'[__title__](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[italic([plain('title')])]
),
]),
],
],
[
'[__**~~title~~**__](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[italic([bold([strike([plain('title')])])])]
),
]),
],
],
[
'[title](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351?query=test12-34)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351?query=test12-34',
[plain('title')]
),
]),
],
],
[
'[title](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do?query=test12-34#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do?query=test12-34#Cases/dv/413244000073043351',
[plain('title')]
),
]),
],
],
[
'[title](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351?query=test12-34&query2=abc123)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351?query=test12-34&query2=abc123',
[plain('title')]
),
]),
],
],
[
'[title](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases?query=test12-34&query2=abcd!e/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases?query=test12-34&query2=abcd!e/dv/413244000073043351',
[plain('title')]
),
]),
],
],
[
'[title](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351?query=test12-34&query2=abcd!~-._%2B+)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351?query=test12-34&query2=abcd!~-._%2B+',
[plain('title')]
),
]),
],
],
['google.com', [paragraph([link('//google.com', [plain('google.com')])])]],
[
'www.google.com',
[paragraph([link('//www.google.com', [plain('www.google.com')])])],
],
['rocket.chat:8080', [paragraph([link('rocket.chat:8080')])]],
['ShouldNotBeALink', [paragraph([plain('ShouldNotBeALink')])]],
[
'http:/ google.com',
[
paragraph([
plain('http:/ '),
link('//google.com', [plain('google.com')]),
]),
],
],
[
'[custom](custom://google.com)',
[paragraph([link('custom://google.com', [plain('custom')])])],
],
[
'[thing](https://www.thingiverse.com/thing:5451684)',
[
paragraph([
link('https://www.thingiverse.com/thing:5451684', [plain('thing')]),
]),
],
],
[
'https://t.me/joinchat/chatexample',
[paragraph([link('https://t.me/joinchat/chatexample')])],
],
[
'[telegram invite](https://t.me/joinchat/chatexample)',
[
paragraph([
link('https://t.me/joinchat/chatexample', [plain('telegram invite')]),
]),
],
],
[
'[Github link with hash](https://github.com/RocketChat/Rocket.Chat/pull/26751/files#diff-c87b108ecf1ede549f8ede68eca840fbb330180b927df0b8a0b4df5d06cbd89b)',
[
paragraph([
link(
'https://github.com/RocketChat/Rocket.Chat/pull/26751/files#diff-c87b108ecf1ede549f8ede68eca840fbb330180b927df0b8a0b4df5d06cbd89b',
[plain('Github link with hash')]
),
]),
],
],
[
'[Github link with hash](https://github.com/RocketChat/Rocket.Chat/pull/26751/files#diff)',
[
paragraph([
link(
'https://github.com/RocketChat/Rocket.Chat/pull/26751/files#diff',
[plain('Github link with hash')]
),
]),
],
],
[
'[Github link without hash](https://github.com/RocketChat/Rocket.Chat/pull/26751/files)',
[
paragraph([
link('https://github.com/RocketChat/Rocket.Chat/pull/26751/files', [
plain('Github link without hash'),
]),
]),
],
],
[
'[Link with special chars](https://github.com/RocketChat/Rocket.Chat*[/]^_`{}~)',
[
paragraph([
link('https://github.com/RocketChat/Rocket.Chat*[/]^_`{}~', [
plain('Link with special chars'),
]),
]),
],
],
[
'[Google complex Link](https://www.google.com/url?rct=j&sa=t&url=https://ga.de/freizeit/region-erleben/bonn-und-region-tipps-fuers-wochenende-flohmarkt-rheinaue-weltkindertag-stadtfest_aid-53876987&ct=ga&cd=CAIyHDQ0NzEyYWE3MDA1MGNhNTQ6Y29tOmRlOkRFOlI&usg=AOvVaw3ySYrO9lM0iNSnk43gPVwZ)',
[
paragraph([
link(
'https://www.google.com/url?rct=j&sa=t&url=https://ga.de/freizeit/region-erleben/bonn-und-region-tipps-fuers-wochenende-flohmarkt-rheinaue-weltkindertag-stadtfest_aid-53876987&ct=ga&cd=CAIyHDQ0NzEyYWE3MDA1MGNhNTQ6Y29tOmRlOkRFOlI&usg=AOvVaw3ySYrO9lM0iNSnk43gPVwZ',
[plain('Google complex Link')]
),
]),
],
],
[
'[Rocket.Chat](https://rocket.chat) Inline Text',
[
paragraph([
link('https://rocket.chat', [plain('Rocket.Chat')]),
plain(' Inline Text'),
]),
],
],
[
'https://analytics.zoho.com/open-view/123456789 Same Line',
[
paragraph([
link('https://analytics.zoho.com/open-view/123456789', [
plain('https://analytics.zoho.com/open-view/123456789'),
]),
plain(' Same Line'),
]),
],
],
[
`[Rocket.Chat](https://rocket.chat)
Text after in a new line after link`,
[
paragraph([link('https://rocket.chat', [plain('Rocket.Chat')])]),
paragraph([plain('Text after in a new line after link')]),
],
],
[
`https://analytics.zoho.com/open-view/123456789
Second line`,
[
paragraph([
link('https://analytics.zoho.com/open-view/123456789', [
plain('https://analytics.zoho.com/open-view/123456789'),
]),
]),
paragraph([plain('Second line')]),
],
],
[
`[Rocket.Chat](https://rocket.chat)
Text after line break`,
[
paragraph([link('https://rocket.chat', [plain('Rocket.Chat')])]),
lineBreak(),
paragraph([plain('Text after line break')]),
],
],
[
`
[List Header Link](https://rocket.chat)
- First item
- Second item
- Third item
- *Fourth item*
`.trim(),
[
paragraph([link('https://rocket.chat', [plain('List Header Link')])]),
unorderedList([
listItem([plain('First item')]),
listItem([plain('Second item')]),
listItem([plain('Third item')]),
listItem([bold([plain('Fourth item')])]),
]),
],
],
[
`[List Header Link](https://rocket.chat)
7. First item
2. Second item
8. Third item
4. *Fourth item*
15. *Fifteenth item*
`.trim(),
[
paragraph([link('https://rocket.chat', [plain('List Header Link')])]),
orderedList([
listItem([plain('First item')], 7),
listItem([plain('Second item')], 2),
listItem([plain('Third item')], 8),
listItem([bold([plain('Fourth item')])], 4),
listItem([bold([plain('Fifteenth item')])], 15),
]),
],
],
[
'[9gag](https://9gag.com/)',
[paragraph([link('https://9gag.com/', [plain('9gag')])])],
],
['[9gag](9gag.com)', [paragraph([link('9gag.com', [plain('9gag')])])]],
['<9gag.com|9gag>', [paragraph([link('9gag.com', [plain('9gag')])])]],
['9gag.com', [paragraph([link('//9gag.com', [plain('9gag.com')])])]],
[
'[notes link](notes://Server/C3257116002CAD60/0/CCAF6BE2824A1F49432588D2001FA73E)',
[
paragraph([
link(
'notes://Server/C3257116002CAD60/0/CCAF6BE2824A1F49432588D2001FA73E',
[plain('notes link')]
),
]),
],
],
[
'[File Path](C:/Users/user1/Documents/projects/file.js)',
[
paragraph([
link('C:/Users/user1/Documents/projects/file.js', [plain('File Path')]),
]),
],
],
[
'[Test with **bold** element](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[plain('Test with '), bold([plain('bold')]), plain(' element')]
),
]),
],
],
[
'[Test with *bold* element](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[plain('Test with '), bold([plain('bold')]), plain(' element')]
),
]),
],
],
[
'[Test with _italic_ element](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[plain('Test with '), italic([plain('italic')]), plain(' element')]
),
]),
],
],
[
'[Test with ~strike~ element](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[plain('Test with '), strike([plain('strike')]), plain(' element')]
),
]),
],
],
[
'[Test with __**~~title~~**__ element](https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351)',
[
paragraph([
link(
'https://desk.rocket.chat/support/rocketchat/ShowHomePage.do#Cases/dv/413244000073043351',
[
plain('Test with '),
italic([bold([strike([plain('title')])])]),
plain(' element'),
]
),
]),
],
],
[
'([Github Issue: #24929](https://github.com/RocketChat/Rocket.Chat/issues/24929))',
[
paragraph([
plain('('),
link('https://github.com/RocketChat/Rocket.Chat/issues/24929', [
plain('Github Issue: #24929'),
]),
plain(')'),
]),
],
],
[
'the [audio_url and video_url for post message attachments](https://developer.rocket.chat/reference/api/rest-api/endpoints/core-endpoints/chat-endpoints/postmessage)',
[
paragraph([
plain('the '),
link(
'https://developer.rocket.chat/reference/api/rest-api/endpoints/core-endpoints/chat-endpoints/postmessage',
[plain('audio_url and video_url for post message attachments')]
),
]),
],
],
[
'the [Jira [Task] parentheses not working](rocket.chat)',
[
paragraph([
plain('the '),
link('rocket.chat', [plain('Jira [Task] parentheses not working')]),
]),
],
],
[
'the [Jira (Task) parentheses not working](rocket.chat)',
[
paragraph([
plain('the '),
link('rocket.chat', [plain('Jira (Task) parentheses not working')]),
]),
],
],
[
'[Jira [Task] parentheses not working](rocket.chat)',
[
paragraph([
link('rocket.chat', [plain('Jira [Task] parentheses not working')]),
]),
],
],
[
'[Jira (Task) parentheses not working](rocket.chat)',
[
paragraph([
link('rocket.chat', [plain('Jira (Task) parentheses not working')]),
]),
],
],
// Should not parse as link
['77.77%', [paragraph([plain('77.77%')])]],
['77.77', [paragraph([plain('77.77')])]],
['https://77.77', [paragraph([plain('https://77.77')])]],
['test.9gag', [paragraph([plain('test.9gag')])]],
[
'[here](https://github.com/RocketChat/Rocket.Chat/releases/tag/6.0.0-rc.3)',
[
paragraph([
link(
'https://github.com/RocketChat/Rocket.Chat/releases/tag/6.0.0-rc.3',
[plain('here')]
),
]),
],
],
[
'[ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [ ~ [test](https://rocket.chat)',
[
paragraph([
link('https://rocket.chat', [
plain(' '),
strike([plain(' [ ')]),
plain(' [ '),
strike([plain(' [ ')]),
plain(' [ '),
strike([plain(' [ ')]),
plain(' [ '),
strike([plain(' [ ')]),
plain(' [ '),
strike([plain(' [ ')]),
plain(' [ '),
strike([plain(' [ ')]),
plain(' [ '),
strike([plain(' [ ')]),
plain(' [test'),
]),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,34 @@
import { parse } from '../src';
import { paragraph, plain, mentionUser, mentionChannel } from '../src/utils';
test.each([
['@guilherme.gazzo', [paragraph([mentionUser('guilherme.gazzo')])]],
[
'@guilherme.gazzo. ',
[paragraph([mentionUser('guilherme.gazzo.'), plain(' ')])],
],
['#GENERAL', [paragraph([mentionChannel('GENERAL')])]],
['@user:server.com', [paragraph([mentionUser('user:server.com')])]],
[
'@marcos.defendi:matrix.org',
[paragraph([mentionUser('marcos.defendi:matrix.org')])],
],
['@username@example.com', [paragraph([mentionUser('username@example.com')])]],
[
'@099fnd2ee@example.com',
[paragraph([mentionUser('099fnd2ee@example.com')])],
],
['@téstãçâò', [paragraph([mentionUser('téstãçâò')])]],
['@สมชาย', [paragraph([mentionUser('สมชาย')])]],
['@李祖阳', [paragraph([mentionUser('李祖阳')])]],
['@あおい', [paragraph([mentionUser('あおい')])]],
['@アオイ', [paragraph([mentionUser('アオイ')])]],
['@Владимир', [paragraph([mentionUser('Владимир')])]],
['@Кириллица', [paragraph([mentionUser('Кириллица')])]],
[
'test @Кириллица test',
[paragraph([plain('test '), mentionUser('Кириллица'), plain(' test')])],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,25 @@
import { parse } from '../src';
import { bold, plain, orderedList, listItem } from '../src/utils';
test.each([
[
`
7. First item
2. Second item
8. Third item
4. *Fourth item*
15. *Fifteenth item*
`.trim(),
[
orderedList([
listItem([plain('First item')], 7),
listItem([plain('Second item')], 2),
listItem([plain('Third item')], 8),
listItem([bold([plain('Fourth item')])], 4),
listItem([bold([plain('Fifteenth item')])], 15),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,63 @@
import { parse } from '../src';
import { link, paragraph, plain, bold } from '../src/utils';
test.each([
[
'+07563546725',
[paragraph([link('tel:07563546725', [plain('+07563546725')])])],
],
[
'+075-63546725',
[paragraph([link('tel:07563546725', [plain('+075-63546725')])])],
],
[
'+(075)-63546725',
[paragraph([link('tel:07563546725', [plain('+(075)-63546725')])])],
],
[
'+(075)63546725',
[paragraph([link('tel:07563546725', [plain('+(075)63546725')])])],
],
[
'[here](+(075)63546725)',
[paragraph([link('tel:07563546725', [plain('here')])])],
],
[
'[**here**](+(075)63546725)',
[paragraph([link('tel:07563546725', [bold([plain('here')])])])],
],
[
'[**here**](+(075)63546725)',
[paragraph([link('tel:07563546725', [bold([plain('here')])])])],
],
[
'+(11)99999-9999',
[paragraph([link('tel:11999999999', [plain('+(11)99999-9999')])])],
],
[
'5 +51231',
[paragraph([plain('5 '), link('tel:51231', [plain('+51231')])])],
],
[
'5 +51231 5',
[
paragraph([
plain('5 '),
link('tel:51231', [plain('+51231')]),
plain(' 5'),
]),
],
],
['+(12)3-45', [paragraph([link('tel:12345', [plain('+(12)3-45')])])]],
['+1.599123', [paragraph([plain('+1.599123')])]],
['1+1=2', [paragraph([plain('1+1=2')])]],
['1+1=2 text', [paragraph([plain('1+1=2 text')])]],
['+1000,00', [paragraph([plain('+1000,00')])]],
['+ 1199999999', [paragraph([plain('+ 1199999999')])]],
['+1234', [paragraph([plain('+1234')])]],
['+(12)3-4', [paragraph([plain('+(12)3-4')])]],
['+123-4', [paragraph([plain('+123-4')])]],
['5+51231', [paragraph([plain('5+51231')])]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,122 @@
import { parse } from '../src';
import {
emoji,
emojiUnicode,
link,
mentionChannel,
mentionUser,
paragraph,
plain,
strike,
} from '../src/utils';
test.each([
['~:smile:~', [paragraph([strike([emoji('smile')])])]],
[
'~test :smile: test~',
[paragraph([strike([plain('test '), emoji('smile'), plain(' test')])])],
],
['~😀~', [paragraph([strike([emojiUnicode('😀')])])]],
['~test 😀~', [paragraph([strike([plain('test '), emojiUnicode('😀')])])]],
[
'~@guilherme.gazzo~',
[paragraph([strike([mentionUser('guilherme.gazzo')])])],
],
['~#GENERAL~', [paragraph([strike([mentionChannel('GENERAL')])])]],
[
'~test @guilherme.gazzo~',
[paragraph([strike([plain('test '), mentionUser('guilherme.gazzo')])])],
],
[
'~test #GENERAL~',
[paragraph([strike([plain('test '), mentionChannel('GENERAL')])])],
],
[
'~~[A brand new Gist](https://gist.github.com/24dddfa97bef58f46ac2ce0f80c58ba4)~~',
[
paragraph([
strike([
link('https://gist.github.com/24dddfa97bef58f46ac2ce0f80c58ba4', [
plain('A brand new Gist'),
]),
]),
]),
],
],
['~~strike~~', [paragraph([strike([plain('strike')])])]],
[
'pre~~strike~~post',
[paragraph([plain('pre'), strike([plain('strike')]), plain('post')])],
],
[
' pre~~strike~~post ',
[paragraph([plain(' pre'), strike([plain('strike')]), plain('post ')])],
],
['~~', [paragraph([plain('~~')])]],
['~ ~', [paragraph([plain('~ ~')])]],
['~~ ~', [paragraph([plain('~~ ~')])]],
['~~ ~~', [paragraph([plain('~~ ~~')])]],
['~ Hello~', [paragraph([strike([plain(' Hello')])])]],
['~Hello ~', [paragraph([strike([plain('Hello ')])])]],
[
':custom~emoji~case:',
[paragraph([plain(`:custom`), strike([plain('emoji')]), plain(`case:`)])],
],
[
'text~hello~text',
[paragraph([plain(`text`), strike([plain('hello')]), plain(`text`)])],
],
['~hello~text', [paragraph([strike([plain('hello')]), plain(`text`)])]],
['text~hello~', [paragraph([plain(`text`), strike([plain('hello')])])]],
['~Hel lo~', [paragraph([strike([plain('Hel lo')])])]],
['~Hello~', [paragraph([strike([plain('Hello')])])]],
['~~Hello~~', [paragraph([strike([plain('Hello')])])]],
['~~Hello~', [paragraph([plain(`~`), strike([plain('Hello')])])]],
['~Hello~~', [paragraph([strike([plain('Hello')]), plain(`~`)])]],
['~Hello', [paragraph([plain('~Hello')])]],
['Hello~', [paragraph([plain('Hello~')])]],
['He~llo', [paragraph([plain('He~llo')])]],
[
'~~~Hello~~~',
[paragraph([plain(`~`), strike([plain('Hello')]), plain(`~`)])],
],
['~~~Hello~~', [paragraph([plain(`~`), strike([plain('Hello')])])]],
[
'~Hello~ this is dog',
[paragraph([strike([plain('Hello')]), plain(` this is dog`)])],
],
[
'Rocket cat says ~Hello~',
[paragraph([plain(`Rocket cat says `), strike([plain('Hello')])])],
],
[
'He said ~Hello~ to her',
[
paragraph([
plain(`He said `),
strike([plain('Hello')]),
plain(` to her`),
]),
],
],
[
'~~Hello~~ this is dog',
[paragraph([strike([plain('Hello')]), plain(` this is dog`)])],
],
[
'Rocket cat says ~~Hello~~',
[paragraph([plain(`Rocket cat says `), strike([plain('Hello')])])],
],
[
'He said ~~Hello~~ to her',
[
paragraph([
plain(`He said `),
strike([plain('Hello')]),
plain(` to her`),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,156 @@
import { parse } from '../src';
import {
bold,
link,
paragraph,
plain,
italic,
strike,
emoji,
emojiUnicode,
mentionChannel,
mentionUser,
} from '../src/utils';
test.each([
['*:smile:*', [paragraph([bold([emoji('smile')])])]],
[
'*test :smile: test*',
[paragraph([bold([plain('test '), emoji('smile'), plain(' test')])])],
],
['*😀*', [paragraph([bold([emojiUnicode('😀')])])]],
['*test 😀*', [paragraph([bold([plain('test '), emojiUnicode('😀')])])]],
['*@guilherme.gazzo*', [paragraph([bold([mentionUser('guilherme.gazzo')])])]],
['*#GENERAL*', [paragraph([bold([mentionChannel('GENERAL')])])]],
[
'*test @guilherme.gazzo*',
[paragraph([bold([plain('test '), mentionUser('guilherme.gazzo')])])],
],
[
'*test #GENERAL*',
[paragraph([bold([plain('test '), mentionChannel('GENERAL')])])],
],
[
'*[A brand new Gist](https://gist.github.com/24dddfa97bef58f46ac2ce0f80c58ba4)*',
[
paragraph([
bold([
link('https://gist.github.com/24dddfa97bef58f46ac2ce0f80c58ba4', [
plain('A brand new Gist'),
]),
]),
]),
],
],
['**bold**', [paragraph([bold([plain('bold')])])]],
['** bold**', [paragraph([bold([plain(' bold')])])]],
['** bold **', [paragraph([bold([plain(' bold ')])])]],
['** bo ld **', [paragraph([bold([plain(' bo ld ')])])]],
['pre**bold**', [paragraph([plain('pre'), bold([plain('bold')])])]],
['**bold**pos', [paragraph([bold([plain('bold')]), plain('pos')])]],
[
'**bold****bold**',
[paragraph([bold([plain('bold')]), bold([plain('bold')])])],
],
[
'**bold** **bold**',
[paragraph([bold([plain('bold')]), plain(' '), bold([plain('bold')])])],
],
[
'**bold** __italic__',
[paragraph([bold([plain('bold')]), plain(' '), italic([plain('italic')])])],
],
['**__italicbold__**', [paragraph([bold([italic([plain('italicbold')])])])]],
[
'plain **__italicbold__**',
[paragraph([plain('plain '), bold([italic([plain('italicbold')])])])],
],
[
'plain **__~~strikeitalicbold~~__**',
[
paragraph([
plain('plain '),
bold([italic([strike([plain('strikeitalicbold')])])]),
]),
],
],
['**', [paragraph([plain('**')])]],
['* *', [paragraph([plain('* *')])]],
['** *', [paragraph([plain('** *')])]],
['** **', [paragraph([plain('** **')])]],
['** **', [paragraph([plain('** **')])]],
['* Hello*', [paragraph([bold([plain(' Hello')])])]],
['*Hello *', [paragraph([bold([plain('Hello ')])])]],
[
':custom*emoji*case:',
[paragraph([plain(':custom'), bold([plain('emoji')]), plain('case:')])],
],
[
'text*hello*text',
[paragraph([plain('text'), bold([plain('hello')]), plain('text')])],
],
['*hello*text', [paragraph([bold([plain('hello')]), plain('text')])]],
['text*hello*', [paragraph([plain('text'), bold([plain('hello')])])]],
['*Hel lo*', [paragraph([bold([plain('Hel lo')])])]],
['*Hello*', [paragraph([bold([plain('Hello')])])]],
['**Hello*', [paragraph([plain('*'), bold([plain('Hello')])])]],
['*Hello**', [paragraph([bold([plain('Hello')]), plain('*')])]],
['*Hello', [paragraph([plain('*Hello')])]],
['Hello*', [paragraph([plain('Hello*')])]],
['He*llo', [paragraph([plain('He*llo')])]],
[
'***Hello***',
[paragraph([plain('*'), bold([plain('Hello')]), plain('*')])],
],
['***Hello**', [paragraph([plain('*'), bold([plain('Hello')])])]],
[
'*Hello* this is dog',
[paragraph([bold([plain('Hello')]), plain(' this is dog')])],
],
[
'Rocket cat says *Hello*',
[paragraph([plain('Rocket cat says '), bold([plain('Hello')])])],
],
[
'He said *Hello* to her',
[paragraph([plain('He said '), bold([plain('Hello')]), plain(' to her')])],
],
[
'**Hello** this is dog',
[paragraph([bold([plain('Hello')]), plain(' this is dog')])],
],
[
'Rocket cat says **Hello**',
[paragraph([plain('Rocket cat says '), bold([plain('Hello')])])],
],
[
'He said **Hello** to her',
[paragraph([plain('He said '), bold([plain('Hello')]), plain(' to her')])],
],
[
'He was a**nn**oyed',
[paragraph([plain('He was a'), bold([plain('nn')]), plain('oyed')])],
],
[
'There are two o in f*oo*tball',
[
paragraph([
plain('There are two o in f'),
bold([plain('oo')]),
plain('tball'),
]),
],
],
['*(teste*', [paragraph([bold([plain('(teste')])])]],
['*(teste)*', [paragraph([bold([plain('(teste)')])])]],
[
'*__~bolditalicstrike~_*',
[
paragraph([
bold([plain('_'), italic([strike([plain('bolditalicstrike')])])]),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,49 @@
import { parse } from '../src';
import {
plain,
tasks,
task,
mentionUser,
mentionChannel,
link,
bold,
} from '../src/utils';
test.each([
[
`
- [ ] this is an incomplete item
- [x] this is a complete item
- [x] @mentions, #refs, [links](http://localhost), **formatting**
- [x] list syntax required (any unordered or ordered list supported)
`.trim(),
[
tasks([
task([plain('this is an incomplete item')], false),
task([plain('this is a complete item')], true),
task(
[
mentionUser('mentions'),
plain(', '),
mentionChannel('refs'),
plain(', '),
link('http://localhost', [plain('links')]),
plain(', '),
bold([plain('formatting')]),
],
true
),
task(
[
plain(
'list syntax required (any unordered or ordered list supported)'
),
],
true
),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,78 @@
import { parse } from '../src';
import { unorderedList, plain, listItem, bold } from '../src/utils';
test.each([
[
`
- First item
- Second item
- Third item
- *Fourth item*
`.trim(),
[
unorderedList([
listItem([plain('First item')]),
listItem([plain('Second item')]),
listItem([plain('Third item')]),
listItem([bold([plain('Fourth item')])]),
]),
],
],
[
`
* First item
* Second item
* Third item
* *Fourth item*
`.trim(),
[
unorderedList([
listItem([plain('First item')]),
listItem([plain('Second item')]),
listItem([plain('Third item')]),
listItem([bold([plain('Fourth item')])]),
]),
],
],
[
`
- First item
* Second item
* Third item
* *Fourth item*
`.trim(),
[
unorderedList([listItem([plain('First item')])]),
unorderedList([
listItem([plain('Second item')]),
listItem([plain('Third item')]),
listItem([bold([plain('Fourth item')])]),
]),
],
],
// [
// `
// * First item
// * Second item
// * Third item
// * Indented item
// * Indented item
// * Fourth item
// `.trim(),
// [paragraph([])],
// ],
// [
// `
// - First item
// - Second item
// - Third item
// - Indented item
// - Indented item
// - Fourth item
// `.trim(),
// [paragraph([])],
// ],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

View File

@ -0,0 +1,362 @@
import { parse } from '../src';
import { lineBreak, autoLink, paragraph, plain, link } from '../src/utils';
test.each([
[
'https://pt.wikipedia.org/wiki/Condi%C3%A7%C3%A3o_de_corrida#:~:text=Uma%20condi%C3%A7%C3%A3o%20de%20corrida%20%C3%A9,sequ%C3%AAncia%20ou%20sincronia%20doutros%20eventos',
[
paragraph([
autoLink(
'https://pt.wikipedia.org/wiki/Condi%C3%A7%C3%A3o_de_corrida#:~:text=Uma%20condi%C3%A7%C3%A3o%20de%20corrida%20%C3%A9,sequ%C3%AAncia%20ou%20sincronia%20doutros%20eventos'
),
]),
],
],
[
'https://pt.wikipedia.org/',
[paragraph([autoLink('https://pt.wikipedia.org/')])],
],
[
'https://pt.wikipedia.org/with-hyphen',
[paragraph([autoLink('https://pt.wikipedia.org/with-hyphen')])],
],
[
'https://pt.wikipedia.org/with_underscore',
[paragraph([autoLink('https://pt.wikipedia.org/with_underscore')])],
],
[
'https://www.npmjs.com/package/@rocket.chat/message-parser',
[
paragraph([
autoLink('https://www.npmjs.com/package/@rocket.chat/message-parser'),
]),
],
],
['http:/rocket.chat/teste', [paragraph([plain('http:/rocket.chat/teste')])]],
['https:/rocket.chat/', [paragraph([plain('https:/rocket.chat/')])]],
['https://test', [paragraph([plain('https://test')])]],
[
'httpsss://rocket.chat/test',
[paragraph([autoLink('httpsss://rocket.chat/test')])],
],
[
'https://rocket.chat:3000/test',
[paragraph([autoLink('https://rocket.chat:3000/test')])],
],
[
'https://rocket.chat/test?search',
[paragraph([autoLink('https://rocket.chat/test?search')])],
],
[
'https://rocket.chat/test?search=test',
[paragraph([autoLink('https://rocket.chat/test?search=test')])],
],
['https://rocket.chat', [paragraph([autoLink('https://rocket.chat')])]],
['https://localhost', [paragraph([autoLink('https://localhost')])]],
['https://localhost:3000', [paragraph([autoLink('https://localhost:3000')])]],
[
'https://localhost:3000#fragment',
[paragraph([autoLink('https://localhost:3000#fragment')])],
],
[
'https://localhost:3000#',
[paragraph([autoLink('https://localhost:3000#')])],
],
[
'https://localhost:3000?',
[paragraph([autoLink('https://localhost:3000?')])],
],
[
'https://localhost:3000/',
[paragraph([autoLink('https://localhost:3000/')])],
],
[
'ftp://user:pass@localhost:21/etc/hosts',
[paragraph([autoLink('ftp://user:pass@localhost:21/etc/hosts')])],
],
['ssh://test@example.com', [paragraph([autoLink('ssh://test@example.com')])]],
[
'custom://test@example.com',
[paragraph([autoLink('custom://test@example.com')])],
],
['ftp://example.com', [paragraph([autoLink('ftp://example.com')])]],
[
'https://www.thingiverse.com/thing:5451684',
[paragraph([autoLink('https://www.thingiverse.com/thing:5451684')])],
],
['http://📙.la/❤️', [paragraph([autoLink('http://📙.la/❤️')])]],
[
'https://developer.rocket.chat/reference/api/rest-api#production-security-concerns look at this',
[
paragraph([
autoLink(
'https://developer.rocket.chat/reference/api/rest-api#production-security-concerns'
),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat/reference/api/rest-api look at this',
[
paragraph([
autoLink('https://developer.rocket.chat/reference/api/rest-api'),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat/reference/api/rest-api#fragment?query=query look at this',
[
paragraph([
autoLink(
'https://developer.rocket.chat/reference/api/rest-api#fragment?query=query'
),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat look at this',
[
paragraph([
autoLink('https://developer.rocket.chat'),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat?query=query look at this',
[
paragraph([
autoLink('https://developer.rocket.chat?query=query'),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat?query=query\nline break',
[
paragraph([autoLink('https://developer.rocket.chat?query=query')]),
paragraph([plain('line break')]),
],
],
[
'https://developer.rocket.chat?query=query\n\nline break',
[
paragraph([autoLink('https://developer.rocket.chat?query=query')]),
lineBreak(),
paragraph([plain('line break')]),
],
],
[
'https://developer.rocket.chat?query=query_with_underscore look at this',
[
paragraph([
autoLink('https://developer.rocket.chat?query=query_with_underscore'),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat/path_with_underscore look at this',
[
paragraph([
autoLink('https://developer.rocket.chat/path_with_underscore'),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat#fragment_with_underscore look at this',
[
paragraph([
autoLink('https://developer.rocket.chat#fragment_with_underscore'),
plain(' look at this'),
]),
],
],
[
'https://developer.rocket.chat followed by text',
[
paragraph([
autoLink('https://developer.rocket.chat'),
plain(' followed by text'),
]),
],
],
[
'two urls https://developer.rocket.chat , https://rocket.chat',
[
paragraph([
plain('two urls '),
autoLink('https://developer.rocket.chat'),
plain(' , '),
autoLink('https://rocket.chat'),
]),
],
],
[
'https://1developer.rocket.chat',
[paragraph([autoLink('https://1developer.rocket.chat')])],
],
[
'https://en.m.wikipedia.org/wiki/Main_Page',
[paragraph([autoLink('https://en.m.wikipedia.org/wiki/Main_Page')])],
],
['test.1test.com', [paragraph([autoLink('test.1test.com')])]],
[
'http://test.e-xample.com',
[paragraph([autoLink('http://test.e-xample.com')])],
],
['www.n-tv.de', [paragraph([autoLink('www.n-tv.de')])]],
[
'www.n-tv.de/test, test',
[paragraph([autoLink('www.n-tv.de/test'), plain(', test')])],
],
[
'www.n-tv.de/, test',
[paragraph([autoLink('www.n-tv.de/'), plain(', test')])],
],
[
'www.n-tv.de, test',
[paragraph([autoLink('www.n-tv.de'), plain(', test')])],
],
[
'https://www.n-tv.de, test',
[paragraph([autoLink('https://www.n-tv.de'), plain(', test')])],
],
['http://te_st.com', [paragraph([autoLink('http://te_st.com')])]],
['www.te_st.com', [paragraph([autoLink('www.te_st.com')])]],
[
'[google_search](http://google.com)',
[paragraph([link('http://google.com', [plain('google_search')])])],
],
[
'app...https://rocket.chat https://rocket.chat',
[
paragraph([
plain('app...https://rocket.chat '),
autoLink('https://rocket.chat'),
]),
],
],
[
'Hey check it out the best communication platform https://rocket.chat! There is not discussion about it.',
[
paragraph([
plain('Hey check it out the best communication platform '),
autoLink('https://rocket.chat'),
plain('! There is not discussion about it.'),
]),
],
],
[
'This is a normal phrase.This in another phrase.',
[paragraph([plain('This is a normal phrase.This in another phrase.')])],
],
[
'https://github.com/RocketChat/Rocket.Chat/releases/tag/6.0.0-rc.3',
[
paragraph([
autoLink(
'https://github.com/RocketChat/Rocket.Chat/releases/tag/6.0.0-rc.3'
),
]),
],
],
[
'https://www.rocket.chat/(W(601))/Main?ScreenId=GI000027',
[
paragraph([
autoLink('https://www.rocket.chat/(W(601))/Main?ScreenId=GI000027'),
]),
],
],
[
'https://rocketchat.atlassian.net/browse/OC-718?filter=10078&jql=%22Defect%20from%5BVersion%20Picker%20(multiple%20versions)%5D%22%20%3D%206.0.0%20AND%20%22Defect%20from%5BVersion%20Picker%20(multiple%20versions)%5D%22%20%3D%206.0.0%20AND%20created%20%3E%3D%20-48h%20ORDER%20BY%20cf%5B10070%5D%20ASC%2C%20status%20ASC%2C%20created%20DESC',
[
paragraph([
link(
'https://rocketchat.atlassian.net/browse/OC-718?filter=10078&jql=%22Defect%20from%5BVersion%20Picker%20(multiple%20versions)%5D%22%20%3D%206.0.0%20AND%20%22Defect%20from%5BVersion%20Picker%20(multiple%20versions)%5D%22%20%3D%206.0.0%20AND%20created%20%3E%3D%20-48h%20ORDER%20BY%20cf%5B10070%5D%20ASC%2C%20status%20ASC%2C%20created%20DESC'
),
]),
],
],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});
describe('autoLink with custom hosts settings comming from Rocket.Chat', () => {
test.each([
[
'http://gitlab.local',
[paragraph([autoLink('http://gitlab.local', ['local'])])],
],
['gitlab.local', [paragraph([autoLink('gitlab.local', ['local'])])]],
[
'internaltool.intranet',
[paragraph([autoLink('internaltool.intranet', ['local', 'intranet'])])],
],
])('parses %p', (input, output) => {
expect(
parse(input, { customDomains: ['local', 'intranet'] })
).toMatchObject(output);
});
});
describe('autoLink WITHOUT custom hosts settings comming from Rocket.Chat', () => {
test.each([
[
'https://internaltool.testt',
[paragraph([plain('https://internaltool.testt')])],
],
])('parses %p', (input, output) => {
expect(parse(input, { customDomains: ['local'] })).toMatchObject(output);
});
});
describe('autoLink helper function', () => {
it('should preserve the original protocol if the protocol is http or https', () => {
expect(autoLink('https://rocket.chat/test')).toMatchObject(
link('https://rocket.chat/test')
);
expect(autoLink('http://rocket.chat/test')).toMatchObject(
link('http://rocket.chat/test')
);
});
it('should preserve the original protocol even if for custom protocols', () => {
expect(autoLink('custom://rocket.chat/test')).toMatchObject(
link('custom://rocket.chat/test')
);
});
it('should return // as the protocol if // is the protocol specified', () => {
expect(autoLink('//rocket.chat/test')).toMatchObject(
link('//rocket.chat/test')
);
});
it("should return an url concatenated '//' if the url has no protocol", () => {
expect(autoLink('rocket.chat/test')).toMatchObject(
link('//rocket.chat/test', [plain('rocket.chat/test')])
);
});
it("should return an url concatenated '//' if the url has no protocol and has sub-domain", () => {
expect(autoLink('spark-public.s3.amazonaws.com')).toMatchObject(
link('//spark-public.s3.amazonaws.com', [
plain('spark-public.s3.amazonaws.com'),
])
);
});
it("should return an plain text url due to invalid TLD that's validate with the external library TLDTS", () => {
expect(autoLink('rocket.chattt/url_path')).toMatchObject(
plain('rocket.chattt/url_path')
);
});
});

View File

@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "./src"
},
"include": ["./src"]
}

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"rootDir": ".",
"target": "es5",
"module": "ESNext",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"noImplicitThis": true,
"alwaysStrict": true
}
}

View File

@ -0,0 +1,4 @@
{
"entryPoints": ["src/index.ts"],
"out": "../../static/message-parser"
}

View File

@ -0,0 +1,86 @@
const path = require('path');
const config = (outputDeclarations = false) => ({
entry: './src/index.ts',
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'ts-loader',
options: {
configFile: path.resolve(__dirname, './tsconfig-bundle.json'),
...(!outputDeclarations && {
compilerOptions: {
declaration: false,
declarationMap: undefined,
},
}),
},
},
include: [path.resolve(__dirname, './src')],
exclude: [path.resolve(__dirname, './tests')],
},
{
test: /\.pegjs$/,
use: ['babel-loader', '@rocket.chat/peggy-loader'],
},
],
},
resolve: {
extensions: ['.ts', '.js', '.pegjs'],
},
});
module.exports = [
{
...config(),
mode: 'development',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'messageParser.development.js',
library: {
type: 'commonjs2',
},
},
},
{
...config(),
mode: 'production',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'messageParser.production.js',
library: {
type: 'commonjs2',
},
},
},
{
...config(),
mode: 'production',
experiments: {
outputModule: true,
},
output: {
path: path.resolve(__dirname, './dist'),
filename: 'messageParser.mjs',
library: {
type: 'module',
},
},
},
{
...config(true),
mode: 'production',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'messageParser.umd.js',
library: {
type: 'umd',
name: 'RocketChatMessageParser',
umdNamedDefine: true,
},
globalObject: 'this',
},
},
];

View File

@ -0,0 +1,2 @@
/node_modules
/dist

View File

@ -0,0 +1,8 @@
{
"extends": ["@rocket.chat/eslint-config"],
"plugins": ["jest"],
"env": {
"jest/globals": true
},
"ignorePatterns": ["**/dist"]
}

1
packages/peggy-loader/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/dist

View File

@ -0,0 +1,2 @@
/node_modules
/dist

View File

@ -0,0 +1 @@
module.exports = require('@rocket.chat/prettier-config/fuselage');

View File

@ -0,0 +1,43 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [0.31.0](https://github.com/RocketChat/fuselage/compare/v0.30.1...v0.31.0) (2021-12-28)
### Features
- New hooks for element size tracking ([#413](https://github.com/RocketChat/fuselage/issues/413)) ([8ca682c](https://github.com/RocketChat/fuselage/commit/8ca682c636d2e4813f7d346cb881513382be63cf))
# [0.30.0](https://github.com/RocketChat/fuselage/compare/v0.29.0...v0.30.0) (2021-10-06)
### Bug Fixes
- **jest:** Adjust jest and ts-jest dependencies ([#547](https://github.com/RocketChat/fuselage/issues/547)) ([91a4fa1](https://github.com/RocketChat/fuselage/commit/91a4fa1365394001afe1bd46480bda3bafed5505))
# [0.29.0](https://github.com/RocketChat/fuselage/compare/v0.28.0...v0.29.0) (2021-08-31)
**Note:** Version bump only for package @rocket.chat/peggy-loader
# [0.28.0](https://github.com/RocketChat/fuselage/compare/v0.27.0...v0.28.0) (2021-07-30)
### Features
- **onboarding-ui:** Administrator information form and Organization information form ([#489](https://github.com/RocketChat/fuselage/issues/489)) ([b289f68](https://github.com/RocketChat/fuselage/commit/b289f68676954b91c792d8d97680314178bf2c60))
- styled API; monorepo grooming ([#482](https://github.com/RocketChat/fuselage/issues/482)) ([1b6b70c](https://github.com/RocketChat/fuselage/commit/1b6b70cf67ec16927b1566adc2350295a8927223))
# [0.27.0](https://github.com/RocketChat/fuselage/compare/v0.26.0...v0.27.0) (2021-06-28)
**Note:** Version bump only for package @rocket.chat/peggy-loader
# [0.26.0](https://github.com/RocketChat/fuselage/compare/v0.25.0...v0.26.0) (2021-05-28)
### Bug Fixes
- Peggy loader options ([#459](https://github.com/RocketChat/fuselage/issues/459)) ([fc91054](https://github.com/RocketChat/fuselage/commit/fc91054abeb340718596b0c8f4ce8e14c87574af))
# [0.25.0](https://github.com/RocketChat/fuselage/compare/v0.24.0...v0.25.0) (2021-05-19)
### Features
- Peggy loader ([#450](https://github.com/RocketChat/fuselage/issues/450)) ([0496cad](https://github.com/RocketChat/fuselage/commit/0496cad457d76f8a4d6a217209e4a55e315e8365))

View File

@ -0,0 +1,89 @@
<!--header-->
<p align="center">
<a href="https://rocket.chat" title="Rocket.Chat">
<img src="https://github.com/RocketChat/Rocket.Chat.Artwork/raw/master/Logos/2020/png/logo-horizontal-red.png" alt="Rocket.Chat" />
</a>
</p>
# `@rocket.chat/peggy-loader`
> Peggy loader for webpack
---
[![npm@latest](https://img.shields.io/npm/v/@rocket.chat/peggy-loader/latest?style=flat-square)](https://www.npmjs.com/package/@rocket.chat/peggy-loader/v/latest) [![npm@next](https://img.shields.io/npm/v/@rocket.chat/peggy-loader/next?style=flat-square)](https://www.npmjs.com/package/@rocket.chat/peggy-loader/v/next) ![npm downloads](https://img.shields.io/npm/dw/@rocket.chat/peggy-loader?style=flat-square) ![License: MIT](https://img.shields.io/npm/l/@rocket.chat/peggy-loader?style=flat-square)
![deps](https://img.shields.io/librariesio/release/npm/@rocket.chat/peggy-loader?style=flat-square) ![npm bundle size](https://img.shields.io/bundlephobia/min/@rocket.chat/peggy-loader?style=flat-square)
<!--/header-->
## Install
<!--install-->
Firstly, install the peer dependencies (prerequisites):
```sh
npm i peggy webpack
# or, if you are using yarn:
yarn add peggy webpack
```
Add `@rocket.chat/peggy-loader` as a dependency:
```sh
npm i @rocket.chat/peggy-loader
# or, if you are using yarn:
yarn add @rocket.chat/peggy-loader
```
<!--/install-->
## Contributing
<!--contributing(msg)-->
Contributions, issues, and feature requests are welcome!<br />
Feel free to check the [issues](https://github.com/RocketChat/fuselage/issues).
<!--/contributing(msg)-->
### Building
As this package dependends on others in this monorepo, before anything run the following at the root directory:
<!--yarn(build)-->
```sh
yarn build
```
<!--/yarn(build)-->
### Linting
To ensure the source is matching our coding style, we perform [linting](<https://en.wikipedia.org/wiki/Lint_(software)>).
Before commiting, check if your code fits our style by running:
<!--yarn(lint)-->
```sh
yarn lint
```
<!--/yarn(lint)-->
Some linter warnings and errors can be automatically fixed:
<!--yarn(lint-and-fix)-->
```sh
yarn lint-and-fix
```
<!--/yarn(lint-and-fix)-->

View File

@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
errorOnDeprecated: true,
testMatch: ['<rootDir>/src/**/*.spec.[jt]s?(x)'],
};

View File

@ -0,0 +1,57 @@
{
"name": "@rocket.chat/peggy-loader",
"version": "0.31.25",
"description": "Peggy loader for webpack",
"keywords": [
"peggy",
"loader",
"webpack"
],
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
},
"homepage": "https://github.com/RocketChat/fuselage#readme",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/RocketChat/fuselage.git",
"directory": "packages/peggy-loader"
},
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/esm/index.d.ts",
"files": [
"/dist"
],
"scripts": {
"build": "run-s .:build:clean .:build:esm .:build:cjs",
".:build:clean": "rimraf dist",
".:build:esm": "tsc -p tsconfig.json",
".:build:cjs": "tsc -p tsconfig-cjs.json",
"lint": "eslint src"
},
"bugs": {
"url": "https://github.com/RocketChat/fuselage/issues"
},
"peerDependencies": {
"peggy": "*",
"webpack": "*"
},
"devDependencies": {
"@rocket.chat/eslint-config": "workspace:~",
"@rocket.chat/prettier-config": "~0.31.25",
"@types/node": "~14.18.42",
"eslint": "~8.45.0",
"npm-run-all": "^4.1.5",
"peggy": "3.0.2",
"prettier": "~2.8.7",
"rimraf": "^3.0.2",
"ts-jest": "~29.1.0",
"typescript": "~5.0.4",
"webpack": "~5.78.0"
}
}

View File

@ -0,0 +1,39 @@
import type {
BuildOptionsBase,
OutputFormatAmdCommonjsEs,
OutputFormatBare,
OutputFormatGlobals,
OutputFormatUmd,
SourceOptionsBase,
} from 'peggy';
import peggy from 'peggy';
import type { LoaderContext } from 'webpack';
type Options =
| BuildOptionsBase &
(
| Omit<
OutputFormatAmdCommonjsEs<'source'>,
keyof SourceOptionsBase<'source'>
>
| Omit<OutputFormatUmd<'source'>, keyof SourceOptionsBase<'source'>>
| Omit<OutputFormatGlobals<'source'>, keyof SourceOptionsBase<'source'>>
| Omit<OutputFormatBare<'source'>, keyof SourceOptionsBase<'source'>>
);
function peggyLoader(
this: LoaderContext<Options>,
grammarContent: string
): string {
const options: Options = {
format: 'commonjs',
...this.getOptions(),
};
return peggy.generate(grammarContent, {
output: 'source',
...options,
});
}
export default peggyLoader;

View File

@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "./dist/cjs"
}
}

View File

@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es5",
"module": "ESNext",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist/esm",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true
}
}

View File

@ -27,7 +27,7 @@
"dependencies": {
"@rocket.chat/apps-engine": "1.41.0",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/message-parser": "~0.31.28",
"@rocket.chat/message-parser": "workspace:^",
"@rocket.chat/ui-kit": "workspace:~",
"ajv": "^8.11.0",
"ajv-formats": "^2.1.1"

View File

@ -7,11 +7,11 @@ export default defineConfig(() => ({
esbuild: {},
plugins: [react()],
optimizeDeps: {
include: ['@rocket.chat/ui-contexts'],
include: ['@rocket.chat/ui-contexts', '@rocket.chat/message-parser'],
},
build: {
commonjsOptions: {
include: [/ui-contexts/, /node_modules/],
include: [/ui-contexts/, /message-parser/, /node_modules/],
},
},
}));

1483
yarn.lock

File diff suppressed because it is too large Load Diff