Skip to content

Commit 488e23e

Browse files
committed
fix: Dynamic scope attributes were not being analyzed or rewritten.
Closes #371. Closes #373.
1 parent 8b2d595 commit 488e23e

File tree

6 files changed

+56
-25
lines changed

6 files changed

+56
-25
lines changed

packages/@css-blocks/glimmer/src/ClassnamesHelperGenerator.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
TernaryExpression as TernaryAST,
4242
} from "./ElementAnalyzer";
4343
import { CLASSNAMES_HELPER_NAME, CONCAT_HELPER_NAME } from "./helpers";
44+
import { isMustacheStatement } from "./utils";
4445

4546
const enum SourceExpression {
4647
ternary,
@@ -140,7 +141,11 @@ function constructSourceArgs(builders: Builders, rewrite: IndexedClassRewrite<an
140141
function constructTernary(builders: Builders, classes: DynamicClasses<TernaryAST>, rewrite: IndexedClassRewrite<Style>): AST.Expression[] {
141142
let expr = new Array<AST.Expression>();
142143
// The boolean expression
143-
expr.push(classes.condition!);
144+
if (isMustacheStatement(classes.condition!)) {
145+
expr.push(moustacheToExpression(builders, classes.condition));
146+
} else {
147+
expr.push(classes.condition!);
148+
}
144149
// The true styles
145150
if (isTrueCondition(classes)) {
146151
let trueClasses = resolveInheritance(classes.whenTrue, rewrite);

packages/@css-blocks/glimmer/src/ElementAnalyzer.ts

+19-24
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,20 @@ import * as debugGenerator from "debug";
1414
import { GlimmerAnalysis } from "./Analyzer";
1515
import { getEmberBuiltInStates, isEmberBuiltIn } from "./EmberBuiltins";
1616
import { ResolvedFile } from "./Template";
17-
import { cssBlockError } from "./utils";
17+
import {
18+
cssBlockError,
19+
isBooleanLiteral,
20+
isConcatStatement,
21+
isElementNode,
22+
isMustacheStatement,
23+
isStringLiteral,
24+
isSubExpression,
25+
isTextNode,
26+
} from "./utils";
1827

1928
// Expressions may be null when ElementAnalyzer is used in the second pass analysis
2029
// to re-acquire analysis data for rewrites without storing AST nodes.
21-
export type TernaryExpression = AST.Expression | null;
30+
export type TernaryExpression = AST.Expression | AST.MustacheStatement | null;
2231
export type StringExpression = AST.MustacheStatement | AST.ConcatStatement | null;
2332
export type BooleanExpression = AST.Expression | AST.MustacheStatement;
2433
export type TemplateElement = ElementAnalysis<BooleanExpression, StringExpression, TernaryExpression>;
@@ -309,6 +318,14 @@ export class ElementAnalyzer {
309318
if (value.value) {
310319
element.addStaticClass(block.rootClass);
311320
}
321+
} else if (isMustacheStatement(value) || isSubExpression(value)) {
322+
// We don't have a way to represent a simple boolean conditional for classes like we do for states.
323+
// The rewrite might be slightly simpler if we add that.
324+
element.addDynamicClasses({
325+
condition: value,
326+
whenTrue: [block.rootClass],
327+
whenFalse: [],
328+
});
312329
}
313330
}
314331

@@ -393,28 +410,6 @@ export class ElementAnalyzer {
393410
}
394411
}
395412

396-
function isStringLiteral(value: AST.Node | undefined): value is AST.StringLiteral {
397-
return value !== undefined && value.type === "StringLiteral";
398-
}
399-
function isConcatStatement(value: AST.Node | undefined): value is AST.ConcatStatement {
400-
return !!value && value.type === "ConcatStatement";
401-
}
402-
function isTextNode(value: AST.Node | undefined): value is AST.TextNode {
403-
return !!value && value.type === "TextNode";
404-
}
405-
function isBooleanLiteral(value: AST.Node | undefined): value is AST.BooleanLiteral {
406-
return !!value && value.type === "BooleanLiteral";
407-
}
408-
function isMustacheStatement(value: AST.Node | undefined): value is AST.MustacheStatement {
409-
return !!value && value.type === "MustacheStatement";
410-
}
411-
function isSubExpression(value: AST.Node | undefined): value is AST.SubExpression {
412-
return !!value && value.type === "SubExpression";
413-
}
414-
function isElementNode(value: AST.Node | undefined): value is AST.ElementNode {
415-
return !!value && value.type === "ElementNode";
416-
}
417-
418413
function isStyleIfHelper(node: AST.MustacheStatement | AST.SubExpression): "style-if" | "style-unless" | undefined {
419414
if (node.path.type !== "PathExpression") { return undefined; }
420415
let parts: string[] = (node.path).parts;

packages/@css-blocks/glimmer/src/utils.ts

+22
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,25 @@ export function cssBlockError(message: string, node: AST.Node, template: Templat
3535
end: node.loc.end,
3636
});
3737
}
38+
39+
export function isStringLiteral(value: AST.Node | undefined): value is AST.StringLiteral {
40+
return value !== undefined && value.type === "StringLiteral";
41+
}
42+
export function isConcatStatement(value: AST.Node | undefined): value is AST.ConcatStatement {
43+
return !!value && value.type === "ConcatStatement";
44+
}
45+
export function isTextNode(value: AST.Node | undefined): value is AST.TextNode {
46+
return !!value && value.type === "TextNode";
47+
}
48+
export function isBooleanLiteral(value: AST.Node | undefined): value is AST.BooleanLiteral {
49+
return !!value && value.type === "BooleanLiteral";
50+
}
51+
export function isMustacheStatement(value: AST.Node | undefined): value is AST.MustacheStatement {
52+
return !!value && value.type === "MustacheStatement";
53+
}
54+
export function isSubExpression(value: AST.Node | undefined): value is AST.SubExpression {
55+
return !!value && value.type === "SubExpression";
56+
}
57+
export function isElementNode(value: AST.Node | undefined): value is AST.ElementNode {
58+
return !!value && value.type === "ElementNode";
59+
}

packages/@css-blocks/glimmer/test/fixtures/styled-app/src/ui/components/with-dynamic-classes/template.hbs

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
<div block:class={{style-if isWorld 'world' 'planet'}}>World</div>
44
<div block:class={{style-unless isWorld 'world' 'planet'}}>World</div>
55
<div block:class={{style-unless isWorld 'world'}}>World</div>
6+
<h2 h:scope={{isWorld}}>Dynamic Scope</h2>
67
</div>

packages/@css-blocks/glimmer/test/stylesheet-analysis-test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,13 @@ describe("Stylesheet analysis", function () {
775775
dynamicAttributes: [],
776776
sourceLocation: { start: { line: 5, column: 2, "filename": "template:/styled-app/components/with-dynamic-classes" }, end: { line: 5, column: 2, "filename": "template:/styled-app/components/with-dynamic-classes" } },
777777
},
778+
g: {
779+
tagName: "h2",
780+
staticStyles: [],
781+
dynamicClasses: [{ condition: true, whenTrue: [7] }],
782+
dynamicAttributes: [],
783+
sourceLocation: { start: { line: 6, column: 2, "filename": "template:/styled-app/components/with-dynamic-classes" }, end: { line: 6, column: 2, "filename": "template:/styled-app/components/with-dynamic-classes" } },
784+
},
778785
});
779786
}).catch((error) => {
780787
console.error(error);

packages/@css-blocks/glimmer/test/template-rewrite-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ describe("Template Rewriting", function() {
9393
<div class={{-css-blocks-classnames 1 2 0 isWorld 1 1 1 0 "d" 0 "b" 1}}>World</div>
9494
<div class={{-css-blocks-classnames 1 2 0 isWorld 1 0 1 1 "d" 0 "b" 1}}>World</div>
9595
<div class={{-css-blocks-classnames 1 1 0 isWorld 0 1 0 "b" 0}}>World</div>
96+
<h2 class={{-css-blocks-classnames 1 1 0 isWorld 1 0 0 "e" 0}}>Dynamic Scope</h2>
9697
</div>
9798
`));
9899
});

0 commit comments

Comments
 (0)