Skip to content

Commit

Permalink
Finalize jsx precompile support
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinhagemeister committed Oct 31, 2023
1 parent 6b719a8 commit d1713fe
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 5 deletions.
7 changes: 6 additions & 1 deletion jsx-runtime/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,14 @@ function jsxTemplate(templates, ...exprs) {
* JSX transform
* @param {string} name The attribute name
* @param {*} value The attribute value
* @returns {string | null}
* @returns {string}
*/
function jsxAttr(name, value) {
if (options.attr) {
const result = options.attr(name, value);
if (typeof result === 'string') return result;
}

if (name === 'ref' || name === 'key') return '';

if (
Expand Down
30 changes: 26 additions & 4 deletions jsx-runtime/test/browser/jsx-runtime.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, createElement, createRef } from 'preact';
import { Component, createElement, createRef, options } from 'preact';
import {
jsx,
jsxs,
Expand Down Expand Up @@ -110,14 +110,24 @@ describe('encodeEntities', () => {

describe('precompiled JSX', () => {
describe('jsxAttr', () => {
beforeEach(() => {
options.attr = undefined;
});

afterEach(() => {
options.attr = undefined;
});

it('should render simple values', () => {
expect(jsxAttr('foo', 'bar')).to.equal('foo="bar"');
expect(jsxAttr('foo', "&<'")).to.equal('foo="&amp;&lt;\'"');
});

// Boolean attributes
it('should render boolean values', () => {
expect(jsxAttr('foo', true)).to.equal('foo');
expect(jsxAttr('foo', false)).to.equal('');
});

// Invalid values
it('should ignore invalid values', () => {
expect(jsxAttr('foo', false)).to.equal('');
expect(jsxAttr('foo', null)).to.equal('');
expect(jsxAttr('foo', undefined)).to.equal('');
Expand All @@ -126,6 +136,18 @@ describe('precompiled JSX', () => {
expect(jsxAttr('key', 'foo')).to.equal('');
expect(jsxAttr('ref', 'foo')).to.equal('');
});

it('should escape values', () => {
expect(jsxAttr('foo', "&<'")).to.equal('foo="&amp;&lt;\'"');
});

it('should call options.attr()', () => {
options.attr = (name, value) => {
return `data-${name}="foo${value}"`;
};

expect(jsxAttr('foo', 'bar')).to.equal('data-foo="foobar"');
});
});

describe('jsxTemplate', () => {
Expand Down
6 changes: 6 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,12 @@ export interface Options {
_addHookName?(name: string | number): void;
__suspenseDidResolve?(vnode: VNode, cb: () => void): void;
// __canSuspenseResolve?(vnode: VNode, cb: () => void): void;

/**
* Customize attribute serialization when a precompiled JSX transform
* is used.
*/
attr?(name: string, value: any): string | void;
}

export const options: Options;
Expand Down

0 comments on commit d1713fe

Please sign in to comment.