feat: link in shortcode (#707)
This commit is contained in:
parent
6be11c749e
commit
0fae2ce73d
@ -51,8 +51,8 @@
|
||||
"@babel/runtime": "7.21.0",
|
||||
"@codemirror/autocomplete": "6.4.2",
|
||||
"@codemirror/commands": "6.2.2",
|
||||
"@codemirror/language": "6.6.0",
|
||||
"@codemirror/language-data": "6.2.0",
|
||||
"@codemirror/language": "6.6.0",
|
||||
"@codemirror/legacy-modes": "6.3.2",
|
||||
"@codemirror/lint": "6.2.0",
|
||||
"@codemirror/search": "6.3.0",
|
||||
@ -79,19 +79,19 @@
|
||||
"@styled-icons/fa-brands": "10.47.0",
|
||||
"@styled-icons/fluentui-system-regular": "10.47.0",
|
||||
"@styled-icons/heroicons-outline": "10.47.0",
|
||||
"@styled-icons/material": "10.47.0",
|
||||
"@styled-icons/material-outlined": "10.47.0",
|
||||
"@styled-icons/material-rounded": "10.47.0",
|
||||
"@styled-icons/material": "10.47.0",
|
||||
"@styled-icons/remix-editor": "10.46.0",
|
||||
"@styled-icons/simple-icons": "10.46.0",
|
||||
"@udecode/plate": "20.6.0",
|
||||
"@udecode/plate-juice": "20.4.0",
|
||||
"@udecode/plate-serializer-md": "20.4.1",
|
||||
"@udecode/plate": "20.6.0",
|
||||
"@uiw/codemirror-extensions-langs": "4.19.11",
|
||||
"@uiw/react-codemirror": "4.19.11",
|
||||
"ajv": "8.12.0",
|
||||
"ajv-errors": "3.0.0",
|
||||
"ajv-keywords": "5.1.0",
|
||||
"ajv": "8.12.0",
|
||||
"buffer": "6.0.3",
|
||||
"clean-stack": "5.2.0",
|
||||
"codemirror": "6.0.1",
|
||||
@ -107,8 +107,8 @@
|
||||
"fuzzy": "0.1.3",
|
||||
"globby": "13.1.3",
|
||||
"gotrue-js": "0.9.29",
|
||||
"graphql": "16.6.0",
|
||||
"graphql-tag": "2.12.6",
|
||||
"graphql": "16.6.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"history": "5.3.0",
|
||||
"immer": "9.0.21",
|
||||
@ -119,16 +119,24 @@
|
||||
"jwt-decode": "3.1.2",
|
||||
"localforage": "1.10.0",
|
||||
"lodash": "4.17.21",
|
||||
"mdast-util-gfm-footnote": "1.0.2",
|
||||
"mdast-util-gfm-strikethrough": "1.0.3",
|
||||
"mdast-util-gfm-table": "1.0.7",
|
||||
"mdast-util-gfm-task-list-item": "1.0.2",
|
||||
"micromark-extension-gfm-footnote": "1.1.0",
|
||||
"micromark-extension-gfm-strikethrough": "1.0.5",
|
||||
"micromark-extension-gfm-table": "1.0.5",
|
||||
"micromark-extension-gfm-task-list-item": "1.0.4",
|
||||
"micromark-util-combine-extensions": "1.0.0",
|
||||
"minimatch": "8.0.3",
|
||||
"moment": "2.29.4",
|
||||
"node-polyglot": "2.5.0",
|
||||
"ol": "7.3.0",
|
||||
"path-browserify": "1.0.1",
|
||||
"prop-types": "15.8.1",
|
||||
"react": "18.2.0",
|
||||
"react-color": "2.19.3",
|
||||
"react-dnd": "16.0.1",
|
||||
"react-dnd-html5-backend": "16.0.1",
|
||||
"react-dnd": "16.0.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-frame-component": "5.2.6",
|
||||
"react-is": "18.2.0",
|
||||
@ -140,29 +148,29 @@
|
||||
"react-virtualized-auto-sizer": "1.0.11",
|
||||
"react-waypoint": "10.3.0",
|
||||
"react-window": "1.8.8",
|
||||
"remark-gfm": "3.0.1",
|
||||
"react": "18.2.0",
|
||||
"remark-html": "15.0.2",
|
||||
"remark-mdx": "2.3.0",
|
||||
"remark-parse": "10.0.1",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"scheduler": "0.23.0",
|
||||
"semaphore": "1.1.0",
|
||||
"slate": "0.93.0",
|
||||
"slate-history": "0.93.0",
|
||||
"slate-hyperscript": "0.77.0",
|
||||
"slate-react": "0.93.0",
|
||||
"slate": "0.93.0",
|
||||
"stream-browserify": "3.0.0",
|
||||
"styled-components": "5.3.9",
|
||||
"symbol-observable": "4.0.0",
|
||||
"unified": "10.1.2",
|
||||
"unist-util-visit": "4.1.2",
|
||||
"url": "0.11.0",
|
||||
"url-join": "5.0.0",
|
||||
"url": "0.11.0",
|
||||
"uuid": "9.0.0",
|
||||
"validate-color": "2.2.4",
|
||||
"vfile": "5.3.7",
|
||||
"vfile-message": "3.1.4",
|
||||
"vfile-statistics": "2.0.1",
|
||||
"vfile": "5.3.7",
|
||||
"what-input": "5.2.12",
|
||||
"what-the-diff": "0.6.0",
|
||||
"yaml": "2.2.1"
|
||||
@ -197,13 +205,13 @@
|
||||
"@types/jwt-decode": "2.2.1",
|
||||
"@types/lodash": "4.14.191",
|
||||
"@types/minimatch": "5.1.2",
|
||||
"@types/node": "18.15.11",
|
||||
"@types/node-fetch": "2.6.3",
|
||||
"@types/react": "18.0.33",
|
||||
"@types/node": "18.15.11",
|
||||
"@types/react-color": "3.0.6",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"@types/react-virtualized-auto-sizer": "1.0.1",
|
||||
"@types/react-window": "1.8.5",
|
||||
"@types/react": "18.0.33",
|
||||
"@types/styled-components": "5.1.26",
|
||||
"@types/url-join": "4.0.1",
|
||||
"@types/uuid": "9.0.1",
|
||||
@ -222,25 +230,25 @@
|
||||
"babel-plugin-transform-export-extensions": "6.22.0",
|
||||
"babel-plugin-transform-inline-environment-variables": "0.4.4",
|
||||
"cache-me-outside": "1.0.0",
|
||||
"commonmark": "0.30.0",
|
||||
"commonmark-spec": "0.30.0",
|
||||
"commonmark": "0.30.0",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "6.7.3",
|
||||
"dotenv": "16.0.3",
|
||||
"eslint": "8.37.0",
|
||||
"eslint-import-resolver-typescript": "3.5.4",
|
||||
"eslint-plugin-cypress": "2.13.2",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"eslint-plugin-unicorn": "46.0.0",
|
||||
"eslint": "8.37.0",
|
||||
"execa": "7.1.1",
|
||||
"fs-extra": "11.1.1",
|
||||
"gitlab": "14.2.2",
|
||||
"http-server": "14.1.1",
|
||||
"jest": "29.5.0",
|
||||
"jest-environment-jsdom": "29.5.0",
|
||||
"jest": "29.5.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"mini-css-extract-plugin": "2.7.5",
|
||||
"mockserver-client": "5.15.0",
|
||||
@ -248,8 +256,8 @@
|
||||
"ncp": "2.0.0",
|
||||
"node-fetch": "3.3.1",
|
||||
"npm-run-all": "4.1.5",
|
||||
"postcss": "8.4.21",
|
||||
"postcss-loader": "7.2.4",
|
||||
"postcss": "8.4.21",
|
||||
"prettier": "2.8.7",
|
||||
"process": "0.11.10",
|
||||
"react-refresh": "0.14.0",
|
||||
@ -263,9 +271,9 @@
|
||||
"ts-jest": "29.1.0",
|
||||
"tsconfig-paths-webpack-plugin": "4.0.1",
|
||||
"typescript": "5.0.3",
|
||||
"webpack": "5.77.0",
|
||||
"webpack-cli": "5.0.1",
|
||||
"webpack-dev-server": "4.13.2"
|
||||
"webpack-dev-server": "4.13.2",
|
||||
"webpack": "5.77.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
|
@ -9,7 +9,10 @@ import { markdownToSlate } from '../useMarkdownToSlate';
|
||||
import type { SerializationTestData } from '../../tests-util/serializationTests.util';
|
||||
import type { UseMarkdownToSlateOptions } from '../useMarkdownToSlate';
|
||||
|
||||
jest.unmock('remark-gfm');
|
||||
jest.unmock('mdast-util-gfm-footnote');
|
||||
jest.unmock('mdast-util-gfm-table');
|
||||
jest.unmock('mdast-util-gfm-task-list-item');
|
||||
jest.unmock('micromark-extension-gfm');
|
||||
jest.unmock('remark-mdx');
|
||||
jest.unmock('remark-parse');
|
||||
jest.unmock('unified');
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { ELEMENT_PARAGRAPH } from '@udecode/plate';
|
||||
import { useEffect, useState } from 'react';
|
||||
import gfm from 'remark-gfm';
|
||||
import mdx from 'remark-mdx';
|
||||
import markdown from 'remark-parse';
|
||||
import { unified } from 'unified';
|
||||
|
||||
import { getShortcodes } from '../../../../lib/registry';
|
||||
import gfm from '../serialization/gfm';
|
||||
import toSlatePlugin from '../serialization/slate/toSlatePlugin';
|
||||
|
||||
import type { ShortcodeConfig } from '../../../../interface';
|
||||
|
@ -0,0 +1,61 @@
|
||||
import { gfmFootnoteFromMarkdown, gfmFootnoteToMarkdown } from 'mdast-util-gfm-footnote';
|
||||
import {
|
||||
gfmStrikethroughFromMarkdown,
|
||||
gfmStrikethroughToMarkdown,
|
||||
} from 'mdast-util-gfm-strikethrough';
|
||||
import { gfmTableFromMarkdown, gfmTableToMarkdown } from 'mdast-util-gfm-table';
|
||||
import {
|
||||
gfmTaskListItemFromMarkdown,
|
||||
gfmTaskListItemToMarkdown,
|
||||
} from 'mdast-util-gfm-task-list-item';
|
||||
import { gfmFootnote } from 'micromark-extension-gfm-footnote';
|
||||
import { gfmStrikethrough } from 'micromark-extension-gfm-strikethrough';
|
||||
import { gfmTable } from 'micromark-extension-gfm-table';
|
||||
import { gfmTaskListItem } from 'micromark-extension-gfm-task-list-item';
|
||||
import { combineExtensions } from 'micromark-util-combine-extensions';
|
||||
|
||||
import type { Root } from 'mdast';
|
||||
import type { Plugin, Processor } from 'unified';
|
||||
|
||||
function gfmFromMarkdown() {
|
||||
return [
|
||||
gfmFootnoteFromMarkdown(),
|
||||
gfmStrikethroughFromMarkdown,
|
||||
gfmTableFromMarkdown,
|
||||
gfmTaskListItemFromMarkdown,
|
||||
];
|
||||
}
|
||||
|
||||
function gfmToMarkdown() {
|
||||
return {
|
||||
extensions: [
|
||||
gfmFootnoteToMarkdown(),
|
||||
gfmStrikethroughToMarkdown,
|
||||
gfmTableToMarkdown({}),
|
||||
gfmTaskListItemToMarkdown,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function gfm() {
|
||||
return combineExtensions([gfmFootnote(), gfmStrikethrough({}), gfmTable, gfmTaskListItem]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin to support GFM (footnotes, strikethrough, tables, tasklists).
|
||||
*/
|
||||
const remarkGfm: Plugin<void[], Root> = function (this: Processor) {
|
||||
const data = this.data();
|
||||
|
||||
add('micromarkExtensions', gfm());
|
||||
add('fromMarkdownExtensions', gfmFromMarkdown());
|
||||
add('toMarkdownExtensions', gfmToMarkdown());
|
||||
|
||||
function add(field: string, value: unknown) {
|
||||
const list = (data[field] ? data[field] : (data[field] = [])) as unknown[];
|
||||
|
||||
list.push(value);
|
||||
}
|
||||
};
|
||||
|
||||
export default remarkGfm;
|
@ -0,0 +1,166 @@
|
||||
import { autoLinkToSlate } from '../autoLinkUrls';
|
||||
|
||||
import type { MdastNode } from '../ast-types';
|
||||
|
||||
describe('processShortcodeConfig', () => {
|
||||
describe('autoLinkToSlate', () => {
|
||||
it('converts url to anchor node', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{ type: 'text', value: 'https://www.youtube.com/watch?v=p6h-rYSVX90' },
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'a',
|
||||
url: 'https://www.youtube.com/watch?v=p6h-rYSVX90',
|
||||
children: [{ text: 'https://www.youtube.com/watch?v=p6h-rYSVX90' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(autoLinkToSlate(nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('does not convert url in shortcode node', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['https://www.youtube.com/watch?v=p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{ type: 'text', value: 'https://www.youtube.com/watch?v=p6h-rYSVX90' },
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['https://www.youtube.com/watch?v=p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'a',
|
||||
url: 'https://www.youtube.com/watch?v=p6h-rYSVX90',
|
||||
children: [{ text: 'https://www.youtube.com/watch?v=p6h-rYSVX90' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(autoLinkToSlate(nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts url with text before', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{ type: 'text', value: 'Text before https://www.youtube.com/watch?v=p6h-rYSVX90' },
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'a',
|
||||
url: 'https://www.youtube.com/watch?v=p6h-rYSVX90',
|
||||
children: [{ text: 'https://www.youtube.com/watch?v=p6h-rYSVX90' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(autoLinkToSlate(nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts url with text after', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{ type: 'text', value: 'https://www.youtube.com/watch?v=p6h-rYSVX90 and text after' },
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'a',
|
||||
url: 'https://www.youtube.com/watch?v=p6h-rYSVX90',
|
||||
children: [{ text: 'https://www.youtube.com/watch?v=p6h-rYSVX90' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' and text after',
|
||||
},
|
||||
];
|
||||
|
||||
expect(autoLinkToSlate(nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts url with text before and after', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before https://www.youtube.com/watch?v=p6h-rYSVX90 and text after',
|
||||
},
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'a',
|
||||
url: 'https://www.youtube.com/watch?v=p6h-rYSVX90',
|
||||
children: [{ text: 'https://www.youtube.com/watch?v=p6h-rYSVX90' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' and text after',
|
||||
},
|
||||
];
|
||||
|
||||
expect(autoLinkToSlate(nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts multiple urls', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'Text before https://www.youtube.com/watch?v=p6h-rYSVX90 and https://www.youtube.com/watch?v=p6h-rYSVX90 text after',
|
||||
},
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'a',
|
||||
url: 'https://www.youtube.com/watch?v=p6h-rYSVX90',
|
||||
children: [{ text: 'https://www.youtube.com/watch?v=p6h-rYSVX90' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' and ',
|
||||
},
|
||||
{
|
||||
type: 'a',
|
||||
url: 'https://www.youtube.com/watch?v=p6h-rYSVX90',
|
||||
children: [{ text: 'https://www.youtube.com/watch?v=p6h-rYSVX90' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' text after',
|
||||
},
|
||||
];
|
||||
|
||||
expect(autoLinkToSlate(nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('does not convert plain text', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Some text about something going on somewhere',
|
||||
},
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Some text about something going on somewhere',
|
||||
},
|
||||
];
|
||||
|
||||
expect(autoLinkToSlate(nodes)).toEqual(slate);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,7 +1,265 @@
|
||||
import { processShortcodeConfigToMdx } from '../processShortcodeConfig';
|
||||
import {
|
||||
processShortcodeConfigToMdx,
|
||||
processShortcodeConfigsToSlate,
|
||||
} from '../processShortcodeConfig';
|
||||
import { testShortcodeConfigs } from '../../../tests-util/serializationTests.util';
|
||||
|
||||
import type { MdastNode } from '../ast-types';
|
||||
|
||||
describe('processShortcodeConfig', () => {
|
||||
describe('processShortcodeConfigsToSlate', () => {
|
||||
it('converts shortcode', () => {
|
||||
const nodes: MdastNode[] = [{ type: 'text', value: '[youtube|p6h-rYSVX90]' }];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts shortcode with no args', () => {
|
||||
const nodes: MdastNode[] = [{ type: 'text', value: '[youtube]' }];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: [],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts shortcode with multiple args', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{ type: 'text', value: '[youtube|p6h-rYSVX90|somethingElse|andOneMore]' },
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90', 'somethingElse', 'andOneMore'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts shortcode with text before', () => {
|
||||
const nodes: MdastNode[] = [{ type: 'text', value: 'Text before [youtube|p6h-rYSVX90]' }];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts shortcode with text after', () => {
|
||||
const nodes: MdastNode[] = [{ type: 'text', value: '[youtube|p6h-rYSVX90] and text after' }];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' and text after',
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts shortcode with text before and after', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{ type: 'text', value: 'Text before [youtube|p6h-rYSVX90] and text after' },
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' and text after',
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts multiple shortcodes', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before [youtube|p6h-rYSVX90] and {{< twitter 917359331535966209 >}}',
|
||||
},
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' and ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'twitter',
|
||||
args: ['917359331535966209'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('converts multiple of the same shortcodes', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'Text before [youtube|p6h-rYSVX90], [youtube|p6h-rYSVX90], {{< twitter 917359331535966209 >}} and [youtube|p6h-rYSVX90]',
|
||||
},
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ', ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ', ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'twitter',
|
||||
args: ['917359331535966209'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' and ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('does not convert unrecognized shortcode', () => {
|
||||
const nodes: MdastNode[] = [{ type: 'text', value: '[someOtherShortcode|andstuff]' }];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: '[someOtherShortcode|andstuff]',
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('does not convert unrecognized shortcode surrounded by recognized shortcodes', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'Text before [youtube|p6h-rYSVX90], [someOtherShortcode|andstuff] and {{< twitter 917359331535966209 >}}',
|
||||
},
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Text before ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'youtube',
|
||||
args: ['p6h-rYSVX90'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ', [someOtherShortcode|andstuff] and ',
|
||||
},
|
||||
{
|
||||
type: 'shortcode',
|
||||
shortcode: 'twitter',
|
||||
args: ['917359331535966209'],
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
|
||||
it('does not convert plain text', () => {
|
||||
const nodes: MdastNode[] = [
|
||||
{ type: 'text', value: 'Some text about something going on somewhere' },
|
||||
];
|
||||
const slate: MdastNode[] = [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'Some text about something going on somewhere',
|
||||
},
|
||||
];
|
||||
|
||||
expect(processShortcodeConfigsToSlate(testShortcodeConfigs, nodes)).toEqual(slate);
|
||||
});
|
||||
});
|
||||
|
||||
describe('processShortcodeConfigToMdx', () => {
|
||||
it('converts to mdx', () => {
|
||||
const markdown = '[youtube|p6h-rYSVX90]';
|
||||
@ -25,21 +283,21 @@ describe('processShortcodeConfig', () => {
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('shortcode with text before', () => {
|
||||
it('converts shortcode with text before', () => {
|
||||
const markdown = 'Text before [youtube|p6h-rYSVX90]';
|
||||
const mdx = 'Text before <Shortcode shortcode="youtube" args={[\'p6h-rYSVX90\']} />';
|
||||
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('shortcode with text after', () => {
|
||||
it('converts shortcode with text after', () => {
|
||||
const markdown = '[youtube|p6h-rYSVX90] and text after';
|
||||
const mdx = '<Shortcode shortcode="youtube" args={[\'p6h-rYSVX90\']} /> and text after';
|
||||
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('shortcode with text before and after', () => {
|
||||
it('converts shortcode with text before and after', () => {
|
||||
const markdown = 'Text before [youtube|p6h-rYSVX90] and text after';
|
||||
const mdx =
|
||||
'Text before <Shortcode shortcode="youtube" args={[\'p6h-rYSVX90\']} /> and text after';
|
||||
@ -47,7 +305,7 @@ describe('processShortcodeConfig', () => {
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('multiple shortcodes', () => {
|
||||
it('converts multiple shortcodes', () => {
|
||||
const markdown = 'Text before [youtube|p6h-rYSVX90] and {{< twitter 917359331535966209 >}}';
|
||||
const mdx =
|
||||
'Text before <Shortcode shortcode="youtube" args={[\'p6h-rYSVX90\']} /> and <Shortcode shortcode="twitter" args={[\'917359331535966209\']} />';
|
||||
@ -55,7 +313,7 @@ describe('processShortcodeConfig', () => {
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('multiple of the same shortcodes', () => {
|
||||
it('converts multiple of the same shortcodes', () => {
|
||||
const markdown =
|
||||
'Text before [youtube|p6h-rYSVX90], [youtube|p6h-rYSVX90], {{< twitter 917359331535966209 >}} and [youtube|p6h-rYSVX90]';
|
||||
const mdx =
|
||||
@ -64,14 +322,14 @@ describe('processShortcodeConfig', () => {
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('unrecognized shortcode', () => {
|
||||
it('does not convert unrecognized shortcode', () => {
|
||||
const markdown = '[someOtherShortcode|andstuff]';
|
||||
const mdx = '[someOtherShortcode|andstuff]';
|
||||
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('unrecognized shortcode surrounded by recognized shortcodes', () => {
|
||||
it('does not convert unrecognized shortcode surrounded by recognized shortcodes', () => {
|
||||
const markdown =
|
||||
'Text before [youtube|p6h-rYSVX90], [someOtherShortcode|andstuff] and {{< twitter 917359331535966209 >}}';
|
||||
const mdx =
|
||||
@ -80,7 +338,7 @@ describe('processShortcodeConfig', () => {
|
||||
expect(processShortcodeConfigToMdx(testShortcodeConfigs, markdown)).toBe(mdx);
|
||||
});
|
||||
|
||||
it('plain text', () => {
|
||||
it('does not convert plain text', () => {
|
||||
const markdown = 'Some text about something going on somewhere';
|
||||
const mdx = 'Some text about something going on somewhere';
|
||||
|
||||
|
@ -1,31 +0,0 @@
|
||||
import {
|
||||
deserializationOnlyTestData,
|
||||
runSerializationTests,
|
||||
testShortcodeConfigs as shortcodeConfigs,
|
||||
} from '../../../tests-util/serializationTests.util';
|
||||
import { slateCompiler } from '../toSlatePlugin';
|
||||
|
||||
import type { SerializationTestData } from '../../../tests-util/serializationTests.util';
|
||||
import type { MdastNode } from '../ast-types';
|
||||
|
||||
async function expectNodes(
|
||||
mdast: MdastNode,
|
||||
useMdx: boolean,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
children: any[],
|
||||
) {
|
||||
const compiler = slateCompiler({ useMdx, shortcodeConfigs });
|
||||
|
||||
expect(compiler(mdast)).toEqual(children);
|
||||
}
|
||||
|
||||
function testRunner(key: string, mode: 'markdown' | 'mdx' | 'both', data: SerializationTestData) {
|
||||
it(`deserializes ${key}`, async () => {
|
||||
await expectNodes(data.mdast, mode === 'mdx', data.slate);
|
||||
});
|
||||
}
|
||||
|
||||
describe('markdownToSlate', () => {
|
||||
runSerializationTests(testRunner);
|
||||
runSerializationTests(testRunner, deserializationOnlyTestData);
|
||||
});
|
@ -0,0 +1,45 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
import { isNotEmpty } from '@staticcms/core/lib/util/string.util';
|
||||
import { NodeTypes } from './ast-types';
|
||||
|
||||
import type { BaseMdastNode, MdastNode } from './ast-types';
|
||||
|
||||
export function autoLinkToSlate(nodes: BaseMdastNode[]) {
|
||||
const output: MdastNode[] = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
if (node.type === 'text' && node.value) {
|
||||
const regex =
|
||||
/([\w\W]*?)((?:http(?:s)?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_+.~#?&//=]*))([\w\W]*)/g;
|
||||
let matches: RegExpExecArray | null;
|
||||
let rest = node.value;
|
||||
while (isNotEmpty(rest) && (matches = regex.exec(rest)) !== null && matches.length === 4) {
|
||||
if (isNotEmpty(matches[1])) {
|
||||
output.push({
|
||||
type: 'text',
|
||||
value: matches[1],
|
||||
});
|
||||
}
|
||||
output.push({
|
||||
type: NodeTypes.link,
|
||||
url: matches[2],
|
||||
children: [{ text: matches[2] }],
|
||||
});
|
||||
rest = matches[3];
|
||||
regex.lastIndex = 0;
|
||||
}
|
||||
if (isNotEmpty(rest)) {
|
||||
output.push({
|
||||
type: 'text',
|
||||
value: rest,
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
output.push(node);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
import { ELEMENT_PARAGRAPH } from '@udecode/plate';
|
||||
|
||||
import { LIST_TYPES, MarkNodeTypes, NodeTypes } from './ast-types';
|
||||
import { processShortcodeConfigToSlate } from './processShortcodeConfig';
|
||||
import { autoLinkToSlate } from './autoLinkUrls';
|
||||
import { processShortcodeConfigsToSlate } from './processShortcodeConfig';
|
||||
|
||||
import type { ShortcodeConfig } from '@staticcms/core/interface';
|
||||
import type { MdBlockElement } from '@staticcms/markdown';
|
||||
@ -350,11 +351,7 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
||||
return { text: '' };
|
||||
}
|
||||
|
||||
let nodes: MdastNode[] = [node];
|
||||
|
||||
for (const shortcode in shortcodeConfigs) {
|
||||
nodes = processShortcodeConfigToSlate(shortcode, shortcodeConfigs[shortcode], nodes);
|
||||
}
|
||||
const nodes = autoLinkToSlate(processShortcodeConfigsToSlate(shortcodeConfigs, [node]));
|
||||
|
||||
return nodes.map(node => (node.type === 'text' ? { text: node.value ?? '' } : node));
|
||||
|
||||
|
@ -19,7 +19,7 @@ function createShortcodeRegex(name: string, config: ShortcodeConfig) {
|
||||
)}?([\\w\\W]*?)${cleanRegex(config.closeTag)}`;
|
||||
}
|
||||
|
||||
export function processShortcodeConfigToSlate(
|
||||
function processShortcodeConfigToSlate(
|
||||
name: string,
|
||||
config: ShortcodeConfig,
|
||||
nodes: BaseMdastNode[],
|
||||
@ -68,6 +68,19 @@ export function processShortcodeConfigToSlate(
|
||||
return output;
|
||||
}
|
||||
|
||||
export function processShortcodeConfigsToSlate(
|
||||
configs: Record<string, ShortcodeConfig>,
|
||||
nodes: BaseMdastNode[],
|
||||
) {
|
||||
let finalNodes: MdastNode[] = nodes;
|
||||
|
||||
for (const shortcode in configs) {
|
||||
finalNodes = processShortcodeConfigToSlate(shortcode, configs[shortcode], finalNodes);
|
||||
}
|
||||
|
||||
return finalNodes;
|
||||
}
|
||||
|
||||
export function processShortcodeConfigToMdx(
|
||||
configs: Record<string, ShortcodeConfig>,
|
||||
markdown: string,
|
||||
|
File diff suppressed because it is too large
Load Diff
30
yarn.lock
30
yarn.lock
@ -12779,7 +12779,7 @@ mdast-util-gfm-autolink-literal@^1.0.0:
|
||||
mdast-util-find-and-replace "^2.0.0"
|
||||
micromark-util-character "^1.0.0"
|
||||
|
||||
mdast-util-gfm-footnote@^1.0.0:
|
||||
mdast-util-gfm-footnote@1.0.2, mdast-util-gfm-footnote@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz#ce5e49b639c44de68d5bf5399877a14d5020424e"
|
||||
integrity sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==
|
||||
@ -12788,7 +12788,7 @@ mdast-util-gfm-footnote@^1.0.0:
|
||||
mdast-util-to-markdown "^1.3.0"
|
||||
micromark-util-normalize-identifier "^1.0.0"
|
||||
|
||||
mdast-util-gfm-strikethrough@^1.0.0:
|
||||
mdast-util-gfm-strikethrough@1.0.3, mdast-util-gfm-strikethrough@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz#5470eb105b483f7746b8805b9b989342085795b7"
|
||||
integrity sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==
|
||||
@ -12796,7 +12796,7 @@ mdast-util-gfm-strikethrough@^1.0.0:
|
||||
"@types/mdast" "^3.0.0"
|
||||
mdast-util-to-markdown "^1.3.0"
|
||||
|
||||
mdast-util-gfm-table@^1.0.0:
|
||||
mdast-util-gfm-table@1.0.7, mdast-util-gfm-table@^1.0.0:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz#3552153a146379f0f9c4c1101b071d70bbed1a46"
|
||||
integrity sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==
|
||||
@ -12806,7 +12806,7 @@ mdast-util-gfm-table@^1.0.0:
|
||||
mdast-util-from-markdown "^1.0.0"
|
||||
mdast-util-to-markdown "^1.3.0"
|
||||
|
||||
mdast-util-gfm-task-list-item@^1.0.0:
|
||||
mdast-util-gfm-task-list-item@1.0.2, mdast-util-gfm-task-list-item@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz#b280fcf3b7be6fd0cc012bbe67a59831eb34097b"
|
||||
integrity sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==
|
||||
@ -13043,6 +13043,20 @@ micromark-extension-gfm-autolink-literal@^1.0.0:
|
||||
micromark-util-types "^1.0.0"
|
||||
uvu "^0.5.0"
|
||||
|
||||
micromark-extension-gfm-footnote@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.0.tgz#73e3db823db9defef25f68074cb4cf4bb9cf6a8c"
|
||||
integrity sha512-RWYce7j8+c0n7Djzv5NzGEGitNNYO3uj+h/XYMdS/JinH1Go+/Qkomg/rfxExFzYTiydaV6GLeffGO5qcJbMPA==
|
||||
dependencies:
|
||||
micromark-core-commonmark "^1.0.0"
|
||||
micromark-factory-space "^1.0.0"
|
||||
micromark-util-character "^1.0.0"
|
||||
micromark-util-normalize-identifier "^1.0.0"
|
||||
micromark-util-sanitize-uri "^1.0.0"
|
||||
micromark-util-symbol "^1.0.0"
|
||||
micromark-util-types "^1.0.0"
|
||||
uvu "^0.5.0"
|
||||
|
||||
micromark-extension-gfm-footnote@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz#cbfd8873b983e820c494498c6dac0105920818d5"
|
||||
@ -13057,7 +13071,7 @@ micromark-extension-gfm-footnote@^1.0.0:
|
||||
micromark-util-types "^1.0.0"
|
||||
uvu "^0.5.0"
|
||||
|
||||
micromark-extension-gfm-strikethrough@^1.0.0:
|
||||
micromark-extension-gfm-strikethrough@1.0.5, micromark-extension-gfm-strikethrough@^1.0.0:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.5.tgz#4db40b87d674a6fe1d00d59ac91118e4f5960f12"
|
||||
integrity sha512-X0oI5eYYQVARhiNfbETy7BfLSmSilzN1eOuoRnrf9oUNsPRrWOAe9UqSizgw1vNxQBfOwL+n2610S3bYjVNi7w==
|
||||
@ -13069,7 +13083,7 @@ micromark-extension-gfm-strikethrough@^1.0.0:
|
||||
micromark-util-types "^1.0.0"
|
||||
uvu "^0.5.0"
|
||||
|
||||
micromark-extension-gfm-table@^1.0.0:
|
||||
micromark-extension-gfm-table@1.0.5, micromark-extension-gfm-table@^1.0.0:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz#7b708b728f8dc4d95d486b9e7a2262f9cddbcbb4"
|
||||
integrity sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==
|
||||
@ -13087,7 +13101,7 @@ micromark-extension-gfm-tagfilter@^1.0.0:
|
||||
dependencies:
|
||||
micromark-util-types "^1.0.0"
|
||||
|
||||
micromark-extension-gfm-task-list-item@^1.0.0:
|
||||
micromark-extension-gfm-task-list-item@1.0.4, micromark-extension-gfm-task-list-item@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.4.tgz#4b66d87847de40cef2b5ceddb9f9629a6dfe7472"
|
||||
integrity sha512-9XlIUUVnYXHsFF2HZ9jby4h3npfX10S1coXTnV035QGPgrtNYQq3J6IfIvcCIUAJrrqBVi5BqA/LmaOMJqPwMQ==
|
||||
@ -13261,7 +13275,7 @@ micromark-util-classify-character@^1.0.0:
|
||||
micromark-util-symbol "^1.0.0"
|
||||
micromark-util-types "^1.0.0"
|
||||
|
||||
micromark-util-combine-extensions@^1.0.0:
|
||||
micromark-util-combine-extensions@1.0.0, micromark-util-combine-extensions@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5"
|
||||
integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==
|
||||
|
Loading…
x
Reference in New Issue
Block a user