diff --git a/src/extensions/markdown/CodeBlock/CodeBlock.test.ts b/src/extensions/markdown/CodeBlock/CodeBlock.test.ts
index f9964df2..6a64d8af 100644
--- a/src/extensions/markdown/CodeBlock/CodeBlock.test.ts
+++ b/src/extensions/markdown/CodeBlock/CodeBlock.test.ts
@@ -5,8 +5,7 @@ import {createMarkupChecker} from '../../../../tests/sameMarkup';
import {ExtensionsManager} from '../../../core';
import {BaseNode, BaseSpecsPreset} from '../../base/specs';
-import {CodeBlockSpecs} from './CodeBlockSpecs';
-import {codeBlockLangAttr, codeBlockNodeName} from './const';
+import {CodeBlockNodeAttr, CodeBlockSpecs, codeBlockNodeName} from './CodeBlockSpecs';
const {schema, parser, serializer} = new ExtensionsManager({
extensions: (builder) => builder.use(BaseSpecsPreset, {}).use(CodeBlockSpecs, {}),
@@ -24,7 +23,7 @@ describe('CodeBlock extension', () => {
it('should parse a code block', () =>
same(
'Some code:\n\n```\nHere it is\n```\n\nPara',
- doc(p('Some code:'), cb({[codeBlockLangAttr]: ''}, 'Here it is'), p('Para')),
+ doc(p('Some code:'), cb('Here it is'), p('Para')),
));
it('parses an intended code block', () =>
@@ -36,14 +35,17 @@ describe('CodeBlock extension', () => {
it('should parse a fenced code block with info string', () =>
same(
'foo\n\n```javascript\n1\n```',
- doc(p('foo'), cb({[codeBlockLangAttr]: 'javascript'}, '1')),
+ doc(p('foo'), cb({[CodeBlockNodeAttr.Lang]: 'javascript'}, '1')),
));
it('should parse a fenced code block with multiple new lines at the end', () =>
- same('```\nsome code\n\n\n\n```', doc(cb({[codeBlockLangAttr]: ''}, 'some code\n\n\n'))));
+ same('```\nsome code\n\n\n\n```', doc(cb('some code\n\n\n'))));
// TODO: parsed: doc(paragraph("code\nblock"))
it.skip('should parse html - pre tag', () => {
parseDOM(schema, '
code\nblock
', doc(cb('code\nblock')));
});
+
+ it('should support different markup', () =>
+ same('~~~\n123\n~~~', doc(cb({[CodeBlockNodeAttr.Markup]: '~~~'}, '123'))));
});
diff --git a/src/extensions/markdown/CodeBlock/CodeBlockSpecs/index.ts b/src/extensions/markdown/CodeBlock/CodeBlockSpecs/index.ts
index f0a7cc64..31fe48bd 100644
--- a/src/extensions/markdown/CodeBlock/CodeBlockSpecs/index.ts
+++ b/src/extensions/markdown/CodeBlock/CodeBlockSpecs/index.ts
@@ -1,8 +1,14 @@
import type {ExtensionAuto, YENodeSpec} from '../../../../core';
import {nodeTypeFactory} from '../../../../utils/schema';
+export const CodeBlockNodeAttr = {
+ Lang: 'data-language',
+ Markup: 'data-markup',
+} as const;
+
export const codeBlockNodeName = 'code_block';
-export const codeBlockLangAttr = 'data-language';
+/** @deprecated Use __CodeBlockNodeAttr__ instead */
+export const codeBlockLangAttr = CodeBlockNodeAttr.Lang;
export const codeBlockType = nodeTypeFactory(codeBlockNodeName);
export type CodeBlockSpecsOptions = {
@@ -13,7 +19,10 @@ export const CodeBlockSpecs: ExtensionAuto = (builder, op
builder.addNode(codeBlockNodeName, () => ({
view: opts.nodeview,
spec: {
- attrs: {[codeBlockLangAttr]: {default: 'text'}},
+ attrs: {
+ [CodeBlockNodeAttr.Lang]: {default: ''},
+ [CodeBlockNodeAttr.Markup]: {default: '```'},
+ },
content: 'text*',
group: 'block',
code: true,
@@ -25,13 +34,13 @@ export const CodeBlockSpecs: ExtensionAuto = (builder, op
tag: 'pre',
preserveWhitespace: 'full',
getAttrs: (node) => ({
- [codeBlockLangAttr]:
- (node as Element).getAttribute(codeBlockLangAttr) || '',
+ [CodeBlockNodeAttr.Lang]:
+ (node as Element).getAttribute(CodeBlockNodeAttr.Lang) || '',
}),
},
],
toDOM({attrs}) {
- return ['pre', attrs[codeBlockLangAttr] ? attrs : {}, ['code', 0]];
+ return ['pre', attrs, ['code', 0]];
},
},
fromYfm: {
@@ -43,11 +52,14 @@ export const CodeBlockSpecs: ExtensionAuto = (builder, op
},
},
toYfm: (state, node) => {
- state.write('```' + (node.attrs[codeBlockLangAttr] || '') + '\n');
+ const lang: string = node.attrs[CodeBlockNodeAttr.Lang];
+ const markup: string = node.attrs[CodeBlockNodeAttr.Markup];
+
+ state.write(markup + lang + '\n');
state.text(node.textContent, false);
// Add a newline to the current content before adding closing marker
state.write('\n');
- state.write('```');
+ state.write(markup);
state.closeBlock(node);
},
}));
@@ -60,7 +72,17 @@ export const CodeBlockSpecs: ExtensionAuto = (builder, op
name: codeBlockNodeName,
type: 'block',
noCloseToken: true,
- getAttrs: (tok) => ({[codeBlockLangAttr]: tok.info || ''}),
+ getAttrs: (tok) => {
+ const attrs: Record = {
+ [CodeBlockNodeAttr.Markup]: tok.markup,
+ };
+ if (tok.info) {
+ // like in markdown-it
+ // https://github.com/markdown-it/markdown-it/blob/d07d585b6b15aaee2bc8f7a54b994526dad4dbc5/lib/renderer.mjs#L36-L37
+ attrs[CodeBlockNodeAttr.Lang] = tok.info.split(/(\s+)/g)[0];
+ }
+ return attrs;
+ },
prepareContent: removeNewLineAtEnd, // content of fence blocks contains extra \n at the end
},
},
diff --git a/src/extensions/markdown/CodeBlock/const.ts b/src/extensions/markdown/CodeBlock/const.ts
index 1db42ad3..9ce37a7d 100644
--- a/src/extensions/markdown/CodeBlock/const.ts
+++ b/src/extensions/markdown/CodeBlock/const.ts
@@ -1,6 +1,10 @@
import {codeBlockType} from './CodeBlockSpecs';
-export {codeBlockNodeName, codeBlockLangAttr} from './CodeBlockSpecs';
+export {
+ codeBlockNodeName,
+ codeBlockLangAttr,
+ CodeBlockNodeAttr as CodeBlockAttr,
+} from './CodeBlockSpecs';
export const cbAction = 'toCodeBlock';
/** @deprecated Use `codeBlockType` instead */
export const cbType = codeBlockType;
diff --git a/src/extensions/markdown/CodeBlock/index.ts b/src/extensions/markdown/CodeBlock/index.ts
index 0f6649f5..cb4c0ea5 100644
--- a/src/extensions/markdown/CodeBlock/index.ts
+++ b/src/extensions/markdown/CodeBlock/index.ts
@@ -13,7 +13,12 @@ import {cbAction, cbType} from './const';
import {handlePaste} from './handle-paste';
export {resetCodeblock} from './commands';
-export {codeBlockNodeName, codeBlockLangAttr, codeBlockType} from './CodeBlockSpecs';
+export {
+ codeBlockNodeName,
+ CodeBlockNodeAttr,
+ codeBlockLangAttr,
+ codeBlockType,
+} from './CodeBlockSpecs';
export type CodeBlockOptions = CodeBlockSpecsOptions & {
codeBlockKey?: string | null;