@wix/zero-config-implementation 1.75.0 → 1.77.0
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/dist/{index-DNi5gVDn.js → index-CuKmaUAA.js} +1 -1
- package/dist/{index-FEhWzHzO.js → index-DRWoSsTZ.js} +12985 -12878
- package/dist/index.d.ts +42 -5
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/src/converters/data-item-builder.test.ts +14 -3
- package/src/converters/data-item-builder.ts +23 -1
- package/src/converters/to-editor-component.test.ts +154 -1
- package/src/converters/to-editor-component.ts +57 -6
- package/src/information-extractors/css/parse.test.ts +99 -0
- package/src/information-extractors/css/parse.ts +162 -1
- package/src/information-extractors/css/types.ts +43 -5
|
@@ -3,7 +3,14 @@ import { camelCase } from 'case-anything'
|
|
|
3
3
|
import { generate, lexer, parse, walk } from 'css-tree'
|
|
4
4
|
import type { Atrule, CssNode, Declaration, FunctionNode, Rule, Selector, Value } from 'css-tree'
|
|
5
5
|
import { stateNameFromModifier } from '../../utils/css-class'
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
CSSParserAPI,
|
|
8
|
+
CSSProperty,
|
|
9
|
+
CssDataType,
|
|
10
|
+
NativePseudoClass,
|
|
11
|
+
RegisteredCustomProperty,
|
|
12
|
+
StateClassRule,
|
|
13
|
+
} from './types'
|
|
7
14
|
|
|
8
15
|
type WalkContext = {
|
|
9
16
|
atrule?: Atrule | null
|
|
@@ -22,6 +29,7 @@ export function parseCss(cssString: string): CSSParserAPI {
|
|
|
22
29
|
const parsedSelectors = new Map<string, Selector>()
|
|
23
30
|
const { propertiesMap: allProperties, varUsagesByProperty } = parseAllProperties(cssString, parsedSelectors)
|
|
24
31
|
const stateClasses = parseStateClasses(cssString)
|
|
32
|
+
const registeredProperties = parseRegisteredProperties(cssString)
|
|
25
33
|
|
|
26
34
|
return {
|
|
27
35
|
getStateClasses(): StateClassRule[] {
|
|
@@ -77,6 +85,11 @@ export function parseCss(cssString: string): CSSParserAPI {
|
|
|
77
85
|
},
|
|
78
86
|
|
|
79
87
|
getVarPropertyType(varName: string, defaultValue: string): string | undefined {
|
|
88
|
+
// A `@property` registration is the declared type and wins over usage inference.
|
|
89
|
+
const normalizedVarName = varName.startsWith('--') ? varName : `--${varName}`
|
|
90
|
+
const registered = registeredProperties.get(normalizedVarName)
|
|
91
|
+
if (registered) return registered.cssPropertyType
|
|
92
|
+
|
|
80
93
|
const usages = this.getVarUsages(varName)
|
|
81
94
|
if (usages.length === 0) return undefined
|
|
82
95
|
const uniqueProperties = [...new Set(usages)]
|
|
@@ -87,6 +100,10 @@ export function parseCss(cssString: string): CSSParserAPI {
|
|
|
87
100
|
}
|
|
88
101
|
return inferCssDataType(defaultValue)
|
|
89
102
|
},
|
|
103
|
+
|
|
104
|
+
getRegisteredCustomProperties(): Map<string, RegisteredCustomProperty> {
|
|
105
|
+
return new Map(registeredProperties)
|
|
106
|
+
},
|
|
90
107
|
}
|
|
91
108
|
}
|
|
92
109
|
|
|
@@ -329,6 +346,150 @@ function extractVarNames(valueNode: CssNode): string[] {
|
|
|
329
346
|
return varNames
|
|
330
347
|
}
|
|
331
348
|
|
|
349
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
350
|
+
// @property at-rule parsing (CSS Properties and Values API)
|
|
351
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* A single `syntax` component (a CSS type reference) → manifest `cssPropertyType`.
|
|
355
|
+
*
|
|
356
|
+
* Only types with a matching schema `cssPropertyType` appear here. `<integer>` has no
|
|
357
|
+
* dedicated schema type, so it maps to `number`. Types with no schema equivalent —
|
|
358
|
+
* `<image>`, `<url>`, `<resolution>`, `<transform-function>`, `<transform-list>`,
|
|
359
|
+
* `<custom-ident>` — are deliberately absent; see {@link cssPropertyTypeFromSyntax}.
|
|
360
|
+
*/
|
|
361
|
+
const SYNTAX_TYPE_BY_COMPONENT: Record<string, CssDataType> = {
|
|
362
|
+
'<color>': CSS_PROPERTIES.CSS_DATA_TYPE.color,
|
|
363
|
+
'<number>': CSS_PROPERTIES.CSS_DATA_TYPE.number,
|
|
364
|
+
'<integer>': CSS_PROPERTIES.CSS_DATA_TYPE.number,
|
|
365
|
+
'<length>': CSS_PROPERTIES.CSS_DATA_TYPE.length,
|
|
366
|
+
'<percentage>': CSS_PROPERTIES.CSS_DATA_TYPE.percentage,
|
|
367
|
+
'<length-percentage>': CSS_PROPERTIES.CSS_DATA_TYPE.lengthPercentage,
|
|
368
|
+
'<angle>': CSS_PROPERTIES.CSS_DATA_TYPE.angle,
|
|
369
|
+
'<time>': CSS_PROPERTIES.CSS_DATA_TYPE.time,
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// A CSS custom-ident: a bare keyword (no `<...>` type reference), e.g. `space-between`.
|
|
373
|
+
const CUSTOM_IDENT_PATTERN = /^-?[A-Za-z_][\w-]*$/
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Derives the manifest type from a `@property` `syntax` descriptor, or `undefined`
|
|
377
|
+
* when the declared type has no matching schema `cssPropertyType` and the registration
|
|
378
|
+
* should be dropped rather than surfaced.
|
|
379
|
+
*
|
|
380
|
+
* Resolution order:
|
|
381
|
+
* - a pipe-separated ident list (≥2 bare keywords) → `customEnum` with its options;
|
|
382
|
+
* - otherwise the first recognized `<type>` component (list multipliers `+`/`#` stripped);
|
|
383
|
+
* - anything else — the universal `*`, a lone keyword, or an unsupported `<type>` such as
|
|
384
|
+
* `<image>` / `<url>` / `<resolution>` / `<transform-function>` / `<custom-ident>` —
|
|
385
|
+
* has no schema type, so returns `undefined` (dropped).
|
|
386
|
+
*/
|
|
387
|
+
function cssPropertyTypeFromSyntax(
|
|
388
|
+
rawSyntax: string,
|
|
389
|
+
): { cssPropertyType: CssDataType; enumOptions?: string[] } | undefined {
|
|
390
|
+
const { CSS_DATA_TYPE } = CSS_PROPERTIES
|
|
391
|
+
const syntax = rawSyntax
|
|
392
|
+
.trim()
|
|
393
|
+
.replace(/^["']|["']$/g, '')
|
|
394
|
+
.trim()
|
|
395
|
+
if (syntax === '' || syntax === '*') return undefined
|
|
396
|
+
|
|
397
|
+
const components = syntax
|
|
398
|
+
.split('|')
|
|
399
|
+
.map((component) => component.trim())
|
|
400
|
+
.filter((component) => component.length > 0)
|
|
401
|
+
|
|
402
|
+
const identComponents = components.filter((component) => CUSTOM_IDENT_PATTERN.test(component))
|
|
403
|
+
if (identComponents.length === components.length && components.length >= 2) {
|
|
404
|
+
return { cssPropertyType: CSS_DATA_TYPE.customEnum, enumOptions: components }
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
for (const component of components) {
|
|
408
|
+
const baseType = component.replace(/[+#]$/, '')
|
|
409
|
+
const mappedType = SYNTAX_TYPE_BY_COMPONENT[baseType]
|
|
410
|
+
if (mappedType) return { cssPropertyType: mappedType }
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return undefined
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Collects the descriptor declarations (`syntax`, `initial-value`) from a `@property`
|
|
418
|
+
* block. Re-parses the raw block text when css-tree yields a Raw block, so parsing
|
|
419
|
+
* doesn't depend on css-tree's at-rule support.
|
|
420
|
+
*/
|
|
421
|
+
function extractAtruleDescriptors(block: CssNode): Map<string, string> {
|
|
422
|
+
const descriptors = new Map<string, string>()
|
|
423
|
+
const declarations: Declaration[] = []
|
|
424
|
+
|
|
425
|
+
walk(block, {
|
|
426
|
+
visit: 'Declaration',
|
|
427
|
+
enter(declaration: Declaration) {
|
|
428
|
+
declarations.push(declaration)
|
|
429
|
+
},
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
if (declarations.length === 0) {
|
|
433
|
+
const innerText = generate(block)
|
|
434
|
+
.replace(/^\s*\{/, '')
|
|
435
|
+
.replace(/\}\s*$/, '')
|
|
436
|
+
try {
|
|
437
|
+
const parsedBlock = parse(innerText, { context: 'declarationList' })
|
|
438
|
+
walk(parsedBlock, {
|
|
439
|
+
visit: 'Declaration',
|
|
440
|
+
enter(declaration: Declaration) {
|
|
441
|
+
declarations.push(declaration)
|
|
442
|
+
},
|
|
443
|
+
})
|
|
444
|
+
} catch {
|
|
445
|
+
// Leave descriptors empty if the raw block can't be re-parsed.
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
for (const declaration of declarations) {
|
|
450
|
+
descriptors.set(declaration.property, generate(declaration.value).trim())
|
|
451
|
+
}
|
|
452
|
+
return descriptors
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Walks the stylesheet for `@property` at-rules and builds a map of registered custom
|
|
457
|
+
* properties keyed by the `--`-prefixed variable name.
|
|
458
|
+
*/
|
|
459
|
+
function parseRegisteredProperties(cssString: string): Map<string, RegisteredCustomProperty> {
|
|
460
|
+
const registered = new Map<string, RegisteredCustomProperty>()
|
|
461
|
+
|
|
462
|
+
try {
|
|
463
|
+
const ast = parse(cssString)
|
|
464
|
+
|
|
465
|
+
walk(ast, {
|
|
466
|
+
visit: 'Atrule',
|
|
467
|
+
enter(atrule: Atrule) {
|
|
468
|
+
if (atrule.name !== 'property' || !atrule.prelude || !atrule.block) return
|
|
469
|
+
|
|
470
|
+
const varName = generate(atrule.prelude).trim()
|
|
471
|
+
if (!varName.startsWith('--')) return
|
|
472
|
+
|
|
473
|
+
const descriptors = extractAtruleDescriptors(atrule.block)
|
|
474
|
+
const resolved = cssPropertyTypeFromSyntax(descriptors.get('syntax') ?? '*')
|
|
475
|
+
if (!resolved) return
|
|
476
|
+
const { cssPropertyType, enumOptions } = resolved
|
|
477
|
+
const initialValue = descriptors.get('initial-value')
|
|
478
|
+
|
|
479
|
+
registered.set(varName, {
|
|
480
|
+
cssPropertyType,
|
|
481
|
+
...(enumOptions && { enumOptions }),
|
|
482
|
+
...(initialValue !== undefined && { defaultValue: initialValue }),
|
|
483
|
+
})
|
|
484
|
+
},
|
|
485
|
+
})
|
|
486
|
+
} catch (error) {
|
|
487
|
+
console.error('CSS @property parsing error:', error)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return registered
|
|
491
|
+
}
|
|
492
|
+
|
|
332
493
|
// Native pseudo-classes mapped to their design-state key. `:focus-visible` and
|
|
333
494
|
// `:focus-within` both collapse to `focus` (the schema has a single focus state).
|
|
334
495
|
const NATIVE_PSEUDO_BY_NAME: Record<string, NativePseudoClass> = {
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import type { CSS_PROPERTIES } from '@wix/react-component-schema'
|
|
1
2
|
import type { CssNode } from 'css-tree'
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The subset of manifest `cssPropertyType` values a `@property` `syntax` can resolve to —
|
|
6
|
+
* the schema's CSS data types (`color`, `number`, `length`, …, `customEnum`). Derived from
|
|
7
|
+
* the schema so it stays in sync with `CssCustomPropertyItem['cssPropertyType']`.
|
|
8
|
+
*/
|
|
9
|
+
export type CssDataType = (typeof CSS_PROPERTIES.CSS_DATA_TYPE)[keyof typeof CSS_PROPERTIES.CSS_DATA_TYPE]
|
|
10
|
+
|
|
3
11
|
export interface CSSProperty {
|
|
4
12
|
name: string
|
|
5
13
|
value: string
|
|
@@ -20,6 +28,27 @@ export interface MatchedCssData {
|
|
|
20
28
|
customProperties: Record<string, string>
|
|
21
29
|
}
|
|
22
30
|
|
|
31
|
+
/**
|
|
32
|
+
* A CSS custom property registered via the standard `@property` at-rule.
|
|
33
|
+
* The `syntax` descriptor gives the type (and, for a pipe-separated ident list, a
|
|
34
|
+
* finite set of options); the `initial-value` descriptor gives the default. Unlike
|
|
35
|
+
* usage-inferred types, this is a declared source of truth and takes precedence.
|
|
36
|
+
*/
|
|
37
|
+
export interface RegisteredCustomProperty {
|
|
38
|
+
/**
|
|
39
|
+
* The manifest `cssPropertyType` derived from the `@property` `syntax` descriptor
|
|
40
|
+
* (e.g. `color`, `number`, `length`, or `customEnum` for a pipe-separated ident list).
|
|
41
|
+
*/
|
|
42
|
+
cssPropertyType: CssDataType
|
|
43
|
+
/** The default value from the `@property` `initial-value` descriptor, if declared. */
|
|
44
|
+
defaultValue?: string
|
|
45
|
+
/**
|
|
46
|
+
* The custom-ident options when `syntax` is a pipe-separated ident list
|
|
47
|
+
* (`a | b | c`). Present only when `cssPropertyType` is `customEnum`.
|
|
48
|
+
*/
|
|
49
|
+
enumOptions?: string[]
|
|
50
|
+
}
|
|
51
|
+
|
|
23
52
|
export type NativePseudoClass = 'hover' | 'focus' | 'disabled' | 'invalid'
|
|
24
53
|
|
|
25
54
|
/**
|
|
@@ -88,16 +117,25 @@ export interface CSSParserAPI {
|
|
|
88
117
|
getSelectorSpecificity: (selector: string) => [number, number, number] | null
|
|
89
118
|
|
|
90
119
|
/**
|
|
91
|
-
* Determines the CSS property type for a custom property
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
120
|
+
* Determines the CSS property type for a custom property.
|
|
121
|
+
* A `@property` registration is the top-priority source (declared type). Otherwise
|
|
122
|
+
* falls back to usage: if all usages of varName are within the same CSS property,
|
|
123
|
+
* returns that property name; if usages differ, returns the CSS data type inferred
|
|
124
|
+
* from the initial value ('color', 'length', 'number', or 'string').
|
|
125
|
+
* Returns undefined if the variable is neither registered nor used via var().
|
|
96
126
|
* @param varName - The CSS variable name (with or without --)
|
|
97
127
|
* @param defaultValue - The initial value string of the custom property
|
|
98
128
|
*/
|
|
99
129
|
getVarPropertyType: (varName: string, defaultValue: string) => string | undefined
|
|
100
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Returns every custom property registered via a `@property` at-rule, keyed by the
|
|
133
|
+
* variable name including its leading `--`. Each entry carries the type derived from
|
|
134
|
+
* `syntax`, the default from `initial-value`, and (for a pipe-separated ident list)
|
|
135
|
+
* the enum options.
|
|
136
|
+
*/
|
|
137
|
+
getRegisteredCustomProperties: () => Map<string, RegisteredCustomProperty>
|
|
138
|
+
|
|
101
139
|
/**
|
|
102
140
|
* Returns every `:global(.modifier)` design-state class found in the CSS, paired
|
|
103
141
|
* with any native pseudo-class on the same base element within the same rule.
|