mirror of
https://github.com/Shadowfita/docmost.git
synced 2025-11-12 07:42:34 +10:00
feat: support pasting markdown (#606)
This commit is contained in:
@ -58,7 +58,6 @@
|
||||
"happy-dom": "^15.11.6",
|
||||
"kysely": "^0.27.4",
|
||||
"kysely-migration-cli": "^0.4.2",
|
||||
"marked": "^13.0.3",
|
||||
"mime-types": "^2.1.35",
|
||||
"nanoid": "^5.0.9",
|
||||
"nestjs-kysely": "^1.0.0",
|
||||
|
||||
@ -11,9 +11,9 @@ import { InjectKysely } from 'nestjs-kysely';
|
||||
import { KyselyDB } from '@docmost/db/types/kysely.types';
|
||||
import { generateSlugId } from '../../common/helpers';
|
||||
import { generateJitteredKeyBetween } from 'fractional-indexing-jittered';
|
||||
import { markdownToHtml } from './utils/marked.utils';
|
||||
import { TiptapTransformer } from '@hocuspocus/transformer';
|
||||
import * as Y from 'yjs';
|
||||
import { markdownToHtml } from "@docmost/editor-ext";
|
||||
|
||||
@Injectable()
|
||||
export class ImportService {
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
import { Token, marked } from 'marked';
|
||||
|
||||
interface CalloutToken {
|
||||
type: 'callout';
|
||||
calloutType: string;
|
||||
text: string;
|
||||
raw: string;
|
||||
}
|
||||
|
||||
export const calloutExtension = {
|
||||
name: 'callout',
|
||||
level: 'block',
|
||||
start(src: string) {
|
||||
return src.match(/:::/)?.index ?? -1;
|
||||
},
|
||||
tokenizer(src: string): CalloutToken | undefined {
|
||||
const rule = /^:::([a-zA-Z0-9]+)\s+([\s\S]+?):::/;
|
||||
const match = rule.exec(src);
|
||||
|
||||
const validCalloutTypes = ['info', 'success', 'warning', 'danger'];
|
||||
|
||||
if (match) {
|
||||
let type = match[1];
|
||||
if (!validCalloutTypes.includes(type)) {
|
||||
type = 'info';
|
||||
}
|
||||
return {
|
||||
type: 'callout',
|
||||
calloutType: type,
|
||||
raw: match[0],
|
||||
text: match[2].trim(),
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer(token: Token) {
|
||||
const calloutToken = token as CalloutToken;
|
||||
const body = marked.parse(calloutToken.text);
|
||||
|
||||
return `<div data-type="callout" data-callout-type="${calloutToken.calloutType}">${body}</div>`;
|
||||
},
|
||||
};
|
||||
@ -1,41 +0,0 @@
|
||||
import { marked } from 'marked';
|
||||
import { calloutExtension } from './callout.marked';
|
||||
import { mathBlockExtension } from './math-block.marked';
|
||||
import { mathInlineExtension } from "./math-inline.marked";
|
||||
|
||||
marked.use({
|
||||
renderer: {
|
||||
// @ts-ignore
|
||||
list(body: string, isOrdered: boolean, start: number) {
|
||||
if (isOrdered) {
|
||||
const startAttr = start !== 1 ? ` start="${start}"` : '';
|
||||
return `<ol ${startAttr}>\n${body}</ol>\n`;
|
||||
}
|
||||
|
||||
const dataType = body.includes(`<input`) ? ' data-type="taskList"' : '';
|
||||
return `<ul${dataType}>\n${body}</ul>\n`;
|
||||
},
|
||||
// @ts-ignore
|
||||
listitem({ text, raw, task: isTask, checked: isChecked }): string {
|
||||
if (!isTask) {
|
||||
return `<li>${text}</li>\n`;
|
||||
}
|
||||
const checkedAttr = isChecked
|
||||
? 'data-checked="true"'
|
||||
: 'data-checked="false"';
|
||||
return `<li data-type="taskItem" ${checkedAttr}>${text}</li>\n`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
marked.use({ extensions: [calloutExtension, mathBlockExtension, mathInlineExtension] });
|
||||
|
||||
export async function markdownToHtml(markdownInput: string): Promise<string> {
|
||||
const YAML_FONT_MATTER_REGEX = /^\s*---[\s\S]*?---\s*/;
|
||||
|
||||
const markdown = markdownInput
|
||||
.replace(YAML_FONT_MATTER_REGEX, '')
|
||||
.trimStart();
|
||||
|
||||
return marked.parse(markdown);
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
import { Token, marked } from 'marked';
|
||||
|
||||
interface MathBlockToken {
|
||||
type: 'mathBlock';
|
||||
text: string;
|
||||
raw: string;
|
||||
}
|
||||
|
||||
export const mathBlockExtension = {
|
||||
name: 'mathBlock',
|
||||
level: 'block',
|
||||
start(src: string) {
|
||||
return src.match(/\$\$/)?.index ?? -1;
|
||||
},
|
||||
tokenizer(src: string): MathBlockToken | undefined {
|
||||
const rule = /^\$\$(?!(\$))([\s\S]+?)\$\$/;
|
||||
const match = rule.exec(src);
|
||||
|
||||
if (match) {
|
||||
return {
|
||||
type: 'mathBlock',
|
||||
raw: match[0],
|
||||
text: match[2]?.trim(),
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer(token: Token) {
|
||||
const mathBlockToken = token as MathBlockToken;
|
||||
// parse to prevent escaping slashes
|
||||
const latex = marked
|
||||
.parse(mathBlockToken.text)
|
||||
.toString()
|
||||
.replace(/<(\/)?p>/g, '');
|
||||
|
||||
return `<div data-type="${mathBlockToken.type}" data-katex="true">${latex}</div>`;
|
||||
},
|
||||
};
|
||||
@ -1,55 +0,0 @@
|
||||
import { Token, marked } from 'marked';
|
||||
|
||||
interface MathInlineToken {
|
||||
type: 'mathInline';
|
||||
text: string;
|
||||
raw: string;
|
||||
}
|
||||
|
||||
const inlineMathRegex = /^\$(?!\s)(.+?)(?<!\s)\$(?!\d)/;
|
||||
|
||||
export const mathInlineExtension = {
|
||||
name: 'mathInline',
|
||||
level: 'inline',
|
||||
start(src: string) {
|
||||
let index: number;
|
||||
let indexSrc = src;
|
||||
|
||||
while (indexSrc) {
|
||||
index = indexSrc.indexOf('$');
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
const f = index === 0 || indexSrc.charAt(index - 1) === ' ';
|
||||
if (f) {
|
||||
const possibleKatex = indexSrc.substring(index);
|
||||
if (possibleKatex.match(inlineMathRegex)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
indexSrc = indexSrc.substring(index + 1).replace(/^\$+/, '');
|
||||
}
|
||||
},
|
||||
tokenizer(src: string): MathInlineToken | undefined {
|
||||
const match = inlineMathRegex.exec(src);
|
||||
|
||||
if (match) {
|
||||
return {
|
||||
type: 'mathInline',
|
||||
raw: match[0],
|
||||
text: match[1]?.trim(),
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer(token: Token) {
|
||||
const mathInlineToken = token as MathInlineToken;
|
||||
// parse to prevent escaping slashes
|
||||
const latex = marked
|
||||
.parse(mathInlineToken.text)
|
||||
.toString()
|
||||
.replace(/<(\/)?p>/g, '');
|
||||
|
||||
return `<span data-type="${mathInlineToken.type}" data-katex="true">${latex}</span>`;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user