···6464use crate::{MdxExpressionKind, MdxExpressionParse, MdxSignal};
6565use alloc::boxed::Box;
66666767-// Tab-size to eat has to be the same as what we serialize as.
6868-// While in some places in markdown that’s 4, in JS it’s more common as 2.
6969-// Which is what’s also in `mdast-util-mdx-jsx`:
7070-// <https://github.com/syntax-tree/mdast-util-mdx-jsx/blob/40b951b/lib/index.js#L52>
7171-// <https://github.com/micromark/micromark-extension-mdx-expression/blob/7c305ff/packages/micromark-factory-mdx-expression/dev/index.js#L37>
7272-pub const INDENT_SIZE: usize = 2;
7373-7467/// Start of an MDX expression.
7568///
7669/// ```markdown
···206199}
207200208201pub fn prefix(tokenizer: &mut Tokenizer) -> State {
209209- tokenizer.tokenize_state.size_c += 1;
210210- if matches!(tokenizer.current, Some(b'\t' | b' '))
211211- && tokenizer.tokenize_state.size_c < INDENT_SIZE - 1
212212- {
202202+ // Tab-size to eat has to be the same as what we serialize as.
203203+ // While in some places in markdown that’s 4, in JS it’s more common as 2.
204204+ // Which is what’s also in `mdast-util-mdx-jsx`:
205205+ // <https://github.com/syntax-tree/mdast-util-mdx-jsx/blob/40b951b/lib/index.js#L52>
206206+ // <https://github.com/micromark/micromark-extension-mdx-expression/blob/7c305ff/packages/micromark-factory-mdx-expression/dev/index.js#L37>
207207+ if matches!(tokenizer.current, Some(b'\t' | b' ')) && tokenizer.tokenize_state.size_c < 2 {
208208+ tokenizer.tokenize_state.size_c += 1;
213209 tokenizer.consume();
214210 return State::Next(StateName::MdxExpressionPrefix);
215211 }
+180-10
tests/mdx_expression_flow.rs
···11mod test_utils;
22use markdown::{
33- mdast::{MdxFlowExpression, Node, Root},
33+ mdast::{
44+ AttributeContent, AttributeValue, AttributeValueExpression, Blockquote, MdxFlowExpression,
55+ MdxJsxAttribute, MdxJsxTextElement, MdxTextExpression, Node, Paragraph, Root, Text,
66+ },
47 message, to_html_with_options, to_mdast,
58 unist::Position,
69 Constructs, Options, ParseOptions,
···811use pretty_assertions::assert_eq;
912use test_utils::swc::{parse_esm, parse_expression};
10131414+/// Note: these tests are also in `micromark/micromark-extension-mdx-expression`
1515+/// at `tests/index.js`.
1116#[test]
1217fn mdx_expression_flow_agnostic() -> Result<(), message::Message> {
1318 let mdx = Options {
···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>",
103103- "should support lists after non-expressions (GH-11)"
108108+ "should support lists after non-expressions (wooorm/markdown-rs#11)"
104109 );
105110106111 assert_eq!(
···160165 Ok(())
161166}
162167168168+/// Note: these tests are also in `micromark/micromark-extension-mdx-expression`
169169+/// at `tests/index.js`.
163170#[test]
164171fn mdx_expression_flow_gnostic() -> Result<(), message::Message> {
165172 let swc = Options {
···235242 "should support expressions padded w/ parens and comments"
236243 );
237244245245+ assert_eq!(
246246+ to_mdast("{`\n\t`}", &swc.parse)?,
247247+ Node::Root(Root {
248248+ children: vec![Node::MdxFlowExpression(MdxFlowExpression {
249249+ value: "`\n `".into(),
250250+ position: Some(Position::new(1, 1, 0, 2, 7, 6)),
251251+ stops: vec![(0, 1), (1, 2), (2, 3)]
252252+ })],
253253+ position: Some(Position::new(1, 1, 0, 2, 7, 6))
254254+ }),
255255+ "should use correct positional info when tabs are used (1, indent)"
256256+ );
257257+258258+ assert_eq!(
259259+ to_mdast("{`\nalpha\t`}", &swc.parse)?,
260260+ Node::Root(Root {
261261+ children: vec![Node::MdxFlowExpression(MdxFlowExpression {
262262+ value: "`\nalpha\t`".into(),
263263+ position: Some(Position::new(1, 1, 0, 2, 11, 11)),
264264+ stops: vec![(0, 1), (1, 2), (2, 3)]
265265+ })],
266266+ position: Some(Position::new(1, 1, 0, 2, 11, 11))
267267+ }),
268268+ "should use correct positional info when tabs are used (2, content)"
269269+ );
270270+271271+ assert_eq!(
272272+ to_mdast("> aaa <b c={`\n> d\n> `} /> eee", &swc.parse)?,
273273+ Node::Root(Root {
274274+ children: vec![Node::Blockquote(Blockquote {
275275+ children: vec![Node::Paragraph(Paragraph {
276276+ children: vec![
277277+ Node::Text(Text {
278278+ value: "aaa ".into(),
279279+ position: Some(Position::new(1, 4, 3, 1, 8, 7))
280280+ }),
281281+ Node::MdxJsxTextElement(MdxJsxTextElement {
282282+ children: vec![],
283283+ name: Some("b".into()),
284284+ attributes: vec![AttributeContent::Property(MdxJsxAttribute {
285285+ name: "c".into(),
286286+ value: Some(AttributeValue::Expression(AttributeValueExpression {
287287+ value: "`\n d\n`".into(),
288288+ stops: vec![(0, 13), (1, 14), (2, 19), (6, 23), (7, 27)]
289289+ }))
290290+ })],
291291+ position: Some(Position::new(1, 8, 7, 3, 9, 32))
292292+ }),
293293+ Node::Text(Text {
294294+ value: " eee".into(),
295295+ position: Some(Position::new(3, 9, 32, 3, 13, 36))
296296+ })
297297+ ],
298298+ position: Some(Position::new(1, 3, 2, 3, 13, 36))
299299+ })],
300300+ position: Some(Position::new(1, 1, 0, 3, 13, 36))
301301+ })],
302302+ position: Some(Position::new(1, 1, 0, 3, 13, 36))
303303+ }),
304304+ "should support template strings in JSX (text) in block quotes"
305305+ );
306306+307307+ assert_eq!(
308308+ to_mdast("> ab {`\n>\t`}", &swc.parse)?,
309309+ Node::Root(Root {
310310+ children: vec![Node::Blockquote(Blockquote {
311311+ children: vec![Node::Paragraph(Paragraph {
312312+ children: vec![
313313+ Node::Text(Text {
314314+ value: "ab ".into(),
315315+ position: Some(Position::new(1, 3, 2, 1, 6, 5))
316316+ }),
317317+ Node::MdxTextExpression(MdxTextExpression {
318318+ value: "`\n`".into(),
319319+ stops: vec![(0, 6), (1, 7), (2, 10)],
320320+ position: Some(Position::new(1, 6, 5, 2, 7, 12))
321321+ })
322322+ ],
323323+ position: Some(Position::new(1, 3, 2, 2, 7, 12))
324324+ })],
325325+ position: Some(Position::new(1, 1, 0, 2, 7, 12))
326326+ })],
327327+ position: Some(Position::new(1, 1, 0, 2, 7, 12))
328328+ }),
329329+ "should use correct positional when there are virtual spaces due to a block quote"
330330+ );
331331+332332+ assert_eq!(
333333+ to_mdast(
334334+ "> {`\n> alpha\n> bravo\n> charlie\n> delta\n> `}",
335335+ &swc.parse
336336+ )?,
337337+ Node::Root(Root {
338338+ children: vec![Node::Blockquote(Blockquote {
339339+ children: vec![Node::MdxFlowExpression(MdxFlowExpression {
340340+ value: "`\nalpha\nbravo\ncharlie\n delta\n`".into(),
341341+ position: Some(Position::new(1, 3, 2, 6, 5, 49)),
342342+ stops: vec![
343343+ (0, 3),
344344+ (1, 4),
345345+ (2, 7),
346346+ (7, 12),
347347+ (8, 16),
348348+ (13, 21),
349349+ (14, 26),
350350+ (21, 33),
351351+ (22, 38),
352352+ (28, 44),
353353+ (29, 47)
354354+ ]
355355+ })],
356356+ position: Some(Position::new(1, 1, 0, 6, 5, 49))
357357+ })],
358358+ position: Some(Position::new(1, 1, 0, 6, 5, 49))
359359+ }),
360360+ "should keep the correct number of spaces in a blockquote (flow)"
361361+ );
362362+363363+ assert_eq!(
364364+ to_mdast(
365365+ "> {`\n> alpha\n> bravo\n> charlie\n> delta\n> `}",
366366+ &swc.parse
367367+ )?,
368368+ Node::Root(Root {
369369+ children: vec![Node::Blockquote(Blockquote {
370370+ children: vec![Node::MdxFlowExpression(MdxFlowExpression {
371371+ value: "`\nalpha\nbravo\ncharlie\n delta\n`".into(),
372372+ position: Some(Position::new(1, 3, 2, 6, 5, 49)),
373373+ stops: vec![
374374+ (0, 3),
375375+ (1, 4),
376376+ (2, 7),
377377+ (7, 12),
378378+ (8, 16),
379379+ (13, 21),
380380+ (14, 26),
381381+ (21, 33),
382382+ (22, 38),
383383+ (28, 44),
384384+ (29, 47)
385385+ ]
386386+ })],
387387+ position: Some(Position::new(1, 1, 0, 6, 5, 49))
388388+ })],
389389+ position: Some(Position::new(1, 1, 0, 6, 5, 49))
390390+ }),
391391+ "should keep the correct number of spaces in a blockquote (flow)"
392392+ );
393393+394394+ // Note: the weird character test has to go in mdxjs-rs.
395395+238396 Ok(())
239397}
240398399399+/// Note: these tests are also in `micromark/micromark-extension-mdx-expression`
400400+/// at `tests/index.js`.
401401+/// This project includes *all* extensions which means that it can use JSX.
402402+/// There we test something that does not exist in actual MDX but which is used
403403+/// by the separate JSX extension.
241404#[test]
242405fn mdx_expression_spread() -> Result<(), message::Message> {
243406 let swc = Options {
···253416 assert_eq!(
254417 to_html_with_options("<a {...b} />", &swc)?,
255418 "",
256256- "should support spreads for attribute expression"
419419+ "should support a spread"
257420 );
258421259422 assert_eq!(
···272435 );
273436274437 assert_eq!(
438438+ to_html_with_options("<a {b=c}={} d>", &swc).err().unwrap().to_string(),
439439+ "1:5: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",
440440+ "should crash on an incorrect spread that looks like an assignment"
441441+ );
442442+443443+ assert_eq!(
275444 to_html_with_options("<a {...b,c} d>", &swc).err().unwrap().to_string(),
276445 "1:5: Unexpected extra content in spread (such as `{...x,y}`): only a single spread is supported (such as `{...x}`) (mdx:swc)",
277446 "should crash if a spread and other things"
278447 );
279448280449 assert_eq!(
281281- to_html_with_options("<a {} />", &swc).err().unwrap().to_string(),
282282- "1:9: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",
283283- "should crash on an empty spread"
284284- );
285285-286286- assert_eq!(
287287- to_html_with_options("<a {a=b} />", &swc)
450450+ 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"
456456+ );
457457+458458+ // Note: `markdown-rs` has no `allowEmpty`.
459459+ assert_eq!(
460460+ to_html_with_options("<a {} />", &swc).err().unwrap().to_string(),
461461+ "1:9: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",
462462+ "should crash on an empty spread"
293463 );
294464295465 assert_eq!(