@@ -76,7 +76,7 @@ export async function constructBlock(configuration: Configuration, root: postcss
7676
7777 // If this is an external Style, move on. These are validated
7878 // in `assert-foreign-global-attribute`.
79- let blockName = sel . nodes . find ( n => n . type === selectorParser . TAG ) ;
79+ let blockName = sel . nodes . find ( n => isAttributeNode ( n ) && n . namespace ) ;
8080 if ( blockName ) {
8181 sel = sel . next && sel . next . selector ;
8282 continue ;
@@ -226,24 +226,19 @@ function assertValidSelector(configuration: Configuration, block: Block, rule: p
226226 */
227227function assertBlockObject ( configuration : Configuration , block : Block , sel : CompoundSelector , rule : postcss . Rule , file : string ) : NodeAndType {
228228
229- // If selecting a block or tag, check that the referenced block has been imported.
230- // Otherwise, referencing a tag name is not allowed in blocks, throw an error.
231- let blockName = sel . nodes . find ( selectorParser . isTag ) ;
232- if ( blockName ) {
233- let refBlock = block . getReferencedBlock ( blockName . value ) ;
234- if ( ! refBlock ) {
235- throw new errors . InvalidBlockSyntax (
236- `Tag name selectors are not allowed: ${ rule . selector } ` ,
237- range ( configuration , block . stylesheet , file , rule , blockName ) ,
238- ) ;
239- }
229+ let tagNode = sel . nodes . find ( selectorParser . isTag ) ;
230+ if ( tagNode ) {
231+ throw new errors . InvalidBlockSyntax (
232+ `Tag name selectors are not allowed: ${ rule . selector } ` ,
233+ range ( configuration , block . stylesheet , file , rule , tagNode ) ,
234+ ) ;
240235 }
241236
242237 // Targeting attributes that are not state selectors is not allowed in blocks, throw.
243238 let nonStateAttribute = sel . nodes . find ( n => selectorParser . isAttribute ( n ) && ! isAttributeNode ( n ) ) ;
244239 if ( nonStateAttribute ) {
245240 throw new errors . InvalidBlockSyntax (
246- `Cannot select attributes other than states : ${ rule . selector } ` ,
241+ `Cannot select attributes in the \` ${ selectorParser . isAttribute ( nonStateAttribute ) && nonStateAttribute . namespaceString } \` namespace : ${ rule . selector } ` ,
247242 range ( configuration , block . stylesheet , file , rule , nonStateAttribute ) ,
248243 ) ;
249244 }
@@ -264,23 +259,6 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
264259 // Test each node in selector
265260 let result = sel . nodes . reduce < NodeAndType | null > (
266261 ( found , n ) => {
267-
268- // If this is an external Block reference, indicate we have encountered it.
269- // If this is not the first BlockType encountered, throw the appropriate error.
270- if ( n . type === selectorParser . TAG ) {
271- if ( found === null ) {
272- found = {
273- blockType : BlockType . block ,
274- node : n ,
275- } ;
276- } else {
277- throw new errors . InvalidBlockSyntax (
278- `External Block ${ n } must be the first selector in "${ rule . selector } "` ,
279- range ( configuration , block . stylesheet , file , rule , sel . nodes [ 0 ] ) ,
280- ) ;
281- }
282- }
283-
284262 // If selecting the root element, indicate we have encountered it. If this
285263 // is not the first BlockType encountered, throw the appropriate error
286264 if ( isRootNode ( n ) ) {
@@ -314,10 +292,19 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
314292 `States without an explicit :scope or class selector are not supported: ${ rule . selector } ` ,
315293 range ( configuration , block . stylesheet , file , rule , n ) ,
316294 ) ;
317- } else if ( found . blockType === BlockType . class || found . blockType === BlockType . classAttribute ) {
295+ }
296+ if ( found . blockType === BlockType . class || found . blockType === BlockType . classAttribute ) {
318297 found = { node : n , blockType : BlockType . classAttribute } ;
319- } else if ( found . blockType === BlockType . block || found . blockType === BlockType . root || found . blockType === BlockType . attribute ) {
320- found = { node : n , blockType : BlockType . attribute } ;
298+ } else if ( found . blockType === BlockType . root || found . blockType === BlockType . attribute ) {
299+ if ( n . namespace === true ) {
300+ throw new errors . InvalidBlockSyntax (
301+ `The "any namespace" selector is not supported: ${ rule . selector } ` ,
302+ range ( configuration , block . stylesheet , file , rule , n ) ,
303+ ) ;
304+ }
305+ // XXX this is where we drop the ref to the other attribute nodes,
306+ // XXX potentially causing the interface to not be fully discovered
307+ found = { node : n , blockType : BlockType . attribute , blockName : n . namespace } ;
321308 }
322309 }
323310
@@ -348,9 +335,9 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
348335 }
349336 }
350337 return found ;
351- } ,
338+ } ,
352339 null ,
353- ) ;
340+ ) ;
354341
355342 // If no rules found in selector, we have a problem. Throw.
356343 if ( ! result ) {
@@ -360,24 +347,33 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
360347 }
361348
362349 if ( isExternalBlock ( result ) ) {
363- let external = block . getReferencedBlock ( result . node . value ! ) ;
364- if ( ! external ) { throw new errors . InvalidBlockSyntax ( `` , range ( configuration , block . stylesheet , file , rule , sel . nodes [ 0 ] ) ) ; }
350+ let blockName : string | undefined ;
351+ if ( result . blockType === BlockType . attribute ) {
352+ blockName = result . blockName ! ;
353+ } else {
354+ blockName = result . node . value ;
355+ }
356+ let external = block . getReferencedBlock ( blockName ) ;
357+ if ( ! external ) {
358+ throw new errors . InvalidBlockSyntax ( `A block named "${ blockName } " does not exist in this context.` ,
359+ range ( configuration , block . stylesheet , file , rule , sel . nodes [ 0 ] ) ) ;
360+ }
365361 let globalStates = external . rootClass . allAttributeValues ( ) . filter ( ( a ) => a . isGlobal ) ;
366362 if ( ! globalStates . length ) {
367363 throw new errors . InvalidBlockSyntax (
368- `External Block '${ result . node . value } ' has no global states.` ,
364+ `External Block '${ blockName } ' has no global states.` ,
369365 range ( configuration , block . stylesheet , file , rule , sel . nodes [ 0 ] ) ) ;
370366 }
371- throw new errors . InvalidBlockSyntax (
372- `Missing global state selector on external Block '${ result . node . value } '. Did you mean one of: ${ globalStates . map ( ( s ) => s . asSource ( ) ) . join ( " " ) } ` ,
373- range ( configuration , block . stylesheet , file , rule , sel . nodes [ 0 ] ) ) ;
367+ if ( result . blockType !== BlockType . attribute ) {
368+ throw new errors . InvalidBlockSyntax (
369+ `Missing global state selector on external Block '${ blockName } '. Did you mean one of: ${ globalStates . map ( ( s ) => s . asSource ( ) ) . join ( " " ) } ` ,
370+ range ( configuration , block . stylesheet , file , rule , sel . nodes [ 0 ] ) ) ;
371+ }
372+ return result ;
374373 }
375374
376375 // Otherwise, return the block, type and associated node.
377376 else {
378- return {
379- blockName : blockName && blockName . value ,
380- ...result ,
381- } ;
377+ return result ;
382378 }
383379}
0 commit comments