diff --git a/__tests__/compilers/variable.test.ts b/__tests__/compilers/variable.test.ts index f6232e3b9..aae497a86 100644 --- a/__tests__/compilers/variable.test.ts +++ b/__tests__/compilers/variable.test.ts @@ -1,7 +1,7 @@ import * as rmdx from '../../index'; describe('variable compiler', () => { - it('compiles back to the ', () => { + it('compiles back to the original mdx', () => { const mdx = ` ## Hello! @@ -13,4 +13,11 @@ describe('variable compiler', () => { expect(rmdx.mdx(tree).trim()).toStrictEqual(mdx.trim()); }); + + it('with spaces in a variable, it compiles back to the original', () => { + const mdx = `{user["oh no"]}`; + const tree = rmdx.mdast(mdx); + + expect(rmdx.mdx(tree).trim()).toStrictEqual(mdx.trim()); + }); }); diff --git a/__tests__/lib/mdast/index.test.ts b/__tests__/lib/mdast/index.test.ts index af5a711f1..43ca8519b 100644 --- a/__tests__/lib/mdast/index.test.ts +++ b/__tests__/lib/mdast/index.test.ts @@ -9,6 +9,9 @@ import tablesJson from './tables/out.json'; import variablesMdx from './variables/in.mdx?raw'; import variablesJson from './variables/out.json'; +import variablesWithSpacesMdx from './variables-with-spaces/in.mdx?raw'; +import variablesWithSpacesJson from './variables-with-spaces/out.json'; + import inlineImagesMdx from './images/inline/in.mdx?raw'; import inlineImagesJson from './images/inline/out.json'; @@ -28,6 +31,11 @@ describe('mdast transformer', async () => { expect(mdast(variablesMdx)).toStrictEqualExceptPosition(variablesJson); }); + it('parses variables with spaces', () => { + // @ts-ignore + expect(mdast(variablesWithSpacesMdx)).toStrictEqualExceptPosition(variablesWithSpacesJson); + }); + it('parses inline images', () => { // @ts-ignore expect(mdast(inlineImagesMdx)).toStrictEqualExceptPosition(inlineImagesJson); diff --git a/__tests__/lib/mdast/variables-with-spaces/in.mdx b/__tests__/lib/mdast/variables-with-spaces/in.mdx new file mode 100644 index 000000000..12b445c0a --- /dev/null +++ b/__tests__/lib/mdast/variables-with-spaces/in.mdx @@ -0,0 +1 @@ +Hello, { user['this is cursed'] } diff --git a/__tests__/lib/mdast/variables-with-spaces/out.json b/__tests__/lib/mdast/variables-with-spaces/out.json new file mode 100644 index 000000000..413361bb7 --- /dev/null +++ b/__tests__/lib/mdast/variables-with-spaces/out.json @@ -0,0 +1,72 @@ +{ + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 8, + "line": 1, + "offset": 7 + }, + "start": { + "column": 1, + "line": 1, + "offset": 0 + } + }, + "type": "text", + "value": "Hello, " + }, + { + "data": { + "hName": "Variable", + "hProperties": { + "name": "this is cursed" + } + }, + "position": { + "end": { + "column": 19, + "line": 1, + "offset": 18 + }, + "start": { + "column": 8, + "line": 1, + "offset": 7 + } + }, + "type": "readme-variable", + "value": "{ user['this is cursed'] }" + } + ], + "position": { + "end": { + "column": 19, + "line": 1, + "offset": 18 + }, + "start": { + "column": 1, + "line": 1, + "offset": 0 + } + }, + "type": "paragraph" + } + ], + "position": { + "end": { + "column": 1, + "line": 2, + "offset": 19 + }, + "start": { + "column": 1, + "line": 1, + "offset": 0 + } + }, + "type": "root" +} diff --git a/__tests__/transformers/variables.test.tsx b/__tests__/transformers/variables.test.tsx index 8fbf2cfbe..5b4abecb8 100644 --- a/__tests__/transformers/variables.test.tsx +++ b/__tests__/transformers/variables.test.tsx @@ -52,4 +52,11 @@ describe('variables transformer', () => { type: 'root', }); }); + + it('does not parse regular expressions into variables', () => { + const mdx = `{notUser.name}`; + + // @ts-ignore + expect(rmdx.mdast(mdx).children[0].type).toBe('mdxFlowExpression'); + }); }); diff --git a/processor/compile/variable.ts b/processor/compile/variable.ts index 7b96ef679..2d39b82d0 100644 --- a/processor/compile/variable.ts +++ b/processor/compile/variable.ts @@ -4,7 +4,7 @@ const variable = (node: Variable) => { // @note: coming from RDMD, it's set as `variable`. But when mdx is parsed, // it's set as `name` const name = node.data.hProperties.variable || node.data.hProperties.name; - return `{user.${name}}`; + return name.toString().match(/ /) ? `{user[${JSON.stringify(name)}]}` : `{user.${name}}`; }; export default variable; diff --git a/processor/parse/reusable-content-parser.js b/processor/parse/reusable-content-parser.js deleted file mode 100644 index 271d86fa4..000000000 --- a/processor/parse/reusable-content-parser.js +++ /dev/null @@ -1,36 +0,0 @@ -const { insertBlockTokenizerBefore } = require('./utils'); - -export const type = 'reusable-content'; - -function tokenizeReusableContent(eat, value, silent) { - const { tags, disabled } = this.data('reusableContent'); - if (disabled) return false; - - // Modifies the regular expression to match from - // the start of the line - const match = /^<(?[A-Z]\S+)\s*\/>\s*/.exec(value); - - if (!match || !match.groups.tag) return false; - const { tag } = match.groups; - - /* istanbul ignore if */ - if (silent) return true; - - const node = { - type: 'reusable-content', - tag, - children: tag in tags ? tags[tag] : [], - }; - - return eat(match[0])(node); -} - -function parser() { - insertBlockTokenizerBefore.call(this, { - name: 'reusableContent', - before: 'html', - tokenizer: tokenizeReusableContent.bind(this), - }); -} - -export default parser; diff --git a/processor/transform/variables.ts b/processor/transform/variables.ts index 826354004..8c68148f9 100644 --- a/processor/transform/variables.ts +++ b/processor/transform/variables.ts @@ -12,8 +12,22 @@ const variables = visit(tree, (node, index, parent) => { if (!['mdxFlowExpression', 'mdxTextExpression'].includes(node.type) || !('value' in node)) return; - const match = node.value.match(/^user\.(?.*)$/); - if (!match) return; + // @ts-expect-error - estree is not defined on our mdx types?! + if (node.data.estree.type !== 'Program') return; + // @ts-expect-error - estree is not defined on our mdx types?! + const [expression] = node.data.estree.body; + if ( + !expression || + expression.type !== 'ExpressionStatement' || + expression.expression.object?.name !== 'user' || + !['Literal', 'Identifier'].includes(expression.expression.property?.type) + ) + return; + + const name = + expression.expression.property.type === 'Identifier' + ? expression.expression.property.name + : expression.expression.property.value; let variable = asMdx ? ({ @@ -23,7 +37,7 @@ const variables = { type: 'mdxJsxAttribute', name: 'name', - value: match.groups.value, + value: name, }, ], children: [], @@ -34,7 +48,7 @@ const variables = data: { hName: 'Variable', hProperties: { - name: match.groups.value, + name, }, }, value: `{${node.value}}`,