preact-render-to-string 5.2.6 → 6.0.0
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/LICENSE +21 -21
- package/README.md +147 -91
- package/dist/commonjs.js +1 -1
- package/dist/commonjs.js.map +1 -1
- package/dist/index.d.ts +3 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.module.js +1 -1
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/internal.d.ts +38 -0
- package/dist/jsx-entry.js +1 -1
- package/dist/jsx-entry.js.map +1 -1
- package/dist/jsx.d.ts +21 -13
- package/dist/jsx.js.map +1 -1
- package/dist/jsx.mjs +1 -1
- package/dist/jsx.mjs.map +1 -0
- package/dist/jsx.module.js +1 -1
- package/dist/jsx.module.js.map +1 -1
- package/dist/jsx.umd.js +2 -0
- package/dist/jsx.umd.js.map +1 -0
- package/dist/preact-render-to-string-tests.d.ts +1 -1
- package/jsx.js +1 -1
- package/package.json +152 -149
- package/src/constants.js +16 -16
- package/src/index.d.ts +3 -16
- package/src/index.js +381 -457
- package/src/jsx.d.ts +21 -13
- package/src/jsx.js +104 -76
- package/src/polyfills.js +8 -8
- package/src/preact-render-to-string-tests.d.ts +1 -1
- package/src/pretty.js +433 -389
- package/src/util.js +150 -125
- package/typings.json +5 -5
- package/dist/jsx.modern.js +0 -2
- package/dist/jsx.modern.js.map +0 -1
package/src/index.js
CHANGED
|
@@ -1,457 +1,381 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
name
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
let hasChildren = false;
|
|
383
|
-
|
|
384
|
-
if (html) {
|
|
385
|
-
pieces = pieces + html;
|
|
386
|
-
hasChildren = true;
|
|
387
|
-
} else if (typeof children === 'string') {
|
|
388
|
-
pieces = pieces + encodeEntities(children);
|
|
389
|
-
hasChildren = true;
|
|
390
|
-
} else if (isArray(children)) {
|
|
391
|
-
vnode[CHILDREN] = children;
|
|
392
|
-
for (let i = 0; i < children.length; i++) {
|
|
393
|
-
let child = children[i];
|
|
394
|
-
children[i] = normalizeVNode(child);
|
|
395
|
-
|
|
396
|
-
if (child != null && child !== false) {
|
|
397
|
-
let childSvgMode =
|
|
398
|
-
type === 'svg' || (type !== 'foreignObject' && isSvgMode);
|
|
399
|
-
let ret = _renderToString(
|
|
400
|
-
child,
|
|
401
|
-
context,
|
|
402
|
-
childSvgMode,
|
|
403
|
-
selectValue,
|
|
404
|
-
vnode
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
// Skip if we received an empty string
|
|
408
|
-
if (ret) {
|
|
409
|
-
pieces = pieces + ret;
|
|
410
|
-
hasChildren = true;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
} else if (children != null && children !== false && children !== true) {
|
|
415
|
-
vnode[CHILDREN] = [normalizeVNode(children)];
|
|
416
|
-
let childSvgMode =
|
|
417
|
-
type === 'svg' || (type !== 'foreignObject' && isSvgMode);
|
|
418
|
-
let ret = _renderToString(
|
|
419
|
-
children,
|
|
420
|
-
context,
|
|
421
|
-
childSvgMode,
|
|
422
|
-
selectValue,
|
|
423
|
-
vnode
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
// Skip if we received an empty string
|
|
427
|
-
if (ret) {
|
|
428
|
-
pieces = pieces + ret;
|
|
429
|
-
hasChildren = true;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
if (options[DIFFED]) options[DIFFED](vnode);
|
|
434
|
-
vnode[PARENT] = undefined;
|
|
435
|
-
if (options.unmount) options.unmount(vnode);
|
|
436
|
-
|
|
437
|
-
if (hasChildren) {
|
|
438
|
-
s = s + pieces;
|
|
439
|
-
} else if (VOID_ELEMENTS.test(type)) {
|
|
440
|
-
return startElement + ' />';
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
return s + '</' + type + '>';
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/** The default export is an alias of `render()`. */
|
|
447
|
-
|
|
448
|
-
renderToString.shallowRender = shallowRender;
|
|
449
|
-
|
|
450
|
-
export default renderToString;
|
|
451
|
-
|
|
452
|
-
export {
|
|
453
|
-
renderToString as render,
|
|
454
|
-
renderToString as renderToStaticMarkup,
|
|
455
|
-
renderToString,
|
|
456
|
-
shallowRender
|
|
457
|
-
};
|
|
1
|
+
import { encodeEntities, styleObjToCss, UNSAFE_NAME, XLINK } from './util';
|
|
2
|
+
import { options, h, Fragment } from 'preact';
|
|
3
|
+
import {
|
|
4
|
+
CHILDREN,
|
|
5
|
+
COMMIT,
|
|
6
|
+
COMPONENT,
|
|
7
|
+
DIFF,
|
|
8
|
+
DIFFED,
|
|
9
|
+
DIRTY,
|
|
10
|
+
NEXT_STATE,
|
|
11
|
+
PARENT,
|
|
12
|
+
RENDER,
|
|
13
|
+
SKIP_EFFECTS,
|
|
14
|
+
VNODE
|
|
15
|
+
} from './constants';
|
|
16
|
+
|
|
17
|
+
/** @typedef {import('preact').VNode} VNode */
|
|
18
|
+
|
|
19
|
+
const EMPTY_ARR = [];
|
|
20
|
+
const isArray = Array.isArray;
|
|
21
|
+
const assign = Object.assign;
|
|
22
|
+
|
|
23
|
+
// Global state for the current render pass
|
|
24
|
+
let beforeDiff, afterDiff, renderHook, ummountHook;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Render Preact JSX + Components to an HTML string.
|
|
28
|
+
* @param {VNode} vnode JSX Element / VNode to render
|
|
29
|
+
* @param {Object} [context={}] Initial root context object
|
|
30
|
+
* @returns {string} serialized HTML
|
|
31
|
+
*/
|
|
32
|
+
export default function renderToString(vnode, context) {
|
|
33
|
+
// Performance optimization: `renderToString` is synchronous and we
|
|
34
|
+
// therefore don't execute any effects. To do that we pass an empty
|
|
35
|
+
// array to `options._commit` (`__c`). But we can go one step further
|
|
36
|
+
// and avoid a lot of dirty checks and allocations by setting
|
|
37
|
+
// `options._skipEffects` (`__s`) too.
|
|
38
|
+
const previousSkipEffects = options[SKIP_EFFECTS];
|
|
39
|
+
options[SKIP_EFFECTS] = true;
|
|
40
|
+
|
|
41
|
+
// store options hooks once before each synchronous render call
|
|
42
|
+
beforeDiff = options[DIFF];
|
|
43
|
+
afterDiff = options[DIFFED];
|
|
44
|
+
renderHook = options[RENDER];
|
|
45
|
+
ummountHook = options.unmount;
|
|
46
|
+
|
|
47
|
+
const parent = h(Fragment, null);
|
|
48
|
+
parent[CHILDREN] = [vnode];
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
return _renderToString(
|
|
52
|
+
vnode,
|
|
53
|
+
context || EMPTY_OBJ,
|
|
54
|
+
false,
|
|
55
|
+
undefined,
|
|
56
|
+
parent
|
|
57
|
+
);
|
|
58
|
+
} finally {
|
|
59
|
+
// options._commit, we don't schedule any effects in this library right now,
|
|
60
|
+
// so we can pass an empty queue to this hook.
|
|
61
|
+
if (options[COMMIT]) options[COMMIT](vnode, EMPTY_ARR);
|
|
62
|
+
options[SKIP_EFFECTS] = previousSkipEffects;
|
|
63
|
+
EMPTY_ARR.length = 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Installed as setState/forceUpdate for function components
|
|
68
|
+
function markAsDirty() {
|
|
69
|
+
this.__d = true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const EMPTY_OBJ = {};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @param {VNode} vnode
|
|
76
|
+
* @param {Record<string, unknown>} context
|
|
77
|
+
*/
|
|
78
|
+
function renderClassComponent(vnode, context) {
|
|
79
|
+
let type = /** @type {import("preact").ComponentClass<typeof vnode.props>} */ (vnode.type);
|
|
80
|
+
|
|
81
|
+
let c = new type(vnode.props, context);
|
|
82
|
+
|
|
83
|
+
vnode[COMPONENT] = c;
|
|
84
|
+
c[VNODE] = vnode;
|
|
85
|
+
|
|
86
|
+
c.props = vnode.props;
|
|
87
|
+
c.context = context;
|
|
88
|
+
// turn off stateful re-rendering:
|
|
89
|
+
c[DIRTY] = true;
|
|
90
|
+
|
|
91
|
+
if (c.state == null) c.state = EMPTY_OBJ;
|
|
92
|
+
|
|
93
|
+
if (c[NEXT_STATE] == null) {
|
|
94
|
+
c[NEXT_STATE] = c.state;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (type.getDerivedStateFromProps) {
|
|
98
|
+
c.state = assign(
|
|
99
|
+
{},
|
|
100
|
+
c.state,
|
|
101
|
+
type.getDerivedStateFromProps(c.props, c.state)
|
|
102
|
+
);
|
|
103
|
+
} else if (c.componentWillMount) {
|
|
104
|
+
c.componentWillMount();
|
|
105
|
+
|
|
106
|
+
// If the user called setState in cWM we need to flush pending,
|
|
107
|
+
// state updates. This is the same behaviour in React.
|
|
108
|
+
c.state = c[NEXT_STATE] !== c.state ? c[NEXT_STATE] : c.state;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (renderHook) renderHook(vnode);
|
|
112
|
+
|
|
113
|
+
return c.render(c.props, c.state, context);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Recursively render VNodes to HTML.
|
|
118
|
+
* @param {VNode|any} vnode
|
|
119
|
+
* @param {any} context
|
|
120
|
+
* @param {boolean} isSvgMode
|
|
121
|
+
* @param {any} selectValue
|
|
122
|
+
* @param {VNode} parent
|
|
123
|
+
* @returns {string}
|
|
124
|
+
*/
|
|
125
|
+
function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
126
|
+
// Ignore non-rendered VNodes/values
|
|
127
|
+
if (vnode == null || vnode === true || vnode === false || vnode === '') {
|
|
128
|
+
return '';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Text VNodes: escape as HTML
|
|
132
|
+
if (typeof vnode !== 'object') {
|
|
133
|
+
if (typeof vnode === 'function') return '';
|
|
134
|
+
return encodeEntities(vnode + '');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Recurse into children / Arrays
|
|
138
|
+
if (isArray(vnode)) {
|
|
139
|
+
let rendered = '';
|
|
140
|
+
parent[CHILDREN] = vnode;
|
|
141
|
+
for (let i = 0; i < vnode.length; i++) {
|
|
142
|
+
let child = vnode[i];
|
|
143
|
+
if (child == null || typeof child === 'boolean') continue;
|
|
144
|
+
|
|
145
|
+
rendered =
|
|
146
|
+
rendered +
|
|
147
|
+
_renderToString(child, context, isSvgMode, selectValue, parent);
|
|
148
|
+
}
|
|
149
|
+
return rendered;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// VNodes have {constructor:undefined} to prevent JSON injection:
|
|
153
|
+
if (vnode.constructor !== undefined) return '';
|
|
154
|
+
|
|
155
|
+
vnode[PARENT] = parent;
|
|
156
|
+
if (beforeDiff) beforeDiff(vnode);
|
|
157
|
+
|
|
158
|
+
let type = vnode.type,
|
|
159
|
+
props = vnode.props,
|
|
160
|
+
cctx = context,
|
|
161
|
+
contextType,
|
|
162
|
+
rendered,
|
|
163
|
+
component;
|
|
164
|
+
|
|
165
|
+
// Invoke rendering on Components
|
|
166
|
+
if (typeof type === 'function') {
|
|
167
|
+
if (type === Fragment) {
|
|
168
|
+
rendered = props.children;
|
|
169
|
+
} else {
|
|
170
|
+
contextType = type.contextType;
|
|
171
|
+
if (contextType != null) {
|
|
172
|
+
let provider = context[contextType.__c];
|
|
173
|
+
cctx = provider ? provider.props.value : contextType.__;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (type.prototype && typeof type.prototype.render === 'function') {
|
|
177
|
+
rendered = /**#__NOINLINE__**/ renderClassComponent(vnode, cctx);
|
|
178
|
+
component = vnode[COMPONENT];
|
|
179
|
+
} else {
|
|
180
|
+
component = {
|
|
181
|
+
__v: vnode,
|
|
182
|
+
props,
|
|
183
|
+
context: cctx,
|
|
184
|
+
// silently drop state updates
|
|
185
|
+
setState: markAsDirty,
|
|
186
|
+
forceUpdate: markAsDirty,
|
|
187
|
+
__d: true,
|
|
188
|
+
// hooks
|
|
189
|
+
__h: []
|
|
190
|
+
};
|
|
191
|
+
vnode[COMPONENT] = component;
|
|
192
|
+
|
|
193
|
+
// If a hook invokes setState() to invalidate the component during rendering,
|
|
194
|
+
// re-render it up to 25 times to allow "settling" of memoized states.
|
|
195
|
+
// Note:
|
|
196
|
+
// This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
|
|
197
|
+
// https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
|
|
198
|
+
let count = 0;
|
|
199
|
+
while (component[DIRTY] && count++ < 25) {
|
|
200
|
+
component[DIRTY] = false;
|
|
201
|
+
|
|
202
|
+
if (renderHook) renderHook(vnode);
|
|
203
|
+
|
|
204
|
+
rendered = type.call(component, props, cctx);
|
|
205
|
+
}
|
|
206
|
+
component[DIRTY] = true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (component.getChildContext != null) {
|
|
210
|
+
context = assign({}, context, component.getChildContext());
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// When a component returns a Fragment node we flatten it in core, so we
|
|
215
|
+
// need to mirror that logic here too
|
|
216
|
+
let isTopLevelFragment =
|
|
217
|
+
rendered != null && rendered.type === Fragment && rendered.key == null;
|
|
218
|
+
rendered = isTopLevelFragment ? rendered.props.children : rendered;
|
|
219
|
+
|
|
220
|
+
// Recurse into children before invoking the after-diff hook
|
|
221
|
+
const str = _renderToString(
|
|
222
|
+
rendered,
|
|
223
|
+
context,
|
|
224
|
+
isSvgMode,
|
|
225
|
+
selectValue,
|
|
226
|
+
vnode
|
|
227
|
+
);
|
|
228
|
+
if (afterDiff) afterDiff(vnode);
|
|
229
|
+
vnode[PARENT] = undefined;
|
|
230
|
+
|
|
231
|
+
if (ummountHook) ummountHook(vnode);
|
|
232
|
+
|
|
233
|
+
return str;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Serialize Element VNodes to HTML
|
|
237
|
+
let s = '<' + type,
|
|
238
|
+
html = '',
|
|
239
|
+
children;
|
|
240
|
+
|
|
241
|
+
for (let name in props) {
|
|
242
|
+
let v = props[name];
|
|
243
|
+
|
|
244
|
+
switch (name) {
|
|
245
|
+
case 'children':
|
|
246
|
+
children = v;
|
|
247
|
+
continue;
|
|
248
|
+
|
|
249
|
+
// VDOM-specific props
|
|
250
|
+
case 'key':
|
|
251
|
+
case 'ref':
|
|
252
|
+
case '__self':
|
|
253
|
+
case '__source':
|
|
254
|
+
continue;
|
|
255
|
+
|
|
256
|
+
// prefer for/class over htmlFor/className
|
|
257
|
+
case 'htmlFor':
|
|
258
|
+
if ('for' in props) continue;
|
|
259
|
+
name = 'for';
|
|
260
|
+
break;
|
|
261
|
+
case 'className':
|
|
262
|
+
if ('class' in props) continue;
|
|
263
|
+
name = 'class';
|
|
264
|
+
break;
|
|
265
|
+
|
|
266
|
+
// Form element reflected properties
|
|
267
|
+
case 'defaultChecked':
|
|
268
|
+
name = 'checked';
|
|
269
|
+
break;
|
|
270
|
+
case 'defaultSelected':
|
|
271
|
+
name = 'selected';
|
|
272
|
+
break;
|
|
273
|
+
|
|
274
|
+
// Special value attribute handling
|
|
275
|
+
case 'defaultValue':
|
|
276
|
+
case 'value':
|
|
277
|
+
name = 'value';
|
|
278
|
+
switch (type) {
|
|
279
|
+
// <textarea value="a&b"> --> <textarea>a&b</textarea>
|
|
280
|
+
case 'textarea':
|
|
281
|
+
children = v;
|
|
282
|
+
continue;
|
|
283
|
+
|
|
284
|
+
// <select value> is serialized as a selected attribute on the matching option child
|
|
285
|
+
case 'select':
|
|
286
|
+
selectValue = v;
|
|
287
|
+
continue;
|
|
288
|
+
|
|
289
|
+
// Add a selected attribute to <option> if its value matches the parent <select> value
|
|
290
|
+
case 'option':
|
|
291
|
+
if (selectValue == v && !('selected' in props)) {
|
|
292
|
+
s = s + ' selected';
|
|
293
|
+
}
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
297
|
+
|
|
298
|
+
case 'dangerouslySetInnerHTML':
|
|
299
|
+
html = v && v.__html;
|
|
300
|
+
continue;
|
|
301
|
+
|
|
302
|
+
// serialize object styles to a CSS string
|
|
303
|
+
case 'style':
|
|
304
|
+
if (typeof v === 'object') {
|
|
305
|
+
v = styleObjToCss(v);
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
|
|
309
|
+
default: {
|
|
310
|
+
if (isSvgMode && XLINK.test(name)) {
|
|
311
|
+
name = name.toLowerCase().replace(XLINK_REPLACE_REGEX, 'xlink:');
|
|
312
|
+
} else if (UNSAFE_NAME.test(name)) {
|
|
313
|
+
continue;
|
|
314
|
+
} else if ((name[4] === '-' || name === 'draggable') && v != null) {
|
|
315
|
+
// serialize boolean aria-xyz or draggable attribute values as strings
|
|
316
|
+
// `draggable` is an enumerated attribute and not Boolean. A value of `true` or `false` is mandatory
|
|
317
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/draggable
|
|
318
|
+
v += '';
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// write this attribute to the buffer
|
|
324
|
+
if (v != null && v !== false && typeof v !== 'function') {
|
|
325
|
+
if (v === true || v === '') {
|
|
326
|
+
s = s + ' ' + name;
|
|
327
|
+
} else {
|
|
328
|
+
s = s + ' ' + name + '="' + encodeEntities(v + '') + '"';
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (UNSAFE_NAME.test(type)) {
|
|
334
|
+
// this seems to performs a lot better than throwing
|
|
335
|
+
// return '<!-- -->';
|
|
336
|
+
throw new Error(`${type} is not a valid HTML tag name in ${s}>`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (html) {
|
|
340
|
+
// dangerouslySetInnerHTML defined this node's contents
|
|
341
|
+
} else if (typeof children === 'string') {
|
|
342
|
+
// single text child
|
|
343
|
+
html = encodeEntities(children);
|
|
344
|
+
} else if (children != null && children !== false && children !== true) {
|
|
345
|
+
// recurse into this element VNode's children
|
|
346
|
+
let childSvgMode =
|
|
347
|
+
type === 'svg' || (type !== 'foreignObject' && isSvgMode);
|
|
348
|
+
html = _renderToString(children, context, childSvgMode, selectValue, vnode);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (afterDiff) afterDiff(vnode);
|
|
352
|
+
vnode[PARENT] = undefined;
|
|
353
|
+
if (ummountHook) ummountHook(vnode);
|
|
354
|
+
|
|
355
|
+
// Emit self-closing tag for empty void elements:
|
|
356
|
+
if (!html && SELF_CLOSING.has(type)) {
|
|
357
|
+
return s + '/>';
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return s + '>' + html + '</' + type + '>';
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const XLINK_REPLACE_REGEX = /^xlink:?/;
|
|
364
|
+
const SELF_CLOSING = new Set([
|
|
365
|
+
'area',
|
|
366
|
+
'base',
|
|
367
|
+
'br',
|
|
368
|
+
'col',
|
|
369
|
+
'command',
|
|
370
|
+
'embed',
|
|
371
|
+
'hr',
|
|
372
|
+
'img',
|
|
373
|
+
'input',
|
|
374
|
+
'keygen',
|
|
375
|
+
'link',
|
|
376
|
+
'meta',
|
|
377
|
+
'param',
|
|
378
|
+
'source',
|
|
379
|
+
'track',
|
|
380
|
+
'wbr'
|
|
381
|
+
]);
|