Skip to content

Commit

Permalink
Chore: migrate katex to ts (#25501)
Browse files Browse the repository at this point in the history
  • Loading branch information
KevLehman committed Jun 4, 2022
1 parent 55cfc84 commit 81304fe
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,52 +1,71 @@
import { Random } from 'meteor/random';
import katex from 'katex';
import KatexPackage from 'katex';
import { unescapeHTML, escapeHTML } from '@rocket.chat/string-helpers';

import 'katex/dist/katex.min.css';
import './style.css';
import { IMessage } from '@rocket.chat/core-typings';

class Boundary {
length() {
start: number;

end: number;

length(): number {
return this.end - this.start;
}

extract(str) {
extract(str: string): string {
return str.substr(this.start, this.length());
}
}

type Delimiter = {
opener: string;
closer: string;
displayMode: boolean;
enabled: () => boolean;
};

type OpeningDelimiter = { options: Delimiter; pos: number };

type LatexBoundary = { outer: Boundary; inner: Boundary };

class Katex {
constructor(katex, { dollarSyntax, parenthesisSyntax }) {
katex: KatexPackage;

delimitersMap: Delimiter[];

constructor(katex: KatexPackage, { dollarSyntax, parenthesisSyntax }: { dollarSyntax: boolean; parenthesisSyntax: boolean }) {
this.katex = katex;
this.delimitersMap = [
{
opener: '\\[',
closer: '\\]',
displayMode: true,
enabled: () => parenthesisSyntax,
enabled: (): boolean => parenthesisSyntax,
},
{
opener: '\\(',
closer: '\\)',
displayMode: false,
enabled: () => parenthesisSyntax,
enabled: (): boolean => parenthesisSyntax,
},
{
opener: '$$',
closer: '$$',
displayMode: true,
enabled: () => dollarSyntax,
enabled: (): boolean => dollarSyntax,
},
{
opener: '$',
closer: '$',
displayMode: false,
enabled: () => dollarSyntax,
enabled: (): boolean => dollarSyntax,
},
];
}

findOpeningDelimiter(str, start) {
findOpeningDelimiter(str: string, start: number): OpeningDelimiter | null {
const matches = this.delimitersMap
.filter((options) => options.enabled())
.map((options) => ({
Expand All @@ -70,7 +89,7 @@ class Katex {
return match;
}

getLatexBoundaries(str, { options: { closer }, pos }) {
getLatexBoundaries(str: string, { options: { closer }, pos }: OpeningDelimiter): LatexBoundary | null {
const closerIndex = str.substr(pos + closer.length).indexOf(closer);
if (closerIndex < 0) {
return null;
Expand All @@ -92,15 +111,17 @@ class Katex {
}

// Searches for the first latex block in the given string
findLatex(str) {
findLatex(str: string): (LatexBoundary & { options: Delimiter }) | null {
let start = 0;
let openingDelimiterMatch;

while ((openingDelimiterMatch = this.findOpeningDelimiter(str, start++)) != null) {
const match = this.getLatexBoundaries(str, openingDelimiterMatch);
if (match && match.inner.extract(str).trim().length) {
match.options = openingDelimiterMatch.options;
return match;
if (match?.inner.extract(str).trim().length) {
return {
...match,
options: openingDelimiterMatch.options,
};
}
}

Expand All @@ -109,7 +130,7 @@ class Katex {

// Breaks a message to what comes before, after and to the content of a
// matched latex block
extractLatex(str, match) {
extractLatex(str: string, match: LatexBoundary): { before: string; latex: string; after: string } {
const before = str.substr(0, match.outer.start);
const after = str.substr(match.outer.end);
let latex = match.inner.extract(str);
Expand All @@ -123,9 +144,9 @@ class Katex {

// Takes a latex math string and the desired display mode and renders it
// to HTML using the KaTeX library
renderLatex = (latex, displayMode) => {
renderLatex = (latex: string, displayMode: Delimiter['displayMode']): string => {
try {
return this.katex.renderToString(latex, {
return KatexPackage.renderToString(latex, {
displayMode,
macros: {
'\\href': '\\@secondoftwo',
Expand All @@ -137,11 +158,15 @@ class Katex {
};

// Takes a string and renders all latex blocks inside it
render(str, renderFunction) {
render(str: string, renderFunction: (latex: string, displayMode: Delimiter['displayMode']) => string): string {
let result = '';
while (this.findLatex(str) != null) {
// Find the first latex block in the string
const match = this.findLatex(str);
if (!match) {
continue;
}

const parts = this.extractLatex(str, match);

// Add to the reuslt what comes before the latex block as well as
Expand All @@ -155,7 +180,11 @@ class Katex {
return result;
}

renderMessage = (message) => {
public renderMessage(message: string): string;

public renderMessage(message: IMessage): IMessage;

public renderMessage(message: string | IMessage): string | IMessage {
if (typeof message === 'string') {
return this.render(message, this.renderLatex);
}
Expand All @@ -170,22 +199,48 @@ class Katex {

message.html = this.render(message.html, (latex, displayMode) => {
const token = `=!=${Random.id()}=!=`;
message.tokens.push({
message.tokens?.push({
token,
text: this.renderLatex(latex, displayMode),
});
return token;
});

return message;
};
}
}

export const createKatexMessageRendering = (options) => {
const instance = new Katex(katex, options);
return (message) => instance.renderMessage(message);
};
export function createKatexMessageRendering(
options: {
dollarSyntax: boolean;
parenthesisSyntax: boolean;
},
_isMessage: true,
): (message: IMessage) => IMessage;
export function createKatexMessageRendering(
options: {
dollarSyntax: boolean;
parenthesisSyntax: boolean;
},
_isMessage: false,
): (message: string) => string;
export function createKatexMessageRendering(
options: {
dollarSyntax: boolean;
parenthesisSyntax: boolean;
},
_isMessage: true | false,
): ((message: string) => string) | ((message: IMessage) => IMessage) {
const instance = new Katex(KatexPackage, options);
if (_isMessage) {
return (message: IMessage): IMessage => instance.renderMessage(message);
}
return (message: string): string => instance.renderMessage(message);
}

export const getKatexHtml = (text, katex) => {
return createKatexMessageRendering({ dollarSyntax: katex.dollarSyntaxEnabled, parenthesisSyntax: katex.parenthesisSyntaxEnabled })(text);
export const getKatexHtml = (text: string, katex: { dollarSyntaxEnabled: boolean; parenthesisSyntaxEnabled: boolean }): string => {
return createKatexMessageRendering(
{ dollarSyntax: katex.dollarSyntaxEnabled, parenthesisSyntax: katex.parenthesisSyntaxEnabled },
false,
)(text);
};
File renamed without changes.
2 changes: 1 addition & 1 deletion apps/meteor/client/components/Katex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type KatexProps = {
};

const Katex = ({ text, options }: KatexProps): ReactElement => (
<span dangerouslySetInnerHTML={{ __html: createKatexMessageRendering(options)(text) }} />
<span dangerouslySetInnerHTML={{ __html: createKatexMessageRendering(options, false)(text) }} />
);

export default memo(Katex);
2 changes: 1 addition & 1 deletion apps/meteor/client/startup/renderMessage/katex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Meteor.startup(() => {
};

import('../../../app/katex/client').then(({ createKatexMessageRendering }) => {
const renderMessage = createKatexMessageRendering(options);
const renderMessage = createKatexMessageRendering(options, true);
callbacks.remove('renderMessage', 'katex');
callbacks.add('renderMessage', renderMessage, callbacks.priority.HIGH + 1, 'katex');
});
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@
"@slack/client": "^4.12.0",
"@slack/rtm-api": "^6.0.0",
"@types/cookie": "^0.5.1",
"@types/katex": "^0.14.0",
"@types/lodash": "^4.14.182",
"@types/lodash.debounce": "^4.0.6",
"@types/object-path": "^0.11.1",
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4799,6 +4799,7 @@ __metadata:
"@types/jsdom": ^16.2.12
"@types/jsdom-global": ^3.0.2
"@types/jsrsasign": ^9.0.3
"@types/katex": ^0.14.0
"@types/ldapjs": ^2.2.1
"@types/less": ^3.0.2
"@types/lodash": ^4.14.182
Expand Down Expand Up @@ -7277,6 +7278,13 @@ __metadata:
languageName: node
linkType: hard

"@types/katex@npm:^0.14.0":
version: 0.14.0
resolution: "@types/katex@npm:0.14.0"
checksum: 330e0d0337ba48c87f5b793965fbad673653789bf6e50dfe8d726a7b0cbefd37195055e31503aae629814aa79447e4f23a4b87ad1ac565c0d9a9d9978836f39b
languageName: node
linkType: hard

"@types/keyv@npm:^3.1.1":
version: 3.1.4
resolution: "@types/keyv@npm:3.1.4"
Expand Down

0 comments on commit 81304fe

Please sign in to comment.