@@ -76,7 +76,7 @@ export async function constructBlock(configuration: Configuration, root: postcss
76
76
77
77
// If this is an external Style, move on. These are validated
78
78
// 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 ) ;
80
80
if ( blockName ) {
81
81
sel = sel . next && sel . next . selector ;
82
82
continue ;
@@ -226,24 +226,19 @@ function assertValidSelector(configuration: Configuration, block: Block, rule: p
226
226
*/
227
227
function assertBlockObject ( configuration : Configuration , block : Block , sel : CompoundSelector , rule : postcss . Rule , file : string ) : NodeAndType {
228
228
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
+ ) ;
240
235
}
241
236
242
237
// Targeting attributes that are not state selectors is not allowed in blocks, throw.
243
238
let nonStateAttribute = sel . nodes . find ( n => selectorParser . isAttribute ( n ) && ! isAttributeNode ( n ) ) ;
244
239
if ( nonStateAttribute ) {
245
240
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 } ` ,
247
242
range ( configuration , block . stylesheet , file , rule , nonStateAttribute ) ,
248
243
) ;
249
244
}
@@ -264,23 +259,6 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
264
259
// Test each node in selector
265
260
let result = sel . nodes . reduce < NodeAndType | null > (
266
261
( 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
-
284
262
// If selecting the root element, indicate we have encountered it. If this
285
263
// is not the first BlockType encountered, throw the appropriate error
286
264
if ( isRootNode ( n ) ) {
@@ -314,10 +292,19 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
314
292
`States without an explicit :scope or class selector are not supported: ${ rule . selector } ` ,
315
293
range ( configuration , block . stylesheet , file , rule , n ) ,
316
294
) ;
317
- } else if ( found . blockType === BlockType . class || found . blockType === BlockType . classAttribute ) {
295
+ }
296
+ if ( found . blockType === BlockType . class || found . blockType === BlockType . classAttribute ) {
318
297
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 } ;
321
308
}
322
309
}
323
310
@@ -348,9 +335,9 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
348
335
}
349
336
}
350
337
return found ;
351
- } ,
338
+ } ,
352
339
null ,
353
- ) ;
340
+ ) ;
354
341
355
342
// If no rules found in selector, we have a problem. Throw.
356
343
if ( ! result ) {
@@ -360,24 +347,33 @@ function assertBlockObject(configuration: Configuration, block: Block, sel: Comp
360
347
}
361
348
362
349
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
+ }
365
361
let globalStates = external . rootClass . allAttributeValues ( ) . filter ( ( a ) => a . isGlobal ) ;
366
362
if ( ! globalStates . length ) {
367
363
throw new errors . InvalidBlockSyntax (
368
- `External Block '${ result . node . value } ' has no global states.` ,
364
+ `External Block '${ blockName } ' has no global states.` ,
369
365
range ( configuration , block . stylesheet , file , rule , sel . nodes [ 0 ] ) ) ;
370
366
}
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 ;
374
373
}
375
374
376
375
// Otherwise, return the block, type and associated node.
377
376
else {
378
- return {
379
- blockName : blockName && blockName . value ,
380
- ...result ,
381
- } ;
377
+ return result ;
382
378
}
383
379
}
0 commit comments