11import { BlockPathError , ErrorLocation } from '../errors' ;
22import { CLASS_NAME_IDENT as CSS_IDENT } from "./blockSyntax" ;
3+ import { StateInfo } from "../BlockParser" ;
34
4- export interface BlockToken {
5+ interface BlockToken {
56 type : 'block' ;
67 name : string ;
78}
89
9- export interface ClassToken {
10+ interface ClassToken {
1011 type : 'class' ;
1112 name : string ;
1213}
@@ -18,20 +19,23 @@ export interface StateToken {
1819 value ?: string ;
1920}
2021
21- export type Token = BlockToken | ClassToken | StateToken ;
22+ type Token = BlockToken | ClassToken | StateToken ;
2223
23- export const isBlock = ( token ?: Token ) : token is BlockToken => ! ! token && token . type === 'block' ;
24- export const isClass = ( token ?: Token ) : token is ClassToken => ! ! token && token . type === 'class' ;
25- export const isState = ( token ?: Token ) : token is StateToken => ! ! token && token . type === 'state' ;
26- export const hasName = ( token ?: Token ) : boolean => ! ! token && ! ! token . name ;
27- export const hasNamespace = ( token ?: Token ) : boolean => isState ( token ) && ! ! token . namespace ;
28- export const hasValue = ( token ?: Token ) : boolean => isState ( token ) && ! ! token . value ;
24+ const isBlock = ( token ?: Token ) : token is BlockToken => ! ! token && token . type === 'block' ;
25+ const isClass = ( token ?: Token ) : token is ClassToken => ! ! token && token . type === 'class' ;
26+ const isState = ( token ?: Token ) : token is StateToken => ! ! token && token . type === 'state' ;
27+ const hasName = ( token ?: Token ) : boolean => ! ! token && ! ! token . name ;
28+ const hasNamespace = ( token ?: Token ) : boolean => isState ( token ) && ! ! token . namespace ;
2929
3030const STATE_BEGIN = "[" ;
3131const STATE_END = "]" ;
3232const CLASS_BEGIN = "." ;
3333const NAMESPACE_END = "|" ;
3434const VALUE_START = "=" ;
35+ const SINGLE_QUOTE = `'` ;
36+ const DOUBLE_QUOTE = `"` ;
37+ const WHITESPACE_REGEXP = / \s / g;
38+ const SEPARATORS = new Set ( [ CLASS_BEGIN , STATE_BEGIN ] ) ;
3539
3640export const ERRORS = {
3741 whitespace : "Whitespace is only allowed in quoted state values" ,
@@ -56,8 +60,6 @@ function stringify(tokens: Token[]): string {
5660 return out ;
5761}
5862
59- const SEPARATORS = new Set ( [ "." , "[" ] ) ;
60-
6163/**
6264 * Simple utility to easily walk over string data one character at a time.
6365 */
@@ -99,7 +101,7 @@ export class BlockPath {
99101 private _class : ClassToken ;
100102 private _state : StateToken ;
101103
102- protected tokens : Token [ ] = [ ] ;
104+ private tokens : Token [ ] = [ ] ;
103105
104106 /**
105107 * Throw a new BlockPathError with the given message.
@@ -147,10 +149,10 @@ export class BlockPath {
147149
148150 while ( char = walker . next ( ) ) {
149151
150- switch ( char ) {
152+ switch ( true ) {
151153
152154 // If a period, we've finished the previous token and are now building a class name.
153- case CLASS_BEGIN :
155+ case char === CLASS_BEGIN :
154156 if ( isState ( token ) ) { this . throw ( ERRORS . illegalCharInState ( char ) ) ; }
155157 token . name = working ;
156158 this . addToken ( token ) ;
@@ -159,7 +161,7 @@ export class BlockPath {
159161 break ;
160162
161163 // If the beginning of a state, we've finished the previous token and are now building a state.
162- case STATE_BEGIN :
164+ case char === STATE_BEGIN :
163165 if ( isState ( token ) ) { this . throw ( ERRORS . illegalCharInState ( char ) ) ; }
164166 token . name = working ;
165167 this . addToken ( token ) ;
@@ -168,37 +170,37 @@ export class BlockPath {
168170 break ;
169171
170172 // If the end of a state, set the state part we've been working on and finish.
171- case STATE_END :
173+ case char === STATE_END :
172174 if ( ! isState ( token ) ) { return this . throw ( ERRORS . illegalCharNotInState ( char ) ) ; }
173175 token . name ? ( token . value = working ) : ( token . name = working ) ;
174176 this . addToken ( token ) ;
175177 working = "" ;
176178
177- // The character immediately following a `STATE_END` *must* be another `SEPERATOR `
179+ // The character immediately following a `STATE_END` *must* be another `SEPARATORS `
178180 // Depending on the next value, seed our token input
179181 let next = walker . next ( ) ;
180182 if ( next && ! SEPARATORS . has ( next ) ) { this . throw ( ERRORS . expectsSepInsteadRec ( next ) ) ; }
181183 token = ( next === STATE_BEGIN ) ? { type : 'state' , namespace : '' , name : '' } : { type : 'class' , name : '' } ;
182184 break ;
183185
184186 // When we find a namespace terminator, set the namespace property of the state token we're working on.
185- case NAMESPACE_END :
187+ case char === NAMESPACE_END :
186188 if ( ! isState ( token ) ) { return this . throw ( ERRORS . illegalCharNotInState ( char ) ) ; }
187189 token . namespace = working ;
188190 working = "" ;
189191 break ;
190192
191193 // If the start of the value section of a state part, set the name we've been working on and move on.
192- case VALUE_START :
194+ case char === VALUE_START :
193195 if ( ! isState ( token ) ) { this . throw ( ERRORS . illegalCharNotInState ( char ) ) ; }
194196 if ( ! working ) { this . throw ( ERRORS . noname ) ; }
195197 token . name = working ;
196198 working = "" ;
197199 break ;
198200
199201 // If the opening quote of the value section of a state part, greedily consume everything between quotes.
200- case `"` :
201- case `'` :
202+ case char === SINGLE_QUOTE :
203+ case char === DOUBLE_QUOTE :
202204 if ( ! isState ( token ) ) { return this . throw ( ERRORS . illegalCharNotInState ( char ) ) ; }
203205 working = walker . consume ( char ) ;
204206 if ( walker . peek ( ) !== char ) { this . throw ( ERRORS . mismatchedQuote ) ; }
@@ -208,7 +210,7 @@ export class BlockPath {
208210 // We should never encounter whitespace in this switch statement.
209211 // The only place whitespace is allowed is between quotes, which
210212 // is handled above.
211- case ` ` :
213+ case WHITESPACE_REGEXP . test ( char ) :
212214 this . throw ( ERRORS . whitespace ) ;
213215
214216 // If none of the above special characters, add this character to our working string.
@@ -239,45 +241,51 @@ export class BlockPath {
239241 * @param path The BlockPath input data.
240242 * @param location An optional ErrorLocation object for more detailed error reporting.
241243 */
242- constructor ( path : string | BlockPath | Token [ ] , location ?: ErrorLocation ) {
244+ constructor ( path : string | BlockPath , location ?: ErrorLocation ) {
243245 this . _location = location ;
244246 if ( path instanceof BlockPath ) {
245247 this . tokens = path . tokens ;
246248 }
247- else if ( path instanceof Array ) {
248- this . tokens = path ;
249- }
250249 else {
251250 this . tokenize ( path ) ;
252251 }
253252 }
254253
255- /**
256- * Get the parsed block name of this Block Path
257- */
258- get block ( ) : string {
259- return this . _block . name ;
254+ private static from ( tokens : Token [ ] ) {
255+ let path = new BlockPath ( '' ) ;
256+ path . tokens = tokens ;
257+ return path ;
260258 }
261259
262260 /**
263261 * Get the parsed Style path of this Block Path
264262 */
265263 get path ( ) : string {
266- return stringify ( this . tokens . slice ( 1 ) ) || '.root' ;
264+ return stringify ( this . tokens . slice ( 1 ) ) ;
265+ }
266+
267+ /**
268+ * Get the parsed block name of this Block Path
269+ */
270+ get block ( ) : string {
271+ return this . _block ? this . _block . name : "" ;
267272 }
268273
269274 /**
270275 * Get the parsed class name of this Block Path
271276 */
272277 get class ( ) : string {
273- return this . _class && this . _class . name || ' root' ;
278+ return this . _class && this . _class . name || " root" ;
274279 }
275280
276281 /**
277- * Get the parsed state name of this Block Path
282+ * Get the parsed state name of this Block Path and return the `StateInfo`
278283 */
279- get state ( ) : StateToken | undefined {
280- return this . _state ;
284+ get state ( ) : StateInfo | undefined {
285+ return {
286+ group : this . _state . value ? this . _state . name : undefined ,
287+ name : this . _state . value || this . _state . name ,
288+ } ;
281289 }
282290
283291 /**
@@ -291,14 +299,14 @@ export class BlockPath {
291299 * Return a new BlockPath without the parent-most token.
292300 */
293301 childPath ( ) {
294- return new BlockPath ( this . tokens . slice ( 1 ) ) ;
302+ return BlockPath . from ( this . tokens . slice ( 1 ) ) ;
295303 }
296304
297305 /**
298306 * Return a new BlockPath without the child-most token.
299307 */
300308 parentPath ( ) {
301- return new BlockPath ( this . tokens . slice ( 0 , - 1 ) ) ;
309+ return BlockPath . from ( this . tokens . slice ( 0 , - 1 ) ) ;
302310 }
303311
304312}
0 commit comments