@lightningjs/blits 1.22.0 → 1.23.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/.github/workflows/run-blits-tests.yml +69 -0
- package/CHANGELOG.md +22 -0
- package/README.md +1 -1
- package/docs/README.md +1 -2
- package/docs/built-in/directives.md +1 -1
- package/docs/built-in/for-loop.md +8 -8
- package/docs/built-in/layout.md +23 -23
- package/docs/components/user_input.md +3 -3
- package/docs/components/utility_methods.md +11 -7
- package/docs/essentials/displaying_images.md +3 -3
- package/docs/essentials/displaying_text.md +3 -3
- package/docs/essentials/element_attributes.md +3 -3
- package/docs/essentials/template_syntax.md +1 -1
- package/docs/getting_started/intro.md +1 -1
- package/docs/plugins/global_app_state.md +2 -2
- package/docs/plugins/language.md +2 -2
- package/docs/plugins/theme.md +1 -1
- package/docs/router/basics.md +4 -4
- package/docs/router/hooks.md +1 -1
- package/docs/transitions_animations/transitions.md +2 -2
- package/index.d.ts +37 -1
- package/package.json +2 -2
- package/src/component/base/index.js +3 -1
- package/src/component/setup/index.js +4 -3
- package/src/component/setup/routes.js +6 -1
- package/src/component.js +24 -7
- package/src/component.test.js +6 -5
- package/src/components/Circle.js +1 -1
- package/src/components/FPScounter.js +1 -1
- package/src/components/RouterView.js +1 -1
- package/src/components/Sprite.js +1 -1
- package/src/lib/codegenerator/generator.js +61 -8
- package/src/lib/codegenerator/generator.test.js +1089 -167
- package/src/lib/eventListeners.js +3 -3
- package/src/lib/precompiler/precompiler.js +2 -3
- package/src/lib/reactivity/effect.js +5 -5
- package/src/lib/reactivity/reactive.js +1 -0
- package/src/lib/reactivityguard/computedprops.js +218 -0
- package/src/lib/symbols.js +1 -0
- package/src/router/router.js +28 -6
- package/vite/index.js +3 -1
- package/vite/preCompiler.js +1 -1
- package/vite/reactivityGuard.js +45 -0
|
@@ -39,11 +39,11 @@ export default {
|
|
|
39
39
|
deregisterListener(component, event) {
|
|
40
40
|
let componentsMap = eventsMap.get(event)
|
|
41
41
|
if (componentsMap === undefined) {
|
|
42
|
-
return
|
|
42
|
+
return
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
if (componentsMap.
|
|
46
|
-
componentsMap.delete(component)
|
|
45
|
+
if (componentsMap.has(component)) {
|
|
46
|
+
componentsMap.delete(component)
|
|
47
47
|
eventsMap.set(event, componentsMap)
|
|
48
48
|
callbackCache.delete(event)
|
|
49
49
|
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import parser from '../templateparser/parser.js'
|
|
19
19
|
import generator from '../codegenerator/generator.js'
|
|
20
20
|
|
|
21
|
-
export default (source, filePath) => {
|
|
21
|
+
export default (source, filePath, mode) => {
|
|
22
22
|
if (
|
|
23
23
|
source.indexOf('Blits.Component(') > -1 ||
|
|
24
24
|
source.indexOf('Blits.Application(') > -1 ||
|
|
@@ -42,7 +42,6 @@ export default (source, filePath) => {
|
|
|
42
42
|
const templateStartIndex = template.index + offset
|
|
43
43
|
const templateEndIndex = templateStartIndex + template[0].length
|
|
44
44
|
|
|
45
|
-
|
|
46
45
|
// Parse the template
|
|
47
46
|
let resourceName = 'Blits.Application'
|
|
48
47
|
if (source.indexOf('Blits.Component(') > -1) {
|
|
@@ -52,7 +51,7 @@ export default (source, filePath) => {
|
|
|
52
51
|
const parsed = parser(templateContent, resourceName, null, filePath)
|
|
53
52
|
|
|
54
53
|
// Generate the code
|
|
55
|
-
const code = generator.call({ components: {} }, parsed)
|
|
54
|
+
const code = generator.call({ components: {} }, parsed, mode === 'development')
|
|
56
55
|
|
|
57
56
|
// Insert the code in the component using the 'code' key, replacing the template key
|
|
58
57
|
const replacement = `/* eslint-disable no-unused-vars */ \ncode: { render: ${code.render.toString()}, effects: [${code.effects.map(
|
|
@@ -45,7 +45,7 @@ export const removeGlobalEffects = (effectsToRemove) => {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export const track = (target, key, global = false) => {
|
|
48
|
-
if (currentEffect) {
|
|
48
|
+
if (currentEffect !== null) {
|
|
49
49
|
if (paused) {
|
|
50
50
|
return
|
|
51
51
|
}
|
|
@@ -55,12 +55,12 @@ export const track = (target, key, global = false) => {
|
|
|
55
55
|
} else if (currentKey !== null && key !== currentKey) return
|
|
56
56
|
|
|
57
57
|
let effectsMap = objectMap.get(target)
|
|
58
|
-
if (
|
|
58
|
+
if (effectsMap === undefined) {
|
|
59
59
|
effectsMap = new Map()
|
|
60
60
|
objectMap.set(target, effectsMap)
|
|
61
61
|
}
|
|
62
62
|
let effects = effectsMap.get(key)
|
|
63
|
-
if (
|
|
63
|
+
if (effects === undefined) {
|
|
64
64
|
effects = new Set()
|
|
65
65
|
effectsMap.set(key, effects)
|
|
66
66
|
}
|
|
@@ -73,11 +73,11 @@ export const track = (target, key, global = false) => {
|
|
|
73
73
|
export const trigger = (target, key, force = false) => {
|
|
74
74
|
if (paused === true) return
|
|
75
75
|
const effectsMap = objectMap.get(target)
|
|
76
|
-
if (
|
|
76
|
+
if (effectsMap === undefined) {
|
|
77
77
|
return
|
|
78
78
|
}
|
|
79
79
|
const effects = effectsMap.get(key)
|
|
80
|
-
if (effects) {
|
|
80
|
+
if (effects !== undefined) {
|
|
81
81
|
for (let effect of effects) {
|
|
82
82
|
effect(force)
|
|
83
83
|
}
|
|
@@ -115,6 +115,7 @@ const reactiveProxy = (original, _parent = null, _key, global) => {
|
|
|
115
115
|
if (Array.isArray(value) === true) {
|
|
116
116
|
value = getRaw(value).slice(0)
|
|
117
117
|
} else if (
|
|
118
|
+
value !== null &&
|
|
118
119
|
target[key] !== null &&
|
|
119
120
|
target[key] !== undefined &&
|
|
120
121
|
Array.isArray(target) === false &&
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 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
|
+
export default (code) => {
|
|
19
|
+
// Find component declarations
|
|
20
|
+
const componentRegex =
|
|
21
|
+
/Blits\.(Component|Application)\s*\(\s*(?:'[^']*'|"[^"]*")?\s*(?:,\s*)?({[\s\S]*?})\s*\)/g
|
|
22
|
+
const modifications = []
|
|
23
|
+
const commentText = ' /* auto-generated reactivity guard */ '
|
|
24
|
+
|
|
25
|
+
let match
|
|
26
|
+
while ((match = componentRegex.exec(code)) !== null) {
|
|
27
|
+
const configObject = match[2]
|
|
28
|
+
|
|
29
|
+
// Find computed section with proper brace balancing
|
|
30
|
+
const computedKeywordMatch = /computed\s*:\s*{/.exec(configObject)
|
|
31
|
+
|
|
32
|
+
if (computedKeywordMatch) {
|
|
33
|
+
// Find start position of the computed block
|
|
34
|
+
const computedStart = computedKeywordMatch.index + computedKeywordMatch[0].length - 1 // Position of the opening brace
|
|
35
|
+
|
|
36
|
+
// Find the matching closing brace with balance tracking
|
|
37
|
+
let braceLevel = 1
|
|
38
|
+
let pos = computedStart + 1
|
|
39
|
+
|
|
40
|
+
while (braceLevel > 0 && pos < configObject.length) {
|
|
41
|
+
if (configObject[pos] === '{') braceLevel++
|
|
42
|
+
else if (configObject[pos] === '}') braceLevel--
|
|
43
|
+
pos++
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (braceLevel === 0) {
|
|
47
|
+
const computedEnd = pos
|
|
48
|
+
const computedObj = configObject.substring(computedStart, computedEnd)
|
|
49
|
+
|
|
50
|
+
// Process each computed property
|
|
51
|
+
const computedProps = []
|
|
52
|
+
let currentPos = 1 // Start after the opening brace
|
|
53
|
+
|
|
54
|
+
// Process computed properties content
|
|
55
|
+
// intentionally not using regexes to extract functions and their content
|
|
56
|
+
// using cursor-based parsing gives better accuracy
|
|
57
|
+
while (currentPos < computedObj.length - 1) {
|
|
58
|
+
// -1 to exclude the closing brace
|
|
59
|
+
// Find the next function name
|
|
60
|
+
const functionNameMatch = /\s*(\w+)\s*\(\)/.exec(computedObj.substring(currentPos))
|
|
61
|
+
if (!functionNameMatch) break
|
|
62
|
+
|
|
63
|
+
const funcName = functionNameMatch[1]
|
|
64
|
+
const funcNamePos = currentPos + functionNameMatch.index
|
|
65
|
+
|
|
66
|
+
// Find opening brace for this function
|
|
67
|
+
const openingBracePos = computedObj.indexOf('{', funcNamePos)
|
|
68
|
+
if (openingBracePos === -1) break
|
|
69
|
+
|
|
70
|
+
// Find closing brace with proper nesting
|
|
71
|
+
let braceLevel = 1
|
|
72
|
+
let closingBracePos = openingBracePos + 1
|
|
73
|
+
|
|
74
|
+
while (braceLevel > 0 && closingBracePos < computedObj.length) {
|
|
75
|
+
if (computedObj[closingBracePos] === '{') braceLevel++
|
|
76
|
+
else if (computedObj[closingBracePos] === '}') braceLevel--
|
|
77
|
+
closingBracePos++
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (braceLevel !== 0) {
|
|
81
|
+
// Could not find matching brace
|
|
82
|
+
break
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Extract the entire function and its body
|
|
86
|
+
// This is better and more accurate than using regex to avoid nested braces
|
|
87
|
+
const functionStartPos = funcNamePos
|
|
88
|
+
const functionEndPos = closingBracePos
|
|
89
|
+
const fullFunction = computedObj.substring(functionStartPos, functionEndPos)
|
|
90
|
+
const functionBody = computedObj
|
|
91
|
+
.substring(openingBracePos + 1, closingBracePos - 1)
|
|
92
|
+
.trim()
|
|
93
|
+
|
|
94
|
+
computedProps.push({
|
|
95
|
+
name: funcName,
|
|
96
|
+
fullText: fullFunction,
|
|
97
|
+
body: functionBody,
|
|
98
|
+
startPos: functionStartPos,
|
|
99
|
+
endPos: functionEndPos,
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// Move past this function
|
|
103
|
+
currentPos = closingBracePos
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Store the original computed object for later replacement
|
|
107
|
+
const originalComputedObj = configObject.substring(
|
|
108
|
+
computedStart - 'computed: '.length,
|
|
109
|
+
computedEnd
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
let modifiedComputedObj = originalComputedObj
|
|
113
|
+
let hasChanges = false
|
|
114
|
+
|
|
115
|
+
for (const prop of computedProps) {
|
|
116
|
+
const thisRefs = extractThisReferences(prop.body)
|
|
117
|
+
|
|
118
|
+
if (thisRefs.size > 0) {
|
|
119
|
+
// Skip if already modified
|
|
120
|
+
if (
|
|
121
|
+
prop.body.includes(commentText) ||
|
|
122
|
+
Array.from(thisRefs).some((ref) => prop.body.startsWith(ref))
|
|
123
|
+
) {
|
|
124
|
+
continue
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// reactivity code
|
|
128
|
+
const refCode = Array.from(thisRefs)
|
|
129
|
+
.map((ref) => `${ref};`)
|
|
130
|
+
.join(' ')
|
|
131
|
+
|
|
132
|
+
// replacement with the same whitespace
|
|
133
|
+
const openBraceIndex = prop.fullText.indexOf('{')
|
|
134
|
+
|
|
135
|
+
if (openBraceIndex !== -1) {
|
|
136
|
+
// Extract indentation from the original function body
|
|
137
|
+
const indentMatch = prop.body.match(/^(\s+)/)
|
|
138
|
+
const indent = indentMatch ? indentMatch[1] + ' ' : ' ' // Default to 4 spaces if no indent found
|
|
139
|
+
|
|
140
|
+
const modifiedPropText =
|
|
141
|
+
prop.fullText.substring(0, openBraceIndex + 1) +
|
|
142
|
+
'\n' +
|
|
143
|
+
indent +
|
|
144
|
+
commentText +
|
|
145
|
+
'\n' +
|
|
146
|
+
indent +
|
|
147
|
+
refCode +
|
|
148
|
+
'\n' +
|
|
149
|
+
indent +
|
|
150
|
+
prop.body +
|
|
151
|
+
'\n' +
|
|
152
|
+
prop.fullText.substring(0, openBraceIndex).match(/^(\s*)/)[0] +
|
|
153
|
+
'}'
|
|
154
|
+
|
|
155
|
+
// Replace this property in the computed object text
|
|
156
|
+
modifiedComputedObj = modifiedComputedObj.replace(prop.fullText, modifiedPropText)
|
|
157
|
+
hasChanges = true
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (hasChanges) {
|
|
163
|
+
// Store the modification of the entire computed object
|
|
164
|
+
modifications.push({
|
|
165
|
+
original: originalComputedObj,
|
|
166
|
+
replacement: modifiedComputedObj,
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Apply all modifications at once, from last to first to preserve positions
|
|
174
|
+
if (modifications.length > 0) {
|
|
175
|
+
let modifiedCode = code
|
|
176
|
+
// Sort modifications from last to first to avoid position changes
|
|
177
|
+
modifications.sort((a, b) => {
|
|
178
|
+
const posA = modifiedCode.indexOf(a.original)
|
|
179
|
+
const posB = modifiedCode.indexOf(b.original)
|
|
180
|
+
return posB - posA
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
for (const mod of modifications) {
|
|
184
|
+
modifiedCode = modifiedCode.replace(mod.original, mod.replacement)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return { code: modifiedCode }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return null
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const extractThisReferences = (funcBody) => {
|
|
194
|
+
const thisRefs = new Set()
|
|
195
|
+
|
|
196
|
+
// Find all this.X references, but exclude method calls
|
|
197
|
+
const refRegex = /this\.\w+(?!\s*\()/g // matches this.X but not this.X() or this.X.Y()
|
|
198
|
+
let refMatch
|
|
199
|
+
|
|
200
|
+
while ((refMatch = refRegex.exec(funcBody)) !== null) {
|
|
201
|
+
const fullRef = refMatch[0]
|
|
202
|
+
|
|
203
|
+
// Extract just the variable part (this.X)
|
|
204
|
+
// We need to avoid method calls or chained methods
|
|
205
|
+
const varRef = fullRef.split('.').slice(0, 2).join('.')
|
|
206
|
+
|
|
207
|
+
// Don't add if it's part of a method call
|
|
208
|
+
if (
|
|
209
|
+
!funcBody
|
|
210
|
+
.substring(refMatch.index)
|
|
211
|
+
.match(new RegExp(`^${varRef.replace(/\./g, '\\.')}\\s*\\(`))
|
|
212
|
+
) {
|
|
213
|
+
thisRefs.add(varRef)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return thisRefs
|
|
218
|
+
}
|
package/src/lib/symbols.js
CHANGED
package/src/router/router.js
CHANGED
|
@@ -33,7 +33,9 @@ export const state = reactive({
|
|
|
33
33
|
hash: '',
|
|
34
34
|
})
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
// Changed from WeakMap to Map to allow for caching of views by the url hash.
|
|
37
|
+
// We are manually doing the cleanup of the cache when the route is not marked as keepAlive.
|
|
38
|
+
const cacheMap = new Map()
|
|
37
39
|
const history = []
|
|
38
40
|
|
|
39
41
|
let overrideOptions = {}
|
|
@@ -133,8 +135,22 @@ export const navigate = async function () {
|
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
currentRoute = route
|
|
136
|
-
let beforeHookOutput
|
|
137
138
|
if (route) {
|
|
139
|
+
let beforeEachResult
|
|
140
|
+
if (this.parent[symbols.routerHooks]) {
|
|
141
|
+
const hooks = this.parent[symbols.routerHooks]
|
|
142
|
+
if (hooks.beforeAll) {
|
|
143
|
+
beforeEachResult = await hooks.beforeAll(route, previousRoute)
|
|
144
|
+
if (isString(beforeEachResult)) {
|
|
145
|
+
to(beforeEachResult)
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// If the resolved result is an object, assign it to the target route object
|
|
151
|
+
route = isObject(beforeEachResult) ? beforeEachResult : route
|
|
152
|
+
|
|
153
|
+
let beforeHookOutput
|
|
138
154
|
if (route.hooks) {
|
|
139
155
|
if (route.hooks.before) {
|
|
140
156
|
beforeHookOutput = await route.hooks.before.call(this.parent, route, previousRoute)
|
|
@@ -163,7 +179,7 @@ export const navigate = async function () {
|
|
|
163
179
|
|
|
164
180
|
let holder
|
|
165
181
|
let routeData
|
|
166
|
-
let { view, focus } = cacheMap.get(route) || {}
|
|
182
|
+
let { view, focus } = cacheMap.get(route.hash) || {}
|
|
167
183
|
|
|
168
184
|
if (!view) {
|
|
169
185
|
// create a holder element for the new view
|
|
@@ -312,9 +328,15 @@ const removeView = async (route, view, transition) => {
|
|
|
312
328
|
}
|
|
313
329
|
|
|
314
330
|
// cache the page when it's as 'keepAlive' instead of destroying
|
|
315
|
-
if (route.options && route.options.keepAlive === true) {
|
|
316
|
-
cacheMap.set(route, { view: view, focus: previousFocus })
|
|
317
|
-
} else {
|
|
331
|
+
if (route.options && route.options.keepAlive === true && navigatingBack === false) {
|
|
332
|
+
cacheMap.set(route.hash, { view: view, focus: previousFocus })
|
|
333
|
+
} else if (navigatingBack === true) {
|
|
334
|
+
// remove the previous route from the cache when navigating back
|
|
335
|
+
// cacheMap.delete will not throw an error if the route is not in the cache
|
|
336
|
+
cacheMap.delete(route.hash)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (route.options && route.options.keepAlive !== true) {
|
|
318
340
|
view.destroy()
|
|
319
341
|
view = null
|
|
320
342
|
}
|
package/vite/index.js
CHANGED
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
import preCompiler from './preCompiler.js'
|
|
19
19
|
import msdfGenerator from './msdfGenerator.js'
|
|
20
20
|
import blitsFileConverter from './blitsFileConverter.js'
|
|
21
|
+
import reactivityGuard from './reactivityGuard.js'
|
|
21
22
|
|
|
22
23
|
export { default as preCompiler } from './preCompiler.js'
|
|
23
24
|
export { default as msdfGenerator } from './msdfGenerator.js'
|
|
24
25
|
export { default as blitsFileConverter } from './blitsFileConverter.js'
|
|
26
|
+
export { default as reactivityGuard } from './reactivityGuard.js'
|
|
25
27
|
|
|
26
|
-
export default [blitsFileConverter(), preCompiler(), msdfGenerator()]
|
|
28
|
+
export default [blitsFileConverter(), reactivityGuard(), preCompiler(), msdfGenerator()]
|
package/vite/preCompiler.js
CHANGED
|
@@ -32,7 +32,7 @@ export default function () {
|
|
|
32
32
|
|
|
33
33
|
// we should only precompile .blits, .js and .ts files
|
|
34
34
|
if (fileExtension === '.js' || fileExtension === '.ts' || fileExtension === '.blits') {
|
|
35
|
-
return compiler(source, filePath)
|
|
35
|
+
return compiler(source, filePath, config.mode)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// vite expects null if there is no modification
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 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 { default as processComputedProps } from './../src/lib/reactivityguard/computedprops.js'
|
|
19
|
+
|
|
20
|
+
export default function reactivityGuard() {
|
|
21
|
+
return {
|
|
22
|
+
name: 'reactivityGuard',
|
|
23
|
+
// run before other plugings except blitsFileConverter
|
|
24
|
+
// the order between blitsFileConverter and this plugin is maintained by the order of the plugins in the array in index.js
|
|
25
|
+
enforce: 'pre',
|
|
26
|
+
|
|
27
|
+
transform(code, id) {
|
|
28
|
+
if (!id.endsWith('.js') && !id.endsWith('.ts') && !id.endsWith('.blits')) {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Skip if no Blits component/application
|
|
33
|
+
if (!code.includes('Blits.Component') && !code.includes('Blits.Application')) {
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
return processComputedProps(code)
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(`[blits-reactivity-guard] Error processing ${id}:`, error)
|
|
41
|
+
return null // Return original code on error
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
}
|