Skip to content

Commit

Permalink
feat: The JSX and Webpack plugins use updated Analyzer APIs.
Browse files Browse the repository at this point in the history
 - JSX analyzer extends from css-blocks Analyzer and uses new APIs for getting Analyses.
 - Analysis objects propagate Style trackings up to parent Analyzer if present.
 - Analysis and TemplateInfo objects now take the template type generic string.
  • Loading branch information
amiller-gh committed Apr 8, 2018
1 parent ff8795a commit 921ae25
Show file tree
Hide file tree
Showing 38 changed files with 613 additions and 803 deletions.
100 changes: 59 additions & 41 deletions packages/css-blocks/src/Analyzer/Analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
import {
SerializedTemplateInfo,
TemplateAnalysis as OptimizationTemplateAnalysis,
TemplateInfo,
TemplateInfoFactory,
TemplateIntegrationOptions,
TemplateTypes,
Expand All @@ -23,6 +22,7 @@ import { BlockFactory } from "../BlockParser";
import { Block, Style } from "../BlockTree";
import { ResolvedConfiguration } from "../configuration";

import { Analyzer } from "./Analyzer";
import { ElementAnalysis, SerializedElementAnalysis } from "./ElementAnalysis";
import { TemplateValidator, TemplateValidatorOptions } from "./validations";

Expand All @@ -47,10 +47,11 @@ export interface SerializedAnalysis {
* 2. Call [[addExclusiveStyle addExclusiveStyle(alwaysPresent, ...style)]] for all the styles used that are mutually exclusive on the current html element.
* 3. Call [[endElement endElement()]] when done adding styles for the current element.
*/
export class Analysis {
export class Analysis<K extends keyof TemplateTypes> {

template: TemplateInfo<keyof TemplateTypes>;
idGenerator: IdentGenerator;
parent?: Analyzer<K>;
template: TemplateTypes[K];

/**
* A map from a local name for the block to the [[Block]].
Expand All @@ -59,13 +60,53 @@ export class Analysis {
*/
blocks: ObjectDictionary<Block>;


/**
* Return the number of blocks discovered in this Template.
* A per-element correlation of styles used. The current correlation is added
* to this list when [[endElement]] is called.
*/
// tslint:disable-next-line:prefer-whatever-to-any
elements: Map<string, ElementAnalysis<any, any, any>>;

/**
* The current element, created when calling [[startElement]].
* The current element is unset after calling [[endElement]].
*/
blockCount(): number {
return Object.keys(this.blocks).length;
// tslint:disable-next-line:prefer-whatever-to-any
currentElement: ElementAnalysis<any, any, any> | undefined;

/**
* Template validator instance to verify blocks applied to an element.
*/
validator: TemplateValidator;

/**
* @param template The template being analyzed.
*/
constructor(template: TemplateTypes[K], options?: TemplateValidatorOptions, parent?: Analyzer<K>,) {
this.idGenerator = new IdentGenerator();
this.parent = parent;
this.template = template;
this.blocks = {};
this.elements = new Map();
this.validator = new TemplateValidator(options);
}

/**
* Return the number of blocks discovered in this Template.
*/
blockCount(): number { return Object.keys(this.blocks).length; }

/**
* Convenience setter for adding a block to the template scope.
*/
addBlock(name: string, block: Block) { this.blocks[name] = block; }

/**
* Convenience getter for fetching a block from the template scope.
*/
getBlock(name: string): Block { return this.blocks[name]; }

/**
* Return the number of styles discovered in this Analysis' Template.
* This is slow.
Expand All @@ -83,26 +124,10 @@ export class Analysis {
return c;
}

/**
* A per-element correlation of styles used. The current correlation is added
* to this list when [[endElement]] is called.
*/
// tslint:disable-next-line:prefer-whatever-to-any
elements: Map<string, ElementAnalysis<any, any, any>>;

/**
* The current element, created when calling [[startElement]].
* The current element is unset after calling [[endElement]].
*/
// tslint:disable-next-line:prefer-whatever-to-any
currentElement: ElementAnalysis<any, any, any> | undefined;

/**
* Return the number of elements discovered in this Analysis.
*/
elementCount(): number {
return this.elements.size;
}
elementCount(): number { return this.elements.size; }

/**
* Get the nth element discovered in this Analysis.
Expand Down Expand Up @@ -139,22 +164,6 @@ export class Analysis {
return this.elements.get(id);
}

/**
* Template validator instance to verify blocks applied to an element.
*/
validator: TemplateValidator;

/**
* @param template The template being analyzed.
*/
constructor(template: TemplateInfo<keyof TemplateTypes>, options?: TemplateValidatorOptions) {
this.idGenerator = new IdentGenerator();
this.template = template;
this.blocks = {};
this.elements = new Map();
this.validator = new TemplateValidator(options);
}

/**
* @param block The block for which the local name should be returned.
* @return The local name of the given block.
Expand Down Expand Up @@ -218,6 +227,14 @@ export class Analysis {
}
this.validator.validate(this, element);
this.elements.set(element.id, element);
if (this.parent) {
for (let s of [...element.classesFound(false), ...element.attributesFound(false)]) {
this.parent.saveStaticStyle(s, this);
}
for (let s of [...element.classesFound(true), ...element.attributesFound(true)]) {
this.parent.saveDynamicStyle(s, this);
}
}
}

/**
Expand Down Expand Up @@ -322,10 +339,11 @@ export class Analysis {
static async deserialize (
serializedAnalysis: SerializedAnalysis,
blockFactory: BlockFactory,
): Promise<Analysis> {
parent: Analyzer<keyof TemplateTypes>
): Promise<Analysis<keyof TemplateTypes>> {
let blockNames = Object.keys(serializedAnalysis.blocks);
let info = TemplateInfoFactory.deserialize<keyof TemplateTypes>(serializedAnalysis.template);
let analysis = new Analysis(info);
let analysis = new Analysis(info, {}, parent);
let blockPromises = new Array<Promise<{name: string; block: Block}>>();
blockNames.forEach(n => {
let blockIdentifier = serializedAnalysis.blocks[n];
Expand Down
64 changes: 27 additions & 37 deletions packages/css-blocks/src/Analyzer/Analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
TemplateIntegrationOptions,
TemplateTypes,
} from "@opticss/template-api";
import { whatever } from "@opticss/util";
import { MultiMap, whatever } from "@opticss/util";
import * as debugGenerator from "debug";

import { BlockFactory } from "../BlockParser";
Expand All @@ -17,7 +17,6 @@ import {

import { Analysis, SerializedAnalysis } from "./Analysis";
import { TemplateValidatorOptions } from "./validations";
import { Configuration } from "webpack";

const debug = debugGenerator("css-blocks:analyzer");

Expand Down Expand Up @@ -50,9 +49,9 @@ export abstract class Analyzer<K extends keyof TemplateTypes> {
public readonly optimizationOptions: TemplateIntegrationOptions;
public readonly cssBlocksOptions: ResolvedConfiguration;

protected analysisMap: Map<string, Analysis>;
protected stylesFound: Map<Style, Analysis[]>;
protected dynamicStyles: Map<Style, Analysis[]>;
protected analysisMap: Map<string, Analysis<K>>;
protected staticStyles: MultiMap<Style, Analysis<K>>;
protected dynamicStyles: MultiMap<Style, Analysis<K>>;

constructor (
options?: Options,
Expand All @@ -63,43 +62,49 @@ export abstract class Analyzer<K extends keyof TemplateTypes> {
this.optimizationOptions = analysisOpts && analysisOpts.features || DEFAULT_OPTS;
this.blockFactory = new BlockFactory(this.cssBlocksOptions);
this.analysisMap = new Map();
this.stylesFound = new Map();
this.dynamicStyles = new Map();
this.staticStyles = new MultiMap();
this.dynamicStyles = new MultiMap();
}

abstract analyze(...entryPoints: string[]): Promise<Analyzer<keyof TemplateTypes>>;

// TODO: We don't really want to burn the world here.
// We need more targeted Analysis / BlockFactory invalidation.
public reset(): void {
debug(`Resetting Analyzer.`);
this.analysisMap = new Map();
this.stylesFound = new Map();
this.dynamicStyles = new Map();
this.staticStyles = new MultiMap();
this.dynamicStyles = new MultiMap();
this.blockFactory.reset();
}

newAnalysis(info: TemplateInfo<K>): Analysis {
let analysis = new Analysis(info, this.validatorOptions);
newAnalysis(info: TemplateInfo<K>): Analysis<K> {
let analysis = new Analysis<K>(info, this.validatorOptions, this);
this.analysisMap.set(info.identifier, analysis);
return analysis;
}

addAnalysis(analysis: Analysis) {
debug(`MetaAnalysis: Adding analysis for ${analysis.template.identifier}`);
this.analysisMap.set(analysis.template.identifier, analysis);
for (let style of analysis.stylesFound()) {
this.addAnalysisToStyleMap(this.stylesFound, style, analysis);
}
for (let style of analysis.stylesFound(true)) {
this.addAnalysisToStyleMap(this.dynamicStyles, style, analysis);
}
saveStaticStyle(style: Style, analysis: Analysis<K>) {
this.staticStyles.set(style, analysis);
}

saveDynamicStyle(style: Style, analysis: Analysis<K>) {
this.dynamicStyles.set(style, analysis);
}

getAnalysis(idx: number): Analysis<K> { return this.analyses()[idx]; }

analysisCount(): number { return this.analysisMap.size; }

eachAnalysis(cb: (v: Analysis) => whatever) { this.analysisMap.forEach(cb); }
eachAnalysis(cb: (v: Analysis<K>) => whatever) { this.analysisMap.forEach(cb); }

analyses(): Analysis<K>[] {
let analyses: Analysis<K>[] = [];
this.eachAnalysis(a => analyses.push(a));
return analyses;
}

styleCount(): number { return this.stylesFound.size; }
styleCount(): number { return this.staticStyles.size; }

dynamicCount(): number { return this.dynamicStyles.size; }

Expand All @@ -121,12 +126,6 @@ export abstract class Analyzer<K extends keyof TemplateTypes> {
return allBlocks;
}

analyses(): Analysis[] {
let analyses: Analysis[] = [];
this.eachAnalysis(a => analyses.push(a));
return analyses;
}

serialize(): SerializedAnalyzer {
let analyses: SerializedAnalysis[] = [];
this.eachAnalysis(a => {
Expand All @@ -143,13 +142,4 @@ export abstract class Analyzer<K extends keyof TemplateTypes> {
return analyses;
}

private addAnalysisToStyleMap(map: Map<Style, Analysis[]>, style: Style, analysis: Analysis) {
let analyses = map.get(style);
if (analyses) {
analyses.push(analysis);
} else {
analyses = [analysis];
}
map.set(style, analyses);
}
}
2 changes: 1 addition & 1 deletion packages/css-blocks/src/Analyzer/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { Analysis, SerializedAnalysis } from "./Analysis";
export { Analyzer, SerializedAnalyzer } from "./Analyzer";
export { ElementAnalysis, SerializedElementAnalysis } from "./ElementAnalysis";
export * from "./ElementAnalysis";
export {
TemplateValidator,
TemplateValidators,
Expand Down
3 changes: 2 additions & 1 deletion packages/css-blocks/src/Analyzer/validations/Validator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { TemplateTypes } from "@opticss/template-api";
import { whatever } from "@opticss/util";

import { Analysis } from "../Analysis";
import { ElementAnalysis } from "../ElementAnalysis";

export type ErrorCallback = (str: string, loc?: null, details?: string) => void;
export type Validator = (analysis: ElementAnalysis<whatever, whatever, whatever>, templateAnalysis: Analysis, err: ErrorCallback) => void;
export type Validator = (analysis: ElementAnalysis<whatever, whatever, whatever>, templateAnalysis: Analysis<keyof TemplateTypes>, err: ErrorCallback) => void;
3 changes: 2 additions & 1 deletion packages/css-blocks/src/Analyzer/validations/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TemplateTypes } from "@opticss/template-api";
import { ObjectDictionary } from "@opticss/util";

import * as errors from "../../errors";
Expand Down Expand Up @@ -94,7 +95,7 @@ export class TemplateValidator {
* @param locInfo Location info for the elements being validated.
*/
// tslint:disable-next-line:prefer-whatever-to-any
validate(templateAnalysis: Analysis, element: ElementAnalysis<any, any, any>) {
validate(templateAnalysis: Analysis<keyof TemplateTypes>, element: ElementAnalysis<any, any, any>) {

function err (message: string, locInfo?: errors.ErrorLocation | undefined | null, details?: string) {
throw new errors.TemplateAnalysisError(
Expand Down
1 change: 1 addition & 0 deletions packages/css-blocks/src/BlockTree/RulesetContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export type Resolution<S extends Styles = Styles> = {
*/
function expandProp(prop: string, value: string): propParser.Declarations {
let expanded: propParser.Declarations = {};
value = value.replace(/var\([^\)]+\)/gi, "inherit");
if (propParser.isValidDeclaration(prop, value)) {
expanded = propParser.expandShorthandProperty(prop, value, true, false);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/css-blocks/src/TemplateRewriter/StyleMapping.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StyleMapping as OptimizedMapping } from "@opticss/template-api";
import { StyleMapping as OptimizedMapping, TemplateTypes } from "@opticss/template-api";

import { Analysis } from "../Analyzer";
import { ElementAnalysis } from "../Analyzer";
Expand All @@ -7,9 +7,9 @@ import { ResolvedConfiguration } from "../configuration";

import { IndexedClassRewrite } from "./ClassRewrite";
import { IndexedClassMapping, RewriteMapping } from "./RewriteMapping";
export class StyleMapping {
export class StyleMapping<T extends keyof TemplateTypes> {
/** The analyses that were used to create this mapping. */
analyses: Array<Analysis> | undefined;
analyses: Array<Analysis<T>> | undefined;
/** The blocks that were used to create this mapping. */
blocks: Set<Block>;
private configuration: ResolvedConfiguration;
Expand All @@ -19,7 +19,7 @@ export class StyleMapping {
optimizedMap: OptimizedMapping,
blocks: Iterable<Block>,
configuration: ResolvedConfiguration,
analyses?: Array<Analysis>,
analyses?: Array<Analysis<T>>,
) {
this.configuration = configuration;
this.optimizedMap = optimizedMap;
Expand Down
6 changes: 3 additions & 3 deletions packages/css-blocks/test/opticss-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class TemplateAnalysisTests {
}
}
private useBlockStyles(
analysis: Analysis, block: Block, blockName: string,
analysis: Analysis<"Opticss.Template">, block: Block, blockName: string,
useAttrsCallback?: (container: BlockClass, element: ElementAnalysis<whatever, whatever, whatever>) => void,
) {
analysis.blocks[blockName] = block;
Expand Down Expand Up @@ -64,7 +64,7 @@ export class TemplateAnalysisTests {
`;
class TestAnalyzer extends Analyzer<"Opticss.Template"> {
analyze(): Promise<TestAnalyzer> {
let analysis = new Analysis(info);
let analysis = this.newAnalysis(info);
let root = postcss.parse(css, { from: filename });

return this.blockFactory.parse(root, filename, "optimized").then((block: Block) => {
Expand Down Expand Up @@ -101,7 +101,7 @@ export class TemplateAnalysisTests {
.f { font-size: 26px; }
`);
let analyses = analyzer.analyses();
let blockMapping = new StyleMapping(optimized.styleMapping, [block], config, analyses);
let blockMapping = new StyleMapping<"Opticss.Template">(optimized.styleMapping, [block], config, analyses);
let it = analyses[0].elements.values();
let element1 = it.next().value;
let rewrite1 = blockMapping.rewriteMapping(element1);
Expand Down
Loading

0 comments on commit 921ae25

Please sign in to comment.