index.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /**
  2. * @import {CompileContext, Extension as FromMarkdownExtension, Handle as FromMarkdownHandle} from 'mdast-util-from-markdown'
  3. * @import {MdxFlowExpression, MdxTextExpression} from 'mdast-util-mdx-expression'
  4. * @import {Handle as ToMarkdownHandle, Options as ToMarkdownExtension, State} from 'mdast-util-to-markdown'
  5. * @import {Parents} from 'mdast'
  6. */
  7. import {ok as assert} from 'devlop'
  8. /**
  9. * Create an extension for `mdast-util-from-markdown` to enable MDX expressions
  10. * in markdown.
  11. *
  12. * When using the micromark syntax extension with `addResult`, nodes will have
  13. * a `data.estree` field set to an ESTree `Program` node.
  14. *
  15. * @returns {FromMarkdownExtension}
  16. * Extension for `mdast-util-from-markdown` to enable MDX expressions.
  17. */
  18. export function mdxExpressionFromMarkdown() {
  19. return {
  20. enter: {
  21. mdxFlowExpression: enterMdxFlowExpression,
  22. mdxTextExpression: enterMdxTextExpression
  23. },
  24. exit: {
  25. mdxFlowExpression: exitMdxExpression,
  26. mdxFlowExpressionChunk: exitMdxExpressionData,
  27. mdxTextExpression: exitMdxExpression,
  28. mdxTextExpressionChunk: exitMdxExpressionData
  29. }
  30. }
  31. }
  32. /**
  33. * Create an extension for `mdast-util-to-markdown` to enable MDX expressions
  34. * in markdown.
  35. *
  36. * @returns {ToMarkdownExtension}
  37. * Extension for `mdast-util-to-markdown` to enable MDX expressions.
  38. */
  39. export function mdxExpressionToMarkdown() {
  40. return {
  41. handlers: {
  42. mdxFlowExpression: handleMdxExpression,
  43. mdxTextExpression: handleMdxExpression
  44. },
  45. unsafe: [
  46. {character: '{', inConstruct: ['phrasing']},
  47. {atBreak: true, character: '{'}
  48. ]
  49. }
  50. }
  51. /**
  52. * @this {CompileContext}
  53. * @type {FromMarkdownHandle}
  54. */
  55. function enterMdxFlowExpression(token) {
  56. this.enter({type: 'mdxFlowExpression', value: ''}, token)
  57. this.buffer()
  58. }
  59. /**
  60. * @this {CompileContext}
  61. * @type {FromMarkdownHandle}
  62. */
  63. function enterMdxTextExpression(token) {
  64. this.enter({type: 'mdxTextExpression', value: ''}, token)
  65. this.buffer()
  66. }
  67. /**
  68. * @this {CompileContext}
  69. * @type {FromMarkdownHandle}
  70. */
  71. function exitMdxExpression(token) {
  72. const value = this.resume()
  73. const estree = token.estree
  74. const node = this.stack[this.stack.length - 1]
  75. assert(node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression')
  76. this.exit(token)
  77. node.value = value
  78. if (estree) {
  79. node.data = {estree}
  80. }
  81. }
  82. /**
  83. * @this {CompileContext}
  84. * @type {FromMarkdownHandle}
  85. */
  86. function exitMdxExpressionData(token) {
  87. this.config.enter.data.call(this, token)
  88. this.config.exit.data.call(this, token)
  89. }
  90. /**
  91. * @type {ToMarkdownHandle}
  92. * @param {MdxFlowExpression | MdxTextExpression} node
  93. * Node.
  94. * @param {Parents | undefined} parent
  95. * Parent, if any.
  96. * @param {State} state
  97. * Info passed around about the current state.
  98. * @returns {string}
  99. * Serialized markdown.
  100. */
  101. function handleMdxExpression(node, parent, state) {
  102. const value = node.value || ''
  103. const result = state.indentLines(value, function (line, index, blank) {
  104. // Tab-size to eat has to be the same as what we serialize as.
  105. // While in some places in markdown that’s 4, in JS it’s more common as 2.
  106. // Which is what’s also in `mdast-util-mdx-jsx`:
  107. // <https://github.com/syntax-tree/mdast-util-mdx-jsx/blob/40b951b/lib/index.js#L52>
  108. return (index === 0 || blank ? '' : ' ') + line
  109. })
  110. return '{' + result + '}'
  111. }