From 5f6a403255802954be479882e61c408ac4e455a4 Mon Sep 17 00:00:00 2001 From: Troy Alford Date: Thu, 18 Sep 2025 22:21:48 -0700 Subject: [PATCH 1/4] add typings --- source/components/JsxParser.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/source/components/JsxParser.tsx b/source/components/JsxParser.tsx index 165a3bd..2c3a3a7 100644 --- a/source/components/JsxParser.tsx +++ b/source/components/JsxParser.tsx @@ -15,6 +15,14 @@ function handleNaN(child: T): T | 'NaN' { type ParsedJSX = React.ReactNode | boolean | string type ParsedTree = ParsedJSX | ParsedJSX[] | null +type ComponentType = + | React.ComponentType // allows for class components + | React.ExoticComponent // allows for forwardRef + | (() => React.ReactNode) // allows for function components +type ComponentsType = + | ComponentType + | Record + /** * Props for the JsxParser component */ @@ -47,12 +55,7 @@ export type TProps = { className?: string, /** Map of component names to their React component definitions */ - components?: Record< - string, - | React.ComponentType // allows for class components - | React.ExoticComponent // allows for forwardRef - | (() => React.ReactNode) // allows for function components - >, + components?: Record, /** If true, only renders custom components defined in the components prop */ componentsOnly?: boolean, From 6f89cf9fa12bec41fe16fc9ed70a2fd504bb292e Mon Sep 17 00:00:00 2001 From: Troy Alford Date: Thu, 18 Sep 2025 22:40:32 -0700 Subject: [PATCH 2/4] Add support for bitwise and typeof unary operations - Add bitwise NOT (~) operator support - Add typeof operator support - Update test cases to cover new operations - Fix test formatting and organization --- source/components/JsxParser.test.tsx | 47 ++++++++++++++++------------ source/components/JsxParser.tsx | 2 ++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/source/components/JsxParser.test.tsx b/source/components/JsxParser.test.tsx index 5fdaa5d..aedf6cf 100644 --- a/source/components/JsxParser.test.tsx +++ b/source/components/JsxParser.test.tsx @@ -114,32 +114,39 @@ describe('JsxParser Component', () => { }) }) - describe('unary operations', () => { + describe.only('unary operations', () => { const testCases = [ - ['+60', 60], ['-60', -60], - ['!true', false], - ['!false', true], + ['!""', true], ['!0', true], - ['!1', false], + ['!false', true], + ['!NaN', true], ['!null', true], ['!undefined', true], - ['!NaN', true], - ['!""', true], - ['!{}', false], - ['![]', false], - ['+true', 1], - ['+false', 0], - ['+null', 0], - ['+undefined', NaN], - ['+""', 0], - ['+"123"', 123], ['+"-123"', -123], + ['+"123"', 123], + ['+60', 60], + ['+true', 1], + ['~1', -2], + ['~2', -3], + ['typeof "abc"', 'string'], + ['typeof 123', 'number'], + + // react doesn't render `false` + ['![]', undefined], + ['!{}', undefined], + ['!1', undefined], + ['!true', undefined], + ['+""', undefined], + ['+false', undefined], + ['+null', undefined], + ['+undefined', undefined], ] test.each(testCases)( 'should evaluate unary %s correctly', - ({ operation, expected }) => { + (operation, expected) => { + console.log('operation', operation) const { instance } = render() if (Number.isNaN(expected)) { expect(Number.isNaN(instance.ParsedChildren[0])).toBe(true) @@ -1192,13 +1199,13 @@ describe('JsxParser Component', () => { jsx={` {outer => <> -

Outer ({outer.id}): {outer.name}

- - {inner => <> +

Outer ({outer.id}): {outer.name}

+ + {inner => <>

Inner ({inner.id}): {inner.name}

{outer.id} > {outer.name}
} -
+
}
`} diff --git a/source/components/JsxParser.tsx b/source/components/JsxParser.tsx index 2c3a3a7..50065c0 100644 --- a/source/components/JsxParser.tsx +++ b/source/components/JsxParser.tsx @@ -250,6 +250,8 @@ export default class JsxParser extends React.Component { case '+': return +unaryValue case '-': return -unaryValue case '!': return !unaryValue + case '~': return ~unaryValue // eslint-disable-line no-bitwise + case 'typeof': return typeof unaryValue } return undefined case 'ArrowFunctionExpression': From a118235a022feda2a8adf5523353ddd260af6574 Mon Sep 17 00:00:00 2001 From: Troy Alford Date: Thu, 18 Sep 2025 22:48:29 -0700 Subject: [PATCH 3/4] Fix error handling and add renderError test - Move error handling logic before parsing to prevent execution on parse errors - Add test coverage for renderError prop functionality - Remove describe.only from unary operations test suite --- source/components/JsxParser.test.tsx | 15 ++++++++++++++- source/components/JsxParser.tsx | 7 ++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/source/components/JsxParser.test.tsx b/source/components/JsxParser.test.tsx index aedf6cf..1e41c10 100644 --- a/source/components/JsxParser.test.tsx +++ b/source/components/JsxParser.test.tsx @@ -114,7 +114,7 @@ describe('JsxParser Component', () => { }) }) - describe.only('unary operations', () => { + describe('unary operations', () => { const testCases = [ ['-60', -60], ['!""', true], @@ -1045,6 +1045,19 @@ describe('JsxParser Component', () => { expect(() => render( { throw e }} />)).toThrow() expect(() => render( { throw e }} />)).toThrow() }) + + test('renderError catches errors', () => { + const renderError = jest.fn((...args) => console.error(...args)) + render( + , + ) + expect(renderError).toHaveBeenCalledWith({ error: 'Error: Test error' }) + }) + test('supports className prop', () => { const { node } = render() expect(node.classList.contains('foo')).toBeTruthy() diff --git a/source/components/JsxParser.tsx b/source/components/JsxParser.tsx index 50065c0..8902e8f 100644 --- a/source/components/JsxParser.tsx +++ b/source/components/JsxParser.tsx @@ -127,16 +127,13 @@ export default class JsxParser extends React.Component { parsed = parser.parse(wrappedJsx, { ecmaVersion: 'latest' }) // @ts-ignore - AcornJsx doesn't have typescript typings parsed = parsed.body[0].expression.children || [] + return parsed.map(p => this.#parseExpression(p)).filter(Boolean) } catch (error) { if (this.props.showWarnings) console.warn(error) // eslint-disable-line no-console if (this.props.onError) this.props.onError(error as Error) - if (this.props.renderError) { - return this.props.renderError({ error: String(error) }) - } + if (this.props.renderError) return this.props.renderError({ error: String(error) }) return null } - - return parsed.map(p => this.#parseExpression(p)).filter(Boolean) } /** From f1608877958de66d03c8c0895e4d2a1c3ea8880d Mon Sep 17 00:00:00 2001 From: Troy Alford Date: Thu, 18 Sep 2025 22:49:58 -0700 Subject: [PATCH 4/4] bump bun to latest --- .tool-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tool-versions b/.tool-versions index 80d00ee..4c1f215 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -bun 1.2.1 \ No newline at end of file +bun 1.2.22