-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.zig
More file actions
307 lines (248 loc) · 8.51 KB
/
schema.zig
File metadata and controls
307 lines (248 loc) · 8.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
const std = @import("std");
/// crosswind configuration schema
/// This uses zig-config for loading and merging configuration
pub const crosswindConfig = struct {
/// Project name
name: []const u8 = "crosswind",
/// Content paths to scan for class names
content: ContentConfig = .{},
/// Theme configuration
theme: ThemeConfig = .{},
/// Build options
build: BuildConfig = .{},
/// Plugin configuration
plugins: []const PluginConfig = &.{},
/// Cache configuration
cache: CacheConfig = .{},
/// Dark mode configuration
darkMode: DarkModeConfig = .{},
/// Prefix for all utility classes
prefix: []const u8 = "",
/// Separator for variants (default: ":")
separator: []const u8 = ":",
/// Important modifier
important: bool = false,
/// Core plugins to disable
corePlugins: CorePluginsConfig = .{},
/// Attributify mode configuration (UnoCSS-style)
attributify: AttributifyConfig = .{},
/// Grouped syntax mode (UnunuraCSS-style)
groupedSyntax: GroupedSyntaxConfig = .{},
};
pub const ContentConfig = struct {
/// Paths to scan (glob patterns)
files: []const []const u8 = &.{
"src/**/*.{html,js,jsx,ts,tsx,vue,svelte}",
},
/// Paths to exclude
exclude: []const []const u8 = &.{
"node_modules/**",
".git/**",
"dist/**",
"build/**",
},
/// Relative to this directory
relative: ?[]const u8 = null,
};
pub const ThemeConfig = struct {
/// Color palette
colors: ?std.json.Value = null,
/// Spacing scale
spacing: ?std.json.Value = null,
/// Font families
fontFamily: ?std.json.Value = null,
/// Font sizes
fontSize: ?std.json.Value = null,
/// Font weights
fontWeight: ?std.json.Value = null,
/// Line heights
lineHeight: ?std.json.Value = null,
/// Letter spacing
letterSpacing: ?std.json.Value = null,
/// Breakpoints
screens: ?std.json.Value = null,
/// Border radius
borderRadius: ?std.json.Value = null,
/// Box shadows
boxShadow: ?std.json.Value = null,
/// Extend theme (merge with defaults)
extend: ?std.json.Value = null,
};
pub const BuildConfig = struct {
/// Output file path
output: []const u8 = "dist/crosswind.css",
/// Minify output
minify: bool = false,
/// Generate source maps
sourcemap: bool = false,
/// Watch mode
watch: bool = false,
/// Preflight (CSS reset)
preflight: bool = true,
/// Output mode
mode: BuildMode = .development,
};
pub const BuildMode = enum {
development,
production,
};
pub const PluginConfig = struct {
/// Plugin name or path
name: []const u8,
/// Plugin options
options: ?std.json.Value = null,
};
pub const CacheConfig = struct {
/// Enable caching
enabled: bool = true,
/// Cache directory
dir: []const u8 = ".crosswind-cache",
/// Cache TTL in milliseconds
ttl: u32 = 3600000, // 1 hour
};
pub const DarkModeConfig = struct {
/// Strategy: "class" or "media"
strategy: DarkModeStrategy = .class,
/// Class name for dark mode (when strategy is "class")
className: []const u8 = "dark",
};
pub const DarkModeStrategy = enum {
class,
media,
selector,
};
/// Attributify mode configuration
/// Allows using utility classes as HTML attributes
/// Example: <div flex="~ col" items="center"> instead of class="flex flex-col items-center"
pub const AttributifyConfig = struct {
/// Enable attributify mode
enabled: bool = false,
/// Strict mode - only parse known utility prefixes as attributes
/// When false, any attribute with valid utility values will be parsed
strict: bool = true,
/// Prefix for valueless attributes (e.g., prefix="un-" -> <div un-flex>)
prefix: []const u8 = "",
/// List of prefixes to always treat as utilities
/// e.g., ["flex", "grid", "p", "m", "bg", "text", "border"]
prefixes: []const []const u8 = &.{
"flex", "grid", "inline", "block", "hidden",
"p", "px", "py", "pt", "pr",
"pb", "pl", "ps", "pe", "m",
"mx", "my", "mt", "mr", "mb",
"ml", "ms", "me", "w", "h",
"min", "max", "size", "bg", "text",
"font", "leading", "tracking", "border", "rounded",
"ring", "outline", "shadow", "opacity", "blur",
"gap", "space", "items", "justify", "content",
"self", "place", "top", "right", "bottom",
"left", "inset", "z", "order", "overflow",
"overscroll", "cursor", "select", "pointer", "transition",
"duration", "ease", "delay", "animate", "transform",
"scale", "rotate", "translate", "skew", "origin",
"col", "row", "aspect", "object", "list",
"decoration", "underline", "line", "no", "break",
"hyphens", "whitespace", "truncate", "sr", "not",
"fill", "stroke", "table", "caption", "filter",
"backdrop", "mix", "isolation", "accent", "caret",
"scroll", "snap", "touch", "resize", "appearance",
"columns", "break", "divide",
},
/// Ignore these attributes (never treat as utilities)
ignoreAttributes: []const []const u8 = &.{
"class", "className", "id", "style", "href", "src", "alt", "title",
"type", "name", "value", "placeholder", "data-*", "aria-*", "onclick", "onchange",
"onsubmit", "onload", "onerror",
},
};
/// Grouped syntax configuration (UnunuraCSS-style)
/// Allows grouping utilities with brackets and colon syntax
/// Example: flex[col jc-center ai-center] or bg:black
pub const GroupedSyntaxConfig = struct {
/// Enable grouped syntax parsing
enabled: bool = false,
/// Enable bracket grouping: prefix[val1 val2 val3]
/// e.g., flex[col jc-center ai-center] -> flex-col justify-center items-center
brackets: bool = true,
/// Enable colon shorthand: prefix:value
/// e.g., bg:black -> bg-black
colonShorthand: bool = true,
/// Enable reset utilities: reset:type
/// e.g., reset:meyer, reset:normalize, reset:tailwind
resets: bool = true,
/// Expansion rules for grouped values
/// Maps short forms to full utility names
/// Key: prefix, Value: map of short->full
expansions: ?std.json.Value = null,
};
pub const CorePluginsConfig = struct {
preflight: bool = true,
container: bool = true,
accessibility: bool = true,
pointerEvents: bool = true,
visibility: bool = true,
position: bool = true,
inset: bool = true,
zIndex: bool = true,
order: bool = true,
gridColumn: bool = true,
gridColumnStart: bool = true,
gridColumnEnd: bool = true,
gridRow: bool = true,
gridRowStart: bool = true,
gridRowEnd: bool = true,
float: bool = true,
clear: bool = true,
margin: bool = true,
padding: bool = true,
space: bool = true,
width: bool = true,
minWidth: bool = true,
maxWidth: bool = true,
height: bool = true,
minHeight: bool = true,
maxHeight: bool = true,
fontSize: bool = true,
fontWeight: bool = true,
textAlign: bool = true,
textColor: bool = true,
backgroundColor: bool = true,
borderColor: bool = true,
borderRadius: bool = true,
borderWidth: bool = true,
display: bool = true,
flex: bool = true,
flexDirection: bool = true,
flexWrap: bool = true,
alignItems: bool = true,
justifyContent: bool = true,
gap: bool = true,
grid: bool = true,
gridTemplateColumns: bool = true,
gridTemplateRows: bool = true,
};
/// Default configuration
pub fn defaultConfig() crosswindConfig {
return .{};
}
/// Validate configuration
pub fn validate(config: *const crosswindConfig) !void {
if (config.content.files.len == 0) {
return error.ConfigInvalid;
}
if (config.separator.len == 0) {
return error.ConfigInvalid;
}
// Validate build output path
if (config.build.output.len == 0) {
return error.ConfigInvalid;
}
}
test "defaultConfig" {
const config = defaultConfig();
try std.testing.expectEqualStrings("crosswind", config.name);
try std.testing.expectEqualStrings(":", config.separator);
}
test "validate" {
const config = defaultConfig();
try validate(&config);
}