@lightningjs/blits 0.10.0 → 1.1.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/CHANGELOG.md +23 -0
- package/boilerplate/js/default/src/index.js +1 -0
- package/docs/essentials/displaying_text.md +1 -1
- package/package.json +5 -5
- package/src/application.js +2 -1
- package/src/component/base/events.js +1 -1
- package/src/component/base/utils.js +34 -1
- package/src/component/setup/props.js +3 -1
- package/src/component/setup/props.test.js +51 -19
- package/src/component.d.ts +2 -1
- package/src/component.js +20 -13
- package/src/component.test.js +340 -4
- package/src/components/Circle.js +13 -12
- package/src/components/FPScounter.js +388 -536
- package/src/components/Image.js +7 -9
- package/src/components/Layout.js +49 -0
- package/src/components/Layout.orig.js +34 -0
- package/src/components/RouterView.js +6 -10
- package/src/components/Sprite.js +10 -12
- package/src/components/index.js +2 -2
- package/src/components/index.orig.js +2 -2
- package/src/constants.js +14 -0
- package/src/engine.js +1 -1
- package/src/engines/L3/element.js +193 -180
- package/src/engines/L3/element.test.js +170 -0
- package/src/engines/L3/fontLoader.js +4 -5
- package/src/engines/L3/index.js +2 -2
- package/src/engines/L3/launch.js +10 -16
- package/src/engines/L3/shaderLoader.js +12 -0
- package/src/engines/index.js +1 -1
- package/src/focus.js +3 -2
- package/src/launch.d.ts +31 -3
- package/src/launch.js +1 -1
- package/src/lib/codegenerator/generator.js +212 -84
- package/src/lib/codegenerator/generator.test.js +657 -942
- package/src/lib/colors/colors.js +59 -46
- package/src/lib/componentId.js +9 -0
- package/src/lib/componentId.test.js +2 -1
- package/src/lib/precompiler/precompiler.js +3 -4
- package/src/lib/reactivity/effect.js +10 -13
- package/src/lib/reactivity/reactive.js +24 -14
- package/src/lib/symbols.js +1 -0
- package/src/router/router.js +17 -3
- package/vite/index.js +1 -4
- package/vite/preCompiler.js +3 -1
- package/boilerplate/js/default/src/renderer.js +0 -4
- package/src/components/Text.js +0 -119
- package/src/components/Text.orig.js +0 -81
|
@@ -19,7 +19,7 @@ let counter
|
|
|
19
19
|
|
|
20
20
|
export default function (templateObject = { children: [] }) {
|
|
21
21
|
const ctx = {
|
|
22
|
-
renderCode: ['const elms = []'],
|
|
22
|
+
renderCode: ['const elms = []', 'let componentType', 'const rootComponent = component'],
|
|
23
23
|
effectsCode: [],
|
|
24
24
|
context: { props: [], components: this.components },
|
|
25
25
|
}
|
|
@@ -29,9 +29,18 @@ export default function (templateObject = { children: [] }) {
|
|
|
29
29
|
ctx.renderCode.push('return elms')
|
|
30
30
|
|
|
31
31
|
return {
|
|
32
|
-
render: new Function(
|
|
32
|
+
render: new Function(
|
|
33
|
+
'parent',
|
|
34
|
+
'component',
|
|
35
|
+
'context',
|
|
36
|
+
'components',
|
|
37
|
+
'effect',
|
|
38
|
+
'getRaw',
|
|
39
|
+
ctx.renderCode.join('\n')
|
|
40
|
+
),
|
|
33
41
|
effects: ctx.effectsCode.map(
|
|
34
|
-
(code) =>
|
|
42
|
+
(code) =>
|
|
43
|
+
new Function('component', 'elms', 'context', 'components', 'rootComponent', 'effect', code)
|
|
35
44
|
),
|
|
36
45
|
context: ctx.context,
|
|
37
46
|
}
|
|
@@ -40,7 +49,7 @@ export default function (templateObject = { children: [] }) {
|
|
|
40
49
|
const generateElementCode = function (
|
|
41
50
|
templateObject,
|
|
42
51
|
parent = false,
|
|
43
|
-
options = { key: false, component: 'component.', forceEffect: false }
|
|
52
|
+
options = { key: false, component: 'component.', forceEffect: false, forloop: false }
|
|
44
53
|
) {
|
|
45
54
|
const renderCode = options.forceEffect ? this.effectsCode : this.renderCode
|
|
46
55
|
if (parent) {
|
|
@@ -52,17 +61,26 @@ const generateElementCode = function (
|
|
|
52
61
|
|
|
53
62
|
if (options.key) {
|
|
54
63
|
renderCode.push(`
|
|
55
|
-
elms[${counter}]
|
|
64
|
+
if(elms[${counter}] === undefined) {
|
|
65
|
+
elms[${counter}] = {}
|
|
66
|
+
}
|
|
56
67
|
`)
|
|
57
68
|
}
|
|
58
69
|
|
|
70
|
+
renderCode.push(`const elementConfig${counter} = {}`)
|
|
71
|
+
|
|
72
|
+
if (options.forloop) {
|
|
73
|
+
renderCode.push(`if(!${elm}) {`)
|
|
74
|
+
}
|
|
75
|
+
|
|
59
76
|
renderCode.push(`
|
|
60
|
-
|
|
61
|
-
${elm} = this.element({parent: parent || 'root'}, component)
|
|
62
|
-
}
|
|
63
|
-
const elementConfig${counter} = {}
|
|
77
|
+
${elm} = this.element({parent: parent || 'root'}, component)
|
|
64
78
|
`)
|
|
65
79
|
|
|
80
|
+
if (options.forloop) {
|
|
81
|
+
renderCode.push('}')
|
|
82
|
+
}
|
|
83
|
+
|
|
66
84
|
const children = templateObject['children']
|
|
67
85
|
delete templateObject['children']
|
|
68
86
|
|
|
@@ -77,11 +95,19 @@ const generateElementCode = function (
|
|
|
77
95
|
`)
|
|
78
96
|
}
|
|
79
97
|
|
|
98
|
+
if (key === 'key') return
|
|
99
|
+
|
|
80
100
|
if (isReactiveKey(key)) {
|
|
81
101
|
if (options.holder && key === ':color') return
|
|
82
102
|
this.effectsCode.push(
|
|
83
103
|
`${elm}.set('${key.substring(1)}', ${interpolate(templateObject[key], options.component)})`
|
|
84
104
|
)
|
|
105
|
+
renderCode.push(
|
|
106
|
+
`elementConfig${counter}['${key.substring(1)}'] = ${interpolate(
|
|
107
|
+
templateObject[key],
|
|
108
|
+
options.component
|
|
109
|
+
)}`
|
|
110
|
+
)
|
|
85
111
|
} else {
|
|
86
112
|
renderCode.push(
|
|
87
113
|
`elementConfig${counter}['${key}'] = ${cast(templateObject[key], key, options.component)}`
|
|
@@ -99,11 +125,15 @@ const generateElementCode = function (
|
|
|
99
125
|
`)
|
|
100
126
|
}
|
|
101
127
|
|
|
102
|
-
|
|
103
|
-
if(!${elm}.nodeId) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
`)
|
|
128
|
+
if (options.forloop) {
|
|
129
|
+
renderCode.push(`if(!${elm}.nodeId) {`)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
renderCode.push(`${elm}.populate(elementConfig${counter})`)
|
|
133
|
+
|
|
134
|
+
if (options.forloop) {
|
|
135
|
+
renderCode.push('}')
|
|
136
|
+
}
|
|
107
137
|
|
|
108
138
|
if (children) {
|
|
109
139
|
generateCode.call(this, { children }, `${elm}`, options)
|
|
@@ -113,7 +143,13 @@ const generateElementCode = function (
|
|
|
113
143
|
const generateComponentCode = function (
|
|
114
144
|
templateObject,
|
|
115
145
|
parent = false,
|
|
116
|
-
options = {
|
|
146
|
+
options = {
|
|
147
|
+
key: false,
|
|
148
|
+
component: 'component.',
|
|
149
|
+
forceEffect: false,
|
|
150
|
+
holder: false,
|
|
151
|
+
forloop: false,
|
|
152
|
+
}
|
|
117
153
|
) {
|
|
118
154
|
const renderCode = options.forceEffect ? this.effectsCode : this.renderCode
|
|
119
155
|
|
|
@@ -140,7 +176,9 @@ const generateComponentCode = function (
|
|
|
140
176
|
|
|
141
177
|
if (options.key) {
|
|
142
178
|
renderCode.push(`
|
|
143
|
-
elms[${counter}]
|
|
179
|
+
if(elms[${counter}] === undefined) {
|
|
180
|
+
elms[${counter}] = {}
|
|
181
|
+
}
|
|
144
182
|
`)
|
|
145
183
|
}
|
|
146
184
|
|
|
@@ -169,43 +207,56 @@ const generateComponentCode = function (
|
|
|
169
207
|
}
|
|
170
208
|
})
|
|
171
209
|
|
|
210
|
+
if (options.forloop) {
|
|
211
|
+
renderCode.push(`if(!${elm}) {`)
|
|
212
|
+
}
|
|
213
|
+
|
|
172
214
|
renderCode.push(`
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
component${counter} = context.components && context.components[componentType] || components[componentType]
|
|
181
|
-
if(!component${counter}) {
|
|
182
|
-
throw new Error('Component "${templateObject[Symbol.for('componentType')]}" not found')
|
|
183
|
-
}
|
|
184
|
-
} else if(typeof componentType === 'function' && componentType.name === 'factory') {
|
|
185
|
-
component${counter} = componentType
|
|
215
|
+
componentType = props${counter}['is'] || '${templateObject[Symbol.for('componentType')]}'
|
|
216
|
+
|
|
217
|
+
let component${counter}
|
|
218
|
+
if(typeof componentType === 'string') {
|
|
219
|
+
component${counter} = context.components && context.components[componentType] || components[componentType]
|
|
220
|
+
if(!component${counter}) {
|
|
221
|
+
throw new Error('Component "${templateObject[Symbol.for('componentType')]}" not found')
|
|
186
222
|
}
|
|
223
|
+
} else if(typeof componentType === 'function' && componentType.name === 'factory') {
|
|
224
|
+
component${counter} = componentType
|
|
225
|
+
}
|
|
187
226
|
|
|
188
|
-
|
|
227
|
+
${elm} = component${counter}.call(null, {props: props${counter}}, ${parent}, component)
|
|
189
228
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
229
|
+
if (${elm}[Symbol.for('slots')][0]) {
|
|
230
|
+
parent = ${elm}[Symbol.for('slots')][0]
|
|
231
|
+
component = ${elm}
|
|
232
|
+
} else {
|
|
233
|
+
parent = ${elm}[Symbol.for('children')][0]
|
|
196
234
|
}
|
|
197
235
|
`)
|
|
198
236
|
|
|
237
|
+
if (options.forloop) {
|
|
238
|
+
renderCode.push('}')
|
|
239
|
+
}
|
|
240
|
+
|
|
199
241
|
if (children) {
|
|
200
242
|
counter++
|
|
201
243
|
generateElementCode.call(this, { children }, false, { ...options })
|
|
202
244
|
}
|
|
245
|
+
// if (!options.forloop) {
|
|
246
|
+
// renderCode.push(`
|
|
247
|
+
// component = rootComponent
|
|
248
|
+
// `)
|
|
249
|
+
// }
|
|
203
250
|
}
|
|
204
251
|
|
|
205
252
|
const generateForLoopCode = function (templateObject, parent) {
|
|
206
253
|
const forLoop = templateObject[':for']
|
|
207
254
|
delete templateObject[':for']
|
|
208
255
|
|
|
256
|
+
const key = templateObject['key']
|
|
257
|
+
const forKey = interpolate(key, 'scope.')
|
|
258
|
+
|
|
259
|
+
delete templateObject['key']
|
|
209
260
|
const regex = /(.+)\s+in\s+(.+)/gi
|
|
210
261
|
// const regex = /(:?\(*)(.+)\s+in\s+(.+)/gi
|
|
211
262
|
|
|
@@ -217,6 +268,8 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
217
268
|
.replace(')', '')
|
|
218
269
|
.split(/\s*,\s*/)
|
|
219
270
|
|
|
271
|
+
const scopeRegex = new RegExp(`(scope\\.(?!${item}\\.|${index}|key)(\\w+))`, 'gi')
|
|
272
|
+
|
|
220
273
|
// local context
|
|
221
274
|
const ctx = {
|
|
222
275
|
renderCode: [],
|
|
@@ -225,87 +278,157 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
225
278
|
}
|
|
226
279
|
|
|
227
280
|
if (parent) {
|
|
228
|
-
ctx.renderCode.push(`
|
|
281
|
+
ctx.renderCode.push(`parent = ${parent}`)
|
|
229
282
|
}
|
|
230
283
|
|
|
231
284
|
const forStartCounter = counter
|
|
232
285
|
|
|
233
|
-
// reference all reactive attributes (except those referencing the iterator item),
|
|
234
|
-
// to ensure that reactivity is registered, even when the initial array is empty
|
|
235
|
-
Object.keys(templateObject).forEach((k) => {
|
|
236
|
-
if (isReactiveKey(k) && templateObject[k].indexOf('$' + item) === -1) {
|
|
237
|
-
ctx.renderCode.push(`
|
|
238
|
-
void ${interpolate(templateObject[k], 'component.')}
|
|
239
|
-
`)
|
|
240
|
-
}
|
|
241
|
-
})
|
|
242
|
-
|
|
243
286
|
ctx.renderCode.push(`
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
287
|
+
const created${forStartCounter} = []
|
|
288
|
+
const forloop${forStartCounter} = (collection = [], elms, created) => {
|
|
289
|
+
const rawCollection = getRaw(collection)
|
|
290
|
+
const keys = new Set(rawCollection.map((${item}) => '' + ${interpolate(key, '')}))
|
|
291
|
+
`)
|
|
292
|
+
|
|
293
|
+
// keep track of the index in the render code so we can inject
|
|
294
|
+
// the code that takes care of destroying elements (generated later on)
|
|
295
|
+
// in the right spot
|
|
296
|
+
const indexToInjectDestroyCode = ctx.renderCode.length
|
|
254
297
|
|
|
298
|
+
ctx.renderCode.push(`
|
|
299
|
+
created.length = 0
|
|
300
|
+
const length = collection.length
|
|
301
|
+
for(let __index = 0; __index < length; __index++) {
|
|
302
|
+
const scope = Object.create(component)
|
|
303
|
+
parent = ${parent}
|
|
304
|
+
scope['${index}'] = __index
|
|
305
|
+
scope['${item}'] = rawCollection[__index]
|
|
306
|
+
scope['key'] = ${forKey || '__index'}
|
|
307
|
+
`)
|
|
255
308
|
if ('ref' in templateObject && templateObject.ref.indexOf('$') === -1) {
|
|
256
309
|
// automatically map the ref for each item in the loop based on the given ref key
|
|
257
310
|
ctx.renderCode.push(`
|
|
258
|
-
|
|
311
|
+
scope['__ref'] = '${templateObject.ref}' + __index
|
|
259
312
|
`)
|
|
260
313
|
templateObject.ref = '$__ref'
|
|
261
314
|
}
|
|
315
|
+
|
|
262
316
|
ctx.renderCode.push(`
|
|
263
|
-
|
|
317
|
+
created.push(scope.key)
|
|
264
318
|
`)
|
|
265
319
|
|
|
266
|
-
if ('key' in templateObject) {
|
|
267
|
-
ctx.renderCode.push(`
|
|
268
|
-
keys.push(${interpolate(templateObject.key, 'scope.')}.toString())
|
|
269
|
-
`)
|
|
270
|
-
} else {
|
|
271
|
-
ctx.renderCode.push(`
|
|
272
|
-
keys.push(scope.key.toString())
|
|
273
|
-
`)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
320
|
if (
|
|
277
321
|
templateObject[Symbol.for('componentType')] === 'Element' ||
|
|
278
|
-
templateObject[Symbol.for('componentType')] === 'Slot'
|
|
322
|
+
templateObject[Symbol.for('componentType')] === 'Slot' ||
|
|
323
|
+
templateObject[Symbol.for('componentType')] === 'Text'
|
|
279
324
|
) {
|
|
280
325
|
generateElementCode.call(ctx, templateObject, parent, {
|
|
281
326
|
key: 'scope.key',
|
|
282
327
|
component: 'scope.',
|
|
283
328
|
forceEffect: false,
|
|
329
|
+
forloop: true,
|
|
284
330
|
})
|
|
285
331
|
} else {
|
|
286
332
|
generateComponentCode.call(ctx, templateObject, false, {
|
|
287
333
|
key: 'scope.key',
|
|
288
334
|
component: 'scope.',
|
|
289
335
|
forceEffect: false,
|
|
336
|
+
forloop: true,
|
|
290
337
|
})
|
|
291
338
|
}
|
|
292
|
-
ctx.renderCode = ctx.renderCode.concat(ctx.effectsCode)
|
|
293
|
-
ctx.renderCode.push('}')
|
|
294
339
|
|
|
340
|
+
// separate effects that only rely on variables in the itteration
|
|
341
|
+
const innerScopeEffects = ctx.effectsCode.filter(
|
|
342
|
+
(effect) => [...effect.matchAll(scopeRegex)].length === 0
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
// separate effects that (also) rely on variables in the outer scope
|
|
346
|
+
const outerScopeEffects = ctx.effectsCode.filter(
|
|
347
|
+
(effect) => [...effect.matchAll(scopeRegex)].length !== 0
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
ctx.renderCode.push(`
|
|
351
|
+
scope['${item}'] = collection[__index]
|
|
352
|
+
`)
|
|
353
|
+
|
|
354
|
+
// inner scope variables are part of the main forloop
|
|
355
|
+
innerScopeEffects.forEach((effect) => {
|
|
356
|
+
const key = effect.indexOf(`scope.${index}`) > -1 ? `'${interpolate(result[2], '')}'` : null
|
|
357
|
+
ctx.renderCode.push(`
|
|
358
|
+
effect(() => {
|
|
359
|
+
${effect}
|
|
360
|
+
}, ${key})
|
|
361
|
+
`)
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
ctx.renderCode.push(`
|
|
365
|
+
if(elms[${forStartCounter}][0] && elms[${forStartCounter}][0].forComponent && elms[${forStartCounter}][0].forComponent.___layout) {
|
|
366
|
+
elms[${forStartCounter}][0].forComponent.___layout()
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}`)
|
|
370
|
+
|
|
371
|
+
// generate code that destroys items
|
|
372
|
+
const destroyCode = []
|
|
373
|
+
destroyCode.push(`
|
|
374
|
+
let i = created.length
|
|
375
|
+
|
|
376
|
+
while (i--) {
|
|
377
|
+
const key = created[i]
|
|
378
|
+
if (!keys.has(key)) {
|
|
379
|
+
`)
|
|
295
380
|
const forEndCounter = counter
|
|
381
|
+
|
|
382
|
+
for (let i = forStartCounter; i <= forEndCounter; i++) {
|
|
383
|
+
destroyCode.push(`
|
|
384
|
+
elms[${i}][key] && elms[${i}][key].destroy()
|
|
385
|
+
delete elms[${i}][key]
|
|
386
|
+
`)
|
|
387
|
+
}
|
|
388
|
+
destroyCode.push(`
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
`)
|
|
392
|
+
|
|
393
|
+
// inject the destroy code in the correct spot
|
|
394
|
+
ctx.renderCode.splice(indexToInjectDestroyCode, 0, ...destroyCode)
|
|
296
395
|
ctx.renderCode.push(`
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
396
|
+
effect(() => {
|
|
397
|
+
forloop${forStartCounter}(${cast(result[2], ':for')}, elms, created${forStartCounter})
|
|
398
|
+
}, '${interpolate(result[2], '')}')
|
|
399
|
+
`)
|
|
400
|
+
|
|
401
|
+
outerScopeEffects.forEach((effect) => {
|
|
402
|
+
const matches = [...effect.matchAll(scopeRegex)]
|
|
403
|
+
|
|
404
|
+
let l = matches.length
|
|
405
|
+
const refs = []
|
|
406
|
+
while (l--) {
|
|
407
|
+
const match = matches[l]
|
|
408
|
+
const ref = `component.${match[2]}`
|
|
409
|
+
refs.indexOf(ref) === -1 && refs.push(ref)
|
|
410
|
+
effect =
|
|
411
|
+
effect.substring(0, match.index) + ref + effect.substring(match.index + match[1].length)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
ctx.renderCode.push(`
|
|
415
|
+
effect(() => {
|
|
416
|
+
void ${refs.join(', ')}
|
|
417
|
+
for(let __index = 0; __index < ${interpolate(result[2])}.length; __index++) {
|
|
418
|
+
const scope = {}
|
|
419
|
+
scope['${index}'] = __index
|
|
420
|
+
scope['${item}'] = ${interpolate(result[2])}[__index]
|
|
421
|
+
scope['key'] = ${forKey || '__index'}
|
|
422
|
+
`)
|
|
423
|
+
|
|
424
|
+
ctx.renderCode.push(`
|
|
425
|
+
${effect}
|
|
304
426
|
}
|
|
305
427
|
})
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
428
|
+
`)
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
this.renderCode.push(ctx.renderCode.join('\n'))
|
|
309
432
|
}
|
|
310
433
|
|
|
311
434
|
const generateCode = function (templateObject, parent = false, options = {}) {
|
|
@@ -318,8 +441,12 @@ const generateCode = function (templateObject, parent = false, options = {}) {
|
|
|
318
441
|
} else {
|
|
319
442
|
if (
|
|
320
443
|
childTemplateObject[Symbol.for('componentType')] === 'Element' ||
|
|
321
|
-
childTemplateObject[Symbol.for('componentType')] === 'Slot'
|
|
444
|
+
childTemplateObject[Symbol.for('componentType')] === 'Slot' ||
|
|
445
|
+
childTemplateObject[Symbol.for('componentType')] === 'Text'
|
|
322
446
|
) {
|
|
447
|
+
if (childTemplateObject[Symbol.for('componentType')] === 'Text') {
|
|
448
|
+
childTemplateObject.__textnode = 'true'
|
|
449
|
+
}
|
|
323
450
|
generateElementCode.call(this, childTemplateObject, parent, options)
|
|
324
451
|
} else {
|
|
325
452
|
generateComponentCode.call(this, childTemplateObject, parent, options)
|
|
@@ -329,6 +456,7 @@ const generateCode = function (templateObject, parent = false, options = {}) {
|
|
|
329
456
|
}
|
|
330
457
|
|
|
331
458
|
const interpolate = (val, component = 'component.') => {
|
|
459
|
+
if (val === undefined) return val
|
|
332
460
|
const replaceString = /('.*?')+/gi
|
|
333
461
|
const replaceDollar = /\$/gi
|
|
334
462
|
const matches = val.matchAll(replaceString)
|
|
@@ -344,7 +472,7 @@ const interpolate = (val, component = 'component.') => {
|
|
|
344
472
|
}
|
|
345
473
|
|
|
346
474
|
// replace remaining dollar signs
|
|
347
|
-
val = val.replace(replaceDollar, component)
|
|
475
|
+
val = val.replace(replaceDollar, component || '')
|
|
348
476
|
|
|
349
477
|
// restore string replacemenet
|
|
350
478
|
restore.forEach((el, idx) => {
|