Skip to content

Commit 52b421c

Browse files
authored
fix(bundle): fixed YfmTable serialization inside quotes at any nesting level (#635)
1 parent 9b98e40 commit 52b421c

File tree

4 files changed

+211
-9
lines changed

4 files changed

+211
-9
lines changed

package-lock.json

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
"react-error-boundary": "^3.1.4",
204204
"react-hotkeys-hook": "4.5.0",
205205
"react-use": "^17.3.2",
206+
"ts-dedent": "2.2.0",
206207
"tslib": "^2.3.1",
207208
"uuid": "11.0.5"
208209
},
@@ -269,7 +270,6 @@
269270
"sass": "^1.84.0",
270271
"sass-loader": "^13.3.2",
271272
"stylelint": "15.11.0",
272-
"ts-dedent": "2.2.0",
273273
"ts-jest": "^29.2.5",
274274
"typescript": "^5.7.3"
275275
},
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import {ExtensionsManager} from '../../core';
2+
import {SchemaDynamicModifier} from '../../core/SchemaDynamicModifier';
3+
import {MarkdownParserDynamicModifier} from '../../core/markdown/MarkdownParser';
4+
import {MarkdownSerializerDynamicModifier} from '../../core/markdown/MarkdownSerializerDynamicModifier';
5+
import {convertDynamicModifiersConfigs} from '../../core/utils/dynamicModifiers';
6+
import {FullSpecsPreset} from '../../presets/full-specs';
7+
import {MarkupManager} from '../MarkupManager';
8+
9+
import {createDynamicModifiers} from './dynamicModifiers';
10+
11+
const markupManager = new MarkupManager();
12+
13+
const dynamicModifiersConfig = convertDynamicModifiersConfigs(
14+
createDynamicModifiers(markupManager),
15+
);
16+
17+
const dynamicModifiers = {
18+
schema: new SchemaDynamicModifier(dynamicModifiersConfig.schema),
19+
parser: new MarkdownParserDynamicModifier(dynamicModifiersConfig.parser),
20+
serializer: new MarkdownSerializerDynamicModifier(dynamicModifiersConfig.serializer),
21+
};
22+
23+
const {markupParser: parser, serializer} = ExtensionsManager.process(
24+
(builder) =>
25+
builder.use(FullSpecsPreset, {
26+
color: {},
27+
}),
28+
{
29+
dynamicModifiers,
30+
},
31+
);
32+
33+
describe('dynamicModifiers', () => {
34+
it('should correctly process YFM tables in different contexts', () => {
35+
const initialMarkup = `
36+
## YFM Table
37+
### Simple table
38+
#|
39+
|| **Header1** | **Header2** ||
40+
|| Text | Text ||
41+
|#
42+
### Multiline content
43+
#|
44+
|| Text
45+
on two lines |
46+
- Potatoes
47+
- Carrot
48+
- Onion
49+
- Cucumber
50+
||
51+
|#
52+
53+
### Nested tables
54+
#|
55+
|| 1 | Text before other table
56+
57+
#|
58+
|| 5 | 6 ||
59+
|| 7 | 8 ||
60+
|#
61+
62+
Text after other table
63+
||
64+
|| 3 | 4 ||
65+
66+
|#
67+
68+
### Table inside quote
69+
> #|
70+
> || **Header1** | **Header2** ||
71+
> || Text | Text ||
72+
> |#
73+
74+
### Table inside tabs
75+
76+
{% list tabs %}
77+
78+
- tab1
79+
80+
#|
81+
|| **Header1** | **Header2** ||
82+
|| Text | Text ||
83+
|#
84+
85+
- tab2
86+
87+
#|
88+
|| Text
89+
on two lines |
90+
- Potatoes
91+
- Carrot
92+
- Onion
93+
- Cucumber
94+
||
95+
|#
96+
97+
98+
{% endlist %}
99+
`;
100+
101+
const expectedMarkup = `## YFM Table
102+
103+
### Simple table
104+
105+
#|
106+
|| **Header1** | **Header2** ||
107+
|| Text | Text ||
108+
|#
109+
### Multiline content
110+
111+
#|
112+
|| Text
113+
on two lines |
114+
- Potatoes
115+
- Carrot
116+
- Onion
117+
- Cucumber
118+
||
119+
|#
120+
121+
### Nested tables
122+
123+
#|
124+
|| 1 | Text before other table
125+
126+
#|
127+
|| 5 | 6 ||
128+
|| 7 | 8 ||
129+
|#
130+
131+
Text after other table
132+
||
133+
|| 3 | 4 ||
134+
135+
|#
136+
137+
### Table inside quote
138+
139+
>${` `}
140+
> #|
141+
> ||
142+
>${` `}
143+
> **Header1**
144+
>
145+
> |
146+
>${` `}
147+
> **Header2**
148+
>
149+
> ||
150+
> ||
151+
>${` `}
152+
> Text
153+
>
154+
> |
155+
>${` `}
156+
> Text
157+
>
158+
> ||
159+
> |#
160+
>${` `}
161+
162+
### Table inside tabs
163+
164+
{% list tabs %}
165+
166+
- tab1
167+
168+
${` `}
169+
#|
170+
|| **Header1** | **Header2** ||
171+
|| Text | Text ||
172+
|#
173+
${` `}
174+
175+
- tab2
176+
177+
${` `}
178+
#|
179+
|| Text
180+
on two lines |
181+
- Potatoes
182+
- Carrot
183+
- Onion
184+
- Cucumber
185+
||
186+
|#
187+
${` `}
188+
189+
{% endlist %}`;
190+
191+
const doc = parser.parse(initialMarkup);
192+
const serialized = serializer.serialize(doc);
193+
194+
expect(serialized).toBe(expectedMarkup);
195+
});
196+
});

src/bundle/config/dynamicModifiers.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import dedent from 'ts-dedent';
12
import {v5} from 'uuid';
23

34
import type {DynamicModifiers} from '../../core/types/dynamicModifiers';
45
import type {MarkupManager} from '../MarkupManager';
56

67
const YFM_TABLE_TOKEN_ATTR = 'data-token-id';
78
const YFM_TABLE_NODE_ATTR = 'data-node-id';
8-
const PARENTS_WITH_AFFECT = ['blockquote', 'yfm_tabs'];
99

1010
export function createDynamicModifiers(markupManager: MarkupManager): DynamicModifiers[] {
1111
return [
@@ -20,11 +20,13 @@ export function createDynamicModifiers(markupManager: MarkupManager): DynamicMod
2020
const {map} = token;
2121

2222
if (map) {
23-
const content = rawMarkup.split('\n').slice(map[0], map[1]).join('\n');
23+
const content = rawMarkup.split('\n').slice(map[0], map[1]).join('\n').trim();
2424
const tokenId = v5(content, markupManager.getNamespace());
2525

26-
token.attrSet(YFM_TABLE_TOKEN_ATTR, tokenId);
27-
markupManager.setMarkup(tokenId, content);
26+
if (/^\s*#\|/.test(content)) {
27+
token.attrSet(YFM_TABLE_TOKEN_ATTR, tokenId);
28+
markupManager.setMarkup(tokenId, dedent(content));
29+
}
2830
}
2931
return token;
3032
},
@@ -63,8 +65,13 @@ export function createDynamicModifiers(markupManager: MarkupManager): DynamicMod
6365
const nodeId = node.attrs[YFM_TABLE_NODE_ATTR];
6466
const savedNode = markupManager.getNode(nodeId);
6567

66-
if (!PARENTS_WITH_AFFECT.includes(parent?.type?.name) && savedNode?.eq(node)) {
67-
state.write(markupManager.getMarkup(nodeId) + '\n');
68+
if (savedNode?.eq(node)) {
69+
const content: string = markupManager.getMarkup(nodeId) || '';
70+
state.ensureNewLine();
71+
state.text(content, false);
72+
state.ensureNewLine();
73+
state.closeBlock();
74+
state.write('\n');
6875
return;
6976
}
7077

0 commit comments

Comments
 (0)