@@ -2,9 +2,7 @@ import * as fs from 'fs';
22import * as path from 'path' ;
33import glob from 'glob' ;
44import * as sass from 'sass' ;
5- import Parser , { SyntaxNode } from 'tree-sitter' ;
6- // @ts -ignore
7- import CSS from 'tree-sitter-css' ;
5+ import postcss , { Root , Rule , Declaration , Comment , Container } from 'postcss' ;
86
97type SDK = 'Angular' | 'React' ;
108
@@ -15,11 +13,9 @@ export type ComponentInfo = {
1513} ;
1614
1715export const extractComponents = ( fromGlob : string ) => {
18- const parser = new Parser ( ) ;
19- parser . setLanguage ( CSS ) ;
20-
2116 const componentInfos : ComponentInfo [ ] = [ ] ;
2217 const files = glob . sync ( fromGlob ) ;
18+
2319 files . forEach ( ( file ) => {
2420 const [ , componentName ] = file . split ( / .* \/ ( .* ) - ( t h e m e | l a y o u t | v a r i a b l e s ) \. s c s s $ / ) ;
2521 // sass fails to resolve the `../utils` file for some reason, therefore
@@ -33,25 +29,27 @@ export const extractComponents = (fromGlob: string) => {
3329 loadPaths : [ path . resolve ( './src/v2/styles' ) ] ,
3430 } ) ;
3531
32+ const css = compilation . css ;
33+ const root : Root = postcss . parse ( css ) ;
34+
3635 let sdkRestriction : SDK | undefined = undefined ;
3736 let variableType : 'layout' | 'theme' | undefined = undefined ;
38- const ast = parser . parse ( compilation . css ) ;
39- ast . rootNode . descendantsOfType ( 'rule_set' ) . forEach ( ( ruleSet ) => {
40- const ruleSetComment = extractComment ( ruleSet ) ;
37+
38+ root . walkRules ( ( rule : Rule ) => {
39+ const ruleSetComment = extractLeadingComment ( rule ) ;
4140 if ( ruleSetComment ) {
4241 const matches = ruleSetComment . match ( / A n g u l a r | R e a c t / g) ;
4342 if ( matches ) {
4443 sdkRestriction = matches [ 0 ] as SDK ;
4544 }
4645 }
47- for ( let i = 0 ; i < ruleSet . descendantsOfType ( 'declaration' ) . length ; i ++ ) {
48- const node = ruleSet . descendantsOfType ( 'declaration' ) [ i ] ;
49- const identifier = node . text ;
50- if ( identifier . startsWith ( '--str-chat' ) ) {
46+
47+ rule . walkDecls ( ( decl : Declaration ) => {
48+ // custom property name is in decl.prop
49+ if ( decl . prop . startsWith ( '--str-chat' ) ) {
5150 variableType = file . includes ( 'theme' ) ? 'theme' : 'layout' ;
52- break ;
5351 }
54- }
52+ } ) ;
5553 } ) ;
5654
5755 if ( variableType ) {
@@ -73,14 +71,19 @@ export const extractComponents = (fromGlob: string) => {
7371 return componentInfos ;
7472} ;
7573
76- const extractComment = ( node : SyntaxNode ) => {
77- if ( node . previousSibling ?. type === 'comment' ) {
78- const match = node . previousSibling . text . match ( / \* \s * ( .+ ?) \* \/ / ) ! ;
79- if ( match ) {
80- const [ , comment ] = match ;
81- return comment . trim ( ) ;
82- }
83- } else {
84- return undefined ;
74+ const extractLeadingComment = ( rule : Rule ) : string | undefined => {
75+ const parent = rule . parent as Container | undefined ;
76+ if ( ! parent || ! ( 'nodes' in parent ) || ! parent . nodes ) return ;
77+
78+ const idx = parent . nodes . indexOf ( rule ) ;
79+ if ( idx <= 0 ) return ;
80+
81+ const prev = parent . nodes [ idx - 1 ] ;
82+ if ( prev . type === 'comment' ) {
83+ // PostCSS comment text is everything inside /* ... */
84+ const comment = ( prev as Comment ) . text ;
85+ return comment . trim ( ) ;
8586 }
87+
88+ return undefined ;
8689} ;
0 commit comments