Skip to content

Commit 752b89f

Browse files
chriseppsteinamiller-gh
authored andcommitted
feat(css-blocks): Remove BlockTree abstraction.
After spending considerable time exploring this new structure, I found the BlockTree abstraction mostly obfuscated the connections between core models of the Block (Block, Class, and State). By keeping the Inheritable data type and going directly to the concrete classes without an intermediate abstraction, we're still able to keep the Block types split up, but have less cognitive overhead while navigating the data model.
1 parent 461dbe8 commit 752b89f

File tree

12 files changed

+224
-298
lines changed

12 files changed

+224
-298
lines changed

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

+21-21
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ import { FileIdentifier } from "../importing";
2323
import { LocalScopedContext } from "../util/LocalScope";
2424

2525
import { BlockClass } from "./BlockClass";
26-
import { SourceContainer } from "./BlockTree";
27-
import { State } from "./State";
28-
29-
export type Style = BlockClass | State;
26+
import { Inheritable } from "./Inheritable";
27+
import { Styles } from "./Styles";
3028

3129
export const OBJ_REF_SPLITTER = (s: string): [string, string] | undefined => {
3230
let index = s.indexOf(".");
@@ -37,13 +35,13 @@ export const OBJ_REF_SPLITTER = (s: string): [string, string] | undefined => {
3735
return;
3836
};
3937

40-
export class Block extends SourceContainer<Block, BlockClass> {
38+
export class Block extends Inheritable<Block, Block, never, BlockClass> {
4139
private _rootClass: BlockClass;
4240
private _blockReferences: ObjectDictionary<Block> = {};
4341
private _blockReferencesReverseLookup: Map<Block, string> = new Map();
4442
private _identifier: FileIdentifier;
4543
private _implements: Block[] = [];
46-
private _localScope: LocalScopedContext<Block, Style>;
44+
private _localScope: LocalScopedContext<Block, Styles>;
4745
private hasHadNameReset = false;
4846
/**
4947
* array of paths that this block depends on and, if changed, would
@@ -59,12 +57,14 @@ export class Block extends SourceContainer<Block, BlockClass> {
5957
super(name);
6058
this._identifier = identifier;
6159
this.parsedRuleSelectors = new WeakMap();
62-
this._localScope = new LocalScopedContext<Block, Style>(OBJ_REF_SPLITTER, this);
60+
this._localScope = new LocalScopedContext<Block, Styles>(OBJ_REF_SPLITTER, this);
6361
this._dependencies = new Set<string>();
6462
this._rootClass = new BlockClass(ROOT_CLASS, this);
6563
this.addClass(this._rootClass);
6664
}
6765

66+
get block(): Block { return this.root; }
67+
6868
get name() { return this._name; }
6969
set name(name: string) {
7070
if (this.hasHadNameReset) {
@@ -79,7 +79,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
7979
}
8080

8181
/// Start of methods to implement LocalScope<Block, Style>
82-
subScope(name: string): LocalScopedContext<Block, Style> | undefined {
82+
subScope(name: string): LocalScopedContext<Block, Styles> | undefined {
8383
let block = this._blockReferences[name];
8484
if (block) {
8585
return block._localScope;
@@ -88,7 +88,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
8888
}
8989
}
9090

91-
lookupLocal(name: string): Style | undefined {
91+
lookupLocal(name: string): Styles | undefined {
9292
let blockRef = this._blockReferences[name];
9393
if (blockRef) {
9494
return blockRef.rootClass;
@@ -118,7 +118,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
118118
* A single dot by itself returns the current block.
119119
* @returns The Style referenced at the supplied path.
120120
*/
121-
public lookup(path: string | BlockPath, errLoc?: SourceLocation): Style | undefined {
121+
public lookup(path: string | BlockPath, errLoc?: SourceLocation): Styles | undefined {
122122
path = new BlockPath(path);
123123
let block = this.getReferencedBlock(path.block);
124124
if (!block) {
@@ -183,8 +183,8 @@ export class Block extends SourceContainer<Block, BlockClass> {
183183
* @param b The block to check implementation against.
184184
* @returns The Styles from b that are missing in the block.
185185
*/
186-
checkImplementation(b: Block): Style[] {
187-
let missing: Style[] = [];
186+
checkImplementation(b: Block): Styles[] {
187+
let missing: Styles[] = [];
188188
for (let o of b.all()) {
189189
if (!this.find(o.asSource())) {
190190
missing.push(o);
@@ -198,7 +198,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
198198
*/
199199
checkImplementations(): void {
200200
for (let b of this.getImplementedBlocks()) {
201-
let missing: Style[] = this.checkImplementation(b);
201+
let missing: Styles[] = this.checkImplementation(b);
202202
let paths = missing.map(o => o.asSource()).join(", ");
203203
if (missing.length > 0) {
204204
let s = missing.length > 1 ? "s" : "";
@@ -208,7 +208,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
208208
}
209209

210210
// This is a really dumb impl
211-
find(sourceName: string): Style | undefined {
211+
find(sourceName: string): Styles | undefined {
212212
let blockRefName: string | undefined;
213213
let md = sourceName.match(CLASS_NAME_IDENT);
214214
if (md && md.index === 0) {
@@ -284,8 +284,8 @@ export class Block extends SourceContainer<Block, BlockClass> {
284284
* @param shallow Pass true to not include inherited objects.
285285
* @returns Array of Styles.
286286
*/
287-
all(shallow?: boolean): Style[] {
288-
let result = new Array<Style>();
287+
all(shallow?: boolean): Styles[] {
288+
let result = new Array<Styles>();
289289
for (let blockClass of this.classes) {
290290
result.push(...blockClass.all());
291291
}
@@ -295,8 +295,8 @@ export class Block extends SourceContainer<Block, BlockClass> {
295295
return result;
296296
}
297297

298-
merged(): MultiMap<string, Style> {
299-
let map = new MultiMap<string, Style>(false);
298+
merged(): MultiMap<string, Styles> {
299+
let map = new MultiMap<string, Styles>(false);
300300
for (let obj of this.all()) {
301301
map.set(obj.asSource(), obj);
302302
}
@@ -307,7 +307,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
307307
* Fetch a the cached `Style` from `Block` given `NodeAndType`.
308308
* @param obj The `NodeAndType` object to use for `Style` lookup.
309309
*/
310-
nodeAndTypeToStyle(obj: NodeAndType): Style | null {
310+
nodeAndTypeToStyle(obj: NodeAndType): Styles | null {
311311
switch (obj.blockType) {
312312
case BlockType.root:
313313
return this.rootClass;
@@ -327,7 +327,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
327327
}
328328
}
329329

330-
nodeAsStyle(node: selectorParser.Node): [Style, number] | null {
330+
nodeAsStyle(node: selectorParser.Node): [Styles, number] | null {
331331
if (node.type === selectorParser.CLASS && node.value === ROOT_CLASS) {
332332
return [this.rootClass, 0];
333333
} else if (node.type === selectorParser.TAG) {
@@ -444,7 +444,7 @@ export class Block extends SourceContainer<Block, BlockClass> {
444444
let sortedNames = [...sourceNames].sort();
445445
for (let n of sortedNames) {
446446
if (n !== `.${ROOT_CLASS}`) {
447-
let o = this.find(n) as Style;
447+
let o = this.find(n) as Styles;
448448
result.push(o.asDebug(opts));
449449
}
450450
}

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

+13-5
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { OptionsReader } from "../OptionsReader";
55
import { OutputMode } from "../OutputMode";
66

77
import { Block } from "./Block";
8-
import { StyleNode } from "./BlockTree";
8+
import { RulesetContainer } from "./RulesetContainer";
99
import { State } from "./State";
1010
import { StateGroup } from "./StateGroup";
11+
import { Style } from "./Style";
12+
import { Styles } from "./Styles";
1113

1214
/**
1315
* Holds state values to be passed to the StateContainer.
@@ -20,8 +22,14 @@ export interface StateInfo {
2022
/**
2123
* Represents a Class present in the Block.
2224
*/
23-
export class BlockClass extends StyleNode<BlockClass, Block, Block, StateGroup> {
25+
export class BlockClass extends Style<BlockClass, Block, Block, StateGroup> {
2426
private _sourceAttribute: Attribute | undefined;
27+
public readonly rulesets: RulesetContainer<BlockClass>;
28+
29+
constructor(name: string, parent: Block) {
30+
super(name, parent);
31+
this.rulesets = new RulesetContainer(this);
32+
}
2533

2634
protected newChild(name: string): StateGroup { return new StateGroup(name, this); }
2735

@@ -116,7 +124,7 @@ export class BlockClass extends StyleNode<BlockClass, Block, Block, StateGroup>
116124
* @param shallow Pass false to not include children.
117125
* @returns Array of Styles.
118126
*/
119-
all(shallow?: boolean): (State | BlockClass)[] {
127+
all(shallow?: boolean): Styles[] {
120128
let result: (State | BlockClass)[] = [this];
121129
if (!shallow) {
122130
result = result.concat(this.allStates());
@@ -189,8 +197,8 @@ export class BlockClass extends StyleNode<BlockClass, Block, Block, StateGroup>
189197
*/
190198
debug(opts: OptionsReader): string[] {
191199
let result: string[] = [];
192-
for (let state of this.all()) {
193-
result.push(state.asDebug(opts));
200+
for (let style of this.all()) {
201+
result.push(style.asDebug(opts));
194202
}
195203
return result;
196204
}

packages/css-blocks/src/Block/BlockTree/index.ts

-122
This file was deleted.

packages/css-blocks/src/Block/BlockTree/Inheritable.ts packages/css-blocks/src/Block/Inheritable.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,23 @@
1313
*/
1414
import { ObjectDictionary } from "@opticss/util";
1515

16-
import { SourceLocation } from "../../SourceLocation";
16+
import { SourceLocation } from "../SourceLocation";
1717

1818
/* tslint:disable:prefer-whatever-to-any */
1919
export type AnyNode = Inheritable<any, any, any, any>;
2020

2121
export abstract class Inheritable<
2222
Self extends Inheritable<Self, Root, Parent, Child>,
23-
Root extends Inheritable<any, Root, null, AnyNode> | Self,
23+
Root extends Inheritable<any, Root, never, AnyNode> | Self,
2424
Parent extends Inheritable<any, Root, AnyNode | null, Self> | null,
25-
Child extends Inheritable<any, Root, Self, AnyNode | null> | null
25+
Child extends Inheritable<any, Root, Self, AnyNode | never> | never
2626
> {
2727
/* tslint:enable:prefer-whatever-to-any */
2828

2929
protected _name: string;
3030
protected _base: Self | undefined;
3131
protected _root: Root | Self;
32-
protected _parent: Parent;
32+
protected _parent: Parent | null;
3333
protected _children: Map<string, Child> = new Map();
3434

3535
/**
@@ -43,14 +43,17 @@ export abstract class Inheritable<
4343
* @param name Name for this Inheritable instance.
4444
* @param parent The parent Inheritable of this node.
4545
*/
46-
constructor(name: string, parent: Parent) {
46+
constructor(name: string, parent?: Parent) {
4747
this._name = name;
48-
this._parent = parent;
48+
this._parent = parent || null;
4949
this._root = parent ? parent.root : this.asSelf(); // `Root` is only set to `Self` for `Source` nodes.
5050
}
5151

5252
public get name(): string { return this._name; }
53-
public get parent(): Parent { return this._parent; }
53+
54+
public get parent(): Parent {
55+
return <Parent>this._parent;
56+
}
5457

5558
/**
5659
* Get the style that this style inherits from, if any.

0 commit comments

Comments
 (0)