@lightningjs/blits 0.6.3 → 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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ # v0.6.5
4
+
5
+ _16 jan 2024_
6
+
7
+ - Added `path` to boilerplate vite.config.js for deployments in a sub folder
8
+ - Improved error handling in the template parser, with more contextual error messages
9
+
10
+ # v0.6.4
11
+
12
+ _15 jan 2024_
13
+
14
+ - Added fix for sprites not working on certain devices
15
+
3
16
  # v0.6.3
4
17
 
5
18
  _12 jan 2024_
@@ -6,6 +6,6 @@
6
6
  </head>
7
7
  <body>
8
8
  <div id="app"></div>
9
- <script type="module" src="/src/index.js"></script>
9
+ <script type="module" src="src/index.js"></script>
10
10
  </body>
11
11
  </html>
@@ -31,6 +31,6 @@
31
31
  "vite": "^4.0.4"
32
32
  },
33
33
  "dependencies": {
34
- "@lightningjs/blits": "^0.6.3"
34
+ "@lightningjs/blits": "^0.6.5"
35
35
  }
36
36
  }
@@ -11,8 +11,22 @@ Blits.Launch(App, 'app', {
11
11
  debugLevel: 1,
12
12
  fontLoader: fontLoader,
13
13
  fonts: [
14
- {family: 'lato', type: 'msdf', png: '/fonts/Lato-Regular.msdf.png', json: '/fonts/Lato-Regular.msdf.json'},
15
- {family: 'raleway', type: 'msdf', png: '/fonts/Raleway-ExtraBold.msdf.png', json: '/fonts/Raleway-ExtraBold.msdf.json'},
16
- {family: 'opensans', type: 'web', file: '/fonts/OpenSans-Medium.ttf'}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.cjs",
6
6
  "exports": {
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
@@ -22,7 +22,7 @@ import symbols from '../lib/symbols.js'
22
22
  export default () =>
23
23
  Component('Sprite', {
24
24
  template: `
25
- <Element w="$w" h="$h" color="#fff" :texture="$texture" />
25
+ <Element w="$w" h="$h" :texture="$texture" />
26
26
  `,
27
27
  props: ['image', 'map', 'frame', 'w', 'h'],
28
28
  state() {
@@ -34,7 +34,7 @@ export default () =>
34
34
  texture() {
35
35
  const options =
36
36
  'frames' in this.map
37
- ? { ...(this.map.defaults || {}), ...this.map.frames[this.frame] }
37
+ ? Object.assign({}, this.map.defaults || {}, this.map.frames[this.frame])
38
38
  : this.map[this.frame]
39
39
 
40
40
  if (this.spriteTexture && options) {
package/src/element.js CHANGED
@@ -119,6 +119,9 @@ const Props = {
119
119
  },
120
120
  set texture(v) {
121
121
  this._props.texture = v
122
+ if (!this._set.has('color')) {
123
+ this._props.color = 0xffffffff
124
+ }
122
125
  this._set.add('texture')
123
126
  },
124
127
  set mount(v) {
@@ -1,5 +1,6 @@
1
1
  export default {
2
2
  currentView: Symbol('currentView'),
3
+ cursorTagStart: Symbol('cursorTagStart'),
3
4
  computedKeys: Symbol('computedKeys'),
4
5
  destroy: Symbol('destroy'),
5
6
  index: Symbol('index'),
@@ -17,16 +17,9 @@
17
17
 
18
18
  import symbols from '../symbols.js'
19
19
 
20
- class TemplateParseError extends Error {
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 instanceof TemplateParseError) {
49
- console.error(`${error.message} | ${error.name}`)
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
- // return errors gracefully
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 = (template) => {
56
+ const clean = (templateText) => {
67
57
  // remove all unnecessary new lines and comments
68
- return template
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) cursor += match[0].length
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({ type: null, [symbols.type]: 'opening', [symbols.level]: currentLevel })
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({ type: null, [symbols.type]: 'closing', [symbols.level]: currentLevel })
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 = { type: match[1], [symbols.type]: 'closing', [symbols.level]: currentLevel }
117
+ currentTag[symbols.type] = 'closing'
118
+ currentTag[symbols.level] = currentLevel
111
119
  } else {
112
- currentTag = { type: match[1], [symbols.type]: 'opening', [symbols.level]: currentLevel }
120
+ currentTag[symbols.type] = 'opening'
113
121
  currentLevel++
114
122
  }
115
123
  parseLoop(parseTagEnd)
116
124
  } else {
117
- throw new TemplateParseError('InvalidTag', template.slice(cursor))
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
- // 10 is arbitrary, just to show some context by moving the cursor back a bit
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 new TemplateParseError('MissingOrInvalidAttributeValue', template.slice(cursor))
175
+ throw TemplateParseError('MissingOrInvalidAttributeValue')
164
176
  }
165
177
  } else {
166
- throw new TemplateParseError('InvalidAttribute', template.slice(cursor))
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 new TemplateParseError('MultipleTopLevelTags', formatErrorContext(element))
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 new TemplateParseError('MismatchedClosingTag', formatErrorContext(element))
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
- const unclosedTags = stack
255
- .map((item) => {
256
- return formatErrorContext(item)
257
- })
258
- .join(', ')
259
- throw new TemplateParseError('UnclosedTags', unclosedTags)
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
- function formatErrorContext(element) {
263
- return `${element.type || 'empty-tag'}[${element[symbols.type]}] at level ${
264
- element[symbols.level]
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
- return output
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
- const actual = parser(template)
978
- assert.equal(actual, null, 'Parser should throw an error')
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
- const actual = parser(template)
991
- assert.equal(actual, null, 'Parser should throw an error')
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
- const actual = parser(template)
1008
- assert.equal(actual, null, 'Parser should throw an error')
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
- const actual = parser(template)
1021
- assert.equal(actual, null, 'Parser should throw an error')
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
- const actual = parser(template)
1033
- assert.equal(actual, null, 'Parser should throw an error')
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
- const actual = parser(template)
1046
- assert.equal(actual, null, 'Parser should throw an error')
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
  })
@@ -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
- const parsed = parser(templateContentResult[1])
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)