Skip to content

Commit

Permalink
Add support for babel jsx/jsxs/jsxDEV
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinhagemeister committed Mar 4, 2020
1 parent 0aaa855 commit 25ba0f1
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/create-element.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import options from './options';
import { assign } from './util';

/**
* Create an virtual node (used for JSX)
Expand Down Expand Up @@ -82,6 +83,50 @@ export function createVNode(type, props, key, ref) {
return vnode;
}

/**
* Create an virtual node (used for JSX). It's the successor of `createElement`.
* @param {import('./internal').VNode["type"]} type The node name or Component
* constructor for this virtual node
* @param {object | null | undefined} [props] The properties of the virtual node
* @param {string | undefined} [key] Optional key
* @param {boolean} [isStaticChildren] Marks if `jsx` or `jsxs` should be used.
* For us they are the same thing as our debug warnings live in a separate
* module (`preact/debug`). Only available via `jsxDEV`
* @param {import('./internal').DevSource} [source] Optional source location
* info from babel. Only available via `jsxDEV`
* @param {import('./internal').DevSource} [self] Optional reference to the
* component this node is part of. Only available via `jsxDEV`
* @returns {import('./internal').VNode}
*/
export function jsx(type, props, key, isStaticChildren, source, self) {
let normalizedProps = assign({}, props),
i;

// If a Component VNode, check for and apply defaultProps
// Note: type may be undefined in development, must never error here.
if (typeof type === 'function' && type.defaultProps != null) {
for (i in type.defaultProps) {
if (normalizedProps[i] === undefined) {
normalizedProps[i] = type.defaultProps[i];
}
}
}

const vnode = createVNode(type, normalizedProps, key, props && props.ref);

// TODO: Should this be inlined into `createVNode`?
vnode.__source = source;
vnode.__self = self;
return vnode;
}

// The difference between `jsxs` and `jsx` is that the former is used by babel
// when the node has more than one child
export const jsxs = jsx;

// Same as `jsx`, but with supplied `source` and `self` information
export const jsxDEV = jsx;

export function createRef() {
return {};
}
Expand Down
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ export { render, hydrate } from './render';
export {
createElement,
createElement as h,
jsx,
jsxs,
jsxDEV,
Fragment,
createRef,
isValidElement
Expand Down
5 changes: 5 additions & 0 deletions src/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,8 @@ export interface PreactContext extends preact.Context<any> {
_id: string;
_defaultValue: any;
}

export interface DevSource {
fileName: string;
lineNumber: number;
}
38 changes: 38 additions & 0 deletions test/browser/babel-jsx.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { jsx } from 'preact';
import { setupScratch, teardown } from '../_util/helpers';

describe('Babel jsx/jsxDEV', () => {
let scratch;

beforeEach(() => {
scratch = setupScratch();
});

afterEach(() => {
teardown(scratch);
});

it('should keep ref in props', () => {
const ref = () => null;
const vnode = jsx('div', { ref });
expect(vnode.props.ref).to.equal(ref);
expect(vnode.ref).to.equal(ref);
});

it('should add keys', () => {
const vnode = jsx('div', null, 'foo');
expect(vnode.props.key).to.equal(undefined);
expect(vnode.key).to.equal('foo');
});

it('should support source and self', () => {
const self = 'foo';
const source = {
fileName: '/foo.js',
lineNumber: 2
};
const vnode = jsx('div', null, 'foo', false, source, self);
expect(vnode.__source).to.equal(source);
expect(vnode.__self).to.equal(self);
});
});

0 comments on commit 25ba0f1

Please sign in to comment.