@@ -30,20 +30,24 @@ const slotTypes = {
30
30
function processNodes ( tree , options , messages ) {
31
31
tree = applyPluginsToTree ( tree , options . plugins ) ;
32
32
33
- match . call ( tree , [ { tag : options . tagName } , { tag : options . tagRegExp } ] , node => {
33
+ match . call ( tree , options . matcher , node => {
34
34
if ( ! node . attrs ) {
35
35
node . attrs = { } ;
36
36
}
37
37
38
- const filePath = node . attrs . src || findPathFromTagName ( node , options ) ;
38
+ // For compatibility with extends and modules plugins
39
+ // we want to support multiple attributes for define path
40
+ const attributePath = ( options . attributes . length > 0 && options . attributes . find ( attribute => node . attrs [ attribute ] ) ) || options . attribute ;
41
+
42
+ const filePath = node . attrs [ attributePath ] || findPathFromTagName ( node , options ) ;
39
43
40
44
// Return node as-is when strict mode is disabled
41
45
// otherwise raise error happen in find-path.js
42
46
if ( ! filePath ) {
43
47
return node ;
44
48
}
45
49
46
- delete node . attrs . src ;
50
+ delete node . attrs [ attributePath ] ;
47
51
48
52
const layoutPath = path . resolve ( options . root , filePath ) ;
49
53
@@ -60,7 +64,7 @@ function processNodes(tree, options, messages) {
60
64
const layoutTree = processNodes ( applyPluginsToTree ( html , plugins ) , options , messages ) ;
61
65
62
66
node . tag = false ;
63
- node . content = mergeSlots ( layoutTree , node , options . strict , options . slotTagName ) ;
67
+ node . content = mergeSlots ( layoutTree , node , options . strict , options ) ;
64
68
65
69
const index = node . content . findIndex ( content => typeof content === 'object' ) ;
66
70
@@ -133,10 +137,11 @@ function parseLocals(options, {attrs}, html) {
133
137
* @param {Object } node
134
138
* @param {Boolean } strict
135
139
* @param {String } slotTagName
140
+ * @param {Boolean|String } fallbackSlotTagName
136
141
* @return {Object } tree
137
142
*/
138
- function mergeSlots ( tree , node , strict , slotTagName ) {
139
- const slots = getSlots ( slotTagName , tree ) ; // Slot in component.html
143
+ function mergeSlots ( tree , node , strict , { slotTagName, fallbackSlotTagName } ) {
144
+ const slots = getSlots ( slotTagName , tree , fallbackSlotTagName ) ; // Slot in component.html
140
145
const fillSlots = getSlots ( slotTagName , node . content ) ; // Slot in page.html
141
146
142
147
// Retrieve main content, means everything that is not inside slots
@@ -223,12 +228,16 @@ function mergeContent(slotContent, defaultContent, slotType) {
223
228
* Get all slots from content
224
229
* @param {String } tag
225
230
* @param {Object } content
231
+ * @param {Boolean|String } fallbackSlotTagName
226
232
* @return {Object }
227
233
*/
228
- function getSlots ( tag , content = [ ] ) {
234
+ function getSlots ( tag , content = [ ] , fallbackSlotTagName = false ) {
229
235
const slots = { } ;
230
236
231
- match . call ( content , { tag} , node => {
237
+ // For compatibility with module slot name <content>
238
+ const matcher = fallbackSlotTagName === false ? { tag} : [ { tag} , { tag : fallbackSlotTagName === true ? 'content' : fallbackSlotTagName } ] ;
239
+
240
+ match . call ( content , matcher , node => {
232
241
if ( ! node . attrs ) {
233
242
node . attrs = { } ;
234
243
}
@@ -310,19 +319,25 @@ module.exports = (options = {}) => {
310
319
fileExtension : 'html' ,
311
320
tagPrefix : 'x-' ,
312
321
tagRegExp : new RegExp ( `^${ options . tagPrefix || 'x-' } ` , 'i' ) ,
313
- defaultSlotRegex : new RegExp ( '^((?!(slot)).)*$' ) ,
314
322
slotTagName : 'slot' ,
323
+ // Used for compatibility with modules plugin <content> slot, set to true only if you have migrated from modules plugin
324
+ fallbackSlotTagName : false ,
315
325
tagName : 'component' ,
326
+ tagNames : [ ] ,
327
+ attribute : 'src' ,
328
+ attributes : [ ] ,
316
329
locals : { } ,
317
330
expressions : { } ,
318
331
plugins : [ ] ,
319
332
encoding : 'utf8' ,
320
333
strict : true ,
321
- scriptLocalAttribute : 'defaultLocals'
334
+ scriptLocalAttribute : 'defaultLocals' ,
335
+ matcher : [ ]
322
336
} ,
323
337
...options
324
338
} ;
325
339
340
+ /** Set root, roots and namespace's roots */
326
341
options . root = path . resolve ( options . root ) ;
327
342
328
343
options . roots = Array . isArray ( options . roots ) ? options . roots : [ options . roots ] ;
@@ -344,10 +359,41 @@ module.exports = (options = {}) => {
344
359
}
345
360
} ) ;
346
361
362
+ if ( ! Array . isArray ( options . attributes ) ) {
363
+ options . attributes = [ ] ;
364
+ }
365
+
366
+ if ( ! Array . isArray ( options . matcher ) ) {
367
+ options . matcher = options . matcher ? [ options . matcher ] : [ ] ;
368
+ }
369
+
370
+ if ( ! Array . isArray ( options . tagNames ) ) {
371
+ options . tagNames = [ ] ;
372
+ }
373
+
374
+ /** Set one or multiple matcher */
375
+ if ( options . matcher . length === 0 ) {
376
+ if ( options . tagRegExp ) {
377
+ options . matcher . push ( { tag : options . tagRegExp } ) ;
378
+ }
379
+
380
+ if ( options . tagNames . length > 0 ) {
381
+ options . tagNames . forEach ( tagName => {
382
+ options . matcher . push ( { tag : tagName } ) ;
383
+ } ) ;
384
+ } else if ( options . tagName ) {
385
+ options . matcher . push ( { tag : options . tagName } ) ;
386
+ }
387
+
388
+ if ( options . matcher . length === 0 ) {
389
+ throw new Error ( '[components] No matcher found in options. Please to define almost one.' ) ;
390
+ }
391
+ }
392
+
347
393
return function ( tree ) {
348
394
tree = processNodes ( tree , options , tree . messages ) ;
349
395
350
- const slots = getSlots ( options . slotTagName , tree ) ;
396
+ const slots = getSlots ( options . slotTagName , tree , options . fallbackSlotTagName ) ;
351
397
352
398
for ( const slotName of Object . keys ( slots ) ) {
353
399
const nodes = slots [ slotName ] ;
0 commit comments