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