@@ -1684,6 +1684,62 @@ function handleAstroElement(ctx: CaseHandlerContext) {
16841684 }
16851685}
16861686
1687+ function handleCssCssAtrule ( ctx : CaseHandlerContext ) {
1688+ ctx . nonCommentNodes . push ( ctx . currentASTNode ) ;
1689+
1690+ if (
1691+ isTypeof (
1692+ ctx . node ,
1693+ z . object ( {
1694+ name : z . literal ( 'apply' ) ,
1695+ nodes : z . undefined ( ) ,
1696+ raws : z . object ( {
1697+ afterName : z . string ( ) ,
1698+ params : z . string ( ) ,
1699+ } ) ,
1700+ source : z . object ( {
1701+ start : z . object ( {
1702+ line : z . number ( ) ,
1703+ } ) ,
1704+ } ) ,
1705+ } ) ,
1706+ )
1707+ ) {
1708+ // Note: In fact, the `@apply` rule is not a `keywordStartingNode`, but it is considered a kind of safe list to maintain the `classNameNode`s obtained from the code inside the rule.
1709+ ctx . keywordStartingNodes . push ( ctx . currentASTNode ) ;
1710+
1711+ const offset = '@apply' . length ;
1712+
1713+ const classNameNodeRangeStart = ctx . currentASTNode . start + offset ;
1714+ const classNameNodeRangeEnd = ctx . currentASTNode . end ;
1715+
1716+ const nodeStartLineIndex = ctx . node . source . start . line - 1 ;
1717+
1718+ // Note: In fact, since CSS code does not have a delimiter, it might be better to create a new node type. However, if we consider the characters on the left and right of the class name as a delimiter, the formatting method is the same as AttributeNode, so I have processed it as an AttributeNode type for now.
1719+ ctx . classNameNodes . push ( {
1720+ type : 'attribute' ,
1721+ isTheFirstLineOnTheSameLineAsTheOpeningTag : true ,
1722+ elementName : '' ,
1723+ range : [ classNameNodeRangeStart , classNameNodeRangeEnd ] ,
1724+ startLineIndex : nodeStartLineIndex ,
1725+ } ) ;
1726+ }
1727+ }
1728+
1729+ function handleCssCssComment ( ctx : CaseHandlerContext ) {
1730+ if (
1731+ isTypeof (
1732+ ctx . node ,
1733+ z . object ( {
1734+ text : z . string ( ) ,
1735+ } ) ,
1736+ ) &&
1737+ ctx . node . text . trim ( ) === 'prettier-ignore'
1738+ ) {
1739+ ctx . prettierIgnoreNodes . push ( ctx . currentASTNode ) ;
1740+ }
1741+ }
1742+
16871743function handleAstroFrontmatter ( ctx : CaseHandlerContext ) {
16881744 ctx . nonCommentNodes . push ( ctx . currentASTNode ) ;
16891745
@@ -1747,6 +1803,11 @@ const typescriptCaseHandlers: CaseHandlers = {
17471803 Line : handleTypeScriptBlock ,
17481804} ;
17491805
1806+ const cssCaseHandlers : CaseHandlers = {
1807+ 'css-atrule' : handleCssCssAtrule ,
1808+ 'css-comment' : handleCssCssComment ,
1809+ } ;
1810+
17501811const parserCaseHandlers : ParserCaseHandlers = {
17511812 babel : {
17521813 ...babelCaseHandlers ,
@@ -1800,6 +1861,15 @@ const parserCaseHandlers: ParserCaseHandlers = {
18001861 element : handleAngularElement ,
18011862 comment : handleHtmlComment ,
18021863 } ,
1864+ css : {
1865+ ...cssCaseHandlers ,
1866+ } ,
1867+ scss : {
1868+ ...cssCaseHandlers ,
1869+ } ,
1870+ less : {
1871+ ...cssCaseHandlers ,
1872+ } ,
18031873 astro : {
18041874 frontmatter : handleAstroFrontmatter ,
18051875 attribute : handleAstroAttribute ,
@@ -2190,6 +2260,121 @@ export function findTargetClassNameNodesBasedOnHtml(
21902260 ) ;
21912261}
21922262
2263+ export function findTargetClassNameNodesBasedOnCss (
2264+ formattedText : string ,
2265+ ast : AST ,
2266+ options : ResolvedOptions ,
2267+ ) : ClassNameNode [ ] {
2268+ const supportedAttributes : string [ ] = [ 'class' , 'className' , ...options . customAttributes ] ;
2269+ const supportedFunctions : string [ ] = [ 'classNames' , ...options . customFunctions ] ;
2270+ /**
2271+ * Most nodes
2272+ */
2273+ const nonCommentNodes : ASTNode [ ] = [ ] ;
2274+ /**
2275+ * Nodes with a valid 'prettier-ignore' syntax
2276+ */
2277+ const prettierIgnoreNodes : ASTNode [ ] = [ ] ;
2278+ /**
2279+ * Nodes starting with supported attribute names or supported function names
2280+ */
2281+ const keywordStartingNodes : ASTNode [ ] = [ ] ;
2282+ /**
2283+ * Class names enclosed in delimiters
2284+ */
2285+ const classNameNodes : ClassNameNode [ ] = [ ] ;
2286+
2287+ function recursion ( node : unknown , parentNode ?: { type : string } ) : void {
2288+ if ( ! isTypeof ( node , z . object ( { type : z . string ( ) } ) ) ) {
2289+ return ;
2290+ }
2291+
2292+ let recursiveProps : string [ ] = [ ] ;
2293+
2294+ switch ( node . type ) {
2295+ case 'css-atrule' :
2296+ case 'css-root' :
2297+ case 'css-rule' : {
2298+ recursiveProps = [ 'nodes' ] ;
2299+ break ;
2300+ }
2301+ default : {
2302+ break ;
2303+ }
2304+ }
2305+
2306+ Object . entries ( node ) . forEach ( ( [ key , value ] ) => {
2307+ if ( ! recursiveProps . includes ( key ) ) {
2308+ return ;
2309+ }
2310+
2311+ if ( Array . isArray ( value ) ) {
2312+ value . forEach ( ( childNode : unknown ) => {
2313+ recursion ( childNode , node ) ;
2314+ } ) ;
2315+ return ;
2316+ }
2317+
2318+ recursion ( value , node ) ;
2319+ } ) ;
2320+
2321+ if (
2322+ ! isTypeof (
2323+ node ,
2324+ z . object ( {
2325+ source : z . object ( {
2326+ startOffset : z . number ( ) ,
2327+ endOffset : z . number ( ) ,
2328+ } ) ,
2329+ } ) ,
2330+ )
2331+ ) {
2332+ return ;
2333+ }
2334+
2335+ const nodeType = node . type ;
2336+ const currentNodeRangeStart = node . source . startOffset ;
2337+ const currentNodeRangeEnd = node . source . endOffset ;
2338+
2339+ const currentASTNode : ASTNode = {
2340+ type : nodeType ,
2341+ start : currentNodeRangeStart ,
2342+ end : currentNodeRangeEnd ,
2343+ } ;
2344+
2345+ const handler = parserCaseHandlers [ String ( options . parser ) ] ?. [ nodeType ] ;
2346+
2347+ if ( handler ) {
2348+ const context : CaseHandlerContext = {
2349+ formattedText,
2350+ options,
2351+ supportedAttributes,
2352+ supportedFunctions,
2353+ nonCommentNodes,
2354+ prettierIgnoreNodes,
2355+ keywordStartingNodes,
2356+ classNameNodes,
2357+ node,
2358+ parentNode,
2359+ currentASTNode,
2360+ } ;
2361+
2362+ handler ( context ) ;
2363+ } else {
2364+ nonCommentNodes . push ( currentASTNode ) ;
2365+ }
2366+ }
2367+
2368+ recursion ( ast ) ;
2369+
2370+ return filterAndSortClassNameNodes (
2371+ nonCommentNodes ,
2372+ prettierIgnoreNodes ,
2373+ keywordStartingNodes ,
2374+ classNameNodes ,
2375+ ) ;
2376+ }
2377+
21932378export function findTargetClassNameNodesBasedOnAstro (
21942379 formattedText : string ,
21952380 ast : AST ,
0 commit comments