From ec05bd95d25f4a238b081e00fa2a68f0e5efb034 Mon Sep 17 00:00:00 2001 From: eagletrhost Date: Wed, 10 Dec 2025 23:33:45 +1100 Subject: [PATCH] fix: set up default jsx context for operations --- .../preprocess-jsx-expressions.test.ts | 37 +++++++++++++++++++ lib/mdxish.ts | 4 +- .../mdxish/preprocess-jsx-expressions.ts | 14 ++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/__tests__/transformers/preprocess-jsx-expressions.test.ts b/__tests__/transformers/preprocess-jsx-expressions.test.ts index fcf0fd88b..6f5012c35 100644 --- a/__tests__/transformers/preprocess-jsx-expressions.test.ts +++ b/__tests__/transformers/preprocess-jsx-expressions.test.ts @@ -1,6 +1,43 @@ +import { mix } from '../../lib'; import { preprocessJSXExpressions } from '../../processor/transform/mdxish/preprocess-jsx-expressions'; describe('preprocessJSXExpressions', () => { + describe('using the default jsx context', () => { + it('should evaluate the string operations', () => { + const content = 'Hello {uppercase("world")} {lowercase("WORLD")}'; + const result = mix(content); + expect(result).toContain('Hello WORLD world'); + expect(result).not.toContain('{uppercase("world")}'); + expect(result).not.toContain('{lowercase("WORLD")}'); + }); + + it('should evaluate the number operations when the operations are mentioned', () => { + const content = 'Hello {add(1, 2)} {subtract(3, 4)} {multiply(5, 6)} {divide(4, 2)}'; + const result = mix(content); + expect(result).toContain('Hello 3 -1 30 2'); + expect(result).not.toContain('{add(1, 2)}'); + expect(result).not.toContain('{subtract(3, 4)}'); + expect(result).not.toContain('{multiply(5, 6)}'); + expect(result).not.toContain('{divide(4, 2)}'); + }); + + it('should evaluate number operations when math symbols are used', () => { + const content = '{1 + 2 - 1} {4 * 2 / 2}'; + const result = mix(content); + expect(result).toContain('2 4'); + expect(result).not.toContain('{1 + 2 - 1}'); + expect(result).not.toContain('{4 * 2 / 2}'); + }); + + it('should not evaluate operations when not in braces', () => { + const content = '1 + 2 uppercase("world")'; + const result = mix(content); + expect(result).toContain(content); + expect(result).not.toContain('WORLD'); + expect(result).not.toContain('3'); + }); + }); + describe('Step 3: Evaluate attribute expressions', () => { it('should evaluate JSX attribute expressions and convert them to string attributes', () => { const context = { diff --git a/lib/mdxish.ts b/lib/mdxish.ts index c20b5caf1..2f3fc1543 100644 --- a/lib/mdxish.ts +++ b/lib/mdxish.ts @@ -24,7 +24,7 @@ import mdxishComponentBlocks from '../processor/transform/mdxish/mdxish-componen import mdxishHtmlBlocks from '../processor/transform/mdxish/mdxish-html-blocks'; import magicBlockRestorer from '../processor/transform/mdxish/mdxish-magic-blocks'; import mdxishTables from '../processor/transform/mdxish/mdxish-tables'; -import { preprocessJSXExpressions, type JSXContext } from '../processor/transform/mdxish/preprocess-jsx-expressions'; +import { preprocessJSXExpressions, type JSXContext, DEFAULT_JSX_CONTEXT } from '../processor/transform/mdxish/preprocess-jsx-expressions'; import variablesTextTransformer from '../processor/transform/mdxish/variables-text'; import tailwindTransformer from '../processor/transform/tailwind'; @@ -46,7 +46,7 @@ const defaultTransformers = [calloutTransformer, codeTabsTransformer, gemojiTran * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md} */ export function mdxish(mdContent: string, opts: MdxishOpts = {}): Root { - const { components: userComponents = {}, jsxContext = {}, useTailwind } = opts; + const { components: userComponents = {}, jsxContext = DEFAULT_JSX_CONTEXT, useTailwind } = opts; const components: CustomComponents = { ...loadComponents(), diff --git a/processor/transform/mdxish/preprocess-jsx-expressions.ts b/processor/transform/mdxish/preprocess-jsx-expressions.ts index 3fe2c9cf3..03f8a1a3b 100644 --- a/processor/transform/mdxish/preprocess-jsx-expressions.ts +++ b/processor/transform/mdxish/preprocess-jsx-expressions.ts @@ -2,9 +2,21 @@ * Pre-processes JSX-like expressions before markdown parsing. * Converts href={'value'} to href="value", evaluates {expressions}, etc. */ - export type JSXContext = Record; +// Common operations that might be used in JSX expressions +// These are not exhaustive, but are a good starting point +// We probably want to just use a library that'll load most of the common operations for us +export const DEFAULT_JSX_CONTEXT: JSXContext = { + uppercase: (value: string) => value.toUpperCase(), + lowercase: (value: string) => value.toLowerCase(), + + add: (a: number, b: number) => a + b, + subtract: (a: number, b: number) => a - b, + multiply: (a: number, b: number) => a * b, + divide: (a: number, b: number) => a / b, +}; + // Base64 encode (Node.js + browser compatible) function base64Encode(str: string): string { if (typeof Buffer !== 'undefined') {