Skip to content

Commit 2f04eb1

Browse files
committed
fix(css-blocks): Updated with more of Chris' comments and use the renamed MultiMap methods
1 parent 29d2316 commit 2f04eb1

File tree

4 files changed

+64
-48
lines changed

4 files changed

+64
-48
lines changed

packages/css-blocks/src/Block/RulesetContainer.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,15 @@ export class RulesetContainer {
193193
}
194194
return new Set(res);
195195
}
196-
return new Set([...this.concerns.subkeys(pseudo)]);
196+
return new Set([...this.concerns.subKeys(pseudo)]);
197197
}
198198

199199
/**
200200
* Retrieve all pseudo elements which were found to have properties for this Style.
201201
* @returns A set of pseudo element names.
202202
*/
203203
getPseudos(): Set<string> {
204-
return new Set([...this.concerns.subkeys()]);
204+
return new Set([...this.concerns.primaryKeys()]);
205205
}
206206

207207
/**

packages/css-blocks/src/BlockSyntax/BlockPath.ts

+46-38
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { BlockPathError, ErrorLocation } from '../errors';
22
import { 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

3030
const STATE_BEGIN = "[";
3131
const STATE_END = "]";
3232
const CLASS_BEGIN = ".";
3333
const NAMESPACE_END = "|";
3434
const 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

3640
export 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
}

packages/css-blocks/src/TemplateAnalysis/validations/property-conflict-validator.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ const propertyConflictValidator: Validator = (elAnalysis, _templateAnalysis, err
164164
});
165165
}
166166

167-
allConditions.merge(truthyConditions);
168-
allConditions.merge(falsyConditions);
167+
allConditions.setAll(truthyConditions);
168+
allConditions.setAll(falsyConditions);
169169

170170
});
171171

@@ -178,7 +178,7 @@ const propertyConflictValidator: Validator = (elAnalysis, _templateAnalysis, err
178178
evaluate(state, allConditions, conflicts);
179179
add(stateConditions, state);
180180
});
181-
allConditions.merge(stateConditions);
181+
allConditions.setAll(stateConditions);
182182
}
183183

184184
else if (isBooleanState(condition)) {

packages/css-blocks/test/BlockSyntax/block-path-test.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ export class BlockPathTests {
9292
@test "parentPath returns the parent's path"() {
9393
let path = new BlockPath("block.class[state|my-state]");
9494
assert.equal(path.parentPath().toString(), "block.class");
95+
path = new BlockPath(".class[state|my-state]");
96+
assert.equal(path.parentPath().toString(), ".class");
9597
path = new BlockPath("block.class");
9698
assert.equal(path.parentPath().toString(), "block");
9799
path = new BlockPath("block[state|my-state]");
@@ -101,6 +103,8 @@ export class BlockPathTests {
101103
@test "childPath returns the child's path"() {
102104
let path = new BlockPath("block.class[state|my-state]");
103105
assert.equal(path.childPath().toString(), ".class[state|my-state]");
106+
path = new BlockPath(".class[state|my-state]");
107+
assert.equal(path.childPath().toString(), "[state|my-state]");
104108
path = new BlockPath("block.class");
105109
assert.equal(path.childPath().toString(), ".class");
106110
path = new BlockPath("block[state|my-state]");
@@ -112,16 +116,16 @@ export class BlockPathTests {
112116
assert.equal(path.block, "block");
113117
assert.equal(path.path, ".class[state|my-state]");
114118
assert.equal(path.class, "class");
115-
assert.equal(path.state && path.state.namespace, "state");
119+
// assert.equal(path.state && path.state.namespace, "state");
116120
assert.equal(path.state && path.state.name, "my-state");
117121

118122
path = new BlockPath("block[state|my-state=foobar]");
119123
assert.equal(path.block, "block");
120124
assert.equal(path.path, `[state|my-state="foobar"]`);
121125
assert.equal(path.class, "root");
122-
assert.equal(path.state && path.state.namespace, "state");
123-
assert.equal(path.state && path.state.name, "my-state");
124-
assert.equal(path.state && path.state.value, "foobar");
126+
// assert.equal(path.state && path.state.namespace, "state");
127+
assert.equal(path.state && path.state.group, "my-state");
128+
assert.equal(path.state && path.state.name, "foobar");
125129
}
126130

127131
@test "mismatched State value quotes throw"() {
@@ -155,9 +159,12 @@ export class BlockPathTests {
155159
assert.throws(() => {
156160
let path = new BlockPath(`[state|my-state=my value]`);
157161
}, ERRORS.whitespace);
162+
assert.throws(() => {
163+
let path = new BlockPath(`[state|my-state=my\nvalue]`);
164+
}, ERRORS.whitespace);
158165
}
159166

160-
@test "state are required to have namespaces"() {
167+
@test "states are required to have namespaces"() {
161168
let path = new BlockPath(`[namespace|name=value]`);
162169

163170
assert.throws(() => {
@@ -241,6 +248,7 @@ export class BlockPathTests {
241248

242249
// Quoted values may have illegal strings
243250
let path = new BlockPath(`block[name|foo="1bar"]`);
251+
assert.equal(path.state && path.state.name, "1bar");
244252
}
245253

246254
@test @skip "escaped illegal characters in identifiers are processed"() {

0 commit comments

Comments
 (0)