@@ -30,20 +30,24 @@ const slotTypes = {
3030function processNodes ( tree , options , messages ) {
3131 tree = applyPluginsToTree ( tree , options . plugins ) ;
3232
33- match . call ( tree , [ { tag : options . tagName } , { tag : options . tagRegExp } ] , node => {
33+ match . call ( tree , options . matcher , node => {
3434 if ( ! node . attrs ) {
3535 node . attrs = { } ;
3636 }
3737
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 ) ;
3943
4044 // Return node as-is when strict mode is disabled
4145 // otherwise raise error happen in find-path.js
4246 if ( ! filePath ) {
4347 return node ;
4448 }
4549
46- delete node . attrs . src ;
50+ delete node . attrs [ attributePath ] ;
4751
4852 const layoutPath = path . resolve ( options . root , filePath ) ;
4953
@@ -60,7 +64,7 @@ function processNodes(tree, options, messages) {
6064 const layoutTree = processNodes ( applyPluginsToTree ( html , plugins ) , options , messages ) ;
6165
6266 node . tag = false ;
63- node . content = mergeSlots ( layoutTree , node , options . strict , options . slotTagName ) ;
67+ node . content = mergeSlots ( layoutTree , node , options . strict , options ) ;
6468
6569 const index = node . content . findIndex ( content => typeof content === 'object' ) ;
6670
@@ -133,10 +137,11 @@ function parseLocals(options, {attrs}, html) {
133137 * @param {Object } node
134138 * @param {Boolean } strict
135139 * @param {String } slotTagName
140+ * @param {Boolean|String } fallbackSlotTagName
136141 * @return {Object } tree
137142 */
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
140145 const fillSlots = getSlots ( slotTagName , node . content ) ; // Slot in page.html
141146
142147 // Retrieve main content, means everything that is not inside slots
@@ -223,12 +228,16 @@ function mergeContent(slotContent, defaultContent, slotType) {
223228 * Get all slots from content
224229 * @param {String } tag
225230 * @param {Object } content
231+ * @param {Boolean|String } fallbackSlotTagName
226232 * @return {Object }
227233 */
228- function getSlots ( tag , content = [ ] ) {
234+ function getSlots ( tag , content = [ ] , fallbackSlotTagName = false ) {
229235 const slots = { } ;
230236
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 => {
232241 if ( ! node . attrs ) {
233242 node . attrs = { } ;
234243 }
@@ -310,19 +319,25 @@ module.exports = (options = {}) => {
310319 fileExtension : 'html' ,
311320 tagPrefix : 'x-' ,
312321 tagRegExp : new RegExp ( `^${ options . tagPrefix || 'x-' } ` , 'i' ) ,
313- defaultSlotRegex : new RegExp ( '^((?!(slot)).)*$' ) ,
314322 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 ,
315325 tagName : 'component' ,
326+ tagNames : [ ] ,
327+ attribute : 'src' ,
328+ attributes : [ ] ,
316329 locals : { } ,
317330 expressions : { } ,
318331 plugins : [ ] ,
319332 encoding : 'utf8' ,
320333 strict : true ,
321- scriptLocalAttribute : 'defaultLocals'
334+ scriptLocalAttribute : 'defaultLocals' ,
335+ matcher : [ ]
322336 } ,
323337 ...options
324338 } ;
325339
340+ /** Set root, roots and namespace's roots */
326341 options . root = path . resolve ( options . root ) ;
327342
328343 options . roots = Array . isArray ( options . roots ) ? options . roots : [ options . roots ] ;
@@ -344,10 +359,41 @@ module.exports = (options = {}) => {
344359 }
345360 } ) ;
346361
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+
347393 return function ( tree ) {
348394 tree = processNodes ( tree , options , tree . messages ) ;
349395
350- const slots = getSlots ( options . slotTagName , tree ) ;
396+ const slots = getSlots ( options . slotTagName , tree , options . fallbackSlotTagName ) ;
351397
352398 for ( const slotName of Object . keys ( slots ) ) {
353399 const nodes = slots [ slotName ] ;
0 commit comments