Skip to content

Commit ba40892

Browse files
authored
feat: parse additional color spaces (#15)
1 parent 4a2c805 commit ba40892

16 files changed

+405
-104
lines changed

.config/cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"xcworkspace"
1111
],
1212
"words": [
13+
"colorjs",
1314
"prebuild"
1415
]
15-
}
16+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"!**/__mocks__"
112112
],
113113
"dependencies": {
114+
"colorjs.io": "0.6.0-alpha.1",
114115
"comment-json": "^4.2.5",
115116
"debug": "^4.4.1"
116117
},

src/compiler/__tests__/compiler.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import { compile } from "../compiler";
22

3+
test("reads global CSS variables", () => {
4+
const compiled = compile(`
5+
@layer theme {
6+
:root, :host {
7+
--color-red-500: oklch(63.7% 0.237 25.331);
8+
}
9+
}`);
10+
11+
expect(compiled).toStrictEqual({
12+
vr: [["color-red-500", ["#fb2c36"]]],
13+
});
14+
});
15+
316
test.skip("test compiler", () => {
417
const compiled = compile(`
518
.test {

src/compiler/add.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { isStyleDescriptorArray } from "../runtime/utils/style-value";
33
import type {
44
CompilerCollection,
5+
CompilerOptions,
56
EasingFunction,
67
StyleDeclaration,
78
StyleDescriptor,
@@ -17,6 +18,7 @@ export function buildAddFn(
1718
rule: StyleRule,
1819
collection: CompilerCollection,
1920
mapping: StyleRuleMapping,
21+
options: CompilerOptions,
2022
) {
2123
let staticDeclarations: Record<string, StyleDescriptor> | undefined;
2224

@@ -100,6 +102,7 @@ export function buildAddFn(
100102

101103
if (property.startsWith("--")) {
102104
if (
105+
options.stripUnusedVariables &&
103106
!property.startsWith("--__rn-css") &&
104107
!collection.varUsageCount.has(property)
105108
) {

src/compiler/compiler.ts

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import {
44
transform as lightningcss,
55
type ContainerRule,
66
type MediaQuery as CSSMediaQuery,
7+
type CustomAtRules,
78
type Declaration,
89
type DeclarationBlock,
910
type MediaRule,
1011
type ParsedComponent,
1112
type Rule,
1213
type SelectorList,
1314
type TokenOrValue,
15+
type Visitor,
1416
} from "lightningcss";
1517

1618
import { Specificity } from "../runtime/utils/specificity";
@@ -61,8 +63,9 @@ type ReactNativeAtRule = {
6163
*/
6264
export function compile(
6365
code: Buffer | string,
64-
{ logger = debug("react-native-css"), ...options }: CompilerOptions = {},
66+
options: CompilerOptions = {},
6567
): ReactNativeCssStyleSheet {
68+
const { logger = debug("react-native-css") } = options;
6669
const features = Object.assign({}, options.features);
6770

6871
logger(`Features ${JSON.stringify(features)}`);
@@ -100,35 +103,44 @@ export function compile(
100103
}
101104
};
102105

106+
const customAtRules: CustomAtRules = {
107+
"react-native": {
108+
body: "declaration-list",
109+
},
110+
};
111+
112+
const visitor: Visitor<typeof customAtRules> = {
113+
Rule(rule) {
114+
if (isReactNativeAtRule(rule)) {
115+
extractReactNativeOptions(rule, collection);
116+
}
117+
},
118+
StyleSheetExit(sheet) {
119+
logger(`Found ${sheet.rules.length} rules to process`);
120+
121+
for (const rule of sheet.rules) {
122+
// Extract the style declarations and animations from the current rule
123+
extractRule(rule, collection, {}, options);
124+
// We have processed this rule, so now delete it from the AST
125+
}
126+
127+
logger(`Exiting lightningcss`);
128+
},
129+
};
130+
131+
if (options.stripUnusedVariables) {
132+
visitor.Declaration = (decl) => {
133+
if (decl.property !== "unparsed" && decl.property !== "custom") return;
134+
decl.value.value.forEach((varObj) => onVarUsage(varObj));
135+
return decl;
136+
};
137+
}
138+
103139
// Use the lightningcss library to traverse the CSS AST and extract style declarations and animations
104140
lightningcss({
105141
filename: "style.css", // This is ignored, but required
106142
code: typeof code === "string" ? new TextEncoder().encode(code) : code,
107-
visitor: {
108-
Declaration(decl) {
109-
// Track variable usage, we remove any unused variables
110-
if (decl.property !== "unparsed" && decl.property !== "custom") return;
111-
decl.value.value.forEach((varObj) => onVarUsage(varObj));
112-
return decl;
113-
},
114-
StyleSheetExit(sheet) {
115-
logger(`Found ${sheet.rules.length} rules to process`);
116-
117-
for (const rule of sheet.rules) {
118-
// Extract the style declarations and animations from the current rule
119-
extractRule(rule, collection);
120-
// We have processed this rule, so now delete it from the AST
121-
}
122-
123-
logger(`Exiting lightningcss`);
124-
},
125-
},
126-
customAtRules: {
127-
"react-native": {
128-
prelude: "<custom-ident>+",
129-
body: "declaration-list",
130-
},
131-
},
143+
visitor,
132144
});
133145

134146
logger(`Found ${collection.rules.size} valid rules`);
@@ -184,6 +196,7 @@ function extractRule(
184196
rule: ExtractableRules,
185197
collection: CompilerCollection,
186198
partialStyle: Partial<StyleRule> = {},
199+
options: CompilerOptions,
187200
) {
188201
// Check the rule's type to determine which extraction function to call
189202
switch (rule.type) {
@@ -209,6 +222,7 @@ function extractRule(
209222
rule.value.declarations,
210223
collection,
211224
parseReactNativeStyleAtRule(rule.value.rules),
225+
options,
212226
)) {
213227
setStyleForSelectorList(
214228
{ ...partialStyle, ...style },
@@ -220,11 +234,33 @@ function extractRule(
220234
}
221235
break;
222236
}
223-
case "custom": {
224-
if (isReactNativeAtRule(rule)) {
225-
extractReactNativeOptions(rule, collection);
237+
case "layer-block":
238+
for (const layerRule of rule.value.rules) {
239+
extractRule(layerRule, collection, partialStyle, options);
226240
}
227-
}
241+
break;
242+
case "custom":
243+
case "font-face":
244+
case "font-palette-values":
245+
case "font-feature-values":
246+
case "namespace":
247+
case "layer-statement":
248+
case "property":
249+
case "view-transition":
250+
case "ignored":
251+
case "unknown":
252+
case "import":
253+
case "page":
254+
case "supports":
255+
case "counter-style":
256+
case "moz-document":
257+
case "nesting":
258+
case "nested-declarations":
259+
case "viewport":
260+
case "custom-media":
261+
case "scope":
262+
case "starting-style":
263+
break;
228264
}
229265
}
230266

@@ -377,7 +413,7 @@ function extractMedia(mediaRule: MediaRule, collection: CompilerCollection) {
377413

378414
// Iterate over all rules in the mediaRule and extract their styles using the updated CompilerCollection
379415
for (const rule of mediaRule.rules) {
380-
extractRule(rule, collection, { m });
416+
extractRule(rule, collection, { m }, options);
381417
}
382418
}
383419

@@ -405,7 +441,7 @@ function extractedContainer(
405441
query.n = containerRule.name;
406442
}
407443

408-
extractRule(rule, collection, { cq: [query] });
444+
extractRule(rule, collection, { cq: [query] }, options);
409445
}
410446
}
411447

@@ -564,6 +600,7 @@ function getExtractedStyles(
564600
declarationBlock: DeclarationBlock<Declaration>,
565601
collection: CompilerCollection,
566602
mapping: StyleRuleMapping = {},
603+
options: CompilerOptions,
567604
): StyleRule[] {
568605
const extractedStyles = [];
569606

@@ -577,6 +614,7 @@ function getExtractedStyles(
577614
collection,
578615
specificity,
579616
mapping,
617+
options,
580618
),
581619
);
582620
}
@@ -592,6 +630,7 @@ function getExtractedStyles(
592630
collection,
593631
specificity,
594632
mapping,
633+
options,
595634
),
596635
);
597636
}
@@ -604,6 +643,7 @@ function declarationsToStyle(
604643
collection: CompilerCollection,
605644
specificity: SpecificityArray,
606645
mapping: StyleRuleMapping,
646+
options: CompilerOptions,
607647
): StyleRule {
608648
const extractedStyle: StyleRule = {
609649
s: [...specificity],
@@ -617,7 +657,7 @@ function declarationsToStyle(
617657
// TODO
618658
};
619659

620-
const addFn = buildAddFn(extractedStyle, collection, mapping);
660+
const addFn = buildAddFn(extractedStyle, collection, mapping, options);
621661

622662
for (const declaration of declarations) {
623663
parseDeclaration(declaration, parseDeclarationOptions, addFn, addWarning);

src/compiler/compiler.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export interface CompilerOptions {
1515
stylesheetOrder?: number;
1616
features?: FeatureFlagRecord;
1717
logger?: (message: string) => void;
18+
/** Strip unused variables declarations. Defaults: false */
19+
stripUnusedVariables?: boolean;
1820
/** @internal */
1921
ignorePropertyWarningRegex?: (string | RegExp)[];
2022
}

0 commit comments

Comments
 (0)