preact-render-to-string 6.0.0-experimental.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/jsx.d.ts CHANGED
@@ -3,11 +3,19 @@ import { VNode } from 'preact';
3
3
  interface Options {
4
4
  jsx?: boolean;
5
5
  xml?: boolean;
6
+ pretty?: boolean | string;
7
+ shallow?: boolean;
6
8
  functions?: boolean;
7
9
  functionNames?: boolean;
8
10
  skipFalseAttributes?: boolean;
9
- pretty?: boolean | string;
10
11
  }
11
12
 
12
- export function render(vnode: VNode, context?: any, options?: Options): string;
13
+ export default function renderToStringPretty(
14
+ vnode: VNode,
15
+ context?: any,
16
+ options?: Options
17
+ ): string;
18
+
19
+ export function shallowRender(vnode: VNode, context?: any): string;
20
+
13
21
  export default render;
package/src/jsx.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import './polyfills';
2
- import renderToString from './index';
3
- import { indent, encodeEntities, assign } from './util';
2
+ import renderToString from './pretty';
3
+ import { indent, encodeEntities } from './util';
4
4
  import prettyFormat from 'pretty-format';
5
5
 
6
+ /** @typedef {import('preact').VNode} VNode */
7
+
6
8
  // we have to patch in Array support, Possible issue in npm.im/pretty-format
7
9
  let preactPlugin = {
8
10
  test(object) {
@@ -67,10 +69,36 @@ let defaultOpts = {
67
69
  pretty: ' '
68
70
  };
69
71
 
70
- function renderToJsxString(vnode, context, opts, inner) {
71
- opts = assign(assign({}, defaultOpts), opts || {});
72
- return renderToString(vnode, context, opts, inner);
72
+ /**
73
+ * Render Preact JSX + Components to a pretty-printed HTML-like string.
74
+ * @param {VNode} vnode JSX Element / VNode to render
75
+ * @param {Object} [context={}] Initial root context object
76
+ * @param {Object} [options={}] Rendering options
77
+ * @param {Boolean} [options.jsx=true] Generate JSX/XML output instead of HTML
78
+ * @param {Boolean} [options.xml=false] Use self-closing tags for elements without children
79
+ * @param {Boolean} [options.shallow=false] Serialize nested Components (`<Foo a="b" />`) instead of rendering
80
+ * @param {Boolean} [options.pretty=false] Add whitespace for readability
81
+ * @param {RegExp|undefined} [options.voidElements] RegeEx to define which element types are self-closing
82
+ * @returns {String} a pretty-printed HTML-like string
83
+ */
84
+ export default function renderToStringPretty(vnode, context, options) {
85
+ const opts = Object.assign({}, defaultOpts, options || {});
86
+ if (!opts.jsx) opts.attributeHook = null;
87
+ return renderToString(vnode, context, opts);
73
88
  }
89
+ export { renderToStringPretty as render };
90
+
91
+ const SHALLOW = { shallow: true };
74
92
 
75
- export default renderToJsxString;
76
- export { renderToJsxString as render };
93
+ /** Only render elements, leaving Components inline as `<ComponentName ... />`.
94
+ * This method is just a convenience alias for `render(vnode, context, { shallow:true })`
95
+ * @name shallow
96
+ * @function
97
+ * @param {VNode} vnode JSX VNode to render.
98
+ * @param {Object} [context={}] Optionally pass an initial context object through the render path.
99
+ * @param {Parameters<typeof renderToStringPretty>[2]} [options] Optionally pass an initial context object through the render path.
100
+ */
101
+ export function shallowRender(vnode, context, options) {
102
+ const opts = Object.assign({}, SHALLOW, options || {});
103
+ return renderToStringPretty(vnode, context, opts);
104
+ }
package/src/pretty.js ADDED
@@ -0,0 +1,433 @@
1
+ import {
2
+ encodeEntities,
3
+ indent,
4
+ isLargeString,
5
+ styleObjToCss,
6
+ getChildren,
7
+ createComponent,
8
+ UNSAFE_NAME,
9
+ XLINK,
10
+ VOID_ELEMENTS
11
+ } from './util';
12
+ import { COMMIT, DIFF, DIFFED, RENDER, SKIP_EFFECTS } from './constants';
13
+ import { options, Fragment } from 'preact';
14
+
15
+ /** @typedef {import('preact').VNode} VNode */
16
+
17
+ // components without names, kept as a hash for later comparison to return consistent UnnamedComponentXX names.
18
+ const UNNAMED = [];
19
+
20
+ const EMPTY_ARR = [];
21
+
22
+ /**
23
+ * Render Preact JSX + Components to a pretty-printed HTML-like string.
24
+ * @param {VNode} vnode JSX Element / VNode to render
25
+ * @param {Object} [context={}] Initial root context object
26
+ * @param {Object} [opts={}] Rendering options
27
+ * @param {Boolean} [opts.shallow=false] Serialize nested Components (`<Foo a="b" />`) instead of rendering
28
+ * @param {Boolean} [opts.xml=false] Use self-closing tags for elements without children
29
+ * @param {Boolean} [opts.pretty=false] Add whitespace for readability
30
+ * @param {RegExp|undefined} [opts.voidElements] RegeEx to define which element types are self-closing
31
+ * @param {boolean} [_inner]
32
+ * @returns {String} a pretty-printed HTML-like string
33
+ */
34
+ export default function renderToStringPretty(vnode, context, opts, _inner) {
35
+ // Performance optimization: `renderToString` is synchronous and we
36
+ // therefore don't execute any effects. To do that we pass an empty
37
+ // array to `options._commit` (`__c`). But we can go one step further
38
+ // and avoid a lot of dirty checks and allocations by setting
39
+ // `options._skipEffects` (`__s`) too.
40
+ const previousSkipEffects = options[SKIP_EFFECTS];
41
+ options[SKIP_EFFECTS] = true;
42
+
43
+ try {
44
+ return _renderToStringPretty(vnode, context || {}, opts, _inner);
45
+ } finally {
46
+ // options._commit, we don't schedule any effects in this library right now,
47
+ // so we can pass an empty queue to this hook.
48
+ if (options[COMMIT]) options[COMMIT](vnode, EMPTY_ARR);
49
+ options[SKIP_EFFECTS] = previousSkipEffects;
50
+ EMPTY_ARR.length = 0;
51
+ }
52
+ }
53
+
54
+ function _renderToStringPretty(
55
+ vnode,
56
+ context,
57
+ opts,
58
+ inner,
59
+ isSvgMode,
60
+ selectValue
61
+ ) {
62
+ if (vnode == null || typeof vnode === 'boolean') {
63
+ return '';
64
+ }
65
+
66
+ // #text nodes
67
+ if (typeof vnode !== 'object') {
68
+ if (typeof vnode === 'function') return '';
69
+ return encodeEntities(vnode + '');
70
+ }
71
+
72
+ let pretty = opts.pretty,
73
+ indentChar = pretty && typeof pretty === 'string' ? pretty : '\t';
74
+
75
+ if (Array.isArray(vnode)) {
76
+ let rendered = '';
77
+ for (let i = 0; i < vnode.length; i++) {
78
+ if (pretty && i > 0) rendered = rendered + '\n';
79
+ rendered =
80
+ rendered +
81
+ _renderToStringPretty(
82
+ vnode[i],
83
+ context,
84
+ opts,
85
+ inner,
86
+ isSvgMode,
87
+ selectValue
88
+ );
89
+ }
90
+ return rendered;
91
+ }
92
+
93
+ // VNodes have {constructor:undefined} to prevent JSON injection:
94
+ if (vnode.constructor !== undefined) return '';
95
+
96
+ if (options[DIFF]) options[DIFF](vnode);
97
+
98
+ let nodeName = vnode.type,
99
+ props = vnode.props,
100
+ isComponent = false;
101
+
102
+ // components
103
+ if (typeof nodeName === 'function') {
104
+ isComponent = true;
105
+ if (opts.shallow && (inner || opts.renderRootComponent === false)) {
106
+ nodeName = getComponentName(nodeName);
107
+ } else if (nodeName === Fragment) {
108
+ const children = [];
109
+ getChildren(children, vnode.props.children);
110
+ return _renderToStringPretty(
111
+ children,
112
+ context,
113
+ opts,
114
+ opts.shallowHighOrder !== false,
115
+ isSvgMode,
116
+ selectValue
117
+ );
118
+ } else {
119
+ let rendered;
120
+
121
+ let c = (vnode.__c = createComponent(vnode, context));
122
+
123
+ let renderHook = options[RENDER];
124
+
125
+ let cctx = context;
126
+ let cxType = nodeName.contextType;
127
+ if (cxType != null) {
128
+ let provider = context[cxType.__c];
129
+ cctx = provider ? provider.props.value : cxType.__;
130
+ }
131
+
132
+ if (
133
+ !nodeName.prototype ||
134
+ typeof nodeName.prototype.render !== 'function'
135
+ ) {
136
+
137
+ // If a hook invokes setState() to invalidate the component during rendering,
138
+ // re-render it up to 25 times to allow "settling" of memoized states.
139
+ // Note:
140
+ // This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
141
+ // https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
142
+ let count = 0;
143
+ while (c.__d && count++ < 25) {
144
+ c.__d = false;
145
+
146
+ if (renderHook) renderHook(vnode);
147
+
148
+ // stateless functional components
149
+ rendered = nodeName.call(vnode.__c, props, cctx);
150
+ }
151
+ } else {
152
+
153
+ // c = new nodeName(props, context);
154
+ c = vnode.__c = new nodeName(props, cctx);
155
+ c.__v = vnode;
156
+ // turn off stateful re-rendering:
157
+ c._dirty = c.__d = true;
158
+ c.props = props;
159
+ if (c.state == null) c.state = {};
160
+
161
+ if (c._nextState == null && c.__s == null) {
162
+ c._nextState = c.__s = c.state;
163
+ }
164
+
165
+ c.context = cctx;
166
+ if (nodeName.getDerivedStateFromProps)
167
+ c.state = Object.assign(
168
+ {},
169
+ c.state,
170
+ nodeName.getDerivedStateFromProps(c.props, c.state)
171
+ );
172
+ else if (c.componentWillMount) {
173
+ c.componentWillMount();
174
+
175
+ // If the user called setState in cWM we need to flush pending,
176
+ // state updates. This is the same behaviour in React.
177
+ c.state =
178
+ c._nextState !== c.state
179
+ ? c._nextState
180
+ : c.__s !== c.state
181
+ ? c.__s
182
+ : c.state;
183
+ }
184
+
185
+ if (renderHook) renderHook(vnode);
186
+
187
+ rendered = c.render(c.props, c.state, c.context);
188
+ }
189
+
190
+ if (c.getChildContext) {
191
+ context = Object.assign({}, context, c.getChildContext());
192
+ }
193
+
194
+ const res = _renderToStringPretty(
195
+ rendered,
196
+ context,
197
+ opts,
198
+ opts.shallowHighOrder !== false,
199
+ isSvgMode,
200
+ selectValue
201
+ );
202
+
203
+ if (options[DIFFED]) options[DIFFED](vnode);
204
+
205
+ return res;
206
+ }
207
+ }
208
+
209
+ // render JSX to HTML
210
+ let s = '<' + nodeName,
211
+ propChildren,
212
+ html;
213
+
214
+ if (props) {
215
+ let attrs = Object.keys(props);
216
+
217
+ // allow sorting lexicographically for more determinism (useful for tests, such as via preact-jsx-chai)
218
+ if (opts && opts.sortAttributes === true) attrs.sort();
219
+
220
+ for (let i = 0; i < attrs.length; i++) {
221
+ let name = attrs[i],
222
+ v = props[name];
223
+ if (name === 'children') {
224
+ propChildren = v;
225
+ continue;
226
+ }
227
+
228
+ if (UNSAFE_NAME.test(name)) continue;
229
+
230
+ if (
231
+ !(opts && opts.allAttributes) &&
232
+ (name === 'key' ||
233
+ name === 'ref' ||
234
+ name === '__self' ||
235
+ name === '__source')
236
+ )
237
+ continue;
238
+
239
+ if (name === 'defaultValue') {
240
+ name = 'value';
241
+ } else if (name === 'defaultChecked') {
242
+ name = 'checked';
243
+ } else if (name === 'defaultSelected') {
244
+ name = 'selected';
245
+ } else if (name === 'className') {
246
+ if (typeof props.class !== 'undefined') continue;
247
+ name = 'class';
248
+ } else if (isSvgMode && XLINK.test(name)) {
249
+ name = name.toLowerCase().replace(/^xlink:?/, 'xlink:');
250
+ }
251
+
252
+ if (name === 'htmlFor') {
253
+ if (props.for) continue;
254
+ name = 'for';
255
+ }
256
+
257
+ if (name === 'style' && v && typeof v === 'object') {
258
+ v = styleObjToCss(v);
259
+ }
260
+
261
+ // always use string values instead of booleans for aria attributes
262
+ // also see https://github.com/preactjs/preact/pull/2347/files
263
+ if (name[0] === 'a' && name['1'] === 'r' && typeof v === 'boolean') {
264
+ v = String(v);
265
+ }
266
+
267
+ let hooked =
268
+ opts.attributeHook &&
269
+ opts.attributeHook(name, v, context, opts, isComponent);
270
+ if (hooked || hooked === '') {
271
+ s = s + hooked;
272
+ continue;
273
+ }
274
+
275
+ if (name === 'dangerouslySetInnerHTML') {
276
+ html = v && v.__html;
277
+ } else if (nodeName === 'textarea' && name === 'value') {
278
+ // <textarea value="a&b"> --> <textarea>a&amp;b</textarea>
279
+ propChildren = v;
280
+ } else if ((v || v === 0 || v === '') && typeof v !== 'function') {
281
+ if (v === true || v === '') {
282
+ v = name;
283
+ // in non-xml mode, allow boolean attributes
284
+ if (!opts || !opts.xml) {
285
+ s = s + ' ' + name;
286
+ continue;
287
+ }
288
+ }
289
+
290
+ if (name === 'value') {
291
+ if (nodeName === 'select') {
292
+ selectValue = v;
293
+ continue;
294
+ } else if (
295
+ // If we're looking at an <option> and it's the currently selected one
296
+ nodeName === 'option' &&
297
+ selectValue == v &&
298
+ // and the <option> doesn't already have a selected attribute on it
299
+ typeof props.selected === 'undefined'
300
+ ) {
301
+ s = s + ` selected`;
302
+ }
303
+ }
304
+ s = s + ` ${name}="${encodeEntities(v + '')}"`;
305
+ }
306
+ }
307
+ }
308
+
309
+ // account for >1 multiline attribute
310
+ if (pretty) {
311
+ let sub = s.replace(/\n\s*/, ' ');
312
+ if (sub !== s && !~sub.indexOf('\n')) s = sub;
313
+ else if (pretty && ~s.indexOf('\n')) s = s + '\n';
314
+ }
315
+
316
+ s = s + '>';
317
+
318
+ if (UNSAFE_NAME.test(nodeName))
319
+ throw new Error(`${nodeName} is not a valid HTML tag name in ${s}`);
320
+
321
+ let isVoid =
322
+ VOID_ELEMENTS.test(nodeName) ||
323
+ (opts.voidElements && opts.voidElements.test(nodeName));
324
+ let pieces = [];
325
+
326
+ let children;
327
+ if (html) {
328
+ // if multiline, indent.
329
+ if (pretty && isLargeString(html)) {
330
+ html = '\n' + indentChar + indent(html, indentChar);
331
+ }
332
+ s = s + html;
333
+ } else if (
334
+ propChildren != null &&
335
+ getChildren((children = []), propChildren).length
336
+ ) {
337
+ let hasLarge = pretty && ~s.indexOf('\n');
338
+ let lastWasText = false;
339
+
340
+ for (let i = 0; i < children.length; i++) {
341
+ let child = children[i];
342
+
343
+ if (child != null && child !== false) {
344
+ let childSvgMode =
345
+ nodeName === 'svg'
346
+ ? true
347
+ : nodeName === 'foreignObject'
348
+ ? false
349
+ : isSvgMode,
350
+ ret = _renderToStringPretty(
351
+ child,
352
+ context,
353
+ opts,
354
+ true,
355
+ childSvgMode,
356
+ selectValue
357
+ );
358
+
359
+ if (pretty && !hasLarge && isLargeString(ret)) hasLarge = true;
360
+
361
+ // Skip if we received an empty string
362
+ if (ret) {
363
+ if (pretty) {
364
+ let isText = ret.length > 0 && ret[0] != '<';
365
+
366
+ // We merge adjacent text nodes, otherwise each piece would be printed
367
+ // on a new line.
368
+ if (lastWasText && isText) {
369
+ pieces[pieces.length - 1] += ret;
370
+ } else {
371
+ pieces.push(ret);
372
+ }
373
+
374
+ lastWasText = isText;
375
+ } else {
376
+ pieces.push(ret);
377
+ }
378
+ }
379
+ }
380
+ }
381
+ if (pretty && hasLarge) {
382
+ for (let i = pieces.length; i--; ) {
383
+ pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar);
384
+ }
385
+ }
386
+ }
387
+
388
+ if (options[DIFFED]) options[DIFFED](vnode);
389
+
390
+ if (pieces.length || html) {
391
+ s = s + pieces.join('');
392
+ } else if (opts && opts.xml) {
393
+ return s.substring(0, s.length - 1) + ' />';
394
+ }
395
+
396
+ if (isVoid && !children && !html) {
397
+ s = s.replace(/>$/, ' />');
398
+ } else {
399
+ if (pretty && ~s.indexOf('\n')) s = s + '\n';
400
+ s = s + `</${nodeName}>`;
401
+ }
402
+
403
+ return s;
404
+ }
405
+
406
+ function getComponentName(component) {
407
+ return (
408
+ component.displayName ||
409
+ (component !== Function && component.name) ||
410
+ getFallbackComponentName(component)
411
+ );
412
+ }
413
+
414
+ function getFallbackComponentName(component) {
415
+ let str = Function.prototype.toString.call(component),
416
+ name = (str.match(/^\s*function\s+([^( ]+)/) || '')[1];
417
+ if (!name) {
418
+ // search for an existing indexed name for the given component:
419
+ let index = -1;
420
+ for (let i = UNNAMED.length; i--; ) {
421
+ if (UNNAMED[i] === component) {
422
+ index = i;
423
+ break;
424
+ }
425
+ }
426
+ // not found, create a new indexed name:
427
+ if (index < 0) {
428
+ index = UNNAMED.push(component) - 1;
429
+ }
430
+ name = `UnnamedComponent${index}`;
431
+ }
432
+ return name;
433
+ }
package/src/util.js CHANGED
@@ -1,18 +1,43 @@
1
+ export const VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/;
2
+ export const UNSAFE_NAME = /[\s\n\\/='"\0<>]/;
3
+ export const XLINK = /^xlink:?./;
4
+
1
5
  // DOM properties that should NOT have "px" added when numeric
2
- export const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|^--/i;
6
+ const ENCODED_ENTITIES = /["&<]/;
7
+
8
+ /** @param {string} str */
9
+ export function encodeEntities(str) {
10
+ // Skip all work for strings with no entities needing encoding:
11
+ if (str.length === 0 || ENCODED_ENTITIES.test(str) === false) return str;
3
12
 
4
- const ENCODED_ENTITIES = /[&<>"]/;
13
+ let last = 0,
14
+ i = 0,
15
+ out = '',
16
+ ch = '';
5
17
 
6
- export function encodeEntities(input) {
7
- const s = String(input);
8
- if (!ENCODED_ENTITIES.test(s)) {
9
- return s;
18
+ // Seek forward in str until the next entity char:
19
+ for (; i < str.length; i++) {
20
+ switch (str.charCodeAt(i)) {
21
+ case 34:
22
+ ch = '&quot;';
23
+ break;
24
+ case 38:
25
+ ch = '&amp;';
26
+ break;
27
+ case 60:
28
+ ch = '&lt;';
29
+ break;
30
+ default:
31
+ continue;
32
+ }
33
+ // Append skipped/buffered characters and the encoded entity:
34
+ if (i !== last) out += str.slice(last, i);
35
+ out += ch;
36
+ // Start the next seek/buffer after the entity's offset:
37
+ last = i + 1;
10
38
  }
11
- return s
12
- .replace(/&/g, '&amp;')
13
- .replace(/</g, '&lt;')
14
- .replace(/>/g, '&gt;')
15
- .replace(/"/g, '&quot;');
39
+ if (i !== last) out += str.slice(last, i);
40
+ return out;
16
41
  }
17
42
 
18
43
  export let indent = (s, char) =>
@@ -25,42 +50,71 @@ export let isLargeString = (s, length, ignoreLines) =>
25
50
 
26
51
  const JS_TO_CSS = {};
27
52
 
53
+ const IS_NON_DIMENSIONAL = new Set([
54
+ 'animation-iteration-count',
55
+ 'border-image-outset',
56
+ 'border-image-slice',
57
+ 'border-image-width',
58
+ 'box-flex',
59
+ 'box-flex-group',
60
+ 'box-ordinal-group',
61
+ 'column-count',
62
+ 'fill-opacity',
63
+ 'flex',
64
+ 'flex-grow',
65
+ 'flex-negative',
66
+ 'flex-order',
67
+ 'flex-positive',
68
+ 'flex-shrink',
69
+ 'flood-opacity',
70
+ 'font-weight',
71
+ 'grid-column',
72
+ 'grid-row',
73
+ 'line-clamp',
74
+ 'line-height',
75
+ 'opacity',
76
+ 'order',
77
+ 'orphans',
78
+ 'stop-opacity',
79
+ 'stroke-dasharray',
80
+ 'stroke-dashoffset',
81
+ 'stroke-miterlimit',
82
+ 'stroke-opacity',
83
+ 'stroke-width',
84
+ 'tab-size',
85
+ 'widows',
86
+ 'z-index',
87
+ 'zoom'
88
+ ]);
89
+
90
+ const CSS_REGEX = /[A-Z]/g;
28
91
  // Convert an Object style to a CSSText string
29
92
  export function styleObjToCss(s) {
30
93
  let str = '';
31
94
  for (let prop in s) {
32
95
  let val = s[prop];
33
96
  if (val != null && val !== '') {
34
- if (str) str += ' ';
35
- // str += jsToCss(prop);
36
- str +=
97
+ const name =
37
98
  prop[0] == '-'
38
99
  ? prop
39
100
  : JS_TO_CSS[prop] ||
40
- (JS_TO_CSS[prop] = prop.replace(/([A-Z])/g, '-$1').toLowerCase());
41
- str += ': ';
42
- str += val;
43
- if (typeof val === 'number' && IS_NON_DIMENSIONAL.test(prop) === false) {
44
- str += 'px';
101
+ (JS_TO_CSS[prop] = prop.replace(CSS_REGEX, '-$&').toLowerCase());
102
+
103
+ let suffix = ';';
104
+ if (
105
+ typeof val === 'number' &&
106
+ // Exclude custom-attributes
107
+ !name.startsWith('--') &&
108
+ !IS_NON_DIMENSIONAL.has(name)
109
+ ) {
110
+ suffix = 'px;';
45
111
  }
46
- str += ';';
112
+ str = str + name + ':' + val + suffix;
47
113
  }
48
114
  }
49
115
  return str || undefined;
50
116
  }
51
117
 
52
- /**
53
- * Copy all properties from `props` onto `obj`.
54
- * @param {object} obj Object onto which properties should be copied.
55
- * @param {object} props Object from which to copy properties.
56
- * @returns {object}
57
- * @private
58
- */
59
- export function assign(obj, props) {
60
- for (let i in props) obj[i] = props[i];
61
- return obj;
62
- }
63
-
64
118
  /**
65
119
  * Get flattened children from the children prop
66
120
  * @param {Array} accumulator
@@ -77,11 +131,20 @@ export function getChildren(accumulator, children) {
77
131
  return accumulator;
78
132
  }
79
133
 
80
- export function createInternalFromVnode(vnode, context) {
134
+ function markAsDirty() {
135
+ this.__d = true;
136
+ }
137
+
138
+ export function createComponent(vnode, context) {
81
139
  return {
82
- type: vnode.type,
140
+ __v: vnode,
141
+ context,
83
142
  props: vnode.props,
84
- data: {},
85
- c: context
143
+ // silently drop state updates
144
+ setState: markAsDirty,
145
+ forceUpdate: markAsDirty,
146
+ __d: true,
147
+ // hooks
148
+ __h: []
86
149
  };
87
150
  }