preact-render-to-string 5.2.4 → 5.2.5

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/pretty.js CHANGED
@@ -1,385 +1,389 @@
1
- import {
2
- encodeEntities,
3
- indent,
4
- isLargeString,
5
- styleObjToCss,
6
- getChildren,
7
- createComponent,
8
- getContext,
9
- UNSAFE_NAME,
10
- XLINK,
11
- VOID_ELEMENTS
12
- } from './util';
13
- import { options, Fragment } from 'preact';
14
-
15
- // components without names, kept as a hash for later comparison to return consistent UnnamedComponentXX names.
16
- const UNNAMED = [];
17
-
18
- export function _renderToStringPretty(
19
- vnode,
20
- context,
21
- opts,
22
- inner,
23
- isSvgMode,
24
- selectValue
25
- ) {
26
- if (vnode == null || typeof vnode === 'boolean') {
27
- return '';
28
- }
29
-
30
- // #text nodes
31
- if (typeof vnode !== 'object') {
32
- return encodeEntities(vnode);
33
- }
34
-
35
- let pretty = opts.pretty,
36
- indentChar = pretty && typeof pretty === 'string' ? pretty : '\t';
37
-
38
- if (Array.isArray(vnode)) {
39
- let rendered = '';
40
- for (let i = 0; i < vnode.length; i++) {
41
- if (pretty && i > 0) rendered = rendered + '\n';
42
- rendered =
43
- rendered +
44
- _renderToStringPretty(
45
- vnode[i],
46
- context,
47
- opts,
48
- inner,
49
- isSvgMode,
50
- selectValue
51
- );
52
- }
53
- return rendered;
54
- }
55
-
56
- let nodeName = vnode.type,
57
- props = vnode.props,
58
- isComponent = false;
59
-
60
- // components
61
- if (typeof nodeName === 'function') {
62
- isComponent = true;
63
- if (opts.shallow && (inner || opts.renderRootComponent === false)) {
64
- nodeName = getComponentName(nodeName);
65
- } else if (nodeName === Fragment) {
66
- const children = [];
67
- getChildren(children, vnode.props.children);
68
- return _renderToStringPretty(
69
- children,
70
- context,
71
- opts,
72
- opts.shallowHighOrder !== false,
73
- isSvgMode,
74
- selectValue
75
- );
76
- } else {
77
- let rendered;
78
-
79
- let c = (vnode.__c = createComponent(vnode, context));
80
-
81
- // options._diff
82
- if (options.__b) options.__b(vnode);
83
-
84
- // options._render
85
- let renderHook = options.__r;
86
-
87
- if (
88
- !nodeName.prototype ||
89
- typeof nodeName.prototype.render !== 'function'
90
- ) {
91
- let cctx = getContext(nodeName, context);
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 count = 0;
99
- while (c.__d && count++ < 25) {
100
- c.__d = false;
101
-
102
- if (renderHook) renderHook(vnode);
103
-
104
- // stateless functional components
105
- rendered = nodeName.call(vnode.__c, props, cctx);
106
- }
107
- } else {
108
- let cctx = getContext(nodeName, context);
109
-
110
- // c = new nodeName(props, context);
111
- c = vnode.__c = new nodeName(props, cctx);
112
- c.__v = vnode;
113
- // turn off stateful re-rendering:
114
- c._dirty = c.__d = true;
115
- c.props = props;
116
- if (c.state == null) c.state = {};
117
-
118
- if (c._nextState == null && c.__s == null) {
119
- c._nextState = c.__s = c.state;
120
- }
121
-
122
- c.context = cctx;
123
- if (nodeName.getDerivedStateFromProps)
124
- c.state = Object.assign(
125
- {},
126
- c.state,
127
- nodeName.getDerivedStateFromProps(c.props, c.state)
128
- );
129
- else if (c.componentWillMount) {
130
- c.componentWillMount();
131
-
132
- // If the user called setState in cWM we need to flush pending,
133
- // state updates. This is the same behaviour in React.
134
- c.state =
135
- c._nextState !== c.state
136
- ? c._nextState
137
- : c.__s !== c.state
138
- ? c.__s
139
- : c.state;
140
- }
141
-
142
- if (renderHook) renderHook(vnode);
143
-
144
- rendered = c.render(c.props, c.state, c.context);
145
- }
146
-
147
- if (c.getChildContext) {
148
- context = Object.assign({}, context, c.getChildContext());
149
- }
150
-
151
- if (options.diffed) options.diffed(vnode);
152
- return _renderToStringPretty(
153
- rendered,
154
- context,
155
- opts,
156
- opts.shallowHighOrder !== false,
157
- isSvgMode,
158
- selectValue
159
- );
160
- }
161
- }
162
-
163
- // render JSX to HTML
164
- let s = '<' + nodeName,
165
- propChildren,
166
- html;
167
-
168
- if (props) {
169
- let attrs = Object.keys(props);
170
-
171
- // allow sorting lexicographically for more determinism (useful for tests, such as via preact-jsx-chai)
172
- if (opts && opts.sortAttributes === true) attrs.sort();
173
-
174
- for (let i = 0; i < attrs.length; i++) {
175
- let name = attrs[i],
176
- v = props[name];
177
- if (name === 'children') {
178
- propChildren = v;
179
- continue;
180
- }
181
-
182
- if (UNSAFE_NAME.test(name)) continue;
183
-
184
- if (
185
- !(opts && opts.allAttributes) &&
186
- (name === 'key' ||
187
- name === 'ref' ||
188
- name === '__self' ||
189
- name === '__source')
190
- )
191
- continue;
192
-
193
- if (name === 'defaultValue') {
194
- name = 'value';
195
- } else if (name === 'defaultChecked') {
196
- name = 'checked';
197
- } else if (name === 'defaultSelected') {
198
- name = 'selected';
199
- } else if (name === 'className') {
200
- if (typeof props.class !== 'undefined') continue;
201
- name = 'class';
202
- } else if (isSvgMode && XLINK.test(name)) {
203
- name = name.toLowerCase().replace(/^xlink:?/, 'xlink:');
204
- }
205
-
206
- if (name === 'htmlFor') {
207
- if (props.for) continue;
208
- name = 'for';
209
- }
210
-
211
- if (name === 'style' && v && typeof v === 'object') {
212
- v = styleObjToCss(v);
213
- }
214
-
215
- // always use string values instead of booleans for aria attributes
216
- // also see https://github.com/preactjs/preact/pull/2347/files
217
- if (name[0] === 'a' && name['1'] === 'r' && typeof v === 'boolean') {
218
- v = String(v);
219
- }
220
-
221
- let hooked =
222
- opts.attributeHook &&
223
- opts.attributeHook(name, v, context, opts, isComponent);
224
- if (hooked || hooked === '') {
225
- s = s + hooked;
226
- continue;
227
- }
228
-
229
- if (name === 'dangerouslySetInnerHTML') {
230
- html = v && v.__html;
231
- } else if (nodeName === 'textarea' && name === 'value') {
232
- // <textarea value="a&b"> --> <textarea>a&amp;b</textarea>
233
- propChildren = v;
234
- } else if ((v || v === 0 || v === '') && typeof v !== 'function') {
235
- if (v === true || v === '') {
236
- v = name;
237
- // in non-xml mode, allow boolean attributes
238
- if (!opts || !opts.xml) {
239
- s = s + ' ' + name;
240
- continue;
241
- }
242
- }
243
-
244
- if (name === 'value') {
245
- if (nodeName === 'select') {
246
- selectValue = v;
247
- continue;
248
- } else if (
249
- // If we're looking at an <option> and it's the currently selected one
250
- nodeName === 'option' &&
251
- selectValue == v &&
252
- // and the <option> doesn't already have a selected attribute on it
253
- typeof props.selected === 'undefined'
254
- ) {
255
- s = s + ` selected`;
256
- }
257
- }
258
- s = s + ` ${name}="${encodeEntities(v)}"`;
259
- }
260
- }
261
- }
262
-
263
- // account for >1 multiline attribute
264
- if (pretty) {
265
- let sub = s.replace(/\n\s*/, ' ');
266
- if (sub !== s && !~sub.indexOf('\n')) s = sub;
267
- else if (pretty && ~s.indexOf('\n')) s = s + '\n';
268
- }
269
-
270
- s = s + '>';
271
-
272
- if (UNSAFE_NAME.test(nodeName))
273
- throw new Error(`${nodeName} is not a valid HTML tag name in ${s}`);
274
-
275
- let isVoid =
276
- VOID_ELEMENTS.test(nodeName) ||
277
- (opts.voidElements && opts.voidElements.test(nodeName));
278
- let pieces = [];
279
-
280
- let children;
281
- if (html) {
282
- // if multiline, indent.
283
- if (pretty && isLargeString(html)) {
284
- html = '\n' + indentChar + indent(html, indentChar);
285
- }
286
- s = s + html;
287
- } else if (
288
- propChildren != null &&
289
- getChildren((children = []), propChildren).length
290
- ) {
291
- let hasLarge = pretty && ~s.indexOf('\n');
292
- let lastWasText = false;
293
-
294
- for (let i = 0; i < children.length; i++) {
295
- let child = children[i];
296
-
297
- if (child != null && child !== false) {
298
- let childSvgMode =
299
- nodeName === 'svg'
300
- ? true
301
- : nodeName === 'foreignObject'
302
- ? false
303
- : isSvgMode,
304
- ret = _renderToStringPretty(
305
- child,
306
- context,
307
- opts,
308
- true,
309
- childSvgMode,
310
- selectValue
311
- );
312
-
313
- if (pretty && !hasLarge && isLargeString(ret)) hasLarge = true;
314
-
315
- // Skip if we received an empty string
316
- if (ret) {
317
- if (pretty) {
318
- let isText = ret.length > 0 && ret[0] != '<';
319
-
320
- // We merge adjacent text nodes, otherwise each piece would be printed
321
- // on a new line.
322
- if (lastWasText && isText) {
323
- pieces[pieces.length - 1] += ret;
324
- } else {
325
- pieces.push(ret);
326
- }
327
-
328
- lastWasText = isText;
329
- } else {
330
- pieces.push(ret);
331
- }
332
- }
333
- }
334
- }
335
- if (pretty && hasLarge) {
336
- for (let i = pieces.length; i--; ) {
337
- pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar);
338
- }
339
- }
340
- }
341
-
342
- if (pieces.length || html) {
343
- s = s + pieces.join('');
344
- } else if (opts && opts.xml) {
345
- return s.substring(0, s.length - 1) + ' />';
346
- }
347
-
348
- if (isVoid && !children && !html) {
349
- s = s.replace(/>$/, ' />');
350
- } else {
351
- if (pretty && ~s.indexOf('\n')) s = s + '\n';
352
- s = s + `</${nodeName}>`;
353
- }
354
-
355
- return s;
356
- }
357
-
358
- function getComponentName(component) {
359
- return (
360
- component.displayName ||
361
- (component !== Function && component.name) ||
362
- getFallbackComponentName(component)
363
- );
364
- }
365
-
366
- function getFallbackComponentName(component) {
367
- let str = Function.prototype.toString.call(component),
368
- name = (str.match(/^\s*function\s+([^( ]+)/) || '')[1];
369
- if (!name) {
370
- // search for an existing indexed name for the given component:
371
- let index = -1;
372
- for (let i = UNNAMED.length; i--; ) {
373
- if (UNNAMED[i] === component) {
374
- index = i;
375
- break;
376
- }
377
- }
378
- // not found, create a new indexed name:
379
- if (index < 0) {
380
- index = UNNAMED.push(component) - 1;
381
- }
382
- name = `UnnamedComponent${index}`;
383
- }
384
- return name;
385
- }
1
+ import {
2
+ encodeEntities,
3
+ indent,
4
+ isLargeString,
5
+ styleObjToCss,
6
+ getChildren,
7
+ createComponent,
8
+ getContext,
9
+ UNSAFE_NAME,
10
+ XLINK,
11
+ VOID_ELEMENTS
12
+ } from './util';
13
+ import { options, Fragment } from 'preact';
14
+
15
+ // components without names, kept as a hash for later comparison to return consistent UnnamedComponentXX names.
16
+ const UNNAMED = [];
17
+
18
+ export function _renderToStringPretty(
19
+ vnode,
20
+ context,
21
+ opts,
22
+ inner,
23
+ isSvgMode,
24
+ selectValue
25
+ ) {
26
+ if (vnode == null || typeof vnode === 'boolean') {
27
+ return '';
28
+ }
29
+
30
+ // #text nodes
31
+ if (typeof vnode !== 'object') {
32
+ if (typeof vnode === 'function') return '';
33
+ return encodeEntities(vnode);
34
+ }
35
+
36
+ let pretty = opts.pretty,
37
+ indentChar = pretty && typeof pretty === 'string' ? pretty : '\t';
38
+
39
+ if (Array.isArray(vnode)) {
40
+ let rendered = '';
41
+ for (let i = 0; i < vnode.length; i++) {
42
+ if (pretty && i > 0) rendered = rendered + '\n';
43
+ rendered =
44
+ rendered +
45
+ _renderToStringPretty(
46
+ vnode[i],
47
+ context,
48
+ opts,
49
+ inner,
50
+ isSvgMode,
51
+ selectValue
52
+ );
53
+ }
54
+ return rendered;
55
+ }
56
+
57
+ // VNodes have {constructor:undefined} to prevent JSON injection:
58
+ if (vnode.constructor !== undefined) return '';
59
+
60
+ let nodeName = vnode.type,
61
+ props = vnode.props,
62
+ isComponent = false;
63
+
64
+ // components
65
+ if (typeof nodeName === 'function') {
66
+ isComponent = true;
67
+ if (opts.shallow && (inner || opts.renderRootComponent === false)) {
68
+ nodeName = getComponentName(nodeName);
69
+ } else if (nodeName === Fragment) {
70
+ const children = [];
71
+ getChildren(children, vnode.props.children);
72
+ return _renderToStringPretty(
73
+ children,
74
+ context,
75
+ opts,
76
+ opts.shallowHighOrder !== false,
77
+ isSvgMode,
78
+ selectValue
79
+ );
80
+ } else {
81
+ let rendered;
82
+
83
+ let c = (vnode.__c = createComponent(vnode, context));
84
+
85
+ // options._diff
86
+ if (options.__b) options.__b(vnode);
87
+
88
+ // options._render
89
+ let renderHook = options.__r;
90
+
91
+ if (
92
+ !nodeName.prototype ||
93
+ typeof nodeName.prototype.render !== 'function'
94
+ ) {
95
+ let cctx = getContext(nodeName, context);
96
+
97
+ // If a hook invokes setState() to invalidate the component during rendering,
98
+ // re-render it up to 25 times to allow "settling" of memoized states.
99
+ // Note:
100
+ // This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
101
+ // https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
102
+ let count = 0;
103
+ while (c.__d && count++ < 25) {
104
+ c.__d = false;
105
+
106
+ if (renderHook) renderHook(vnode);
107
+
108
+ // stateless functional components
109
+ rendered = nodeName.call(vnode.__c, props, cctx);
110
+ }
111
+ } else {
112
+ let cctx = getContext(nodeName, context);
113
+
114
+ // c = new nodeName(props, context);
115
+ c = vnode.__c = new nodeName(props, cctx);
116
+ c.__v = vnode;
117
+ // turn off stateful re-rendering:
118
+ c._dirty = c.__d = true;
119
+ c.props = props;
120
+ if (c.state == null) c.state = {};
121
+
122
+ if (c._nextState == null && c.__s == null) {
123
+ c._nextState = c.__s = c.state;
124
+ }
125
+
126
+ c.context = cctx;
127
+ if (nodeName.getDerivedStateFromProps)
128
+ c.state = Object.assign(
129
+ {},
130
+ c.state,
131
+ nodeName.getDerivedStateFromProps(c.props, c.state)
132
+ );
133
+ else if (c.componentWillMount) {
134
+ c.componentWillMount();
135
+
136
+ // If the user called setState in cWM we need to flush pending,
137
+ // state updates. This is the same behaviour in React.
138
+ c.state =
139
+ c._nextState !== c.state
140
+ ? c._nextState
141
+ : c.__s !== c.state
142
+ ? c.__s
143
+ : c.state;
144
+ }
145
+
146
+ if (renderHook) renderHook(vnode);
147
+
148
+ rendered = c.render(c.props, c.state, c.context);
149
+ }
150
+
151
+ if (c.getChildContext) {
152
+ context = Object.assign({}, context, c.getChildContext());
153
+ }
154
+
155
+ if (options.diffed) options.diffed(vnode);
156
+ return _renderToStringPretty(
157
+ rendered,
158
+ context,
159
+ opts,
160
+ opts.shallowHighOrder !== false,
161
+ isSvgMode,
162
+ selectValue
163
+ );
164
+ }
165
+ }
166
+
167
+ // render JSX to HTML
168
+ let s = '<' + nodeName,
169
+ propChildren,
170
+ html;
171
+
172
+ if (props) {
173
+ let attrs = Object.keys(props);
174
+
175
+ // allow sorting lexicographically for more determinism (useful for tests, such as via preact-jsx-chai)
176
+ if (opts && opts.sortAttributes === true) attrs.sort();
177
+
178
+ for (let i = 0; i < attrs.length; i++) {
179
+ let name = attrs[i],
180
+ v = props[name];
181
+ if (name === 'children') {
182
+ propChildren = v;
183
+ continue;
184
+ }
185
+
186
+ if (UNSAFE_NAME.test(name)) continue;
187
+
188
+ if (
189
+ !(opts && opts.allAttributes) &&
190
+ (name === 'key' ||
191
+ name === 'ref' ||
192
+ name === '__self' ||
193
+ name === '__source')
194
+ )
195
+ continue;
196
+
197
+ if (name === 'defaultValue') {
198
+ name = 'value';
199
+ } else if (name === 'defaultChecked') {
200
+ name = 'checked';
201
+ } else if (name === 'defaultSelected') {
202
+ name = 'selected';
203
+ } else if (name === 'className') {
204
+ if (typeof props.class !== 'undefined') continue;
205
+ name = 'class';
206
+ } else if (isSvgMode && XLINK.test(name)) {
207
+ name = name.toLowerCase().replace(/^xlink:?/, 'xlink:');
208
+ }
209
+
210
+ if (name === 'htmlFor') {
211
+ if (props.for) continue;
212
+ name = 'for';
213
+ }
214
+
215
+ if (name === 'style' && v && typeof v === 'object') {
216
+ v = styleObjToCss(v);
217
+ }
218
+
219
+ // always use string values instead of booleans for aria attributes
220
+ // also see https://github.com/preactjs/preact/pull/2347/files
221
+ if (name[0] === 'a' && name['1'] === 'r' && typeof v === 'boolean') {
222
+ v = String(v);
223
+ }
224
+
225
+ let hooked =
226
+ opts.attributeHook &&
227
+ opts.attributeHook(name, v, context, opts, isComponent);
228
+ if (hooked || hooked === '') {
229
+ s = s + hooked;
230
+ continue;
231
+ }
232
+
233
+ if (name === 'dangerouslySetInnerHTML') {
234
+ html = v && v.__html;
235
+ } else if (nodeName === 'textarea' && name === 'value') {
236
+ // <textarea value="a&b"> --> <textarea>a&amp;b</textarea>
237
+ propChildren = v;
238
+ } else if ((v || v === 0 || v === '') && typeof v !== 'function') {
239
+ if (v === true || v === '') {
240
+ v = name;
241
+ // in non-xml mode, allow boolean attributes
242
+ if (!opts || !opts.xml) {
243
+ s = s + ' ' + name;
244
+ continue;
245
+ }
246
+ }
247
+
248
+ if (name === 'value') {
249
+ if (nodeName === 'select') {
250
+ selectValue = v;
251
+ continue;
252
+ } else if (
253
+ // If we're looking at an <option> and it's the currently selected one
254
+ nodeName === 'option' &&
255
+ selectValue == v &&
256
+ // and the <option> doesn't already have a selected attribute on it
257
+ typeof props.selected === 'undefined'
258
+ ) {
259
+ s = s + ` selected`;
260
+ }
261
+ }
262
+ s = s + ` ${name}="${encodeEntities(v)}"`;
263
+ }
264
+ }
265
+ }
266
+
267
+ // account for >1 multiline attribute
268
+ if (pretty) {
269
+ let sub = s.replace(/\n\s*/, ' ');
270
+ if (sub !== s && !~sub.indexOf('\n')) s = sub;
271
+ else if (pretty && ~s.indexOf('\n')) s = s + '\n';
272
+ }
273
+
274
+ s = s + '>';
275
+
276
+ if (UNSAFE_NAME.test(nodeName))
277
+ throw new Error(`${nodeName} is not a valid HTML tag name in ${s}`);
278
+
279
+ let isVoid =
280
+ VOID_ELEMENTS.test(nodeName) ||
281
+ (opts.voidElements && opts.voidElements.test(nodeName));
282
+ let pieces = [];
283
+
284
+ let children;
285
+ if (html) {
286
+ // if multiline, indent.
287
+ if (pretty && isLargeString(html)) {
288
+ html = '\n' + indentChar + indent(html, indentChar);
289
+ }
290
+ s = s + html;
291
+ } else if (
292
+ propChildren != null &&
293
+ getChildren((children = []), propChildren).length
294
+ ) {
295
+ let hasLarge = pretty && ~s.indexOf('\n');
296
+ let lastWasText = false;
297
+
298
+ for (let i = 0; i < children.length; i++) {
299
+ let child = children[i];
300
+
301
+ if (child != null && child !== false) {
302
+ let childSvgMode =
303
+ nodeName === 'svg'
304
+ ? true
305
+ : nodeName === 'foreignObject'
306
+ ? false
307
+ : isSvgMode,
308
+ ret = _renderToStringPretty(
309
+ child,
310
+ context,
311
+ opts,
312
+ true,
313
+ childSvgMode,
314
+ selectValue
315
+ );
316
+
317
+ if (pretty && !hasLarge && isLargeString(ret)) hasLarge = true;
318
+
319
+ // Skip if we received an empty string
320
+ if (ret) {
321
+ if (pretty) {
322
+ let isText = ret.length > 0 && ret[0] != '<';
323
+
324
+ // We merge adjacent text nodes, otherwise each piece would be printed
325
+ // on a new line.
326
+ if (lastWasText && isText) {
327
+ pieces[pieces.length - 1] += ret;
328
+ } else {
329
+ pieces.push(ret);
330
+ }
331
+
332
+ lastWasText = isText;
333
+ } else {
334
+ pieces.push(ret);
335
+ }
336
+ }
337
+ }
338
+ }
339
+ if (pretty && hasLarge) {
340
+ for (let i = pieces.length; i--; ) {
341
+ pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar);
342
+ }
343
+ }
344
+ }
345
+
346
+ if (pieces.length || html) {
347
+ s = s + pieces.join('');
348
+ } else if (opts && opts.xml) {
349
+ return s.substring(0, s.length - 1) + ' />';
350
+ }
351
+
352
+ if (isVoid && !children && !html) {
353
+ s = s.replace(/>$/, ' />');
354
+ } else {
355
+ if (pretty && ~s.indexOf('\n')) s = s + '\n';
356
+ s = s + `</${nodeName}>`;
357
+ }
358
+
359
+ return s;
360
+ }
361
+
362
+ function getComponentName(component) {
363
+ return (
364
+ component.displayName ||
365
+ (component !== Function && component.name) ||
366
+ getFallbackComponentName(component)
367
+ );
368
+ }
369
+
370
+ function getFallbackComponentName(component) {
371
+ let str = Function.prototype.toString.call(component),
372
+ name = (str.match(/^\s*function\s+([^( ]+)/) || '')[1];
373
+ if (!name) {
374
+ // search for an existing indexed name for the given component:
375
+ let index = -1;
376
+ for (let i = UNNAMED.length; i--; ) {
377
+ if (UNNAMED[i] === component) {
378
+ index = i;
379
+ break;
380
+ }
381
+ }
382
+ // not found, create a new indexed name:
383
+ if (index < 0) {
384
+ index = UNNAMED.push(component) - 1;
385
+ }
386
+ name = `UnnamedComponent${index}`;
387
+ }
388
+ return name;
389
+ }