Skip to content

Commit 2615eb9

Browse files
committed
fix: Cleanup the deserialization code for analysis.
1 parent f320818 commit 2615eb9

File tree

2 files changed

+111
-79
lines changed

2 files changed

+111
-79
lines changed

packages/@css-blocks/core/src/Analyzer/Analysis.ts

+27-50
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ import {
1111
TemplateInfoFactory,
1212
TemplateTypes,
1313
} from "@opticss/template-api";
14-
import { ObjectDictionary, assertNever, objectValues } from "@opticss/util";
14+
import { ObjectDictionary, objectValues } from "@opticss/util";
1515
import { IdentGenerator } from "opticss";
1616

1717
import { BlockFactory } from "../BlockParser";
18-
import { AttrValue, Attribute, Block, BlockClass, Style } from "../BlockTree";
18+
import { AttrValue, Block, BlockClass, Style } from "../BlockTree";
1919
import { ResolvedConfiguration } from "../configuration";
2020
import { allDone } from "../util";
2121

2222
import { Analyzer } from "./Analyzer";
23-
import { DynamicClasses, ElementAnalysis, FalseCondition, SerializedElementAnalysis, SerializedElementSourceAnalysis, TrueCondition, hasAttrValue, hasDependency, isAttrGroup, isConditional, isFalseCondition, isStaticClass, isSwitch, isTrueCondition } from "./ElementAnalysis";
23+
import { ElementAnalysis, SerializedElementAnalysis, SerializedElementSourceAnalysis } from "./ElementAnalysis";
2424
import { TemplateValidator, TemplateValidatorOptions } from "./validations";
2525

2626
/**
@@ -183,7 +183,7 @@ export class Analysis<K extends keyof TemplateTypes> {
183183
}
184184

185185
_searchForBlock(blockToFind: Block, block: Block, parentPath: string): string | null {
186-
if (block === blockToFind || block.isAncestorOf(blockToFind)) {
186+
if (block === blockToFind) {
187187
return parentPath;
188188
}
189189

@@ -391,8 +391,8 @@ export class Analysis<K extends keyof TemplateTypes> {
391391
/**
392392
* Creates a TemplateAnalysis from its serialized form.
393393
* @param serializedAnalysis The analysis to be recreated.
394-
* @param options The plugin options that are used to parse the blocks.
395-
* @param postcssImpl The instance of postcss that should be used to parse the block's css.
394+
* @param blockFactory for loading blocks referenced in the serialization.
395+
* @param parent The analyzer this analysis will belong to.
396396
*/
397397
static async deserializeSource (
398398
serializedAnalysis: SerializedSourceAnalysis<keyof TemplateTypes>,
@@ -420,30 +420,38 @@ export class Analysis<K extends keyof TemplateTypes> {
420420
analysis.blocks[o.name] = o.block;
421421
localScope.addBlockReference(o.name, o.block);
422422
});
423-
let objects = new Array<Style>();
423+
424+
// We lookup each style by its serialized reference.
425+
// The index into the array is used elsewhere in this
426+
// serialized form to reference these styles.
427+
let styles = new Array<Style>();
424428
serializedAnalysis.stylesFound.forEach(s => {
425429
let style = localScope.find(s);
426430
if (style) {
427-
objects.push(style);
431+
styles.push(style);
428432
} else {
429433
throw new Error(`Cannot resolve ${s} to a block style.`);
430434
}
431435
});
432436

437+
// These are convenience accessors into the styles array that perform
438+
// bounds and type checking assertions.
433439
let styleRef = (index: number) => {
434-
let s = objects[index];
440+
let s = styles[index];
435441
if (!s) {
436442
throw new Error("[internal error] Style index out of bounds!");
437443
}
438444
return s;
439445
};
446+
440447
let classRef = (index: number) => {
441448
let s = styleRef(index);
442449
if (!(s instanceof BlockClass)) {
443450
throw new Error("[internal error] Block class expected.");
444451
}
445452
return s;
446453
};
454+
447455
let attrValueRef = (index: number) => {
448456
let s = styleRef(index);
449457
if (!(s instanceof AttrValue)) {
@@ -457,57 +465,27 @@ export class Analysis<K extends keyof TemplateTypes> {
457465
let data = serializedAnalysis.elements[elID];
458466
let element = new ElementAnalysis<null, null, null>(data.sourceLocation || {start: POSITION_UNKNOWN}, parent.reservedClassNames(), data.tagName, elID);
459467
for (let analyzedStyle of data.analyzedStyles) {
460-
if (isStaticClass(analyzedStyle)) {
461-
element.addStaticClass(<BlockClass>styleRef(analyzedStyle.klass));
462-
} else if (isConditional(analyzedStyle) && (isTrueCondition(analyzedStyle) || isFalseCondition(analyzedStyle))) {
463-
let dynClasses: Partial<DynamicClasses<null>> = { condition: null };
464-
if (isTrueCondition(analyzedStyle)) {
465-
(<TrueCondition<BlockClass>>dynClasses).whenTrue = analyzedStyle.whenTrue.map(c => classRef(c));
466-
}
467-
if (isFalseCondition(analyzedStyle)) {
468-
(<FalseCondition<BlockClass>>dynClasses).whenFalse = analyzedStyle.whenFalse.map(c => classRef(c));
469-
}
470-
element.addDynamicClasses(<Required<DynamicClasses<null>>>dynClasses);
471-
} else if (hasDependency(analyzedStyle) && hasAttrValue(analyzedStyle)) {
472-
let value = attrValueRef(analyzedStyle.value[0]);
473-
let container = classRef(analyzedStyle.container);
474-
if (isConditional(analyzedStyle)) {
475-
element.addDynamicAttr(container, value, null);
476-
} else {
477-
element.addStaticAttr(container, value);
478-
}
479-
} else if (hasDependency(analyzedStyle) && isAttrGroup(analyzedStyle) && isSwitch(analyzedStyle)) {
480-
let container = classRef(analyzedStyle.container);
481-
let group: Attribute | undefined;
482-
// Because the attribute is resolved into styles for serialization
483-
// we have to find the attribute that is in the most specific sub-block
484-
// of this attribute group.
485-
for (let attrValueIdx of Object.values(analyzedStyle.group)) {
486-
let attrValue = attrValueRef(attrValueIdx);
487-
if (!group) {
488-
group = attrValue.attribute;
489-
} else if (group.block.isAncestorOf(attrValue.block)) {
490-
group = attrValue.attribute;
491-
}
492-
}
493-
element.addDynamicGroup(container, group!, null, analyzedStyle.disallowFalsy);
494-
} else {
495-
assertNever(analyzedStyle);
496-
}
468+
ElementAnalysis.deserializeAnalyzedStyle(element, analyzedStyle, styleRef, classRef, attrValueRef);
497469
}
498470
element.seal();
499471
analysis.elements.set(elID, element);
500472
});
501473

502-
// tslint:disable-next-line:prefer-unknown-to-any
503474
return analysis;
504475
}
505476

477+
// XXX `deserialize` doesn't actually deserialize the elements in the
478+
// XXX serialized form. Thankfully, this method is never used.
479+
// TODO: Get rid of this serialized form and use the "source serialization"
480+
// TODO: as the only serialization because it's a better format for serializing
481+
// TODO: this data.
506482
/**
507483
* Creates a TemplateAnalysis from its serialized form.
484+
*
485+
* **DO NOT USE THIS METHOD, ITS NOT FULLY IMPLEMENTED.**
508486
* @param serializedAnalysis The analysis to be recreated.
509-
* @param options The plugin options that are used to parse the blocks.
510-
* @param postcssImpl The instance of postcss that should be used to parse the block's css.
487+
* @param blockFactory for loading blocks referenced in the serialization.
488+
* @param parent The analyzer this analysis will belong to.
511489
*/
512490
static async deserialize (
513491
serializedAnalysis: SerializedAnalysis<keyof TemplateTypes>,
@@ -553,7 +531,6 @@ export class Analysis<K extends keyof TemplateTypes> {
553531
analysis.elements.set(elID, element);
554532
});
555533

556-
// tslint:disable-next-line:prefer-unknown-to-any
557534
return analysis;
558535
}
559536

packages/@css-blocks/core/src/Analyzer/ElementAnalysis.ts

+84-29
Original file line numberDiff line numberDiff line change
@@ -761,35 +761,7 @@ export class ElementAnalysis<BooleanExpression, StringExpression, TernaryExpress
761761
let analyzedStyles = new Array<SerializedAnalyzedStyle>();
762762
let addedStyles = this.sealed ? this.explicitlyAddedStyles : this.addedStyles;
763763
for (let s of addedStyles) {
764-
let serialized: Partial<SerializedAnalyzedStyle> = {};
765-
if (isStaticClass(s)) {
766-
(<SerializedStaticClass>serialized).klass = indexOf(s.klass);
767-
}
768-
if (isConditional(s)) {
769-
(<Conditional<true>>serialized).condition = true;
770-
}
771-
if (isTrueCondition(s)) {
772-
(<TrueCondition<number>>serialized).whenTrue = s.whenTrue.map(indexOf);
773-
}
774-
if (isFalseCondition(s)) {
775-
(<FalseCondition<number>>serialized).whenFalse = s.whenFalse.map(indexOf);
776-
}
777-
if (hasDependency(s)) {
778-
(<Dependency<number>>serialized).container = indexOf(s.container);
779-
}
780-
if (hasAttrValue(s)) {
781-
(<SerializedHasAttrValue>serialized).value = [...s.value].map(indexOf);
782-
}
783-
if (isAttrGroup(s)) {
784-
let group: ObjectDictionary<number> = {};
785-
for (let name of Object.keys(s.group)) {
786-
group[name] = indexOf(s.group[name]);
787-
}
788-
(<HasGroup<number>>serialized).group = group;
789-
(<Switch<true>>serialized).stringExpression = true;
790-
(<Switch<true>>serialized).disallowFalsy = s.disallowFalsy;
791-
}
792-
analyzedStyles.push(<Required<SerializedAnalyzedStyle>>serialized);
764+
analyzedStyles.push(this.serializeAnalyzedStyle(s, indexOf));
793765
}
794766
return {
795767
id,
@@ -799,6 +771,89 @@ export class ElementAnalysis<BooleanExpression, StringExpression, TernaryExpress
799771
};
800772
}
801773

774+
serializeAnalyzedStyle(
775+
s: AnalyzedStyle<BooleanExpression, StringExpression, TernaryExpression>,
776+
indexOf: (s: Style) => number
777+
): SerializedAnalyzedStyle {
778+
let serialized: Partial<SerializedAnalyzedStyle> = {};
779+
780+
if (isStaticClass(s)) {
781+
(<SerializedStaticClass>serialized).klass = indexOf(s.klass);
782+
}
783+
if (isConditional(s)) {
784+
(<Conditional<true>>serialized).condition = true;
785+
}
786+
if (isTrueCondition(s)) {
787+
(<TrueCondition<number>>serialized).whenTrue = s.whenTrue.map(indexOf);
788+
}
789+
if (isFalseCondition(s)) {
790+
(<FalseCondition<number>>serialized).whenFalse = s.whenFalse.map(indexOf);
791+
}
792+
if (hasDependency(s)) {
793+
(<Dependency<number>>serialized).container = indexOf(s.container);
794+
}
795+
if (hasAttrValue(s)) {
796+
(<SerializedHasAttrValue>serialized).value = [...s.value].map(indexOf);
797+
}
798+
if (isAttrGroup(s)) {
799+
let group: ObjectDictionary<number> = {};
800+
for (let name of Object.keys(s.group)) {
801+
group[name] = indexOf(s.group[name]);
802+
}
803+
(<HasGroup<number>>serialized).group = group;
804+
(<Switch<true>>serialized).stringExpression = true;
805+
(<Switch<true>>serialized).disallowFalsy = s.disallowFalsy;
806+
}
807+
808+
return <Required<SerializedAnalyzedStyle>>serialized;
809+
}
810+
811+
static deserializeAnalyzedStyle(
812+
element: ElementAnalysis<null, null, null>,
813+
analyzedStyle: SerializedAnalyzedStyle,
814+
styleRef: (n: number) => Style,
815+
classRef: (n: number) => BlockClass,
816+
attrValueRef: (n: number) => AttrValue
817+
): void {
818+
if (isStaticClass(analyzedStyle)) {
819+
element.addStaticClass(<BlockClass>styleRef(analyzedStyle.klass));
820+
} else if (isConditional(analyzedStyle) && (isTrueCondition(analyzedStyle) || isFalseCondition(analyzedStyle))) {
821+
let dynClasses: Partial<DynamicClasses<null>> = { condition: null };
822+
if (isTrueCondition(analyzedStyle)) {
823+
(<TrueCondition<BlockClass>>dynClasses).whenTrue = analyzedStyle.whenTrue.map(c => classRef(c));
824+
}
825+
if (isFalseCondition(analyzedStyle)) {
826+
(<FalseCondition<BlockClass>>dynClasses).whenFalse = analyzedStyle.whenFalse.map(c => classRef(c));
827+
}
828+
element.addDynamicClasses(<Required<DynamicClasses<null>>>dynClasses);
829+
} else if (hasDependency(analyzedStyle) && hasAttrValue(analyzedStyle)) {
830+
let value = attrValueRef(analyzedStyle.value[0]);
831+
let container = classRef(analyzedStyle.container);
832+
if (isConditional(analyzedStyle)) {
833+
element.addDynamicAttr(container, value, null);
834+
} else {
835+
element.addStaticAttr(container, value);
836+
}
837+
} else if (hasDependency(analyzedStyle) && isAttrGroup(analyzedStyle) && isSwitch(analyzedStyle)) {
838+
let container = classRef(analyzedStyle.container);
839+
let group: Attribute | undefined;
840+
// Because the attribute is resolved into styles for serialization
841+
// we have to find the attribute that is in the most specific sub-block
842+
// of this attribute group.
843+
for (let attrValueIdx of Object.values(analyzedStyle.group)) {
844+
let attrValue = attrValueRef(attrValueIdx);
845+
if (!group) {
846+
group = attrValue.attribute;
847+
} else if (group.block.isAncestorOf(attrValue.block)) {
848+
group = attrValue.attribute;
849+
}
850+
}
851+
element.addDynamicGroup(container, group!, null, analyzedStyle.disallowFalsy);
852+
} else {
853+
assertNever(analyzedStyle);
854+
}
855+
}
856+
802857
/**
803858
* Get a simple object with no circular references that is possible to
804859
* emit and restore as JSON.

0 commit comments

Comments
 (0)