From e71691a2830ff3bfbbdd8b09485684d65d103925 Mon Sep 17 00:00:00 2001 From: Dakshata Date: Wed, 1 Oct 2025 18:15:38 +0000 Subject: [PATCH 1/3] Fix: render { value: 0 } as 0 in template expressions --- src/parser/parser.test.ts | 6 ++++++ src/parser/parser.ts | 29 ++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/parser/parser.test.ts b/src/parser/parser.test.ts index 7b76039..0684cb3 100644 --- a/src/parser/parser.test.ts +++ b/src/parser/parser.test.ts @@ -205,6 +205,12 @@ describe('Parser', () => { expect(template).toEqual(`
${num}
`); }); + it('renders 0 for { value: 0 } expressions', () => { + const expr = { value: 0 }; + const template = rml`
${expr}
`; + expect(template).toEqual('
0
'); + }); + it('handles -0 as "0"', () => { // Don't ask why, it's a JavaScript quirk const num = -0; diff --git a/src/parser/parser.ts b/src/parser/parser.ts index d6b33af..e92fcb8 100644 --- a/src/parser/parser.ts +++ b/src/parser/parser.ts @@ -68,14 +68,20 @@ const getEventName = (eventAttributeString: RMLEventAttributeName): [RMLEventNam * * `; * }; - * ``` - * - * ## Example - * - * ```ts - * import { rml } from 'rimmel'; - * - * const Component = () => { + if(['string', 'number', 'boolean'].includes(printableExpressionType)) { + acc = accPlusString +(expression ?? ''); + } else if ( + expression && typeof expression === 'object' && + 'value' in expression && + (typeof expression.value === 'string' || typeof expression.value === 'number' || typeof expression.value === 'boolean') + ) { + // Render the value property of objects, including 0 + acc = accPlusString + (expression.value ?? ''); + } else { + //other existing logic for different expression types + } + } + * const data = fetch('/api').then(res => res.text()); * * return rml` @@ -127,8 +133,13 @@ export function rml(strings: TemplateStringsArray, ...expressions: RMLTemplateEx const printableExpressionType = typeof (expression ?? ''); if(['string', 'number', 'boolean'].includes(printableExpressionType)) { - // Static expressions, no data binding. Just concatenate and move on acc = accPlusString +(expression ?? ''); + } else if ( + expression && typeof expression === 'object' && + 'value' in expression && + (typeof expression.value === 'string' || typeof expression.value === 'number' || typeof expression.value === 'boolean') + ) { + acc = accPlusString + (expression.value ?? ''); } else if(eventName) { // Event Source // so feed it to an Rx Subject | Observer | Handler Function | POJO | Array From 47d429bf250eaea79fa9d7e1fa1a57245398c8f8 Mon Sep 17 00:00:00 2001 From: Dakshata Date: Fri, 3 Oct 2025 14:19:35 +0000 Subject: [PATCH 2/3] Fix: handle nullish values in template sinks with ?? operator (maintainer feedback) --- src/parser/parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/parser.ts b/src/parser/parser.ts index e92fcb8..05e7bb7 100644 --- a/src/parser/parser.ts +++ b/src/parser/parser.ts @@ -279,7 +279,7 @@ export function rml(strings: TemplateStringsArray, ...expressions: RMLTemplateEx addRef(ref, isSinkBindingConfiguration(_source) ? _source : InnerHTML(_source)); acc = acc +(existingRef ? string : string.replace(/\s*>\s*$/, ` ${RESOLVE_ATTRIBUTE}="${ref}">`)) - +(initialValue || '') + +(initialValue ?? '') ; } else if(/>?\s*[^<]*$/m.test(string) && /^\s*[^<]*\s* Date: Fri, 3 Oct 2025 14:20:25 +0000 Subject: [PATCH 3/3] test: move .value=0 tests to BehaviorSubject block (maintainer feedback) --- src/parser/parser.test.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/parser/parser.test.ts b/src/parser/parser.test.ts index 0684cb3..ca02078 100644 --- a/src/parser/parser.test.ts +++ b/src/parser/parser.test.ts @@ -564,29 +564,36 @@ describe('Parser', () => { describe('Any sink', () => { describe('When a BehaviorSubject (.value) is passed', () => { - describe('When an implicit sink is used', () => { - it('sets the value inline', () => { const bs = new BehaviorSubject(123) const template = rml`
${bs}
`; - expect(template).toMatch(/123<\/div>/); }); - }); - describe('When an explicit sink is used', () => { - it('sets the value inline', () => { const bs = new BehaviorSubject(123) const template = rml`
${InnerText(bs)}
`; - expect(template).toMatch(/123<\/div>/); }); + }); + describe('Content', () => { + it('renders 0 when an object has a .value of 0', () => { + const zeroValueObject = { value: 0 }; + const template = rml`
${zeroValueObject}
`; + expect(template).toEqual('
0
'); + }); }); + describe('Attributes', () => { + it('renders 0 in an attribute when an object has a .value of 0', () => { + const zeroValueObject = { value: 0 }; + const template = rml``; + expect(template).toEqual(``); + }); + }); }); });