@lightningjs/blits 0.6.4 → 0.6.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/CHANGELOG.md +7 -0
- package/boilerplate/index.html +1 -1
- package/boilerplate/package.json +1 -1
- package/boilerplate/src/index.js +17 -3
- package/boilerplate/vite.config.js +1 -0
- package/package.json +1 -1
- package/src/component.js +3 -3
- package/src/element.js +0 -1
- package/src/lib/symbols.js +1 -0
- package/src/lib/templateparser/parser.js +112 -43
- package/src/lib/templateparser/parser.test.js +84 -49
- package/vite/preCompiler.js +8 -2
package/CHANGELOG.md
CHANGED
package/boilerplate/index.html
CHANGED
package/boilerplate/package.json
CHANGED
package/boilerplate/src/index.js
CHANGED
|
@@ -11,8 +11,22 @@ Blits.Launch(App, 'app', {
|
|
|
11
11
|
debugLevel: 1,
|
|
12
12
|
fontLoader: fontLoader,
|
|
13
13
|
fonts: [
|
|
14
|
-
{
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
{
|
|
15
|
+
family: 'lato',
|
|
16
|
+
type: 'msdf',
|
|
17
|
+
png: 'fonts/Lato-Regular.msdf.png',
|
|
18
|
+
json: 'fonts/Lato-Regular.msdf.json',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
family: 'raleway',
|
|
22
|
+
type: 'msdf',
|
|
23
|
+
png: 'fonts/Raleway-ExtraBold.msdf.png',
|
|
24
|
+
json: 'fonts/Raleway-ExtraBold.msdf.json',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
family: 'opensans',
|
|
28
|
+
type: 'web',
|
|
29
|
+
file: 'fonts/OpenSans-Medium.ttf',
|
|
30
|
+
},
|
|
17
31
|
],
|
|
18
32
|
})
|
|
@@ -3,6 +3,7 @@ import blitsVitePlugins from '@lightningjs/blits/vite'
|
|
|
3
3
|
|
|
4
4
|
export default defineConfig(({ command, mode, ssrBuild }) => {
|
|
5
5
|
return {
|
|
6
|
+
base: '/', // Set to your base path if you are deploying to a subdirectory (example: /myApp/)
|
|
6
7
|
plugins: [...blitsVitePlugins],
|
|
7
8
|
resolve: {
|
|
8
9
|
mainFields: ['browser', 'module', 'jsnext:main', 'jsnext'],
|
package/package.json
CHANGED
package/src/component.js
CHANGED
|
@@ -47,11 +47,11 @@ const required = (name) => {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const Component = (name = required('name'), config = required('config')) => {
|
|
50
|
-
const setupComponent = (lifecycle) => {
|
|
50
|
+
const setupComponent = (lifecycle, parentComponent) => {
|
|
51
51
|
// code generation
|
|
52
52
|
if (!config.code) {
|
|
53
53
|
Log.debug(`Generating code for ${name} component`)
|
|
54
|
-
config.code = codegenerator.call(config, parser(config.template))
|
|
54
|
+
config.code = codegenerator.call(config, parser(config.template, name, parentComponent))
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
setupBase(component)
|
|
@@ -115,7 +115,7 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
115
115
|
this.lifecycle = createLifecycle(this)
|
|
116
116
|
|
|
117
117
|
if (!component.setup) {
|
|
118
|
-
setupComponent(this.lifecycle)
|
|
118
|
+
setupComponent(this.lifecycle, parentComponent)
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
this.parent = parentComponent
|
package/src/element.js
CHANGED
package/src/lib/symbols.js
CHANGED
|
@@ -17,16 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
import symbols from '../symbols.js'
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
constructor(message, name, context) {
|
|
22
|
-
super(`TemplateParseError: ${message}`)
|
|
23
|
-
this.name = name
|
|
24
|
-
this.context = context
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export default (template = '') => {
|
|
20
|
+
export default (template = '', componentName, parentComponent, filePath = null) => {
|
|
29
21
|
let cursor = 0
|
|
22
|
+
let prevCursor = 0
|
|
30
23
|
let tags = []
|
|
31
24
|
let currentTag = null
|
|
32
25
|
let currentLevel = 0
|
|
@@ -45,13 +38,10 @@ export default (template = '') => {
|
|
|
45
38
|
parseLoop(parseEmptyTagStart)
|
|
46
39
|
return format(tags)
|
|
47
40
|
} catch (error) {
|
|
48
|
-
if (error
|
|
49
|
-
|
|
50
|
-
} else {
|
|
51
|
-
console.error(error)
|
|
41
|
+
if (error.name == 'TemplateParseError' || error.name == 'TemplateStructureError') {
|
|
42
|
+
error.message = `${error.message}\n${error.context}`
|
|
52
43
|
}
|
|
53
|
-
|
|
54
|
-
return null
|
|
44
|
+
throw error
|
|
55
45
|
}
|
|
56
46
|
}
|
|
57
47
|
|
|
@@ -63,9 +53,9 @@ export default (template = '') => {
|
|
|
63
53
|
}
|
|
64
54
|
|
|
65
55
|
// utils
|
|
66
|
-
const clean = (
|
|
56
|
+
const clean = (templateText) => {
|
|
67
57
|
// remove all unnecessary new lines and comments
|
|
68
|
-
return
|
|
58
|
+
return templateText
|
|
69
59
|
.replace(/<!--.*?-->/gms, '') // remove comments
|
|
70
60
|
.replace(/\r?\n\s*\r\n/gm, ' ') // remove empty lines
|
|
71
61
|
.replace(/\r?\n\s*(\S)/gm, ' $1') // remove line endings & spacing
|
|
@@ -75,7 +65,10 @@ export default (template = '') => {
|
|
|
75
65
|
|
|
76
66
|
const moveCursorOnMatch = (regex) => {
|
|
77
67
|
const match = template.slice(cursor).match(regex)
|
|
78
|
-
if (match)
|
|
68
|
+
if (match) {
|
|
69
|
+
prevCursor = cursor
|
|
70
|
+
cursor += match[0].length
|
|
71
|
+
}
|
|
79
72
|
return match
|
|
80
73
|
}
|
|
81
74
|
|
|
@@ -83,7 +76,12 @@ export default (template = '') => {
|
|
|
83
76
|
const parseEmptyTagStart = () => {
|
|
84
77
|
const match = moveCursorOnMatch(emptyTagStartRegex)
|
|
85
78
|
if (match) {
|
|
86
|
-
tags.push({
|
|
79
|
+
tags.push({
|
|
80
|
+
type: null,
|
|
81
|
+
[symbols.type]: 'opening',
|
|
82
|
+
[symbols.level]: currentLevel,
|
|
83
|
+
[symbols.cursorTagStart]: prevCursor,
|
|
84
|
+
})
|
|
87
85
|
currentLevel++
|
|
88
86
|
parseLoop(parseEmptyTagStart)
|
|
89
87
|
} else {
|
|
@@ -95,7 +93,11 @@ export default (template = '') => {
|
|
|
95
93
|
const match = moveCursorOnMatch(emptyTagEndRegex)
|
|
96
94
|
if (match) {
|
|
97
95
|
currentLevel--
|
|
98
|
-
tags.push({
|
|
96
|
+
tags.push({
|
|
97
|
+
type: null,
|
|
98
|
+
[symbols.type]: 'closing',
|
|
99
|
+
[symbols.level]: currentLevel,
|
|
100
|
+
})
|
|
99
101
|
parseLoop(parseEmptyTagStart)
|
|
100
102
|
} else {
|
|
101
103
|
parseLoop(parseTag)
|
|
@@ -105,16 +107,22 @@ export default (template = '') => {
|
|
|
105
107
|
const parseTag = () => {
|
|
106
108
|
const match = moveCursorOnMatch(tagStartRegex)
|
|
107
109
|
if (match) {
|
|
110
|
+
currentTag = {
|
|
111
|
+
type: match[1],
|
|
112
|
+
[symbols.level]: currentLevel,
|
|
113
|
+
[symbols.cursorTagStart]: prevCursor,
|
|
114
|
+
}
|
|
108
115
|
if (match[0].startsWith('</')) {
|
|
109
116
|
currentLevel--
|
|
110
|
-
currentTag
|
|
117
|
+
currentTag[symbols.type] = 'closing'
|
|
118
|
+
currentTag[symbols.level] = currentLevel
|
|
111
119
|
} else {
|
|
112
|
-
currentTag
|
|
120
|
+
currentTag[symbols.type] = 'opening'
|
|
113
121
|
currentLevel++
|
|
114
122
|
}
|
|
115
123
|
parseLoop(parseTagEnd)
|
|
116
124
|
} else {
|
|
117
|
-
throw
|
|
125
|
+
throw TemplateParseError('InvalidTag')
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
|
|
@@ -123,8 +131,7 @@ export default (template = '') => {
|
|
|
123
131
|
if (match) {
|
|
124
132
|
if (match[1] === '/>') {
|
|
125
133
|
if (currentTag[symbols.type] === 'closing') {
|
|
126
|
-
|
|
127
|
-
throw new TemplateParseError('InvalidClosingTag', template.slice(cursor - 10))
|
|
134
|
+
throw TemplateParseError('InvalidClosingTag')
|
|
128
135
|
}
|
|
129
136
|
currentTag[symbols.type] = 'self-closing'
|
|
130
137
|
currentLevel-- // because it was parsed as opening tag before
|
|
@@ -147,9 +154,14 @@ export default (template = '') => {
|
|
|
147
154
|
}
|
|
148
155
|
}
|
|
149
156
|
|
|
157
|
+
//fixme: closing tags cannot have attributes
|
|
150
158
|
const parseAttributes = () => {
|
|
151
159
|
const attrNameMatch = moveCursorOnMatch(attrNameRegex)
|
|
152
160
|
if (attrNameMatch) {
|
|
161
|
+
if (currentTag[symbols.type] === 'closing') {
|
|
162
|
+
throw TemplateParseError('AttributesInClosingTag')
|
|
163
|
+
}
|
|
164
|
+
|
|
153
165
|
const delimiter = attrNameMatch[2]
|
|
154
166
|
const attrValueRegex = new RegExp(`^(.*?)${delimiter}\\s*`)
|
|
155
167
|
const attrValueMatch = moveCursorOnMatch(attrValueRegex)
|
|
@@ -160,10 +172,10 @@ export default (template = '') => {
|
|
|
160
172
|
currentTag[attr.name] = attr.value
|
|
161
173
|
parseLoop(parseTagEnd)
|
|
162
174
|
} else {
|
|
163
|
-
throw
|
|
175
|
+
throw TemplateParseError('MissingOrInvalidAttributeValue')
|
|
164
176
|
}
|
|
165
177
|
} else {
|
|
166
|
-
throw
|
|
178
|
+
throw TemplateParseError('InvalidAttribute')
|
|
167
179
|
}
|
|
168
180
|
}
|
|
169
181
|
|
|
@@ -177,10 +189,8 @@ export default (template = '') => {
|
|
|
177
189
|
return { name, value }
|
|
178
190
|
}
|
|
179
191
|
|
|
180
|
-
// formating and validation
|
|
181
|
-
|
|
182
192
|
/*
|
|
183
|
-
validation rules:
|
|
193
|
+
Formatting & validation rules:
|
|
184
194
|
#1: Every opening tag must have a corresponding closing tag at the same level. If a closing tag is encountered without
|
|
185
195
|
a preceding opening tag at the same level, or if an opening tag is not followed by a corresponding closing tag at
|
|
186
196
|
the same level, an error should be thrown.
|
|
@@ -200,7 +210,7 @@ export default (template = '') => {
|
|
|
200
210
|
// Rule #1
|
|
201
211
|
if (element[symbols.level] === 0 && element[symbols.type] !== 'closing') {
|
|
202
212
|
if (rootElementDefined) {
|
|
203
|
-
throw
|
|
213
|
+
throw TemplateStructureError('MultipleTopLevelTags', element)
|
|
204
214
|
}
|
|
205
215
|
rootElementDefined = true
|
|
206
216
|
}
|
|
@@ -210,6 +220,7 @@ export default (template = '') => {
|
|
|
210
220
|
stack.push({
|
|
211
221
|
[symbols.level]: element[symbols.level],
|
|
212
222
|
[symbols.type]: element[symbols.type],
|
|
223
|
+
[symbols.cursorTagStart]: element[symbols.cursorTagStart],
|
|
213
224
|
type: element.type,
|
|
214
225
|
parent: currentParent, // helps getting the previous parent when closing tag is encountered
|
|
215
226
|
})
|
|
@@ -223,7 +234,7 @@ export default (template = '') => {
|
|
|
223
234
|
}
|
|
224
235
|
|
|
225
236
|
if (isStackEmpty || isLevelMismatch || isTagMismatch) {
|
|
226
|
-
throw
|
|
237
|
+
throw TemplateStructureError('MismatchedClosingTag', element)
|
|
227
238
|
}
|
|
228
239
|
|
|
229
240
|
// when we remove the closing element from the stack, we should set
|
|
@@ -235,6 +246,7 @@ export default (template = '') => {
|
|
|
235
246
|
const newItem = { ...element }
|
|
236
247
|
delete newItem[symbols.type]
|
|
237
248
|
delete newItem[symbols.level]
|
|
249
|
+
delete newItem[symbols.cursorTagStart]
|
|
238
250
|
|
|
239
251
|
// if it is an opening tag, add children[] to it and update current parent
|
|
240
252
|
if (element[symbols.type] === 'opening') {
|
|
@@ -251,21 +263,78 @@ export default (template = '') => {
|
|
|
251
263
|
|
|
252
264
|
// Check if all tags are closed (so stack should be empty)[Rule #1]
|
|
253
265
|
if (stack.length > 0) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
266
|
+
throw TemplateStructureError('UnclosedTags', stack)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return output
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// error reporting
|
|
273
|
+
const contextPaddingBefore = 10 // number of characters to show before the error location
|
|
274
|
+
const contextPaddingAfter = 50 // number of characters to show after the error location
|
|
275
|
+
|
|
276
|
+
const TemplateParseError = (message, context) => {
|
|
277
|
+
const location = getErrorLocation()
|
|
278
|
+
message = `${message} in ${location}`
|
|
279
|
+
|
|
280
|
+
const error = new Error(message)
|
|
281
|
+
error.name = 'TemplateParseError'
|
|
282
|
+
|
|
283
|
+
// generate context if the error is related to parsing
|
|
284
|
+
if (!context) {
|
|
285
|
+
const start = Math.max(0, prevCursor - contextPaddingBefore)
|
|
286
|
+
const end = Math.min(template.length, cursor + contextPaddingAfter)
|
|
287
|
+
const contextText = template.slice(start, end)
|
|
288
|
+
|
|
289
|
+
// add ^ caret to show where the error is
|
|
290
|
+
const caretPosition = cursor - start
|
|
291
|
+
error.context = insertContextCaret(caretPosition, contextText)
|
|
292
|
+
} else {
|
|
293
|
+
error.context = context
|
|
260
294
|
}
|
|
295
|
+
return error
|
|
296
|
+
}
|
|
261
297
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
298
|
+
const TemplateStructureError = (message, context) => {
|
|
299
|
+
const location = getErrorLocation()
|
|
300
|
+
message = `${message} in ${location}`
|
|
301
|
+
|
|
302
|
+
const error = new Error(message)
|
|
303
|
+
error.name = 'TemplateStructureError'
|
|
304
|
+
|
|
305
|
+
// check if context is an array
|
|
306
|
+
if (Array.isArray(context)) {
|
|
307
|
+
error.context = context.map((tag) => generateContext(tag)).join('\n')
|
|
308
|
+
} else {
|
|
309
|
+
error.context = generateContext(context)
|
|
266
310
|
}
|
|
267
311
|
|
|
268
|
-
|
|
312
|
+
function generateContext(element) {
|
|
313
|
+
const start = Math.max(0, element[symbols.cursorTagStart] - contextPaddingBefore)
|
|
314
|
+
const contextText = template.slice(start, start + contextPaddingAfter)
|
|
315
|
+
// add ^ caret to show where the error is
|
|
316
|
+
return insertContextCaret(contextPaddingBefore, contextText)
|
|
317
|
+
}
|
|
318
|
+
return error
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const insertContextCaret = (position, contextText) => {
|
|
322
|
+
const caret = ' '.repeat(position) + '^'
|
|
323
|
+
return `\n${contextText}\n${caret}\n`
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const getErrorLocation = () => {
|
|
327
|
+
if (parentComponent) {
|
|
328
|
+
let hierarchy = componentName || ''
|
|
329
|
+
let currentParent = parentComponent
|
|
330
|
+
|
|
331
|
+
while (currentParent) {
|
|
332
|
+
hierarchy = `${currentParent.type}/${hierarchy}`
|
|
333
|
+
currentParent = currentParent.parent
|
|
334
|
+
}
|
|
335
|
+
return hierarchy
|
|
336
|
+
}
|
|
337
|
+
return filePath ? filePath : 'Blits.Application'
|
|
269
338
|
}
|
|
270
339
|
|
|
271
340
|
return parse()
|
|
@@ -594,43 +594,6 @@ test('Parse template with a nameless tag', (assert) => {
|
|
|
594
594
|
assert.end()
|
|
595
595
|
})
|
|
596
596
|
|
|
597
|
-
// test('Parse template with a nameless tag but with arguments', (assert) => {
|
|
598
|
-
// const template = `
|
|
599
|
-
// <x="100" y="200">
|
|
600
|
-
// <x="50" y="20">
|
|
601
|
-
// <Component w="100" h="20" />
|
|
602
|
-
// </>
|
|
603
|
-
// </>`
|
|
604
|
-
|
|
605
|
-
// const expected = {
|
|
606
|
-
// children: [
|
|
607
|
-
// {
|
|
608
|
-
// type: null,
|
|
609
|
-
// x: '100',
|
|
610
|
-
// y: '200',
|
|
611
|
-
// children: [
|
|
612
|
-
// {
|
|
613
|
-
// type: null,
|
|
614
|
-
// x: '50',
|
|
615
|
-
// y: '20',
|
|
616
|
-
// children: [
|
|
617
|
-
// {
|
|
618
|
-
// type: 'Component',
|
|
619
|
-
// w: '100',
|
|
620
|
-
// h: '20',
|
|
621
|
-
// },
|
|
622
|
-
// ],
|
|
623
|
-
// },
|
|
624
|
-
// ],
|
|
625
|
-
// },
|
|
626
|
-
// ],
|
|
627
|
-
// }
|
|
628
|
-
// const actual = parser(template)
|
|
629
|
-
|
|
630
|
-
// assert.deepEqual(actual, expected, 'Parser should return object representation of template')
|
|
631
|
-
// assert.end()
|
|
632
|
-
// })
|
|
633
|
-
|
|
634
597
|
test('Parse template with a transition argument (single value)', (assert) => {
|
|
635
598
|
const template = `
|
|
636
599
|
<Element x.transition="$offset" y="200">
|
|
@@ -974,8 +937,16 @@ test('Parse template with multiple top level elements and parsing should fail',
|
|
|
974
937
|
/>
|
|
975
938
|
</Component>`
|
|
976
939
|
|
|
977
|
-
|
|
978
|
-
|
|
940
|
+
try {
|
|
941
|
+
parser(template)
|
|
942
|
+
assert.fail('Parser should throw TemplateStructureError:MultipleTopLevelTags')
|
|
943
|
+
} catch (error) {
|
|
944
|
+
assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
|
|
945
|
+
assert.ok(
|
|
946
|
+
error.message.startsWith('MultipleTopLevelTags'),
|
|
947
|
+
'Parser should throw TemplateStructureError:MultipleTopLevelTags'
|
|
948
|
+
)
|
|
949
|
+
}
|
|
979
950
|
|
|
980
951
|
assert.end()
|
|
981
952
|
})
|
|
@@ -987,8 +958,16 @@ test('Parse template with unclosed tag and parsing should fail', (assert) => {
|
|
|
987
958
|
</Component>
|
|
988
959
|
`
|
|
989
960
|
|
|
990
|
-
|
|
991
|
-
|
|
961
|
+
try {
|
|
962
|
+
parser(template)
|
|
963
|
+
assert.fail('Parser should throw TemplateStructureError:MismatchedClosingTag')
|
|
964
|
+
} catch (error) {
|
|
965
|
+
assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
|
|
966
|
+
assert.ok(
|
|
967
|
+
error.message.startsWith('MismatchedClosingTag'),
|
|
968
|
+
'Parser should throw TemplateStructureError:MismatchedClosingTag'
|
|
969
|
+
)
|
|
970
|
+
}
|
|
992
971
|
assert.end()
|
|
993
972
|
})
|
|
994
973
|
|
|
@@ -1004,8 +983,16 @@ test('Parse template with multiple unclosed tags and parsing should fail', (asse
|
|
|
1004
983
|
</Component>
|
|
1005
984
|
`
|
|
1006
985
|
|
|
1007
|
-
|
|
1008
|
-
|
|
986
|
+
try {
|
|
987
|
+
parser(template)
|
|
988
|
+
assert.fail('Parser should throw TemplateStructureError:MismatchedClosingTag')
|
|
989
|
+
} catch (error) {
|
|
990
|
+
assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
|
|
991
|
+
assert.ok(
|
|
992
|
+
error.message.startsWith('MismatchedClosingTag'),
|
|
993
|
+
'Parser should throw TemplateStructureError:MismatchedClosingTag'
|
|
994
|
+
)
|
|
995
|
+
}
|
|
1009
996
|
assert.end()
|
|
1010
997
|
})
|
|
1011
998
|
|
|
@@ -1017,8 +1004,16 @@ test('Parse template with an invalid closing tag and parsing should fail', (asse
|
|
|
1017
1004
|
</Component>
|
|
1018
1005
|
`
|
|
1019
1006
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1007
|
+
try {
|
|
1008
|
+
parser(template)
|
|
1009
|
+
assert.fail('Parser should throw TemplateParseError:InvalidClosingTag')
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
|
|
1012
|
+
assert.ok(
|
|
1013
|
+
error.message.startsWith('InvalidClosingTag'),
|
|
1014
|
+
'Parser should throw TemplateParseError:InvalidClosingTag'
|
|
1015
|
+
)
|
|
1016
|
+
}
|
|
1022
1017
|
|
|
1023
1018
|
assert.end()
|
|
1024
1019
|
})
|
|
@@ -1029,8 +1024,17 @@ test('Parse template with multiple self-closing tags at the top level and parsin
|
|
|
1029
1024
|
<Element/>
|
|
1030
1025
|
`
|
|
1031
1026
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1027
|
+
try {
|
|
1028
|
+
parser(template)
|
|
1029
|
+
assert.fail('Parser should throw TemplateStructureError:MultipleTopLevelTags')
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
|
|
1032
|
+
assert.ok(
|
|
1033
|
+
error.message.startsWith('MultipleTopLevelTags'),
|
|
1034
|
+
'Parser should throw TemplateStructureError:MultipleTopLevelTags'
|
|
1035
|
+
)
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1034
1038
|
assert.end()
|
|
1035
1039
|
})
|
|
1036
1040
|
|
|
@@ -1042,7 +1046,38 @@ test('Parse template with a closing tag at the beginning and parsing should fail
|
|
|
1042
1046
|
</Component>
|
|
1043
1047
|
`
|
|
1044
1048
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1049
|
+
try {
|
|
1050
|
+
parser(template)
|
|
1051
|
+
assert.fail('Parser should throw TemplateStructureError:MismatchedClosingTag')
|
|
1052
|
+
} catch (error) {
|
|
1053
|
+
assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
|
|
1054
|
+
assert.ok(
|
|
1055
|
+
error.message.startsWith('MismatchedClosingTag'),
|
|
1056
|
+
'Parser should throw TemplateStructureError:MismatchedClosingTag'
|
|
1057
|
+
)
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
assert.end()
|
|
1061
|
+
})
|
|
1062
|
+
|
|
1063
|
+
test('Parse template with a closing tag that has attributes and parsing should fail', (assert) => {
|
|
1064
|
+
const template = `
|
|
1065
|
+
<Component>
|
|
1066
|
+
<Text>Lorem ipsum dolor sit amet</Text>
|
|
1067
|
+
<Element></Element x="200">
|
|
1068
|
+
</Component>
|
|
1069
|
+
`
|
|
1070
|
+
|
|
1071
|
+
try {
|
|
1072
|
+
parser(template)
|
|
1073
|
+
assert.fail('Parser should throw TemplateParseError:AttributesInClosingTag')
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
|
|
1076
|
+
assert.ok(
|
|
1077
|
+
error.message.startsWith('AttributesInClosingTag'),
|
|
1078
|
+
'Parser should throw TemplateParseError:AttributesInClosingTag'
|
|
1079
|
+
)
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1047
1082
|
assert.end()
|
|
1048
1083
|
})
|
package/vite/preCompiler.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import parser from '../src/lib/templateparser/parser.js'
|
|
2
2
|
import generator from '../src/lib/codegenerator/generator.js'
|
|
3
|
+
import path from 'path'
|
|
3
4
|
|
|
4
5
|
export default function () {
|
|
5
6
|
let config
|
|
@@ -8,7 +9,7 @@ export default function () {
|
|
|
8
9
|
configResolved(resolvedConfig) {
|
|
9
10
|
config = resolvedConfig
|
|
10
11
|
},
|
|
11
|
-
transform(source) {
|
|
12
|
+
transform(source, filePath) {
|
|
12
13
|
if (config.blits && config.blits.precompile === false) return source
|
|
13
14
|
if (source.indexOf('Blits.Component(') > -1 || source.indexOf('Blits.Application(') > -1) {
|
|
14
15
|
// get the start of the template key in de component configuration object
|
|
@@ -27,7 +28,12 @@ export default function () {
|
|
|
27
28
|
templateStartIndex + templateContentResult.index + templateContentResult[0].length
|
|
28
29
|
|
|
29
30
|
// Parse the template
|
|
30
|
-
|
|
31
|
+
let resourceName = 'Blits.Application'
|
|
32
|
+
if (source.indexOf('Blits.Component(') > -1) {
|
|
33
|
+
resourceName = source.match(/Blits\.Component\(['"](.*)['"]\s*,/)[1]
|
|
34
|
+
}
|
|
35
|
+
const componentPath = path.relative(process.cwd(), filePath)
|
|
36
|
+
const parsed = parser(templateContentResult[1], resourceName, null, componentPath)
|
|
31
37
|
|
|
32
38
|
// Generate the code
|
|
33
39
|
const code = generator.call({ components: {} }, parsed)
|