preact-render-to-string 5.2.1 → 5.2.4
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 +102 -102
- package/dist/commonjs.js +1 -1
- package/dist/commonjs.js.map +1 -1
- package/dist/index.d.ts +16 -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/jsx-entry.js +1 -1
- package/dist/jsx-entry.js.map +1 -1
- package/dist/jsx.d.ts +13 -13
- package/dist/jsx.js.map +1 -1
- package/dist/jsx.mjs +1 -1
- package/dist/jsx.modern.js +1 -1
- package/dist/jsx.modern.js.map +1 -1
- package/dist/jsx.module.js +1 -1
- package/dist/jsx.module.js.map +1 -1
- package/jsx.js +1 -1
- package/package.json +148 -142
- package/src/constants.js +16 -0
- package/src/index.d.ts +16 -16
- package/src/index.js +396 -462
- package/src/jsx.d.ts +13 -13
- package/src/jsx.js +76 -76
- package/src/polyfills.js +8 -8
- package/src/pretty.js +385 -0
- package/src/util.js +125 -78
- package/typings.json +5 -5
package/src/index.js
CHANGED
|
@@ -1,462 +1,396 @@
|
|
|
1
|
-
import {
|
|
2
|
-
encodeEntities,
|
|
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
|
-
* @param {
|
|
34
|
-
* @param {
|
|
35
|
-
* @param {
|
|
36
|
-
* @param {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
45
|
-
* @
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
// `options.
|
|
59
|
-
|
|
60
|
-
options.__s
|
|
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
|
-
name
|
|
269
|
-
|
|
270
|
-
name
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (name
|
|
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
|
-
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (
|
|
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
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
pieces.push(ret);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
if (pretty && hasLarge) {
|
|
403
|
-
for (let i = pieces.length; i--; ) {
|
|
404
|
-
pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (pieces.length || html) {
|
|
410
|
-
s = s + pieces.join('');
|
|
411
|
-
} else if (opts && opts.xml) {
|
|
412
|
-
return s.substring(0, s.length - 1) + ' />';
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
if (isVoid && !children && !html) {
|
|
416
|
-
s = s.replace(/>$/, ' />');
|
|
417
|
-
} else {
|
|
418
|
-
if (pretty && ~s.indexOf('\n')) s = s + '\n';
|
|
419
|
-
s = s + `</${nodeName}>`;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return s;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function getComponentName(component) {
|
|
426
|
-
return (
|
|
427
|
-
component.displayName ||
|
|
428
|
-
(component !== Function && component.name) ||
|
|
429
|
-
getFallbackComponentName(component)
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
function getFallbackComponentName(component) {
|
|
434
|
-
let str = Function.prototype.toString.call(component),
|
|
435
|
-
name = (str.match(/^\s*function\s+([^( ]+)/) || '')[1];
|
|
436
|
-
if (!name) {
|
|
437
|
-
// search for an existing indexed name for the given component:
|
|
438
|
-
let index = -1;
|
|
439
|
-
for (let i = UNNAMED.length; i--; ) {
|
|
440
|
-
if (UNNAMED[i] === component) {
|
|
441
|
-
index = i;
|
|
442
|
-
break;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
// not found, create a new indexed name:
|
|
446
|
-
if (index < 0) {
|
|
447
|
-
index = UNNAMED.push(component) - 1;
|
|
448
|
-
}
|
|
449
|
-
name = `UnnamedComponent${index}`;
|
|
450
|
-
}
|
|
451
|
-
return name;
|
|
452
|
-
}
|
|
453
|
-
renderToString.shallowRender = shallowRender;
|
|
454
|
-
|
|
455
|
-
export default renderToString;
|
|
456
|
-
|
|
457
|
-
export {
|
|
458
|
-
renderToString as render,
|
|
459
|
-
renderToString as renderToStaticMarkup,
|
|
460
|
-
renderToString,
|
|
461
|
-
shallowRender
|
|
462
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
encodeEntities,
|
|
3
|
+
styleObjToCss,
|
|
4
|
+
getContext,
|
|
5
|
+
createComponent,
|
|
6
|
+
UNSAFE_NAME,
|
|
7
|
+
XLINK,
|
|
8
|
+
VOID_ELEMENTS
|
|
9
|
+
} from './util';
|
|
10
|
+
import { options, h, Fragment } from 'preact';
|
|
11
|
+
import { _renderToStringPretty } from './pretty';
|
|
12
|
+
import {
|
|
13
|
+
COMMIT,
|
|
14
|
+
COMPONENT,
|
|
15
|
+
DIFF,
|
|
16
|
+
DIFFED,
|
|
17
|
+
DIRTY,
|
|
18
|
+
NEXT_STATE,
|
|
19
|
+
PARENT,
|
|
20
|
+
RENDER,
|
|
21
|
+
SKIP_EFFECTS,
|
|
22
|
+
VNODE,
|
|
23
|
+
CHILDREN
|
|
24
|
+
} from './constants';
|
|
25
|
+
|
|
26
|
+
/** @typedef {import('preact').VNode} VNode */
|
|
27
|
+
|
|
28
|
+
const SHALLOW = { shallow: true };
|
|
29
|
+
|
|
30
|
+
/** Render Preact JSX + Components to an HTML string.
|
|
31
|
+
* @name render
|
|
32
|
+
* @function
|
|
33
|
+
* @param {VNode} vnode JSX VNode to render.
|
|
34
|
+
* @param {Object} [context={}] Optionally pass an initial context object through the render path.
|
|
35
|
+
* @param {Object} [options={}] Rendering options
|
|
36
|
+
* @param {Boolean} [options.shallow=false] If `true`, renders nested Components as HTML elements (`<Foo a="b" />`).
|
|
37
|
+
* @param {Boolean} [options.xml=false] If `true`, uses self-closing tags for elements without children.
|
|
38
|
+
* @param {Boolean} [options.pretty=false] If `true`, adds whitespace for readability
|
|
39
|
+
* @param {RegExp|undefined} [options.voidElements] RegeEx that matches elements that are considered void (self-closing)
|
|
40
|
+
*/
|
|
41
|
+
renderToString.render = renderToString;
|
|
42
|
+
|
|
43
|
+
/** Only render elements, leaving Components inline as `<ComponentName ... />`.
|
|
44
|
+
* This method is just a convenience alias for `render(vnode, context, { shallow:true })`
|
|
45
|
+
* @name shallow
|
|
46
|
+
* @function
|
|
47
|
+
* @param {VNode} vnode JSX VNode to render.
|
|
48
|
+
* @param {Object} [context={}] Optionally pass an initial context object through the render path.
|
|
49
|
+
*/
|
|
50
|
+
let shallowRender = (vnode, context) => renderToString(vnode, context, SHALLOW);
|
|
51
|
+
|
|
52
|
+
const EMPTY_ARR = [];
|
|
53
|
+
function renderToString(vnode, context, opts) {
|
|
54
|
+
context = context || {};
|
|
55
|
+
|
|
56
|
+
// Performance optimization: `renderToString` is synchronous and we
|
|
57
|
+
// therefore don't execute any effects. To do that we pass an empty
|
|
58
|
+
// array to `options._commit` (`__c`). But we can go one step further
|
|
59
|
+
// and avoid a lot of dirty checks and allocations by setting
|
|
60
|
+
// `options._skipEffects` (`__s`) too.
|
|
61
|
+
const previousSkipEffects = options[SKIP_EFFECTS];
|
|
62
|
+
options[SKIP_EFFECTS] = true;
|
|
63
|
+
|
|
64
|
+
const parent = h(Fragment, null);
|
|
65
|
+
parent[CHILDREN] = [vnode];
|
|
66
|
+
|
|
67
|
+
let res;
|
|
68
|
+
if (
|
|
69
|
+
opts &&
|
|
70
|
+
(opts.pretty ||
|
|
71
|
+
opts.voidElements ||
|
|
72
|
+
opts.sortAttributes ||
|
|
73
|
+
opts.shallow ||
|
|
74
|
+
opts.allAttributes ||
|
|
75
|
+
opts.xml ||
|
|
76
|
+
opts.attributeHook)
|
|
77
|
+
) {
|
|
78
|
+
res = _renderToStringPretty(vnode, context, opts);
|
|
79
|
+
} else {
|
|
80
|
+
res = _renderToString(vnode, context, false, undefined, parent);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// options._commit, we don't schedule any effects in this library right now,
|
|
84
|
+
// so we can pass an empty queue to this hook.
|
|
85
|
+
if (options[COMMIT]) options[COMMIT](vnode, EMPTY_ARR);
|
|
86
|
+
options[SKIP_EFFECTS] = previousSkipEffects;
|
|
87
|
+
EMPTY_ARR.length = 0;
|
|
88
|
+
|
|
89
|
+
return res;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function renderFunctionComponent(vnode, context) {
|
|
93
|
+
let rendered,
|
|
94
|
+
c = createComponent(vnode, context),
|
|
95
|
+
cctx = getContext(vnode.type, context);
|
|
96
|
+
|
|
97
|
+
vnode[COMPONENT] = c;
|
|
98
|
+
|
|
99
|
+
// If a hook invokes setState() to invalidate the component during rendering,
|
|
100
|
+
// re-render it up to 25 times to allow "settling" of memoized states.
|
|
101
|
+
// Note:
|
|
102
|
+
// This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
|
|
103
|
+
// https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
|
|
104
|
+
let renderHook = options[RENDER];
|
|
105
|
+
let count = 0;
|
|
106
|
+
while (c[DIRTY] && count++ < 25) {
|
|
107
|
+
c[DIRTY] = false;
|
|
108
|
+
|
|
109
|
+
if (renderHook) renderHook(vnode);
|
|
110
|
+
|
|
111
|
+
// stateless functional components
|
|
112
|
+
rendered = vnode.type.call(c, vnode.props, cctx);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return rendered;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function renderClassComponent(vnode, context) {
|
|
119
|
+
let nodeName = vnode.type,
|
|
120
|
+
cctx = getContext(nodeName, context);
|
|
121
|
+
|
|
122
|
+
// c = new nodeName(props, context);
|
|
123
|
+
let c = new nodeName(vnode.props, cctx);
|
|
124
|
+
vnode[COMPONENT] = c;
|
|
125
|
+
c[VNODE] = vnode;
|
|
126
|
+
// turn off stateful re-rendering:
|
|
127
|
+
c[DIRTY] = true;
|
|
128
|
+
c.props = vnode.props;
|
|
129
|
+
if (c.state == null) c.state = {};
|
|
130
|
+
|
|
131
|
+
if (c[NEXT_STATE] == null) {
|
|
132
|
+
c[NEXT_STATE] = c.state;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
c.context = cctx;
|
|
136
|
+
if (nodeName.getDerivedStateFromProps) {
|
|
137
|
+
c.state = assign(
|
|
138
|
+
{},
|
|
139
|
+
c.state,
|
|
140
|
+
nodeName.getDerivedStateFromProps(c.props, c.state)
|
|
141
|
+
);
|
|
142
|
+
} else if (c.componentWillMount) {
|
|
143
|
+
c.componentWillMount();
|
|
144
|
+
|
|
145
|
+
// If the user called setState in cWM we need to flush pending,
|
|
146
|
+
// state updates. This is the same behaviour in React.
|
|
147
|
+
c.state = c[NEXT_STATE] !== c.state ? c[NEXT_STATE] : c.state;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let renderHook = options[RENDER];
|
|
151
|
+
if (renderHook) renderHook(vnode);
|
|
152
|
+
|
|
153
|
+
return c.render(c.props, c.state, c.context);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function normalizePropName(name, isSvgMode) {
|
|
157
|
+
if (name === 'className') {
|
|
158
|
+
return 'class';
|
|
159
|
+
} else if (name === 'htmlFor') {
|
|
160
|
+
return 'for';
|
|
161
|
+
} else if (name === 'defaultValue') {
|
|
162
|
+
return 'value';
|
|
163
|
+
} else if (name === 'defaultChecked') {
|
|
164
|
+
return 'checked';
|
|
165
|
+
} else if (name === 'defaultSelected') {
|
|
166
|
+
return 'selected';
|
|
167
|
+
} else if (isSvgMode && XLINK.test(name)) {
|
|
168
|
+
return name.toLowerCase().replace(/^xlink:?/, 'xlink:');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return name;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function normalizePropValue(name, v) {
|
|
175
|
+
if (name === 'style' && v != null && typeof v === 'object') {
|
|
176
|
+
return styleObjToCss(v);
|
|
177
|
+
} else if (name[0] === 'a' && name[1] === 'r' && typeof v === 'boolean') {
|
|
178
|
+
// always use string values instead of booleans for aria attributes
|
|
179
|
+
// also see https://github.com/preactjs/preact/pull/2347/files
|
|
180
|
+
return String(v);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return v;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const isArray = Array.isArray;
|
|
187
|
+
const assign = Object.assign;
|
|
188
|
+
|
|
189
|
+
/** The default export is an alias of `render()`. */
|
|
190
|
+
function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
191
|
+
// Ignore non-rendered VNodes/values
|
|
192
|
+
if (vnode == null || vnode === true || vnode === false || vnode === '') {
|
|
193
|
+
return '';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Text VNodes: escape as HTML
|
|
197
|
+
if (typeof vnode !== 'object') {
|
|
198
|
+
return encodeEntities(vnode);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Recurse into children / Arrays
|
|
202
|
+
if (isArray(vnode)) {
|
|
203
|
+
let rendered = '';
|
|
204
|
+
parent[CHILDREN] = vnode;
|
|
205
|
+
for (let i = 0; i < vnode.length; i++) {
|
|
206
|
+
rendered =
|
|
207
|
+
rendered +
|
|
208
|
+
_renderToString(vnode[i], context, isSvgMode, selectValue, parent);
|
|
209
|
+
}
|
|
210
|
+
return rendered;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
vnode[PARENT] = parent;
|
|
214
|
+
if (options[DIFF]) options[DIFF](vnode);
|
|
215
|
+
|
|
216
|
+
let type = vnode.type,
|
|
217
|
+
props = vnode.props;
|
|
218
|
+
|
|
219
|
+
// Invoke rendering on Components
|
|
220
|
+
const isComponent = typeof type === 'function';
|
|
221
|
+
if (isComponent) {
|
|
222
|
+
let rendered;
|
|
223
|
+
if (type === Fragment) {
|
|
224
|
+
rendered = props.children;
|
|
225
|
+
} else {
|
|
226
|
+
if (type.prototype && typeof type.prototype.render === 'function') {
|
|
227
|
+
rendered = renderClassComponent(vnode, context);
|
|
228
|
+
} else {
|
|
229
|
+
rendered = renderFunctionComponent(vnode, context);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
let component = vnode[COMPONENT];
|
|
233
|
+
if (component.getChildContext) {
|
|
234
|
+
context = assign({}, context, component.getChildContext());
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Recurse into children before invoking the after-diff hook
|
|
239
|
+
const str = _renderToString(
|
|
240
|
+
rendered,
|
|
241
|
+
context,
|
|
242
|
+
isSvgMode,
|
|
243
|
+
selectValue,
|
|
244
|
+
vnode
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
if (options[DIFFED]) options[DIFFED](vnode);
|
|
248
|
+
vnode[PARENT] = undefined;
|
|
249
|
+
|
|
250
|
+
if (options.unmount) options.unmount(vnode);
|
|
251
|
+
|
|
252
|
+
return str;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Serialize Element VNodes to HTML
|
|
256
|
+
let s = '<',
|
|
257
|
+
children,
|
|
258
|
+
html;
|
|
259
|
+
|
|
260
|
+
s = s + type;
|
|
261
|
+
|
|
262
|
+
if (props) {
|
|
263
|
+
children = props.children;
|
|
264
|
+
for (let name in props) {
|
|
265
|
+
let v = props[name];
|
|
266
|
+
|
|
267
|
+
if (
|
|
268
|
+
name === 'key' ||
|
|
269
|
+
name === 'ref' ||
|
|
270
|
+
name === '__self' ||
|
|
271
|
+
name === '__source' ||
|
|
272
|
+
name === 'children' ||
|
|
273
|
+
(name === 'className' && 'class' in props) ||
|
|
274
|
+
(name === 'htmlFor' && 'for' in props)
|
|
275
|
+
) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (UNSAFE_NAME.test(name)) continue;
|
|
280
|
+
|
|
281
|
+
name = normalizePropName(name, isSvgMode);
|
|
282
|
+
v = normalizePropValue(name, v);
|
|
283
|
+
|
|
284
|
+
if (name === 'dangerouslySetInnerHTML') {
|
|
285
|
+
html = v && v.__html;
|
|
286
|
+
} else if (type === 'textarea' && name === 'value') {
|
|
287
|
+
// <textarea value="a&b"> --> <textarea>a&b</textarea>
|
|
288
|
+
children = v;
|
|
289
|
+
} else if ((v || v === 0 || v === '') && typeof v !== 'function') {
|
|
290
|
+
if (v === true || v === '') {
|
|
291
|
+
v = name;
|
|
292
|
+
s = s + ' ' + name;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (name === 'value') {
|
|
297
|
+
if (type === 'select') {
|
|
298
|
+
selectValue = v;
|
|
299
|
+
continue;
|
|
300
|
+
} else if (
|
|
301
|
+
// If we're looking at an <option> and it's the currently selected one
|
|
302
|
+
type === 'option' &&
|
|
303
|
+
selectValue == v &&
|
|
304
|
+
// and the <option> doesn't already have a selected attribute on it
|
|
305
|
+
!('selected' in props)
|
|
306
|
+
) {
|
|
307
|
+
s = s + ' selected';
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
s = s + ' ' + name + '="' + encodeEntities(v) + '"';
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let startElement = s;
|
|
316
|
+
s = s + '>';
|
|
317
|
+
|
|
318
|
+
if (UNSAFE_NAME.test(type)) {
|
|
319
|
+
throw new Error(`${type} is not a valid HTML tag name in ${s}`);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let pieces = '';
|
|
323
|
+
let hasChildren = false;
|
|
324
|
+
|
|
325
|
+
if (html) {
|
|
326
|
+
pieces = pieces + html;
|
|
327
|
+
hasChildren = true;
|
|
328
|
+
} else if (typeof children === 'string') {
|
|
329
|
+
pieces = pieces + encodeEntities(children);
|
|
330
|
+
hasChildren = true;
|
|
331
|
+
} else if (isArray(children)) {
|
|
332
|
+
vnode[CHILDREN] = children;
|
|
333
|
+
for (let i = 0; i < children.length; i++) {
|
|
334
|
+
let child = children[i];
|
|
335
|
+
if (child != null && child !== false) {
|
|
336
|
+
let childSvgMode =
|
|
337
|
+
type === 'svg' || (type !== 'foreignObject' && isSvgMode);
|
|
338
|
+
let ret = _renderToString(
|
|
339
|
+
child,
|
|
340
|
+
context,
|
|
341
|
+
childSvgMode,
|
|
342
|
+
selectValue,
|
|
343
|
+
vnode
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
// Skip if we received an empty string
|
|
347
|
+
if (ret) {
|
|
348
|
+
pieces = pieces + ret;
|
|
349
|
+
hasChildren = true;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
} else if (children != null && children !== false && children !== true) {
|
|
354
|
+
vnode[CHILDREN] = [children];
|
|
355
|
+
let childSvgMode =
|
|
356
|
+
type === 'svg' || (type !== 'foreignObject' && isSvgMode);
|
|
357
|
+
let ret = _renderToString(
|
|
358
|
+
children,
|
|
359
|
+
context,
|
|
360
|
+
childSvgMode,
|
|
361
|
+
selectValue,
|
|
362
|
+
vnode
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
// Skip if we received an empty string
|
|
366
|
+
if (ret) {
|
|
367
|
+
pieces = pieces + ret;
|
|
368
|
+
hasChildren = true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (options[DIFFED]) options[DIFFED](vnode);
|
|
373
|
+
vnode[PARENT] = undefined;
|
|
374
|
+
if (options.unmount) options.unmount(vnode);
|
|
375
|
+
|
|
376
|
+
if (hasChildren) {
|
|
377
|
+
s = s + pieces;
|
|
378
|
+
} else if (VOID_ELEMENTS.test(type)) {
|
|
379
|
+
return startElement + ' />';
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return s + '</' + type + '>';
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** The default export is an alias of `render()`. */
|
|
386
|
+
|
|
387
|
+
renderToString.shallowRender = shallowRender;
|
|
388
|
+
|
|
389
|
+
export default renderToString;
|
|
390
|
+
|
|
391
|
+
export {
|
|
392
|
+
renderToString as render,
|
|
393
|
+
renderToString as renderToStaticMarkup,
|
|
394
|
+
renderToString,
|
|
395
|
+
shallowRender
|
|
396
|
+
};
|