Skip to content

Commit 38eb4e9

Browse files
committed
feat(rewriter): More functional rewriting and with static class support.
1 parent 5500e36 commit 38eb4e9

File tree

4 files changed

+84
-79
lines changed

4 files changed

+84
-79
lines changed

packages/jsx-analyzer/src/styleFunctions/objstrFunction.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export function analyzeObjstr(blocks: ObjectDictionary<Block>, element: JSXEleme
9999
}
100100
} // else ignore
101101
} else {
102-
let orExpression = logicalExpression('||', prop.value, result.dynamicStateExpression);
102+
let orExpression = logicalExpression('&&', prop.value, result.dynamicStateExpression);
103103
element.addDynamicGroup(result.blockClass || result.block, result.stateGroup, orExpression, false);
104104
}
105105

packages/jsx-analyzer/src/transformer/babel.ts

+28-6
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ import {
1717
JSXOpeningElement,
1818
Statement,
1919
isJSXExpressionContainer,
20+
JSXAttribute,
2021
} from 'babel-types';
2122

2223
import isBlockFilename from '../utils/isBlockFilename';
23-
import { classnamesHelper as generateClassName} from './classNameGenerator';
24+
import { classnamesHelper as generateClassName, HELPER_FN_NAME } from './classNameGenerator';
2425
let { parse } = require('path');
2526

2627
export interface CssBlocksVisitor {
28+
dynamicStylesFound: boolean;
2729
importsToRemove: Array<NodePath<ImportDeclaration>>;
2830
statementsToRemove: Array<NodePath<Statement>>;
2931
elementAnalyzer: JSXElementAnalyzer;
@@ -46,6 +48,7 @@ export default function mkTransform(tranformOpts: { rewriter: Rewriter }): () =>
4648

4749
return {
4850
pre(file: any) {
51+
this.dynamicStylesFound = false;
4952
this.importsToRemove = new Array<NodePath<ImportDeclaration>>();
5053
this.statementsToRemove = new Array<NodePath<Statement>>();
5154
this.filename = file.opts.filename;
@@ -63,8 +66,13 @@ export default function mkTransform(tranformOpts: { rewriter: Rewriter }): () =>
6366
}
6467
},
6568
post(state: any) {
66-
let firstImport = this.importsToRemove.shift()!;
67-
firstImport.replaceWith(importDeclaration([importSpecifier(identifier('cla$$'), identifier('classNameHelper'))], stringLiteral('@css-blocks/jsx')));
69+
if (this.dynamicStylesFound) {
70+
let firstImport = this.importsToRemove.shift()!;
71+
let importDecl = importDeclaration(
72+
[importSpecifier(identifier(HELPER_FN_NAME.localName), identifier(HELPER_FN_NAME.moduleName))],
73+
stringLiteral('@css-blocks/jsx'));
74+
firstImport.replaceWith(importDecl);
75+
}
6876
for (let nodePath of this.importsToRemove) {
6977
nodePath.remove();
7078
}
@@ -88,7 +96,19 @@ export default function mkTransform(tranformOpts: { rewriter: Rewriter }): () =>
8896
let elementAnalysis = this.elementAnalyzer.analyze(this.filename, path);
8997
if (elementAnalysis) {
9098
let classMapping = this.mapping.simpleRewriteMapping(elementAnalysis);
91-
let newClassAttr = jSXAttribute(jSXIdentifier('class'), jSXExpressionContainer(generateClassName(classMapping, elementAnalysis, true)));
99+
let attributeValue: JSXAttribute['value'] | undefined = undefined;
100+
let newClassAttr: JSXAttribute | undefined = undefined;
101+
if (classMapping.dynamicClasses.length > 0) {
102+
this.dynamicStylesFound = true;
103+
attributeValue = jSXExpressionContainer(
104+
generateClassName(classMapping, elementAnalysis,
105+
HELPER_FN_NAME.localName, true));
106+
} else if (classMapping.staticClasses.length > 0) {
107+
attributeValue = stringLiteral(classMapping.staticClasses.join(' '));
108+
}
109+
if (attributeValue) {
110+
newClassAttr = jSXAttribute(jSXIdentifier('class'), attributeValue);
111+
}
92112

93113
let classAttrs = this.elementAnalyzer.classAttributePaths(path);
94114
for (let attrPath of classAttrs) {
@@ -102,8 +122,10 @@ export default function mkTransform(tranformOpts: { rewriter: Rewriter }): () =>
102122
}
103123
}
104124
}
105-
let firstClass = classAttrs.shift()!;
106-
firstClass.replaceWith(newClassAttr);
125+
if (newClassAttr) {
126+
let firstClass = classAttrs.shift()!;
127+
firstClass.replaceWith(newClassAttr);
128+
}
107129
for (let attrPath of classAttrs) {
108130
attrPath.remove();
109131
}

packages/jsx-analyzer/src/transformer/classNameGenerator.ts

+25-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import {
32
IndexedClassRewrite,
43
DynamicClasses,
@@ -30,7 +29,8 @@ import {
3029
isNotExpression,
3130
} from '@opticss/template-api';
3231
import {
33-
assertNever
32+
assertNever,
33+
unwrap,
3434
} from '@opticss/util';
3535
import {
3636
arrayExpression,
@@ -43,6 +43,11 @@ import {
4343
Expression,
4444
} from 'babel-types';
4545

46+
export const HELPER_FN_NAME = {
47+
moduleName: 'c',
48+
localName: 'c$$',
49+
};
50+
4651
const enum SourceExpression {
4752
ternary,
4853
dependency,
@@ -71,27 +76,26 @@ const enum BooleanExpr {
7176
and = -3,
7277
}
7378

74-
export function classnamesHelper(rewrite: IndexedClassRewrite<BlockObject>, element: JSXElementAnalysis, includeStaticClasses = false): CallExpression {
75-
return callExpression(identifier('cla$$'), [arrayExpression(constructArgs(rewrite, element, includeStaticClasses))]);
79+
export function classnamesHelper(rewrite: IndexedClassRewrite<BlockObject>, element: JSXElementAnalysis, helpFnName = HELPER_FN_NAME.localName, includeStaticClasses = false): CallExpression {
80+
let args: Expression[] = [ arrayExpression(constructArgs(rewrite, element)) ];
81+
let staticClassnames = rewrite.staticClasses;
82+
if (includeStaticClasses && staticClassnames.length > 0) {
83+
args.unshift(stringLiteral(staticClassnames.join(' ')));
84+
}
85+
return callExpression(identifier(helpFnName), args);
7686
}
7787

78-
function constructArgs(rewrite: IndexedClassRewrite<BlockObject>, element: JSXElementAnalysis, includeStaticClasses: boolean): Array<Expression> {
88+
function constructArgs(rewrite: IndexedClassRewrite<BlockObject>, element: JSXElementAnalysis): Array<Expression> {
7989
let expr = new Array<Expression>();
80-
expr.push(builders.number(element.dynamicClasses.length + element.dynamicStates.length + (includeStaticClasses ? element.static.size : 0)));
90+
expr.push(builders.number(element.dynamicClasses.length + element.dynamicStates.length));
8191
expr.push(builders.number(rewrite.dynamicClasses.length));
82-
expr.push(...constructSourceArgs(rewrite, element, includeStaticClasses));
83-
expr.push(...constructOutputArgs(rewrite, includeStaticClasses));
92+
expr.push(...constructSourceArgs(rewrite, element));
93+
expr.push(...constructOutputArgs(rewrite));
8494
return expr;
8595
}
8696

87-
function constructSourceArgs(rewrite: IndexedClassRewrite<BlockObject>, element: JSXElementAnalysis, includeStaticClasses: boolean): Array<Expression> {
97+
function constructSourceArgs(rewrite: IndexedClassRewrite<BlockObject>, element: JSXElementAnalysis): Array<Expression> {
8898
let expr = new Array<Expression>();
89-
if (includeStaticClasses) {
90-
for (let style of element.static) {
91-
expr.push(builders.number(SourceExpression.static));
92-
expr.push(builders.number(rewrite.indexOf(style)));
93-
}
94-
}
9599
for (let classes of element.dynamicClasses) {
96100
// type of expression
97101
expr.push(builders.number(SourceExpression.ternary));
@@ -143,15 +147,15 @@ function constructTernary(classes: DynamicClasses<TernaryAST>, rewrite: IndexedC
143147
if (isTrueCondition(classes)) {
144148
expr.push(builders.number(classes.whenTrue.length));
145149
// TODO: inheritance
146-
expr.push(...classes.whenTrue.map(style => builders.number(rewrite.indexOf(style))));
150+
expr.push(...classes.whenTrue.map(style => builders.number(unwrap(rewrite.indexOf(style)))));
147151
} else {
148152
expr.push(builders.number(0));
149153
}
150154
// The false styles
151155
if (isFalseCondition(classes)) {
152156
expr.push(builders.number(classes.whenFalse.length));
153157
// TODO: inheritance
154-
expr.push(...classes.whenFalse.map(style => builders.number(rewrite.indexOf(style))));
158+
expr.push(...classes.whenFalse.map(style => builders.number(unwrap(rewrite.indexOf(style)))));
155159
} else {
156160
expr.push(builders.number(0));
157161
}
@@ -166,7 +170,7 @@ function constructTernary(classes: DynamicClasses<TernaryAST>, rewrite: IndexedC
166170
function constructDependency(stateExpr: Dependency, rewrite: IndexedClassRewrite<BlockObject>): Array<Expression> {
167171
let expr = new Array<Expression>();
168172
expr.push(builders.number(1));
169-
expr.push(builders.number(rewrite.indexOf(stateExpr.container)));
173+
expr.push(builders.number(unwrap(rewrite.indexOf(stateExpr.container))));
170174
return expr;
171175
}
172176

@@ -180,7 +184,7 @@ function constructStateReferences(stateExpr: HasState, rewrite: IndexedClassRewr
180184
let expr = new Array<Expression>();
181185
// TODO: inheritance
182186
expr.push(builders.number(1));
183-
expr.push(builders.number(rewrite.indexOf(stateExpr.state)));
187+
expr.push(builders.number(unwrap(rewrite.indexOf(stateExpr.state))));
184188
return expr;
185189
}
186190
/*
@@ -213,12 +217,12 @@ function constructSwitch(stateExpr: Switch<StringAST> & HasGroup, rewrite: Index
213217
let obj = stateExpr.group[value];
214218
expr.push(builders.string(value));
215219
expr.push(builders.number(1));
216-
expr.push(builders.number(rewrite.indexOf(obj)));
220+
expr.push(builders.number(unwrap(rewrite.indexOf(obj))));
217221
}
218222
return expr;
219223
}
220224

221-
function constructOutputArgs(rewrite: IndexedClassRewrite<any>, includeStaticClasses: boolean): Array<Expression> {
225+
function constructOutputArgs(rewrite: IndexedClassRewrite<any>): Array<Expression> {
222226
let expr = new Array<Expression>();
223227
for (let out of rewrite.dynamicClasses) {
224228
expr.push(builders.string(out));

0 commit comments

Comments
 (0)