@lightningjs/blits 0.5.10 → 0.6.1
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 +14 -0
- package/boilerplate/package.json +1 -1
- package/boilerplate/vite.config.js +2 -2
- package/docs/_sidebar.md +1 -0
- package/docs/text-to-speech-announcer.md +50 -0
- package/package.json +1 -1
- package/src/announcer/announcer.js +48 -0
- package/src/announcer/speechSynthesis.js +127 -0
- package/src/application.d.ts +21 -1
- package/src/component.js +5 -7
- package/src/components/Text.js +2 -1
- package/src/launch.d.ts +9 -0
- package/src/lib/codegenerator/generator.js +5 -4
- package/src/lib/setup/base.js +7 -0
- package/src/router/router.js +12 -1
- package/vite/index.js +6 -0
- package/vite/preCompiler.js +46 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
# v0.6.1
|
|
4
|
+
|
|
5
|
+
_8 jan 2024_
|
|
6
|
+
|
|
7
|
+
- Fixed issue with using single quotes as Text content
|
|
8
|
+
- Added first Text-to-Speech / Announcer functionality
|
|
9
|
+
|
|
10
|
+
# v0.6.0
|
|
11
|
+
|
|
12
|
+
_4 jan 2024_
|
|
13
|
+
|
|
14
|
+
- Added pre-compilation functionality to improve performance. Requires an update to the `vite.config.js` to enable. Read more details in this [blog post](https://lightningjs.io/blogs/blitsPreCompilation.html)
|
|
15
|
+
- Added `defaultFont` to the Launch settings
|
|
16
|
+
|
|
3
17
|
# v0.5.10
|
|
4
18
|
|
|
5
19
|
_3 jan 2024_
|
package/boilerplate/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defineConfig } from 'vite'
|
|
2
|
-
import
|
|
2
|
+
import blitsVitePlugins from '@lightningjs/blits/vite'
|
|
3
3
|
|
|
4
4
|
export default defineConfig(({ command, mode, ssrBuild }) => {
|
|
5
5
|
return {
|
|
6
|
-
plugins: [
|
|
6
|
+
plugins: [...blitsVitePlugins],
|
|
7
7
|
resolve: {
|
|
8
8
|
mainFields: ['browser', 'module', 'jsnext:main', 'jsnext'],
|
|
9
9
|
},
|
package/docs/_sidebar.md
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Blits - Lightning 3 App Development Framework
|
|
2
|
+
|
|
3
|
+
## Text-to-Speech / Announcer
|
|
4
|
+
|
|
5
|
+
Blits comes with a built-in Text-to-Speech / Announcer functionality, to easily make your App more accessible. This is something that's often overlooked when developing an App, but having speech assistance integrated into your App is a huge deal for those users that are visually impaired.
|
|
6
|
+
|
|
7
|
+
### Integrated with the router
|
|
8
|
+
|
|
9
|
+
The Announcer in Blits is directly integrated with the router functionality. This means that through simple configuration, a descriptive message can be announced, when navigating from page to page, without the need for adding extra custom code.
|
|
10
|
+
|
|
11
|
+
Just add an `announce` key in the configuration of your route, that contains the message you would like to be announced when visiting that route.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
const routes = [
|
|
15
|
+
// ...
|
|
16
|
+
{
|
|
17
|
+
path: '/settings',
|
|
18
|
+
component: Settings,
|
|
19
|
+
announce: "Welcome to the Settings page",
|
|
20
|
+
},
|
|
21
|
+
// ...
|
|
22
|
+
]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Custom announcement messages
|
|
26
|
+
|
|
27
|
+
Furthermore it's possible to speak out custom messages anywhere in your App logic, for example when a component receives focus, as a reaction to user input, or to announce error messages when an remote API call
|
|
28
|
+
fails.
|
|
29
|
+
|
|
30
|
+
Each component in Blits has a `this.$announcer.speak()` available, which accepts `string` of a message to be announced.
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
Blits.Component('MyComponent', {
|
|
34
|
+
// ...
|
|
35
|
+
hooks: {
|
|
36
|
+
focus() {
|
|
37
|
+
this.$announcer.speak('MyComponent just got focus')
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
keys: {
|
|
41
|
+
right() {
|
|
42
|
+
if(this.focused === this.items.length - 1) {
|
|
43
|
+
this.$announcer.speak('End of row reached')
|
|
44
|
+
} else {
|
|
45
|
+
//
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
```
|
package/package.json
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Comcast Cable Communications Management, LLC
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*
|
|
15
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import speechSynthesis from './speechSynthesis.js'
|
|
19
|
+
|
|
20
|
+
let debounce
|
|
21
|
+
|
|
22
|
+
const speak = (message, politeness = 'off') => {
|
|
23
|
+
clearTimeout(debounce)
|
|
24
|
+
speechSynthesis.cancel()
|
|
25
|
+
// assertive messages get spoken immediately
|
|
26
|
+
if (politeness === 'assertive') {
|
|
27
|
+
speechSynthesis.speak({ value: message })
|
|
28
|
+
} else {
|
|
29
|
+
debounce = setTimeout(() => {
|
|
30
|
+
speechSynthesis.speak({ value: message })
|
|
31
|
+
}, 400)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const polite = (message) => speak(message, 'polite')
|
|
36
|
+
|
|
37
|
+
const assertive = (message) => speak(message, 'assertive')
|
|
38
|
+
|
|
39
|
+
const stop = () => {
|
|
40
|
+
speechSynthesis.cancel()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default {
|
|
44
|
+
speak,
|
|
45
|
+
polite,
|
|
46
|
+
assertive,
|
|
47
|
+
stop,
|
|
48
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Comcast Cable Communications Management, LLC
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*
|
|
15
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const syn = window.speechSynthesis
|
|
19
|
+
|
|
20
|
+
const getUA = () => (window.navigator || {}).userAgent || ''
|
|
21
|
+
const isAndroid = () => /android/i.test(getUA())
|
|
22
|
+
|
|
23
|
+
let initialized = false
|
|
24
|
+
let infinityTimer = null
|
|
25
|
+
const clear = () => infinityTimer && clearTimeout(infinityTimer)
|
|
26
|
+
|
|
27
|
+
const resumeInfinity = (target) => {
|
|
28
|
+
if (!target || infinityTimer) {
|
|
29
|
+
return clear()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
syn.pause()
|
|
33
|
+
syn.resume()
|
|
34
|
+
|
|
35
|
+
infinityTimer = setTimeout(() => {
|
|
36
|
+
resumeInfinity(target)
|
|
37
|
+
}, 5000)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const utterProps = {
|
|
41
|
+
lang: 'en-US',
|
|
42
|
+
pitch: 1,
|
|
43
|
+
rate: 1,
|
|
44
|
+
voice: null,
|
|
45
|
+
volume: 1,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const initialize = () => {
|
|
49
|
+
utterProps.voice = syn.getVoices()[0]
|
|
50
|
+
initialized = true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const utterance = (scope, e) => {
|
|
54
|
+
const utter = new SpeechSynthesisUtterance(e.value)
|
|
55
|
+
|
|
56
|
+
// utter props
|
|
57
|
+
utter.lang = e.lang || utterProps.lang
|
|
58
|
+
utter.pitch = e.pitch || utterProps.pitch
|
|
59
|
+
utter.rate = e.rate || utterProps.rate
|
|
60
|
+
utter.voice = e.voice || utterProps.voice
|
|
61
|
+
utter.volume = e.volume || utterProps.volume
|
|
62
|
+
|
|
63
|
+
// utter events
|
|
64
|
+
utter.onstart = () => {
|
|
65
|
+
if (!isAndroid()) {
|
|
66
|
+
resumeInfinity(utter)
|
|
67
|
+
}
|
|
68
|
+
scope.onstart()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
utter.onresume = () => {
|
|
72
|
+
if (!isAndroid()) {
|
|
73
|
+
resumeInfinity(utter)
|
|
74
|
+
}
|
|
75
|
+
scope.onresume()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
utter.onpause = () => {
|
|
79
|
+
scope.onpause()
|
|
80
|
+
}
|
|
81
|
+
utter.onend = () => {
|
|
82
|
+
scope.onend()
|
|
83
|
+
}
|
|
84
|
+
utter.onerror = () => {
|
|
85
|
+
clear()
|
|
86
|
+
scope.onerror()
|
|
87
|
+
}
|
|
88
|
+
syn.speak(utter)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default {
|
|
92
|
+
speak(e) {
|
|
93
|
+
if (!initialized) {
|
|
94
|
+
initialize()
|
|
95
|
+
}
|
|
96
|
+
this.cancel()
|
|
97
|
+
utterance(this, e)
|
|
98
|
+
},
|
|
99
|
+
resume() {
|
|
100
|
+
syn.resume()
|
|
101
|
+
},
|
|
102
|
+
pause() {
|
|
103
|
+
syn.pause()
|
|
104
|
+
},
|
|
105
|
+
cancel() {
|
|
106
|
+
syn.cancel()
|
|
107
|
+
clear()
|
|
108
|
+
},
|
|
109
|
+
getVoices() {
|
|
110
|
+
return syn.getVoices()
|
|
111
|
+
},
|
|
112
|
+
onend() {
|
|
113
|
+
//event placeholder
|
|
114
|
+
},
|
|
115
|
+
onerror() {
|
|
116
|
+
//event placeholder
|
|
117
|
+
},
|
|
118
|
+
onstart() {
|
|
119
|
+
//event placeholder
|
|
120
|
+
},
|
|
121
|
+
onresume() {
|
|
122
|
+
//event placeholder
|
|
123
|
+
},
|
|
124
|
+
onpause() {
|
|
125
|
+
//eventplaceholder
|
|
126
|
+
},
|
|
127
|
+
}
|
package/src/application.d.ts
CHANGED
|
@@ -70,6 +70,19 @@ declare namespace Application {
|
|
|
70
70
|
|
|
71
71
|
type RouteTransitionFunction = (previousRoute: Route, currentRoute: Route) => RequireAtLeastOne<RouteTransition>
|
|
72
72
|
|
|
73
|
+
interface RouteAnnounce {
|
|
74
|
+
/**
|
|
75
|
+
* Message to be announced
|
|
76
|
+
*/
|
|
77
|
+
message: String,
|
|
78
|
+
/**
|
|
79
|
+
* Politeness level
|
|
80
|
+
*
|
|
81
|
+
* Defaults to 'off'
|
|
82
|
+
*/
|
|
83
|
+
politeness?: 'off' | 'polite' | 'assertive'
|
|
84
|
+
}
|
|
85
|
+
|
|
73
86
|
function Application(
|
|
74
87
|
config: Application.ApplicationConfig
|
|
75
88
|
) : Application.ApplicationInstance
|
|
@@ -94,7 +107,14 @@ declare namespace Application {
|
|
|
94
107
|
/**
|
|
95
108
|
* Extra route options
|
|
96
109
|
*/
|
|
97
|
-
options?: object // todo: specify which options are available
|
|
110
|
+
options?: object // todo: specify which options are available,
|
|
111
|
+
/**
|
|
112
|
+
* Message to be announced when visiting the route (often used for accessibility purposes)
|
|
113
|
+
*
|
|
114
|
+
* Can be either a `String` with the message or an object that defines the message and the
|
|
115
|
+
* politeness level
|
|
116
|
+
*/
|
|
117
|
+
announce?: String | RouteAnnounce
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
export interface ApplicationInstance extends ComponentInstance {}
|
package/src/component.js
CHANGED
|
@@ -47,13 +47,11 @@ const required = (name) => {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const Component = (name = required('name'), config = required('config')) => {
|
|
50
|
-
let code = null
|
|
51
|
-
|
|
52
50
|
const setupComponent = (lifecycle) => {
|
|
53
51
|
// code generation
|
|
54
|
-
if (!code) {
|
|
52
|
+
if (!config.code) {
|
|
55
53
|
Log.debug(`Generating code for ${name} component`)
|
|
56
|
-
code = codegenerator.call(config, parser(config.template))
|
|
54
|
+
config.code = codegenerator.call(config, parser(config.template))
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
setupBase(component)
|
|
@@ -167,7 +165,7 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
167
165
|
this.lifecycle.state = 'init'
|
|
168
166
|
|
|
169
167
|
Object.defineProperty(this, symbols.children, {
|
|
170
|
-
value: code.render.apply(stage, [parentEl, this,
|
|
168
|
+
value: config.code.render.apply(stage, [parentEl, this, config]),
|
|
171
169
|
writable: false,
|
|
172
170
|
enumerable: false,
|
|
173
171
|
configurable: false,
|
|
@@ -180,9 +178,9 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
180
178
|
configurable: false,
|
|
181
179
|
})
|
|
182
180
|
|
|
183
|
-
code.effects.forEach((eff) => {
|
|
181
|
+
config.code.effects.forEach((eff) => {
|
|
184
182
|
effect(() => {
|
|
185
|
-
eff.apply(stage, [this, this[symbols.children],
|
|
183
|
+
eff.apply(stage, [this, this[symbols.children], config])
|
|
186
184
|
})
|
|
187
185
|
})
|
|
188
186
|
|
package/src/components/Text.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import Component from '../component.js'
|
|
19
|
+
import Settings from '../settings.js'
|
|
19
20
|
|
|
20
21
|
export default () =>
|
|
21
22
|
Component('Text', {
|
|
@@ -41,7 +42,7 @@ export default () =>
|
|
|
41
42
|
'content',
|
|
42
43
|
{
|
|
43
44
|
key: 'font',
|
|
44
|
-
default: 'lato',
|
|
45
|
+
default: Settings.get('defaultFont', 'lato'),
|
|
45
46
|
},
|
|
46
47
|
{
|
|
47
48
|
key: 'size',
|
package/src/launch.d.ts
CHANGED
|
@@ -90,6 +90,15 @@ export interface Settings {
|
|
|
90
90
|
* Fonts to be used in the Application
|
|
91
91
|
*/
|
|
92
92
|
fonts?: Font[],
|
|
93
|
+
/**
|
|
94
|
+
* Default font family to use in the Application when no font attribute is specified
|
|
95
|
+
* on a Text-component
|
|
96
|
+
*
|
|
97
|
+
* The default font must be registered in the `fonts` array in the settings.
|
|
98
|
+
*
|
|
99
|
+
* Defaults to `lato` font family
|
|
100
|
+
*/
|
|
101
|
+
defaultFont?: string,
|
|
93
102
|
/**
|
|
94
103
|
* Custom keymapping
|
|
95
104
|
*/
|
|
@@ -92,8 +92,8 @@ const generateElementCode = function (
|
|
|
92
92
|
if (options.holder === true) {
|
|
93
93
|
renderCode.push(`
|
|
94
94
|
if(typeof cmp${counter} !== 'undefined') {
|
|
95
|
-
for(key in cmp${counter}.config.props) {
|
|
96
|
-
delete
|
|
95
|
+
for(let key in cmp${counter}.config.props) {
|
|
96
|
+
delete elementConfig${counter}[cmp${counter}.config.props[key]]
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
`)
|
|
@@ -171,7 +171,7 @@ const generateComponentCode = function (
|
|
|
171
171
|
|
|
172
172
|
renderCode.push(`
|
|
173
173
|
if(!${elm}) {
|
|
174
|
-
${elm} = (context.components && context.components['${templateObject.type}'] || component[Symbol.for('components')]['${templateObject.type}'] || (() => { console.
|
|
174
|
+
${elm} = (context.components && context.components['${templateObject.type}'] || component[Symbol.for('components')]['${templateObject.type}'] || (() => { console.error('component ${templateObject.type} not found')})).call(null, {props: props${counter}}, ${parent}, component)
|
|
175
175
|
if (${elm}[Symbol.for('slots')][0]) {
|
|
176
176
|
parent = ${elm}[Symbol.for('slots')][0]
|
|
177
177
|
component = ${elm}
|
|
@@ -316,7 +316,8 @@ const cast = (val = '', key = false, component = 'component.') => {
|
|
|
316
316
|
if (val.startsWith('$')) {
|
|
317
317
|
castedValue = `${component}${val.replace('$', '')}`
|
|
318
318
|
} else {
|
|
319
|
-
|
|
319
|
+
// unescaped single quotes must be escaped
|
|
320
|
+
castedValue = `'${parseInlineContent(val.replace(/(?<!\\)'/g, "\\'"), component)}'`
|
|
320
321
|
}
|
|
321
322
|
}
|
|
322
323
|
// numeric
|
package/src/lib/setup/base.js
CHANGED
|
@@ -28,6 +28,7 @@ import { default as log, Log } from '../log.js'
|
|
|
28
28
|
import symbols from '../symbols.js'
|
|
29
29
|
|
|
30
30
|
import { trigger } from '../reactivity/effect.js'
|
|
31
|
+
import Announcer from '../../announcer/announcer.js'
|
|
31
32
|
|
|
32
33
|
const shaderAlias = {
|
|
33
34
|
rounded: 'radius',
|
|
@@ -222,6 +223,12 @@ export default (component) => {
|
|
|
222
223
|
enumerable: false,
|
|
223
224
|
configurable: false,
|
|
224
225
|
},
|
|
226
|
+
$announcer: {
|
|
227
|
+
value: Announcer,
|
|
228
|
+
writable: false,
|
|
229
|
+
enumerable: false,
|
|
230
|
+
configurable: false,
|
|
231
|
+
},
|
|
225
232
|
})
|
|
226
233
|
}
|
|
227
234
|
|
package/src/router/router.js
CHANGED
|
@@ -21,6 +21,7 @@ import symbols from '../lib/symbols.js'
|
|
|
21
21
|
import { Log } from '../lib/log.js'
|
|
22
22
|
import Element from '../element.js'
|
|
23
23
|
import Focus from '../focus.js'
|
|
24
|
+
import Announcer from '../announcer/announcer.js'
|
|
24
25
|
|
|
25
26
|
export let currentRoute
|
|
26
27
|
export let navigating = false
|
|
@@ -55,7 +56,7 @@ export const navigate = async function () {
|
|
|
55
56
|
const route = matchHash(hash, this.parent[symbols.routes])
|
|
56
57
|
|
|
57
58
|
if (route) {
|
|
58
|
-
// add the previous route (
|
|
59
|
+
// add the previous route (technically still the current route at this point)
|
|
59
60
|
// into the history stack, unless navigating back or inHistory flag of route is false
|
|
60
61
|
if (navigatingBack === false && previousRoute && previousRoute.options.inHistory === true) {
|
|
61
62
|
history.push(previousRoute)
|
|
@@ -132,6 +133,16 @@ export const navigate = async function () {
|
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
// Announce route change if a message has been specified for this route
|
|
137
|
+
if (route.announce) {
|
|
138
|
+
if (typeof route.announce === 'string') {
|
|
139
|
+
route.announce = {
|
|
140
|
+
message: route.announce,
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
Announcer.speak(route.announce.message, route.announce.politeness)
|
|
144
|
+
}
|
|
145
|
+
|
|
135
146
|
// focus the new view
|
|
136
147
|
focus ? Focus.set(focus) : view.focus()
|
|
137
148
|
this.activeView = this[symbols.children][this[symbols.children].length - 1]
|
package/vite/index.js
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
import preCompiler from './preCompiler.js'
|
|
2
|
+
import { importChunkUrl } from '@lightningjs/vite-plugin-import-chunk-url'
|
|
3
|
+
|
|
1
4
|
export { importChunkUrl as importChunkUrl } from '@lightningjs/vite-plugin-import-chunk-url'
|
|
5
|
+
export { default as preCompiler } from './preCompiler.js'
|
|
6
|
+
|
|
7
|
+
export default [importChunkUrl(), preCompiler()]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import parser from '../src/lib/templateparser/parser.js'
|
|
2
|
+
import generator from '../src/lib/codegenerator/generator.js'
|
|
3
|
+
|
|
4
|
+
export default function () {
|
|
5
|
+
let config
|
|
6
|
+
return {
|
|
7
|
+
name: 'preCompiler',
|
|
8
|
+
configResolved(resolvedConfig) {
|
|
9
|
+
config = resolvedConfig
|
|
10
|
+
},
|
|
11
|
+
transform(source) {
|
|
12
|
+
if (config.blits && config.blits.precompile === false) return source
|
|
13
|
+
if (source.indexOf('Blits.Component(') > -1 || source.indexOf('Blits.Application(') > -1) {
|
|
14
|
+
// get the start of the template key in de component configuration object
|
|
15
|
+
const templateKeyRegex = /template:\s*([`"'])*/g
|
|
16
|
+
const templateStartResult = templateKeyRegex.exec(source)
|
|
17
|
+
const typeOfQuotesUsed = templateStartResult[1]
|
|
18
|
+
const templateStartIndex = templateStartResult.index
|
|
19
|
+
|
|
20
|
+
// get the template contents from the configuration object
|
|
21
|
+
const templateContentsRegex = new RegExp(
|
|
22
|
+
`${typeOfQuotesUsed}([\\s\\S]*?)${typeOfQuotesUsed}`
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
const templateContentResult = templateContentsRegex.exec(source.slice(templateStartIndex))
|
|
26
|
+
const templateEndIndex =
|
|
27
|
+
templateStartIndex + templateContentResult.index + templateContentResult[0].length
|
|
28
|
+
|
|
29
|
+
// Parse the template
|
|
30
|
+
const parsed = parser(templateContentResult[1])
|
|
31
|
+
|
|
32
|
+
// Generate the code
|
|
33
|
+
const code = generator.call({ components: {} }, parsed)
|
|
34
|
+
|
|
35
|
+
// Insert the code in the component using the 'code' key, replacing the template key
|
|
36
|
+
const replacement = `code: { render: ${code.render.toString()}, effects: [${code.effects.map(
|
|
37
|
+
(fn) => fn.toString() + ','
|
|
38
|
+
)}], context: {}}`
|
|
39
|
+
const newSource =
|
|
40
|
+
source.substring(0, templateStartIndex) + replacement + source.substring(templateEndIndex)
|
|
41
|
+
|
|
42
|
+
return newSource
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
}
|