11import * as fs from 'node:fs' ;
2+ import * as path from 'node:path' ;
23import type { TokenData , ExtractTokensOptions } from './types.js' ;
34
45// Map variable name prefixes to categories
56const CATEGORY_RULES : Array < { test : ( name : string ) => boolean ; category : string } > = [
6- { test : ( n ) => / ^ ( b o x - ) ? s h a d o w / . test ( n ) , category : 'shadows' } ,
7+ { test : ( n ) => / ^ s h a d o w / . test ( n ) , category : 'shadows' } ,
78 { test : ( n ) => / ^ s i z e - ( x s | s m | m d | l g | x l | x x l ) $ / . test ( n ) , category : 'breakpoints' } ,
89 { test : ( n ) => / ^ ( f o n t | l i n e - h e i g h t | h e a d i n g | h \d - ) / . test ( n ) , category : 'typography' } ,
910 { test : ( n ) => / ^ ( s p a c e r | h e i g h t - ) / . test ( n ) , category : 'spacing' } ,
1011 {
1112 test : ( n ) =>
12- / c o l o r $ / . test ( n ) ||
13+ / ^ c o l o r - / . test ( n ) ||
1314 / ^ ( w h i t e | b l a c k | g r a y | r e d | o r a n g e | y e l l o w | g r e e n | t e a l | c y a n | b l u e | i n d i g o | p u r p l e | m a g e n t a ) - / . test ( n ) ||
14- / ^ ( i n f o | s u c c e s s | w a r n i n g | d a n g e r | p r i m a r y ) - / . test ( n ) ||
1515 / ^ ( b o d y - b g | b o d y - c o l o r ) / . test ( n ) ,
1616 category : 'colors' ,
1717 } ,
@@ -25,7 +25,6 @@ function categorize(name: string): string | null {
2525}
2626
2727export function extractTokens ( options : ExtractTokensOptions ) : TokenData {
28- const content = fs . readFileSync ( options . variablesPath , 'utf-8' ) ;
2928 const result : TokenData = {
3029 colors : { } ,
3130 typography : { } ,
@@ -34,11 +33,13 @@ export function extractTokens(options: ExtractTokensOptions): TokenData {
3433 shadows : { } ,
3534 } ;
3635
37- // Match SCSS variable declarations: $name: value !default;
36+ const variablesContent = fs . readFileSync ( options . variablesPath , 'utf-8' ) ;
37+
38+ // Parse SCSS variable declarations: $name: value !default;
3839 const varRegex = / ^ \$ ( [ a - z 0 - 9 - ] + ) : \s * ( .+ ?) \s * ! d e f a u l t \s * ; / gm;
3940 let match : RegExpExecArray | null ;
4041
41- while ( ( match = varRegex . exec ( content ) ) !== null ) {
42+ while ( ( match = varRegex . exec ( variablesContent ) ) !== null ) {
4243 const name = match [ 1 ] ;
4344 const value = match [ 2 ] ;
4445 const category = categorize ( name ) ;
@@ -51,5 +52,30 @@ export function extractTokens(options: ExtractTokensOptions): TokenData {
5152 }
5253 }
5354
55+ // Also parse theme map files in the themes/ directory next to _variables.scss
56+ const themesDir = path . join ( path . dirname ( options . variablesPath ) , 'themes' ) ;
57+ const lightThemePath = path . join ( themesDir , '_light.scss' ) ;
58+
59+ if ( fs . existsSync ( lightThemePath ) ) {
60+ const themeContent = fs . readFileSync ( lightThemePath , 'utf-8' ) ;
61+
62+ // Match map entries: key: value,
63+ // Handles multi-value entries like shadows by matching up to the trailing comma
64+ const mapEntryRegex = / ^ \s + ( [ a - z 0 - 9 - ] + ) : \s * ( .+ ?) , ? \s * $ / gm;
65+
66+ while ( ( match = mapEntryRegex . exec ( themeContent ) ) !== null ) {
67+ const name = match [ 1 ] ;
68+ const value = match [ 2 ] . replace ( / , \s * $ / , '' ) ;
69+ const category = categorize ( name ) ;
70+
71+ if ( category && ! result [ category ] [ name ] ) {
72+ result [ category ] [ name ] = {
73+ variable : `--ty-${ name } ` ,
74+ value,
75+ } ;
76+ }
77+ }
78+ }
79+
5480 return result ;
5581}
0 commit comments