Skip to content

Commit 4e92bb3

Browse files
committed
Fix expression indent, sync tests w/ micromark
1 parent f9b799d commit 4e92bb3

File tree

3 files changed

+242
-26
lines changed

3 files changed

+242
-26
lines changed

src/construct/partial_mdx_expression.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,6 @@ use crate::util::mdx_collect::collect;
6464
use crate::{MdxExpressionKind, MdxExpressionParse, MdxSignal};
6565
use alloc::boxed::Box;
6666

67-
// Tab-size to eat has to be the same as what we serialize as.
68-
// While in some places in markdown that’s 4, in JS it’s more common as 2.
69-
// Which is what’s also in `mdast-util-mdx-jsx`:
70-
// <https://github.com/syntax-tree/mdast-util-mdx-jsx/blob/40b951b/lib/index.js#L52>
71-
// <https://github.com/micromark/micromark-extension-mdx-expression/blob/7c305ff/packages/micromark-factory-mdx-expression/dev/index.js#L37>
72-
pub const INDENT_SIZE: usize = 2;
73-
7467
/// Start of an MDX expression.
7568
///
7669
/// ```markdown
@@ -206,10 +199,13 @@ pub fn eol_after(tokenizer: &mut Tokenizer) -> State {
206199
}
207200

208201
pub fn prefix(tokenizer: &mut Tokenizer) -> State {
209-
tokenizer.tokenize_state.size_c += 1;
210-
if matches!(tokenizer.current, Some(b'\t' | b' '))
211-
&& tokenizer.tokenize_state.size_c < INDENT_SIZE - 1
212-
{
202+
// Tab-size to eat has to be the same as what we serialize as.
203+
// While in some places in markdown that’s 4, in JS it’s more common as 2.
204+
// Which is what’s also in `mdast-util-mdx-jsx`:
205+
// <https://github.com/syntax-tree/mdast-util-mdx-jsx/blob/40b951b/lib/index.js#L52>
206+
// <https://github.com/micromark/micromark-extension-mdx-expression/blob/7c305ff/packages/micromark-factory-mdx-expression/dev/index.js#L37>
207+
if matches!(tokenizer.current, Some(b'\t' | b' ')) && tokenizer.tokenize_state.size_c < 2 {
208+
tokenizer.tokenize_state.size_c += 1;
213209
tokenizer.consume();
214210
return State::Next(StateName::MdxExpressionPrefix);
215211
}

tests/mdx_expression_flow.rs

Lines changed: 180 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
mod test_utils;
22
use markdown::{
3-
mdast::{MdxFlowExpression, Node, Root},
3+
mdast::{
4+
AttributeContent, AttributeValue, AttributeValueExpression, Blockquote, MdxFlowExpression,
5+
MdxJsxAttribute, MdxJsxTextElement, MdxTextExpression, Node, Paragraph, Root, Text,
6+
},
47
message, to_html_with_options, to_mdast,
58
unist::Position,
69
Constructs, Options, ParseOptions,
710
};
811
use pretty_assertions::assert_eq;
912
use test_utils::swc::{parse_esm, parse_expression};
1013

14+
/// Note: these tests are also in `micromark/micromark-extension-mdx-expression`
15+
/// at `tests/index.js`.
1116
#[test]
1217
fn mdx_expression_flow_agnostic() -> Result<(), message::Message> {
1318
let mdx = Options {
@@ -100,7 +105,7 @@ fn mdx_expression_flow_agnostic() -> Result<(), message::Message> {
100105
assert_eq!(
101106
to_html_with_options("a\n\n* b", &mdx)?,
102107
"<p>a</p>\n<ul>\n<li>b</li>\n</ul>",
103-
"should support lists after non-expressions (GH-11)"
108+
"should support lists after non-expressions (wooorm/markdown-rs#11)"
104109
);
105110

106111
assert_eq!(
@@ -160,6 +165,8 @@ fn mdx_expression_flow_agnostic() -> Result<(), message::Message> {
160165
Ok(())
161166
}
162167

168+
/// Note: these tests are also in `micromark/micromark-extension-mdx-expression`
169+
/// at `tests/index.js`.
163170
#[test]
164171
fn mdx_expression_flow_gnostic() -> Result<(), message::Message> {
165172
let swc = Options {
@@ -235,9 +242,165 @@ fn mdx_expression_flow_gnostic() -> Result<(), message::Message> {
235242
"should support expressions padded w/ parens and comments"
236243
);
237244

245+
assert_eq!(
246+
to_mdast("{`\n\t`}", &swc.parse)?,
247+
Node::Root(Root {
248+
children: vec![Node::MdxFlowExpression(MdxFlowExpression {
249+
value: "`\n `".into(),
250+
position: Some(Position::new(1, 1, 0, 2, 7, 6)),
251+
stops: vec![(0, 1), (1, 2), (2, 3)]
252+
})],
253+
position: Some(Position::new(1, 1, 0, 2, 7, 6))
254+
}),
255+
"should use correct positional info when tabs are used (1, indent)"
256+
);
257+
258+
assert_eq!(
259+
to_mdast("{`\nalpha\t`}", &swc.parse)?,
260+
Node::Root(Root {
261+
children: vec![Node::MdxFlowExpression(MdxFlowExpression {
262+
value: "`\nalpha\t`".into(),
263+
position: Some(Position::new(1, 1, 0, 2, 11, 11)),
264+
stops: vec![(0, 1), (1, 2), (2, 3)]
265+
})],
266+
position: Some(Position::new(1, 1, 0, 2, 11, 11))
267+
}),
268+
"should use correct positional info when tabs are used (2, content)"
269+
);
270+
271+
assert_eq!(
272+
to_mdast("> aaa <b c={`\n> d\n> `} /> eee", &swc.parse)?,
273+
Node::Root(Root {
274+
children: vec![Node::Blockquote(Blockquote {
275+
children: vec![Node::Paragraph(Paragraph {
276+
children: vec![
277+
Node::Text(Text {
278+
value: "aaa ".into(),
279+
position: Some(Position::new(1, 4, 3, 1, 8, 7))
280+
}),
281+
Node::MdxJsxTextElement(MdxJsxTextElement {
282+
children: vec![],
283+
name: Some("b".into()),
284+
attributes: vec![AttributeContent::Property(MdxJsxAttribute {
285+
name: "c".into(),
286+
value: Some(AttributeValue::Expression(AttributeValueExpression {
287+
value: "`\n d\n`".into(),
288+
stops: vec![(0, 13), (1, 14), (2, 19), (6, 23), (7, 27)]
289+
}))
290+
})],
291+
position: Some(Position::new(1, 8, 7, 3, 9, 32))
292+
}),
293+
Node::Text(Text {
294+
value: " eee".into(),
295+
position: Some(Position::new(3, 9, 32, 3, 13, 36))
296+
})
297+
],
298+
position: Some(Position::new(1, 3, 2, 3, 13, 36))
299+
})],
300+
position: Some(Position::new(1, 1, 0, 3, 13, 36))
301+
})],
302+
position: Some(Position::new(1, 1, 0, 3, 13, 36))
303+
}),
304+
"should support template strings in JSX (text) in block quotes"
305+
);
306+
307+
assert_eq!(
308+
to_mdast("> ab {`\n>\t`}", &swc.parse)?,
309+
Node::Root(Root {
310+
children: vec![Node::Blockquote(Blockquote {
311+
children: vec![Node::Paragraph(Paragraph {
312+
children: vec![
313+
Node::Text(Text {
314+
value: "ab ".into(),
315+
position: Some(Position::new(1, 3, 2, 1, 6, 5))
316+
}),
317+
Node::MdxTextExpression(MdxTextExpression {
318+
value: "`\n`".into(),
319+
stops: vec![(0, 6), (1, 7), (2, 10)],
320+
position: Some(Position::new(1, 6, 5, 2, 7, 12))
321+
})
322+
],
323+
position: Some(Position::new(1, 3, 2, 2, 7, 12))
324+
})],
325+
position: Some(Position::new(1, 1, 0, 2, 7, 12))
326+
})],
327+
position: Some(Position::new(1, 1, 0, 2, 7, 12))
328+
}),
329+
"should use correct positional when there are virtual spaces due to a block quote"
330+
);
331+
332+
assert_eq!(
333+
to_mdast(
334+
"> {`\n> alpha\n> bravo\n> charlie\n> delta\n> `}",
335+
&swc.parse
336+
)?,
337+
Node::Root(Root {
338+
children: vec![Node::Blockquote(Blockquote {
339+
children: vec![Node::MdxFlowExpression(MdxFlowExpression {
340+
value: "`\nalpha\nbravo\ncharlie\n delta\n`".into(),
341+
position: Some(Position::new(1, 3, 2, 6, 5, 49)),
342+
stops: vec![
343+
(0, 3),
344+
(1, 4),
345+
(2, 7),
346+
(7, 12),
347+
(8, 16),
348+
(13, 21),
349+
(14, 26),
350+
(21, 33),
351+
(22, 38),
352+
(28, 44),
353+
(29, 47)
354+
]
355+
})],
356+
position: Some(Position::new(1, 1, 0, 6, 5, 49))
357+
})],
358+
position: Some(Position::new(1, 1, 0, 6, 5, 49))
359+
}),
360+
"should keep the correct number of spaces in a blockquote (flow)"
361+
);
362+
363+
assert_eq!(
364+
to_mdast(
365+
"> {`\n> alpha\n> bravo\n> charlie\n> delta\n> `}",
366+
&swc.parse
367+
)?,
368+
Node::Root(Root {
369+
children: vec![Node::Blockquote(Blockquote {
370+
children: vec![Node::MdxFlowExpression(MdxFlowExpression {
371+
value: "`\nalpha\nbravo\ncharlie\n delta\n`".into(),
372+
position: Some(Position::new(1, 3, 2, 6, 5, 49)),
373+
stops: vec![
374+
(0, 3),
375+
(1, 4),
376+
(2, 7),
377+
(7, 12),
378+
(8, 16),
379+
(13, 21),
380+
(14, 26),
381+
(21, 33),
382+
(22, 38),
383+
(28, 44),
384+
(29, 47)
385+
]
386+
})],
387+
position: Some(Position::new(1, 1, 0, 6, 5, 49))
388+
})],
389+
position: Some(Position::new(1, 1, 0, 6, 5, 49))
390+
}),
391+
"should keep the correct number of spaces in a blockquote (flow)"
392+
);
393+
394+
// Note: the weird character test has to go in mdxjs-rs.
395+
238396
Ok(())
239397
}
240398

399+
/// Note: these tests are also in `micromark/micromark-extension-mdx-expression`
400+
/// at `tests/index.js`.
401+
/// This project includes *all* extensions which means that it can use JSX.
402+
/// There we test something that does not exist in actual MDX but which is used
403+
/// by the separate JSX extension.
241404
#[test]
242405
fn mdx_expression_spread() -> Result<(), message::Message> {
243406
let swc = Options {
@@ -253,7 +416,7 @@ fn mdx_expression_spread() -> Result<(), message::Message> {
253416
assert_eq!(
254417
to_html_with_options("<a {...b} />", &swc)?,
255418
"",
256-
"should support spreads for attribute expression"
419+
"should support a spread"
257420
);
258421

259422
assert_eq!(
@@ -272,26 +435,33 @@ fn mdx_expression_spread() -> Result<(), message::Message> {
272435
);
273436

274437
assert_eq!(
275-
to_html_with_options("<a {...b,c} d>", &swc).err().unwrap().to_string(),
276-
"1:5: Unexpected extra content in spread (such as `{...x,y}`): only a single spread is supported (such as `{...x}`) (mdx:swc)",
277-
"should crash if a spread and other things"
438+
to_html_with_options("<a {b=c}={} d>", &swc).err().unwrap().to_string(),
439+
"1:5: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",
440+
"should crash on an incorrect spread that looks like an assignment"
278441
);
279442

280443
assert_eq!(
281-
to_html_with_options("<a {} />", &swc).err().unwrap().to_string(),
282-
"1:9: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",
283-
"should crash on an empty spread"
444+
to_html_with_options("<a {...b,c} d>", &swc).err().unwrap().to_string(),
445+
"1:5: Unexpected extra content in spread (such as `{...x,y}`): only a single spread is supported (such as `{...x}`) (mdx:swc)",
446+
"should crash if a spread and other things"
284447
);
285448

286449
assert_eq!(
287-
to_html_with_options("<a {a=b} />", &swc)
450+
to_html_with_options("<a {b=c} />", &swc)
288451
.err()
289452
.unwrap()
290453
.to_string(),
291454
"1:12: Could not parse expression with swc: assignment property is invalid syntax (mdx:swc)",
292455
"should crash if not an identifier"
293456
);
294457

458+
// Note: `markdown-rs` has no `allowEmpty`.
459+
assert_eq!(
460+
to_html_with_options("<a {} />", &swc).err().unwrap().to_string(),
461+
"1:9: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",
462+
"should crash on an empty spread"
463+
);
464+
295465
assert_eq!(
296466
to_html_with_options("<a {/* b */} />", &swc).err().unwrap().to_string(),
297467
"1:5: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",

0 commit comments

Comments
 (0)