1
- import type { IconifyJSON } from '@iconify/types'
2
- import type { UnoGenerator } from '@unocss/core'
3
- import { createGenerator } from '@unocss/core'
4
- import UnocssIcons from '@unocss/preset-icons'
1
+ /* eslint-disable regexp/strict */
2
+ /* eslint-disable unicorn/better-regex */
3
+ import { type IconifyJSON } from '@iconify/types'
4
+ import { createGenerator , type UnoGenerator } from '@unocss/core'
5
+ import presetIcons from '@unocss/preset-icons'
5
6
import { presetTypography } from '@unocss/preset-typography'
7
+ import presetAttributify from '@unocss/preset-attributify'
6
8
import windicssPreset from '@unocss/preset-wind'
7
9
import { parse as CSSParser , walk as CSSWalker } from 'css-tree'
8
10
import fg from 'fast-glob'
9
- import { readFileSync } from 'fs'
10
11
import MagicString from 'magic-string'
12
+ import { readFileSync } from 'node:fs'
11
13
import { parse , preprocess } from 'svelte/compiler'
12
- import type {
13
- PreprocessorGroup ,
14
- Processed ,
15
- } from 'svelte/types/compiler/preprocess'
14
+ import { type PreprocessorGroup , type Processed } from 'svelte/types/compiler/preprocess'
16
15
import { loadConfig } from 'unconfig'
17
16
import { type FullConfig } from 'windicss/types/interfaces'
18
17
19
18
export interface BaseConfig {
20
19
silent ?: boolean
21
20
mode ?: 'development' | 'production'
21
+ attributify ?: {
22
+ strict ?: boolean
23
+ prefix ?: string
24
+ prefixedOnly ?: boolean
25
+ nonValuedAttribute ?: boolean
26
+ ignoreAttributes : string [ ]
27
+ }
22
28
icons ?: {
23
29
prefix ?: string
24
30
collections ?: Record < string , IconifyJSON >
@@ -33,7 +39,6 @@ const defaults: DefaultConfig = {}
33
39
let generatorConfiguration : BaseConfig
34
40
let windiConfiguration : any
35
41
let windiGenerator : UnoGenerator
36
- let iconGenerator : UnoGenerator
37
42
38
43
const styles : {
39
44
[ key : string ] : Set < string >
@@ -43,11 +48,11 @@ const styles: {
43
48
44
49
function splitVariantGroups ( content : string ) {
45
50
return content . replace (
46
- / ( [ ! \w ] [ \w : _ / - ] * ?) : \( ( [ \w \s / - ] * ? ) \) / gm ,
51
+ / ( [ \w ! ] [ \w / : - ] * ?) : \( ( [ \s \w / - ] * ) \) / g ,
47
52
( _ , groupOne : string , groupTwo : string ) =>
48
53
groupTwo
49
54
. split ( / \s / g)
50
- . map ( cssClass => `${ groupOne } :${ cssClass } ` )
55
+ . map ( ( cssClass ) => `${ groupOne } :${ cssClass } ` )
51
56
. join ( ' ' )
52
57
)
53
58
}
@@ -66,25 +71,25 @@ function addStyleTag(content: string) {
66
71
67
72
function cleanUtilities ( utilities : string ) {
68
73
return utilities
69
- . replace ( / w i n d i [ ` ] .+ ?[ ` ] / gi, ' ' ) // windi`XYZ`
70
- . replace ( / (?< ! [ - ] ) [ $ ] (? = [ { ] ) / gi , ' ' ) // if leading char is not -, and next char is {, then remove $
71
- . replace ( / (?< = ( [ { ] [ \w \s ] + [ ^ { ] * ?) ) [ ' " ] / gi , ' ' ) // remove quotes in curly braces
72
- . replace ( / (?< = ( [ { ] [ \w \s ] + [ ^ { ] * ?) \s ) [: ] / gi , ' ' ) // remove : in curly braces
73
- . replace ( / ( [ { ] [ \w \s ] + [ ^ { ] * ?[ ? ] ) / gi , ' ' ) // remove ? and condition in curly braces
74
- . replace ( / [ { } ] / gi , ' ' ) // remove curly braces
75
- . replace ( / \n / gi , ' ' ) // remove newline
76
- . replace ( / { 2 , } / gi , ' ' ) // remove multiple spaces
77
- . replace ( / [ " ' ` ] / gi , '' ) // remove quotes
74
+ . replace ( / w i n d i ` .+ ?` / gi, ' ' ) // windi`XYZ`
75
+ . replace ( / (?< ! - ) \$ (? = \{ ) / g , ' ' ) // if leading char is not -, and next char is {, then remove $
76
+ . replace ( / (?< = ( \{ [ \s \w ] [ ^ { ] * ?) ) [ " ' ] / g , ' ' ) // remove quotes in curly braces
77
+ . replace ( / (?< = ( \{ [ \s \w ] [ ^ { ] * ?) \s ) : / g , ' ' ) // remove : in curly braces
78
+ . replace ( / ( \{ [ \s \w ] [ ^ { ] * ?\? ) / g , ' ' ) // remove ? and condition in curly braces
79
+ . replace ( / [ { } ] / g , ' ' ) // remove curly braces
80
+ . replace ( / \n / g , ' ' ) // remove newline
81
+ . replace ( / { 2 , } / g , ' ' ) // remove multiple spaces
82
+ . replace ( / [ " ' ` ] / g , '' ) // remove quotes
78
83
. trim ( )
79
84
. split ( ' ' )
80
85
}
81
86
82
87
function scanFile ( content : string , filename : string ) {
83
88
//TODO@alexanderniebuhr add attributifies
84
89
const MATCHES = [
85
- ...content . matchAll ( / c l a s s = ( [ ' " ` ] ) (?< utilities > [ ^ \1] + ?) \1/ gi) ,
86
- ...content . matchAll ( / c l a s s = (?< utilities > [ { ] [ ^ } ] + ?) } / gi) ,
87
90
...content . matchAll ( / \s ( c l a s s ) : (?< utility > [ ^ = ] + ) ( = ) / gi) ,
91
+ ...content . matchAll ( / c l a s s = ( [ " ' ` ] ) (?< utilities > [ ^ \1] + ?) \1/ gi) ,
92
+ ...content . matchAll ( / c l a s s = (?< utilities > \{ [ ^ } ] + ) \} / gi) ,
88
93
]
89
94
styles [ filename ] = new Set ( )
90
95
@@ -95,21 +100,19 @@ function scanFile(content: string, filename: string) {
95
100
styles [ filename ] . add ( match . groups . utility )
96
101
}
97
102
if ( match . groups ?. utilities ) {
98
- cleanUtilities ( match . groups ?. utilities ) . forEach ( utility => {
103
+ for ( const utility of cleanUtilities ( match . groups ?. utilities ) ) {
99
104
if ( utility . startsWith ( 'global:' ) ) {
100
105
styles [ '__GLOBAL__' ] . add ( utility . replace ( 'global:' , '' ) )
101
106
} else {
102
107
styles [ filename ] . add ( utility )
103
108
}
104
- } )
109
+ }
105
110
}
106
111
}
107
-
108
- return styles
109
112
}
110
113
111
114
function extractStyles ( ) : PreprocessorGroup {
112
- if ( initialFileName . length == 0 ) {
115
+ if ( initialFileName . length === 0 ) {
113
116
const filePaths = fg . sync ( [ 'src/**/*.svelte' ] , { } )
114
117
for ( const filepath of filePaths ) {
115
118
const content = splitVariantGroups ( readFileSync ( filepath ) . toString ( ) )
@@ -120,7 +123,7 @@ function extractStyles(): PreprocessorGroup {
120
123
return {
121
124
async markup ( { content, filename } ) : Promise < Processed > {
122
125
if ( ! filename ) return { code : content }
123
- if ( initialFileName . length == 0 ) initialFileName = filename
126
+ if ( initialFileName . length === 0 ) initialFileName = filename
124
127
content = addStyleTag ( content )
125
128
content = content . replace ( / g l o b a l : / gi, '' )
126
129
return {
@@ -150,7 +153,8 @@ function generateCSS(): PreprocessorGroup {
150
153
node . prelude . children
151
154
) {
152
155
const applyUtillities : Set < string > = new Set ( )
153
- node . prelude . children . forEach ( identifier => {
156
+ // eslint-disable-next-line unicorn/no-array-for-each
157
+ node . prelude . children . forEach ( ( identifier ) => {
154
158
if ( identifier . type === 'Identifier' ) {
155
159
applyUtillities . add ( identifier . name )
156
160
}
@@ -164,19 +168,13 @@ function generateCSS(): PreprocessorGroup {
164
168
parseValue : false ,
165
169
} )
166
170
167
- CSSWalker ( applyStyleSheet , ( node , item , list ) => {
168
- if ( node . type == 'Declaration' ) {
169
- if ( node . value . type == 'Raw' ) {
170
- generatedApplyCss += `${ node . property } :${ node . value . value } ;`
171
- }
171
+ CSSWalker ( applyStyleSheet , ( node ) => {
172
+ if ( node . type == 'Declaration' && node . value . type == 'Raw' ) {
173
+ generatedApplyCss += `${ node . property } :${ node . value . value } ;`
172
174
}
173
175
} )
174
176
175
- tagStylesCSS . overwrite (
176
- node . loc . start . offset ,
177
- node . loc . end . offset ,
178
- generatedApplyCss
179
- )
177
+ tagStylesCSS . overwrite ( node . loc . start . offset , node . loc . end . offset , generatedApplyCss )
180
178
content = tagStylesCSS . toString ( )
181
179
}
182
180
} )
@@ -415,12 +413,8 @@ function generateCSS(): PreprocessorGroup {
415
413
parseValue : false ,
416
414
} )
417
415
418
- CSSWalker ( globalStyleSheet , ( node , item , list ) => {
419
- if (
420
- node . type === 'Rule' &&
421
- node . prelude . type === 'SelectorList' &&
422
- node . prelude . loc
423
- ) {
416
+ CSSWalker ( globalStyleSheet , ( node ) => {
417
+ if ( node . type === 'Rule' && node . prelude . type === 'SelectorList' && node . prelude . loc ) {
424
418
globalStylesCSS
425
419
. appendLeft ( node . prelude . loc ?. start . offset , ':global(' )
426
420
. appendRight ( node . prelude . loc ?. end . offset , ')' )
@@ -433,10 +427,8 @@ function generateCSS(): PreprocessorGroup {
433
427
node . prelude . type === 'AtrulePrelude' &&
434
428
node . prelude . loc
435
429
) {
436
- globalStylesCSS . appendLeft (
437
- node . prelude . loc ?. start . offset ,
438
- '-global-'
439
- )
430
+ globalStylesCSS . appendLeft ( node . prelude . loc ?. start . offset , '-global-' )
431
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
440
432
return ( CSSWalker as any ) . skip
441
433
}
442
434
} )
@@ -445,11 +437,7 @@ function generateCSS(): PreprocessorGroup {
445
437
const windiStyles = await windiGenerator . generate ( styles [ filename ] )
446
438
const windiStylesCSS = new MagicString ( windiStyles . css )
447
439
const newContent =
448
- ( globalContent ? globalContent : '' ) +
449
- '\n' +
450
- windiStylesCSS . toString ( ) +
451
- '\n' +
452
- content
440
+ ( globalContent ? globalContent : '' ) + '\n' + windiStylesCSS . toString ( ) + '\n' + content
453
441
// console.log(newContent)
454
442
return {
455
443
code : newContent ,
@@ -462,10 +450,18 @@ function generateCSS(): PreprocessorGroup {
462
450
export function generate ( userConfig : UserConfig = { } ) : PreprocessorGroup {
463
451
generatorConfiguration = { ...defaults , ...userConfig }
464
452
465
- const presets = [ windicssPreset ( ) , presetTypography ( ) ]
453
+ const presets = [ ]
454
+ if ( generatorConfiguration . attributify != undefined ) {
455
+ presets . push (
456
+ presetAttributify ( {
457
+ ...generatorConfiguration . attributify ,
458
+ } )
459
+ )
460
+ }
461
+ presets . push ( windicssPreset ( ) , presetTypography ( ) )
466
462
if ( generatorConfiguration . icons != undefined ) {
467
463
presets . push (
468
- UnocssIcons ( {
464
+ presetIcons ( {
469
465
...generatorConfiguration . icons ,
470
466
} )
471
467
)
0 commit comments