zyzz 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/Config.d.ts +1 -0
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js.map +1 -1
- package/dist/Vars.d.ts +22 -15
- package/dist/Vars.d.ts.map +1 -1
- package/dist/Vars.js +26 -0
- package/dist/Vars.js.map +1 -1
- package/dist/cli/index.js +5 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +3 -0
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/internal/Configurations.d.ts.map +1 -1
- package/dist/compiler/internal/Configurations.js +3 -0
- package/dist/compiler/internal/Configurations.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +30 -4
- package/dist/compiler/internal/Contract.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +83 -23
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/default.d.ts +7 -11
- package/dist/default.d.ts.map +1 -1
- package/dist/default.js +4 -5
- package/dist/default.js.map +2 -2
- package/dist/default.js.zyzz.json +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/Token.d.ts +11 -2
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +2 -0
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/VariableSets.d.ts.map +1 -1
- package/dist/internal/VariableSets.js +18 -1
- package/dist/internal/VariableSets.js.map +1 -1
- package/dist/node/Host.d.ts +2 -0
- package/dist/node/Host.d.ts.map +1 -1
- package/dist/node/Host.js +7 -0
- package/dist/node/Host.js.map +1 -1
- package/dist/oxlint/index.d.ts +6 -0
- package/dist/oxlint/index.d.ts.map +1 -0
- package/dist/oxlint/index.js +18 -0
- package/dist/oxlint/index.js.map +1 -0
- package/dist/oxlint/internal/Bindings.d.ts +20 -0
- package/dist/oxlint/internal/Bindings.d.ts.map +1 -0
- package/dist/oxlint/internal/Bindings.js +203 -0
- package/dist/oxlint/internal/Bindings.js.map +1 -0
- package/dist/oxlint/internal/Declarations.d.ts +19 -0
- package/dist/oxlint/internal/Declarations.d.ts.map +1 -0
- package/dist/oxlint/internal/Declarations.js +114 -0
- package/dist/oxlint/internal/Declarations.js.map +1 -0
- package/dist/oxlint/rules/noConflictingProps.d.ts +5 -0
- package/dist/oxlint/rules/noConflictingProps.d.ts.map +1 -0
- package/dist/oxlint/rules/noConflictingProps.js +45 -0
- package/dist/oxlint/rules/noConflictingProps.js.map +1 -0
- package/dist/oxlint/rules/noUnused.d.ts +5 -0
- package/dist/oxlint/rules/noUnused.d.ts.map +1 -0
- package/dist/oxlint/rules/noUnused.js +62 -0
- package/dist/oxlint/rules/noUnused.js.map +1 -0
- package/dist/oxlint/rules/restrictedProperties.d.ts +5 -0
- package/dist/oxlint/rules/restrictedProperties.d.ts.map +1 -0
- package/dist/oxlint/rules/restrictedProperties.js +82 -0
- package/dist/oxlint/rules/restrictedProperties.js.map +1 -0
- package/dist/oxlint/rules/useLogicalProperties.d.ts +5 -0
- package/dist/oxlint/rules/useLogicalProperties.d.ts.map +1 -0
- package/dist/oxlint/rules/useLogicalProperties.js +76 -0
- package/dist/oxlint/rules/useLogicalProperties.js.map +1 -0
- package/dist/oxlint/rules/validStyles.d.ts +5 -0
- package/dist/oxlint/rules/validStyles.d.ts.map +1 -0
- package/dist/oxlint/rules/validStyles.js +75 -0
- package/dist/oxlint/rules/validStyles.js.map +1 -0
- package/dist/react-native/StyleSheet.js +2 -0
- package/dist/react-native/StyleSheet.js.map +1 -1
- package/dist/runtime/Composition.d.ts +1 -1
- package/dist/runtime/ConditionalRecipe.d.ts +1 -1
- package/dist/runtime/PayloadRecipe.d.ts +1 -1
- package/dist/runtime/Recipe.d.ts +1 -1
- package/dist/styleFunction.d.ts +1 -1
- package/dist/styleFunction.d.ts.map +1 -1
- package/dist/styleFunction.js.map +1 -1
- package/dist/variants.d.ts +14 -6
- package/dist/variants.d.ts.map +1 -1
- package/dist/variants.js.map +1 -1
- package/dist/vite/index.d.ts +2 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +75 -30
- package/dist/vite/index.js.map +1 -1
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +4 -0
- package/dist/web/internal/Themes.js.map +1 -1
- package/package.json +7 -1
- package/src/Config.ts +5 -0
- package/src/Vars.ts +88 -29
- package/src/cli/index.ts +5 -0
- package/src/compiler/Source.ts +3 -0
- package/src/compiler/internal/Configurations.ts +3 -0
- package/src/compiler/internal/Contract.ts +47 -4
- package/src/compiler/internal/Themes.ts +109 -34
- package/src/default.ts +8 -10
- package/src/index.ts +15 -0
- package/src/internal/Authoring.ts +1 -1
- package/src/internal/Token.ts +39 -11
- package/src/internal/VariableSets.ts +25 -1
- package/src/node/Host.ts +19 -0
- package/src/oxlint/index.ts +21 -0
- package/src/oxlint/internal/Bindings.ts +270 -0
- package/src/oxlint/internal/Declarations.ts +137 -0
- package/src/oxlint/rules/noConflictingProps.ts +52 -0
- package/src/oxlint/rules/noUnused.ts +67 -0
- package/src/oxlint/rules/restrictedProperties.ts +92 -0
- package/src/oxlint/rules/useLogicalProperties.ts +81 -0
- package/src/oxlint/rules/validStyles.ts +88 -0
- package/src/react-native/StyleSheet.ts +6 -0
- package/src/styleFunction.ts +1 -3
- package/src/variants.ts +38 -16
- package/src/vite/index.ts +94 -33
- package/src/web/internal/Themes.ts +4 -0
package/src/Vars.ts
CHANGED
|
@@ -7,9 +7,16 @@ import * as Token from './internal/Token.js'
|
|
|
7
7
|
import * as VariableSets from './internal/VariableSets.js'
|
|
8
8
|
import type { style } from './styleFunction.js'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
export type { Composition } from './internal/Token.js'
|
|
11
|
+
|
|
12
|
+
/** Portable scalar reference retaining its value domain and optional literal precision. */
|
|
13
|
+
export type Reference<
|
|
14
|
+
group extends Token.Group = Token.Group,
|
|
15
|
+
scalar = never,
|
|
16
|
+
> = Token.Reference<group> &
|
|
17
|
+
([scalar] extends [never]
|
|
18
|
+
? { readonly [Token.scalar]?: unknown }
|
|
19
|
+
: { readonly [Token.scalar]: scalar })
|
|
13
20
|
|
|
14
21
|
const shape = Symbol('zyzz.variables.shape')
|
|
15
22
|
|
|
@@ -18,9 +25,10 @@ export type Value =
|
|
|
18
25
|
| string
|
|
19
26
|
| number
|
|
20
27
|
| Token.Reference
|
|
28
|
+
| Token.Composition
|
|
21
29
|
| {
|
|
22
|
-
readonly light: string | Token.Reference
|
|
23
|
-
readonly dark: string | Token.Reference
|
|
30
|
+
readonly light: string | Token.Reference | Token.Composition<'color'>
|
|
31
|
+
readonly dark: string | Token.Reference | Token.Composition<'color'>
|
|
24
32
|
}
|
|
25
33
|
| ({ readonly default: Value } & {
|
|
26
34
|
readonly [query: `@media ${string}`]: Value
|
|
@@ -47,32 +55,41 @@ export type References<values, root extends boolean = true> = {
|
|
|
47
55
|
keyof values,
|
|
48
56
|
root extends true ? 'breakpoint' | 'containerNames' : never
|
|
49
57
|
>]: values[key] extends Value
|
|
50
|
-
?
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
? Reference<
|
|
59
|
+
Domain<Scalar<values[key]>>,
|
|
60
|
+
Literal.Color extends Scalar<values[key]>
|
|
61
|
+
? never
|
|
62
|
+
: Literal.Length extends Scalar<values[key]>
|
|
63
|
+
? never
|
|
64
|
+
: Scalar<values[key]>
|
|
65
|
+
>
|
|
53
66
|
: References<values[key], false>
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
/** Resolves the scalar types represented by all conditional branches. */
|
|
57
70
|
export type Scalar<value> = Value extends value
|
|
58
71
|
? string | number
|
|
59
|
-
: value extends
|
|
60
|
-
?
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
: value extends Token.Composition<infer group>
|
|
73
|
+
? group extends 'color'
|
|
74
|
+
? Literal.Color
|
|
75
|
+
: Literal.Length
|
|
76
|
+
: value extends { readonly [Token.scalar]: infer scalar }
|
|
77
|
+
? scalar
|
|
78
|
+
: value extends readonly string[]
|
|
79
|
+
? value
|
|
80
|
+
: value extends Token.Reference<infer group>
|
|
81
|
+
? group extends 'color'
|
|
82
|
+
? Literal.Color
|
|
83
|
+
: group extends 'spacing'
|
|
84
|
+
? Literal.Length
|
|
85
|
+
: group extends 'number'
|
|
86
|
+
? number
|
|
87
|
+
: string
|
|
88
|
+
: value extends { default: unknown }
|
|
89
|
+
? Scalar<value[keyof value]>
|
|
90
|
+
: value extends { light: infer light; dark: infer dark }
|
|
91
|
+
? Scalar<light | dark>
|
|
92
|
+
: value
|
|
76
93
|
|
|
77
94
|
/** Scalar domain shared by compatible set alternatives. */
|
|
78
95
|
export type Domain<value> = [value] extends [Literal.Color]
|
|
@@ -83,6 +100,41 @@ export type Domain<value> = [value] extends [Literal.Color]
|
|
|
83
100
|
? 'number'
|
|
84
101
|
: 'string'
|
|
85
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Composes immutable web CSS text and live references in a color or spacing domain.
|
|
105
|
+
* @throws {InvalidError} If parts are empty, nonfinite, contain declaration markers, or include unsupported values.
|
|
106
|
+
*/
|
|
107
|
+
export function compose<group extends 'color' | 'spacing'>(
|
|
108
|
+
group: group,
|
|
109
|
+
parts: readonly (string | number | Reference)[],
|
|
110
|
+
): Token.Composition<group> {
|
|
111
|
+
if (group !== 'color' && group !== 'spacing')
|
|
112
|
+
throw new InvalidError(
|
|
113
|
+
[],
|
|
114
|
+
'Compositions require a color or spacing domain.',
|
|
115
|
+
)
|
|
116
|
+
if (!Array.isArray(parts) || !parts.length)
|
|
117
|
+
throw new InvalidError([], 'Compositions require nonempty CSS parts.')
|
|
118
|
+
|
|
119
|
+
const values = Array.from(parts, (part) => {
|
|
120
|
+
if (Token.is(part)) return part
|
|
121
|
+
if (typeof part === 'number' && Number.isFinite(part)) return String(part)
|
|
122
|
+
if (typeof part === 'string' && !/[;{}!]/.test(part)) return part
|
|
123
|
+
throw new InvalidError(
|
|
124
|
+
[],
|
|
125
|
+
'Composition parts must be CSS text, finite numbers, or variable references.',
|
|
126
|
+
)
|
|
127
|
+
})
|
|
128
|
+
if (!values.some((part) => typeof part !== 'string' || part.trim()))
|
|
129
|
+
throw new InvalidError([], 'Compositions require nonempty CSS parts.')
|
|
130
|
+
|
|
131
|
+
return Object.freeze({
|
|
132
|
+
[Token.expression]: true as const,
|
|
133
|
+
group,
|
|
134
|
+
parts: Object.freeze(values),
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
86
138
|
/** Creates typed references without emitting CSS or reading the environment. */
|
|
87
139
|
export function define<const values extends Values>(
|
|
88
140
|
values: values & NoInfer<Validated<values, false, true>>,
|
|
@@ -166,12 +218,19 @@ type Compatible<scalar> = [scalar] extends [Literal.Color]
|
|
|
166
218
|
?
|
|
167
219
|
| Literal.Color
|
|
168
220
|
| Token.Reference<'color'>
|
|
221
|
+
| Token.Composition<'color'>
|
|
169
222
|
| {
|
|
170
|
-
readonly light:
|
|
171
|
-
|
|
223
|
+
readonly light:
|
|
224
|
+
| Literal.Color
|
|
225
|
+
| Token.Reference<'color'>
|
|
226
|
+
| Token.Composition<'color'>
|
|
227
|
+
readonly dark:
|
|
228
|
+
| Literal.Color
|
|
229
|
+
| Token.Reference<'color'>
|
|
230
|
+
| Token.Composition<'color'>
|
|
172
231
|
}
|
|
173
232
|
: [scalar] extends [Literal.Length]
|
|
174
|
-
? Literal.Length | Token.Reference<'spacing'>
|
|
233
|
+
? Literal.Length | Token.Reference<'spacing'> | Token.Composition<'spacing'>
|
|
175
234
|
: [scalar] extends [number]
|
|
176
235
|
? number | Token.Reference<'number'>
|
|
177
236
|
: string | Token.Reference<'string'>
|
|
@@ -221,7 +280,7 @@ type Validated<
|
|
|
221
280
|
? value
|
|
222
281
|
: value extends readonly string[]
|
|
223
282
|
? never
|
|
224
|
-
: value extends Token.Reference
|
|
283
|
+
: value extends Token.Reference | Token.Composition
|
|
225
284
|
? value
|
|
226
285
|
: value extends string | number
|
|
227
286
|
? Literal.Checked<value>
|
package/src/cli/index.ts
CHANGED
|
@@ -25,6 +25,10 @@ const options = z.object({
|
|
|
25
25
|
.boolean()
|
|
26
26
|
.default(false)
|
|
27
27
|
.describe('Emit only CSS and CSS maps without source transformation'),
|
|
28
|
+
external: z
|
|
29
|
+
.array(z.string())
|
|
30
|
+
.optional()
|
|
31
|
+
.describe('External import name or trailing * prefix (repeatable)'),
|
|
28
32
|
minify: z.boolean().default(false).describe('Minify emitted CSS'),
|
|
29
33
|
'out-dir': z.string().default('dist').describe('Output directory'),
|
|
30
34
|
'package-id': z
|
|
@@ -178,6 +182,7 @@ async function open(context: open.Context) {
|
|
|
178
182
|
: {}),
|
|
179
183
|
compiler: !context.options['css-only'],
|
|
180
184
|
css: { minify: context.options.minify },
|
|
185
|
+
external: context.options.external,
|
|
181
186
|
modules: !context.options['css-only'],
|
|
182
187
|
outDir: Path.resolve(context.options['out-dir']),
|
|
183
188
|
packageId,
|
package/src/compiler/Source.ts
CHANGED
|
@@ -375,6 +375,9 @@ export function extract(options: extract.Options): extract.ReturnType {
|
|
|
375
375
|
if (
|
|
376
376
|
name === 'Config' ||
|
|
377
377
|
name === 'cx' ||
|
|
378
|
+
name === 'defineConfig' ||
|
|
379
|
+
name === 'defineVars' ||
|
|
380
|
+
name === 'extendVars' ||
|
|
378
381
|
name === 'style' ||
|
|
379
382
|
name === 'Theme' ||
|
|
380
383
|
name === 'Vars' ||
|
|
@@ -148,6 +148,7 @@ export function collect(options: collect.Options): Themes.Link {
|
|
|
148
148
|
}
|
|
149
149
|
: {}),
|
|
150
150
|
[Token.identity]: identity,
|
|
151
|
+
...(input.id !== undefined ? { [Token.complete]: true } : {}),
|
|
151
152
|
cssOutput: input.cssOutput ?? 'atomic',
|
|
152
153
|
...(input.defaultLayer !== undefined
|
|
153
154
|
? { defaultLayer: input.defaultLayer }
|
|
@@ -294,6 +295,8 @@ export declare namespace collect {
|
|
|
294
295
|
|
|
295
296
|
/** Encodes validated literal options as a declaration type, never executable text. */
|
|
296
297
|
export function type(value: unknown): string {
|
|
298
|
+
if (Token.isExpression(value) && 'group' in value)
|
|
299
|
+
return `import('zyzz').Vars.Composition<'${value.group}'>`
|
|
297
300
|
if (Token.is(value)) return `import('zyzz').Vars.Reference<'${value.group}'>`
|
|
298
301
|
if (Array.isArray(value)) return `readonly [${value.map(type).join(',')}]`
|
|
299
302
|
if (!value || typeof value !== 'object') return JSON.stringify(value)
|
|
@@ -26,7 +26,7 @@ export function read(
|
|
|
26
26
|
if (
|
|
27
27
|
![
|
|
28
28
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
|
|
29
|
-
22, 23, 24, 25, 26, 27, 28,
|
|
29
|
+
22, 23, 24, 25, 26, 27, 28, 29,
|
|
30
30
|
].includes(data.version as number)
|
|
31
31
|
)
|
|
32
32
|
throw new Error('Unsupported Zyzz contract version.')
|
|
@@ -69,6 +69,26 @@ export function read(
|
|
|
69
69
|
decode(value),
|
|
70
70
|
]),
|
|
71
71
|
)
|
|
72
|
+
if (Object.hasOwn(fields, '$composition')) {
|
|
73
|
+
if ((data.version as number) < 29)
|
|
74
|
+
throw new Error(
|
|
75
|
+
'Composed variables require contract version 29 or later.',
|
|
76
|
+
)
|
|
77
|
+
const composition = record(fields.$composition)
|
|
78
|
+
if (
|
|
79
|
+
(composition.group !== 'color' && composition.group !== 'spacing') ||
|
|
80
|
+
!Array.isArray(composition.parts)
|
|
81
|
+
)
|
|
82
|
+
throw new Error('Invalid packed variable composition.')
|
|
83
|
+
return Vars.compose(
|
|
84
|
+
composition.group,
|
|
85
|
+
composition.parts.map(decode) as readonly (
|
|
86
|
+
| string
|
|
87
|
+
| number
|
|
88
|
+
| Vars.Reference
|
|
89
|
+
)[],
|
|
90
|
+
)
|
|
91
|
+
}
|
|
72
92
|
if (Object.hasOwn(fields, '$variable')) {
|
|
73
93
|
const reference = record(fields.$variable)
|
|
74
94
|
const identity = string(reference.identity)
|
|
@@ -294,7 +314,7 @@ export function read(
|
|
|
294
314
|
if (
|
|
295
315
|
![
|
|
296
316
|
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
|
297
|
-
27, 28,
|
|
317
|
+
27, 28, 29,
|
|
298
318
|
].includes(data.version as number) ||
|
|
299
319
|
![
|
|
300
320
|
'cssFunction',
|
|
@@ -590,7 +610,8 @@ function tokens(tree: Theme.References<Theme.Tokens>): Record<string, unknown> {
|
|
|
590
610
|
}
|
|
591
611
|
|
|
592
612
|
function type(value: unknown): string {
|
|
593
|
-
if (Token.is(value)
|
|
613
|
+
if (Token.is(value) || Token.isExpression(value))
|
|
614
|
+
return Configurations.type(value)
|
|
594
615
|
if (Array.isArray(value)) return `readonly [${value.map(type).join(',')}]`
|
|
595
616
|
if (!value || typeof value !== 'object') return JSON.stringify(value)
|
|
596
617
|
|
|
@@ -727,6 +748,22 @@ export function write(
|
|
|
727
748
|
]),
|
|
728
749
|
),
|
|
729
750
|
version: (() => {
|
|
751
|
+
function composed(value: unknown): boolean {
|
|
752
|
+
if (Token.isExpression(value)) return true
|
|
753
|
+
if (Token.is(value)) return composed(value.value)
|
|
754
|
+
return (
|
|
755
|
+
!!value &&
|
|
756
|
+
typeof value === 'object' &&
|
|
757
|
+
Object.values(value).some(composed)
|
|
758
|
+
)
|
|
759
|
+
}
|
|
760
|
+
if (
|
|
761
|
+
Object.values(themes).some((theme) =>
|
|
762
|
+
composed(theme[Token.definition].values),
|
|
763
|
+
)
|
|
764
|
+
)
|
|
765
|
+
return 29
|
|
766
|
+
|
|
730
767
|
if (
|
|
731
768
|
Object.values(themes).some(
|
|
732
769
|
(theme) =>
|
|
@@ -1031,6 +1068,10 @@ function extended(signature: NonNullable<Themes.Call['function']>): boolean {
|
|
|
1031
1068
|
}
|
|
1032
1069
|
|
|
1033
1070
|
function encode(value: unknown): unknown {
|
|
1071
|
+
if (Token.isExpression(value) && 'group' in value)
|
|
1072
|
+
return {
|
|
1073
|
+
$composition: { group: value.group, parts: value.parts.map(encode) },
|
|
1074
|
+
}
|
|
1034
1075
|
if (Token.is(value))
|
|
1035
1076
|
return {
|
|
1036
1077
|
$variable: {
|
|
@@ -1044,7 +1085,9 @@ function encode(value: unknown): unknown {
|
|
|
1044
1085
|
const fields = Object.fromEntries(
|
|
1045
1086
|
Object.entries(value).map(([key, value]) => [key, encode(value)]),
|
|
1046
1087
|
)
|
|
1047
|
-
return Object.hasOwn(fields, '$
|
|
1088
|
+
return Object.hasOwn(fields, '$composition') ||
|
|
1089
|
+
Object.hasOwn(fields, '$variable') ||
|
|
1090
|
+
Object.hasOwn(fields, '$object')
|
|
1048
1091
|
? { $object: fields }
|
|
1049
1092
|
: fields
|
|
1050
1093
|
}
|
|
@@ -144,6 +144,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
144
144
|
const imports = new Set<number>()
|
|
145
145
|
const variableImports = new Set<number>()
|
|
146
146
|
const configImports = new Set<number>()
|
|
147
|
+
const factoryImports = new Map<number, 'create' | 'define' | 'extend'>()
|
|
147
148
|
const configs = new Map<string, Link>()
|
|
148
149
|
const configBindings = new Map<number, Link>()
|
|
149
150
|
const factoryReferences = new Set<number>()
|
|
@@ -188,11 +189,31 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
188
189
|
: specifier.imported.value) === 'Config'
|
|
189
190
|
)
|
|
190
191
|
configImports.add(specifier.start)
|
|
192
|
+
else if (
|
|
193
|
+
specifier.type === 'ImportSpecifier' &&
|
|
194
|
+
specifier.importKind !== 'type' &&
|
|
195
|
+
['defineConfig', 'defineVars', 'extendVars'].includes(
|
|
196
|
+
specifier.imported.type === 'Identifier'
|
|
197
|
+
? specifier.imported.name
|
|
198
|
+
: specifier.imported.value,
|
|
199
|
+
)
|
|
200
|
+
) {
|
|
201
|
+
const name =
|
|
202
|
+
specifier.imported.type === 'Identifier'
|
|
203
|
+
? specifier.imported.name
|
|
204
|
+
: specifier.imported.value
|
|
205
|
+
if (name === 'defineConfig')
|
|
206
|
+
factoryImports.set(specifier.start, 'create')
|
|
207
|
+
else if (name === 'defineVars')
|
|
208
|
+
factoryImports.set(specifier.start, 'define')
|
|
209
|
+
else factoryImports.set(specifier.start, 'extend')
|
|
210
|
+
}
|
|
191
211
|
}
|
|
192
212
|
|
|
193
213
|
if (
|
|
194
214
|
!imports.size &&
|
|
195
215
|
!configImports.size &&
|
|
216
|
+
!factoryImports.size &&
|
|
196
217
|
!Object.keys(options.links ?? {}).length
|
|
197
218
|
)
|
|
198
219
|
return undefined
|
|
@@ -251,6 +272,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
251
272
|
|
|
252
273
|
const namespaces = new Set<string>()
|
|
253
274
|
const configNamespaces = new Set<string>()
|
|
275
|
+
const factoryFunctions = new Map<string, 'create' | 'define' | 'extend'>()
|
|
254
276
|
const variableNamespaces = new Set<string>()
|
|
255
277
|
for (const node of program.body)
|
|
256
278
|
if (node.type === 'ImportDeclaration')
|
|
@@ -264,6 +286,11 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
264
286
|
if (imports.has(specifier.start)) namespaces.add(specifier.local.name)
|
|
265
287
|
else if (configImports.has(specifier.start))
|
|
266
288
|
configNamespaces.add(specifier.local.name)
|
|
289
|
+
else if (factoryImports.has(specifier.start))
|
|
290
|
+
factoryFunctions.set(
|
|
291
|
+
specifier.local.name,
|
|
292
|
+
factoryImports.get(specifier.start)!,
|
|
293
|
+
)
|
|
267
294
|
|
|
268
295
|
function resolve(node: Ast.Node): Link | undefined {
|
|
269
296
|
if (node.type === 'Identifier') {
|
|
@@ -426,6 +453,35 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
426
453
|
if (node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression')
|
|
427
454
|
return data(node.expression, derived)
|
|
428
455
|
|
|
456
|
+
if (node.type === 'CallExpression' && !node.optional) {
|
|
457
|
+
const callee = node.callee
|
|
458
|
+
if (
|
|
459
|
+
callee.type === 'MemberExpression' &&
|
|
460
|
+
!callee.computed &&
|
|
461
|
+
!callee.optional &&
|
|
462
|
+
callee.object.type === 'Identifier' &&
|
|
463
|
+
variableNamespaces.has(callee.object.name) &&
|
|
464
|
+
derived?.name !== callee.object.name &&
|
|
465
|
+
callee.property.type === 'Identifier' &&
|
|
466
|
+
callee.property.name === 'compose'
|
|
467
|
+
) {
|
|
468
|
+
if (node.arguments.length !== 2)
|
|
469
|
+
return fail(
|
|
470
|
+
'Vars.compose requires a literal domain and parts array.',
|
|
471
|
+
node,
|
|
472
|
+
)
|
|
473
|
+
const group = data(node.arguments[0]!, derived)
|
|
474
|
+
const parts = data(node.arguments[1]!, derived)
|
|
475
|
+
if ((group !== 'color' && group !== 'spacing') || !Array.isArray(parts))
|
|
476
|
+
return fail(
|
|
477
|
+
'Vars.compose requires a literal domain and parts array.',
|
|
478
|
+
node,
|
|
479
|
+
)
|
|
480
|
+
factoryReferences.add(callee.start)
|
|
481
|
+
return Vars.compose(group, parts)
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
429
485
|
if (
|
|
430
486
|
node.type === 'Literal' &&
|
|
431
487
|
(typeof node.value === 'string' || typeof node.value === 'number')
|
|
@@ -536,37 +592,52 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
536
592
|
registerAlias({ declaration, statement, variable })
|
|
537
593
|
|
|
538
594
|
const expression = variable.init
|
|
539
|
-
if (
|
|
540
|
-
expression?.type !== 'CallExpression' ||
|
|
541
|
-
expression.callee.type !== 'MemberExpression' ||
|
|
542
|
-
expression.callee.object.type !== 'Identifier' ||
|
|
543
|
-
(!namespaces.has(expression.callee.object.name) &&
|
|
544
|
-
!configNamespaces.has(expression.callee.object.name))
|
|
545
|
-
)
|
|
546
|
-
continue
|
|
595
|
+
if (expression?.type !== 'CallExpression' || expression.optional) continue
|
|
547
596
|
|
|
548
597
|
const member = expression.callee
|
|
598
|
+
const directFactory =
|
|
599
|
+
member.type === 'Identifier'
|
|
600
|
+
? factoryFunctions.get(member.name)
|
|
601
|
+
: undefined
|
|
549
602
|
if (
|
|
550
|
-
|
|
551
|
-
member.
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
603
|
+
!directFactory &&
|
|
604
|
+
(member.type !== 'MemberExpression' ||
|
|
605
|
+
member.object.type !== 'Identifier' ||
|
|
606
|
+
(!namespaces.has(member.object.name) &&
|
|
607
|
+
!configNamespaces.has(member.object.name)) ||
|
|
608
|
+
member.computed ||
|
|
609
|
+
member.optional ||
|
|
610
|
+
member.property.type !== 'Identifier' ||
|
|
611
|
+
!(
|
|
612
|
+
configNamespaces.has(member.object.name)
|
|
613
|
+
? ['create']
|
|
614
|
+
: ['define', 'extend']
|
|
615
|
+
).includes(member.property.name))
|
|
559
616
|
)
|
|
560
617
|
continue
|
|
561
618
|
|
|
619
|
+
const config =
|
|
620
|
+
directFactory === 'create' ||
|
|
621
|
+
(member.type === 'MemberExpression' &&
|
|
622
|
+
member.object.type === 'Identifier' &&
|
|
623
|
+
configNamespaces.has(member.object.name))
|
|
624
|
+
const method =
|
|
625
|
+
member.type === 'MemberExpression' &&
|
|
626
|
+
member.property.type === 'Identifier'
|
|
627
|
+
? member.property.name
|
|
628
|
+
: directFactory
|
|
629
|
+
const variableSet =
|
|
630
|
+
directFactory === 'define' ||
|
|
631
|
+
directFactory === 'extend' ||
|
|
632
|
+
(member.type === 'MemberExpression' &&
|
|
633
|
+
member.object.type === 'Identifier' &&
|
|
634
|
+
variableNamespaces.has(member.object.name))
|
|
635
|
+
|
|
562
636
|
if (
|
|
563
637
|
(statement.type === 'ExportNamedDeclaration' && !options.linked) ||
|
|
564
638
|
declaration.kind !== 'const' ||
|
|
565
639
|
(variable.id.type !== 'Identifier' &&
|
|
566
|
-
!(
|
|
567
|
-
configNamespaces.has(expression.callee.object.name) &&
|
|
568
|
-
variable.id.type === 'ObjectPattern'
|
|
569
|
-
))
|
|
640
|
+
!(config && variable.id.type === 'ObjectPattern'))
|
|
570
641
|
)
|
|
571
642
|
fail(
|
|
572
643
|
'Define local themes with a module-level const; exported themes require source linking.',
|
|
@@ -601,10 +672,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
601
672
|
fail('Configuration destructuring requires a binding.', variable)
|
|
602
673
|
|
|
603
674
|
let name = `${options.namespace}-${binding}`
|
|
604
|
-
if (
|
|
605
|
-
!configNamespaces.has(expression.callee.object.name) &&
|
|
606
|
-
member.property.name === 'define'
|
|
607
|
-
) {
|
|
675
|
+
if (!config && method === 'define') {
|
|
608
676
|
const argument = expression.arguments[1]
|
|
609
677
|
const callback = argument && Expression.unwrap(argument)
|
|
610
678
|
const id = Identifiers.explicit(
|
|
@@ -617,7 +685,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
617
685
|
if (id !== undefined) name = Identity.requireId(id, 'Vars.define')
|
|
618
686
|
}
|
|
619
687
|
|
|
620
|
-
if (
|
|
688
|
+
if (config) {
|
|
621
689
|
try {
|
|
622
690
|
const link = Configurations.collect({
|
|
623
691
|
data,
|
|
@@ -772,7 +840,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
772
840
|
let output: Call['output']
|
|
773
841
|
|
|
774
842
|
try {
|
|
775
|
-
if (
|
|
843
|
+
if (method === 'define') {
|
|
776
844
|
if (
|
|
777
845
|
expression.arguments.length < 1 ||
|
|
778
846
|
expression.arguments.length > 3
|
|
@@ -786,9 +854,6 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
786
854
|
|
|
787
855
|
tokenType = type(expression.arguments[0]!)
|
|
788
856
|
|
|
789
|
-
const variableSet = variableNamespaces.has(
|
|
790
|
-
expression.callee.object.name,
|
|
791
|
-
)
|
|
792
857
|
const argument = expression.arguments[1]
|
|
793
858
|
const callback = argument && Expression.unwrap(argument)
|
|
794
859
|
if (
|
|
@@ -860,7 +925,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
860
925
|
)
|
|
861
926
|
|
|
862
927
|
factoryReferences.add(base!.start)
|
|
863
|
-
definition =
|
|
928
|
+
definition = variableSet
|
|
864
929
|
? VariableSets.theme(
|
|
865
930
|
Vars.extend(
|
|
866
931
|
VariableSets.from(themes[parent.name]![Token.definition]),
|
|
@@ -892,7 +957,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
892
957
|
}
|
|
893
958
|
|
|
894
959
|
const call = Object.freeze({
|
|
895
|
-
...(
|
|
960
|
+
...(variableSet
|
|
896
961
|
? {
|
|
897
962
|
variableSet: true,
|
|
898
963
|
directVariables: true,
|
|
@@ -1286,12 +1351,22 @@ export function collect(program: Ast.Program, options: collect.Options) {
|
|
|
1286
1351
|
|
|
1287
1352
|
if (
|
|
1288
1353
|
binding?.type === 'Import' &&
|
|
1289
|
-
(imports.has(binding.node.start) ||
|
|
1354
|
+
(imports.has(binding.node.start) ||
|
|
1355
|
+
configImports.has(binding.node.start) ||
|
|
1356
|
+
factoryImports.has(binding.node.start))
|
|
1290
1357
|
) {
|
|
1358
|
+
if (
|
|
1359
|
+
factoryImports.has(binding.node.start) &&
|
|
1360
|
+
parent.type === 'CallExpression' &&
|
|
1361
|
+
factories.has(parent.start)
|
|
1362
|
+
)
|
|
1363
|
+
return true
|
|
1364
|
+
|
|
1291
1365
|
if (
|
|
1292
1366
|
parent.type === 'MemberExpression' &&
|
|
1293
1367
|
grandparent?.type === 'CallExpression' &&
|
|
1294
|
-
factories.has(grandparent.start)
|
|
1368
|
+
(factories.has(grandparent.start) ||
|
|
1369
|
+
factoryReferences.has(parent.start))
|
|
1295
1370
|
)
|
|
1296
1371
|
return true
|
|
1297
1372
|
|
package/src/default.ts
CHANGED
|
@@ -80,8 +80,8 @@ export const tokens = {
|
|
|
80
80
|
1000: { dark: '#fef3dc', light: '#4e2009' },
|
|
81
81
|
},
|
|
82
82
|
background: {
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
primary: { dark: '#000', light: '#fafafa' },
|
|
84
|
+
surface: { dark: '#0a0a0a', light: '#fff' },
|
|
85
85
|
},
|
|
86
86
|
black: '#000',
|
|
87
87
|
blue: {
|
|
@@ -169,7 +169,6 @@ export const tokens = {
|
|
|
169
169
|
900: { dark: '#ff6166', light: '#cb2a2f' },
|
|
170
170
|
1000: { dark: '#feecee', light: '#391417' },
|
|
171
171
|
},
|
|
172
|
-
surface: { dark: '#0a0a0a', light: '#fff' },
|
|
173
172
|
teal: {
|
|
174
173
|
100: { dark: '#04201b', light: '#eefcf9' },
|
|
175
174
|
200: { dark: '#062822', light: '#e5faf6' },
|
|
@@ -428,14 +427,14 @@ export const tokens = {
|
|
|
428
427
|
fontSize: '20px',
|
|
429
428
|
fontWeight: 400,
|
|
430
429
|
letterSpacing: '0px',
|
|
431
|
-
lineHeight: '
|
|
430
|
+
lineHeight: '28px',
|
|
432
431
|
strong: {
|
|
433
432
|
fontFamily:
|
|
434
433
|
'Geist, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
|
435
434
|
fontSize: '20px',
|
|
436
435
|
fontWeight: 550,
|
|
437
436
|
letterSpacing: '0px',
|
|
438
|
-
lineHeight: '
|
|
437
|
+
lineHeight: '28px',
|
|
439
438
|
},
|
|
440
439
|
},
|
|
441
440
|
'24': {
|
|
@@ -722,8 +721,8 @@ const config = Config.create({
|
|
|
722
721
|
1000: { dark: '#fef3dc', light: '#4e2009' },
|
|
723
722
|
},
|
|
724
723
|
background: {
|
|
725
|
-
|
|
726
|
-
|
|
724
|
+
primary: { dark: '#000', light: '#fafafa' },
|
|
725
|
+
surface: { dark: '#0a0a0a', light: '#fff' },
|
|
727
726
|
},
|
|
728
727
|
black: '#000',
|
|
729
728
|
blue: {
|
|
@@ -811,7 +810,6 @@ const config = Config.create({
|
|
|
811
810
|
900: { dark: '#ff6166', light: '#cb2a2f' },
|
|
812
811
|
1000: { dark: '#feecee', light: '#391417' },
|
|
813
812
|
},
|
|
814
|
-
surface: { dark: '#0a0a0a', light: '#fff' },
|
|
815
813
|
teal: {
|
|
816
814
|
100: { dark: '#04201b', light: '#eefcf9' },
|
|
817
815
|
200: { dark: '#062822', light: '#e5faf6' },
|
|
@@ -1070,14 +1068,14 @@ const config = Config.create({
|
|
|
1070
1068
|
fontSize: '20px',
|
|
1071
1069
|
fontWeight: 400,
|
|
1072
1070
|
letterSpacing: '0px',
|
|
1073
|
-
lineHeight: '
|
|
1071
|
+
lineHeight: '28px',
|
|
1074
1072
|
strong: {
|
|
1075
1073
|
fontFamily:
|
|
1076
1074
|
'Geist, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
|
1077
1075
|
fontSize: '20px',
|
|
1078
1076
|
fontWeight: 550,
|
|
1079
1077
|
letterSpacing: '0px',
|
|
1080
|
-
lineHeight: '
|
|
1078
|
+
lineHeight: '28px',
|
|
1081
1079
|
},
|
|
1082
1080
|
},
|
|
1083
1081
|
'24': {
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,21 @@ export * as Config from './Config.js'
|
|
|
8
8
|
export { style } from './styleFunction.js'
|
|
9
9
|
/** Ordered composition of applied styling props. */
|
|
10
10
|
export { cx } from './cx.js'
|
|
11
|
+
/**
|
|
12
|
+
* Creates isolated authoring with optional vars and named alternatives.
|
|
13
|
+
* @alias Config.create
|
|
14
|
+
*/
|
|
15
|
+
export { create as defineConfig } from './Config.js'
|
|
16
|
+
/**
|
|
17
|
+
* Creates immutable typed variable sets without emitting CSS.
|
|
18
|
+
* @alias Vars.define
|
|
19
|
+
*/
|
|
20
|
+
export { define as defineVars } from './Vars.js'
|
|
21
|
+
/**
|
|
22
|
+
* Overrides variable values while preserving their shared contract.
|
|
23
|
+
* @alias Vars.extend
|
|
24
|
+
*/
|
|
25
|
+
export { extend as extendVars } from './Vars.js'
|
|
11
26
|
/** Inferred component inputs from callable style definitions. */
|
|
12
27
|
export type * as Props from './Props.js'
|
|
13
28
|
/** Typed literal style definitions and validation diagnostics. */
|
|
@@ -157,7 +157,7 @@ export function variants(
|
|
|
157
157
|
return (values: Record<string, unknown> & style.Options = {}) => {
|
|
158
158
|
const result = { ...props(values as style.Options) } as {
|
|
159
159
|
className: string
|
|
160
|
-
style?: style.Props['style']
|
|
160
|
+
style?: NonNullable<style.Props['style']>
|
|
161
161
|
[key: `data-${string}`]: string | undefined
|
|
162
162
|
}
|
|
163
163
|
const bindings: Record<string, string | number> = {}
|