diff --git a/jsx.d.ts b/jsx.d.ts index 90042308..25131e32 100644 --- a/jsx.d.ts +++ b/jsx.d.ts @@ -8,6 +8,7 @@ interface Options { functions?: boolean; functionNames?: boolean; skipFalseAttributes?: boolean; + attributeHook?: (name: string) => string; } export default function renderToStringPretty( diff --git a/src/index.d.ts b/src/index.d.ts index 728d13dd..7a65cd7b 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,27 +1,25 @@ import { VNode } from 'preact'; -interface RenderOptions { - attrHook?: (name: string) => string; +interface Options { + attributeHook?: (name: string) => string; } export default function renderToString( vnode: VNode, context?: any, - renderOpts?: RenderOptions + options?: Options ): string; -export function render( - vnode: VNode, - context?: any, - renderOpts?: RenderOptions -): string; +export function render(vnode: VNode, context?: any, options?: Options): string; + export function renderToString( vnode: VNode, context?: any, - renderOpts?: RenderOptions + options?: Options ): string; + export function renderToStaticMarkup( vnode: VNode, context?: any, - renderOpts?: RenderOptions + options?: Options ): string; diff --git a/src/index.js b/src/index.js index 4ce64d24..99ef1662 100644 --- a/src/index.js +++ b/src/index.js @@ -21,7 +21,7 @@ const isArray = Array.isArray; const assign = Object.assign; // Global state for the current render pass -let beforeDiff, afterDiff, renderHook, ummountHook, attrHook; +let beforeDiff, afterDiff, renderHook, ummountHook, attributeHook; /** * Render Preact JSX + Components to an HTML string. @@ -29,7 +29,7 @@ let beforeDiff, afterDiff, renderHook, ummountHook, attrHook; * @param {Object} [context={}] Initial root context object * @returns {string} serialized HTML */ -export function renderToString(vnode, context, renderOpts) { +export function renderToString(vnode, context, opts) { // Performance optimization: `renderToString` is synchronous and we // therefore don't execute any effects. To do that we pass an empty // array to `options._commit` (`__c`). But we can go one step further @@ -43,7 +43,7 @@ export function renderToString(vnode, context, renderOpts) { afterDiff = options[DIFFED]; renderHook = options[RENDER]; ummountHook = options.unmount; - attrHook = renderOpts?.attrHook; + attributeHook = opts && opts.attributeHook; const parent = h(Fragment, null); parent[CHILDREN] = [vnode]; @@ -400,7 +400,7 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) { } } - if (attrHook) name = attrHook(name); + if (attributeHook) name = attributeHook(name); // write this attribute to the buffer if (v != null && v !== false && typeof v !== 'function') { diff --git a/src/jsx.d.ts b/src/jsx.d.ts index 752f3e55..9b79cd4e 100644 --- a/src/jsx.d.ts +++ b/src/jsx.d.ts @@ -8,6 +8,7 @@ interface Options { functions?: boolean; functionNames?: boolean; skipFalseAttributes?: boolean; + attributeHook?: (name: string) => string; } export default function renderToStringPretty( @@ -15,6 +16,7 @@ export default function renderToStringPretty( context?: any, options?: Options ): string; + export function render(vnode: VNode, context?: any, options?: Options): string; export function shallowRender( diff --git a/src/jsx.js b/src/jsx.js index 6007311a..c16e259b 100644 --- a/src/jsx.js +++ b/src/jsx.js @@ -25,7 +25,7 @@ let prettyFormatOpts = { plugins: [preactPlugin] }; -function attributeHook(name, value, context, opts, isComponent) { +function jsxAttributeHook(name, value, context, opts, isComponent) { let type = typeof value; // Use render-to-string's built-in handling for these properties @@ -60,7 +60,7 @@ function attributeHook(name, value, context, opts, isComponent) { } let defaultOpts = { - attributeHook, + jsxAttributeHook, jsx: true, xml: false, functions: true, @@ -83,7 +83,7 @@ let defaultOpts = { */ export default function renderToStringPretty(vnode, context, options) { const opts = Object.assign({}, defaultOpts, options || {}); - if (!opts.jsx) opts.attributeHook = null; + if (!opts.jsx || opts.attributeHook) opts.jsxAttributeHook = null; return renderToString(vnode, context, opts); } export { renderToStringPretty as render }; diff --git a/src/pretty.js b/src/pretty.js index 4e37d92c..7c0c00aa 100644 --- a/src/pretty.js +++ b/src/pretty.js @@ -209,6 +209,8 @@ function _renderToStringPretty( propChildren, html; + const attributeHook = opts && opts.attributeHook; + if (props) { let attrs = Object.keys(props); @@ -263,8 +265,8 @@ function _renderToStringPretty( } let hooked = - opts.attributeHook && - opts.attributeHook(name, v, context, opts, isComponent); + opts.jsxAttributeHook && + opts.jsxAttributeHook(name, v, context, opts, isComponent); if (hooked || hooked === '') { s = s + hooked; continue; @@ -280,6 +282,7 @@ function _renderToStringPretty( v = name; // in non-xml mode, allow boolean attributes if (!opts || !opts.xml) { + if (attributeHook) name = attributeHook(name); s = s + ' ' + name; continue; } @@ -299,6 +302,7 @@ function _renderToStringPretty( s = s + ` selected`; } } + if (attributeHook) name = attributeHook(name); s = s + ` ${name}="${encodeEntities(v + '')}"`; } } diff --git a/test/pretty.test.js b/test/pretty.test.js index 7d6ecd1a..792e0f94 100644 --- a/test/pretty.test.js +++ b/test/pretty.test.js @@ -5,7 +5,7 @@ import { expect } from 'chai'; import { dedent } from './utils.js'; describe('pretty', () => { - let prettyRender = (jsx) => render(jsx, {}, { pretty: true }); + let prettyRender = (jsx, opts) => render(jsx, {}, { pretty: true, ...opts }); it('should render no whitespace by default', () => { let rendered = basicRender( @@ -196,4 +196,44 @@ describe('pretty', () => { it('should not render function children', () => { expect(prettyRender(