Skip to content

Commit 85509ff

Browse files
authored
fix(CodeBlock): fixed parsing of language from token.info and added support for different code_block markup (#202)
1 parent a6d1cec commit 85509ff

File tree

4 files changed

+48
-15
lines changed

4 files changed

+48
-15
lines changed

src/extensions/markdown/CodeBlock/CodeBlock.test.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import {createMarkupChecker} from '../../../../tests/sameMarkup';
55
import {ExtensionsManager} from '../../../core';
66
import {BaseNode, BaseSpecsPreset} from '../../base/specs';
77

8-
import {CodeBlockSpecs} from './CodeBlockSpecs';
9-
import {codeBlockLangAttr, codeBlockNodeName} from './const';
8+
import {CodeBlockNodeAttr, CodeBlockSpecs, codeBlockNodeName} from './CodeBlockSpecs';
109

1110
const {schema, parser, serializer} = new ExtensionsManager({
1211
extensions: (builder) => builder.use(BaseSpecsPreset, {}).use(CodeBlockSpecs, {}),
@@ -24,7 +23,7 @@ describe('CodeBlock extension', () => {
2423
it('should parse a code block', () =>
2524
same(
2625
'Some code:\n\n```\nHere it is\n```\n\nPara',
27-
doc(p('Some code:'), cb({[codeBlockLangAttr]: ''}, 'Here it is'), p('Para')),
26+
doc(p('Some code:'), cb('Here it is'), p('Para')),
2827
));
2928

3029
it('parses an intended code block', () =>
@@ -36,14 +35,17 @@ describe('CodeBlock extension', () => {
3635
it('should parse a fenced code block with info string', () =>
3736
same(
3837
'foo\n\n```javascript\n1\n```',
39-
doc(p('foo'), cb({[codeBlockLangAttr]: 'javascript'}, '1')),
38+
doc(p('foo'), cb({[CodeBlockNodeAttr.Lang]: 'javascript'}, '1')),
4039
));
4140

4241
it('should parse a fenced code block with multiple new lines at the end', () =>
43-
same('```\nsome code\n\n\n\n```', doc(cb({[codeBlockLangAttr]: ''}, 'some code\n\n\n'))));
42+
same('```\nsome code\n\n\n\n```', doc(cb('some code\n\n\n'))));
4443

4544
// TODO: parsed: doc(paragraph("code\nblock"))
4645
it.skip('should parse html - pre tag', () => {
4746
parseDOM(schema, '<pre><code>code\nblock</code></pre>', doc(cb('code\nblock')));
4847
});
48+
49+
it('should support different markup', () =>
50+
same('~~~\n123\n~~~', doc(cb({[CodeBlockNodeAttr.Markup]: '~~~'}, '123'))));
4951
});

src/extensions/markdown/CodeBlock/CodeBlockSpecs/index.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import type {ExtensionAuto, YENodeSpec} from '../../../../core';
22
import {nodeTypeFactory} from '../../../../utils/schema';
33

4+
export const CodeBlockNodeAttr = {
5+
Lang: 'data-language',
6+
Markup: 'data-markup',
7+
} as const;
8+
49
export const codeBlockNodeName = 'code_block';
5-
export const codeBlockLangAttr = 'data-language';
10+
/** @deprecated Use __CodeBlockNodeAttr__ instead */
11+
export const codeBlockLangAttr = CodeBlockNodeAttr.Lang;
612
export const codeBlockType = nodeTypeFactory(codeBlockNodeName);
713

814
export type CodeBlockSpecsOptions = {
@@ -13,7 +19,10 @@ export const CodeBlockSpecs: ExtensionAuto<CodeBlockSpecsOptions> = (builder, op
1319
builder.addNode(codeBlockNodeName, () => ({
1420
view: opts.nodeview,
1521
spec: {
16-
attrs: {[codeBlockLangAttr]: {default: 'text'}},
22+
attrs: {
23+
[CodeBlockNodeAttr.Lang]: {default: ''},
24+
[CodeBlockNodeAttr.Markup]: {default: '```'},
25+
},
1726
content: 'text*',
1827
group: 'block',
1928
code: true,
@@ -25,13 +34,13 @@ export const CodeBlockSpecs: ExtensionAuto<CodeBlockSpecsOptions> = (builder, op
2534
tag: 'pre',
2635
preserveWhitespace: 'full',
2736
getAttrs: (node) => ({
28-
[codeBlockLangAttr]:
29-
(node as Element).getAttribute(codeBlockLangAttr) || '',
37+
[CodeBlockNodeAttr.Lang]:
38+
(node as Element).getAttribute(CodeBlockNodeAttr.Lang) || '',
3039
}),
3140
},
3241
],
3342
toDOM({attrs}) {
34-
return ['pre', attrs[codeBlockLangAttr] ? attrs : {}, ['code', 0]];
43+
return ['pre', attrs, ['code', 0]];
3544
},
3645
},
3746
fromYfm: {
@@ -43,11 +52,14 @@ export const CodeBlockSpecs: ExtensionAuto<CodeBlockSpecsOptions> = (builder, op
4352
},
4453
},
4554
toYfm: (state, node) => {
46-
state.write('```' + (node.attrs[codeBlockLangAttr] || '') + '\n');
55+
const lang: string = node.attrs[CodeBlockNodeAttr.Lang];
56+
const markup: string = node.attrs[CodeBlockNodeAttr.Markup];
57+
58+
state.write(markup + lang + '\n');
4759
state.text(node.textContent, false);
4860
// Add a newline to the current content before adding closing marker
4961
state.write('\n');
50-
state.write('```');
62+
state.write(markup);
5163
state.closeBlock(node);
5264
},
5365
}));
@@ -60,7 +72,17 @@ export const CodeBlockSpecs: ExtensionAuto<CodeBlockSpecsOptions> = (builder, op
6072
name: codeBlockNodeName,
6173
type: 'block',
6274
noCloseToken: true,
63-
getAttrs: (tok) => ({[codeBlockLangAttr]: tok.info || ''}),
75+
getAttrs: (tok) => {
76+
const attrs: Record<string, string> = {
77+
[CodeBlockNodeAttr.Markup]: tok.markup,
78+
};
79+
if (tok.info) {
80+
// like in markdown-it
81+
// https://github.com/markdown-it/markdown-it/blob/d07d585b6b15aaee2bc8f7a54b994526dad4dbc5/lib/renderer.mjs#L36-L37
82+
attrs[CodeBlockNodeAttr.Lang] = tok.info.split(/(\s+)/g)[0];
83+
}
84+
return attrs;
85+
},
6486
prepareContent: removeNewLineAtEnd, // content of fence blocks contains extra \n at the end
6587
},
6688
},
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import {codeBlockType} from './CodeBlockSpecs';
22

3-
export {codeBlockNodeName, codeBlockLangAttr} from './CodeBlockSpecs';
3+
export {
4+
codeBlockNodeName,
5+
codeBlockLangAttr,
6+
CodeBlockNodeAttr as CodeBlockAttr,
7+
} from './CodeBlockSpecs';
48
export const cbAction = 'toCodeBlock';
59
/** @deprecated Use `codeBlockType` instead */
610
export const cbType = codeBlockType;

src/extensions/markdown/CodeBlock/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ import {cbAction, cbType} from './const';
1313
import {handlePaste} from './handle-paste';
1414

1515
export {resetCodeblock} from './commands';
16-
export {codeBlockNodeName, codeBlockLangAttr, codeBlockType} from './CodeBlockSpecs';
16+
export {
17+
codeBlockNodeName,
18+
CodeBlockNodeAttr,
19+
codeBlockLangAttr,
20+
codeBlockType,
21+
} from './CodeBlockSpecs';
1722

1823
export type CodeBlockOptions = CodeBlockSpecsOptions & {
1924
codeBlockKey?: string | null;

0 commit comments

Comments
 (0)