@wix/zero-config-implementation 1.102.0 → 1.103.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.js +5265 -5239
- package/package.json +2 -2
- package/src/converters/css-longhand-resolver.test.ts +27 -0
- package/src/converters/css-longhand-resolver.ts +8 -2
- package/src/information-extractors/react/extractors/css-properties.test.ts +69 -0
- package/src/information-extractors/react/extractors/css-properties.ts +59 -7
- package/src/information-extractors/react/extractors/index.ts +1 -0
- package/src/information-extractors/react/index.ts +1 -0
- package/src/manifest-pipeline.ts +3 -1
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"registry": "https://registry.npmjs.org/",
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.103.0",
|
|
8
8
|
"description": "Core library for extracting component manifests from JS and CSS files",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"main": "dist/index.js",
|
|
@@ -106,5 +106,5 @@
|
|
|
106
106
|
]
|
|
107
107
|
}
|
|
108
108
|
},
|
|
109
|
-
"falconPackageHash": "
|
|
109
|
+
"falconPackageHash": "37bdab4bfdcda072c3c9d9edbfc88017a9270a42765e4b943aa0f51b"
|
|
110
110
|
}
|
|
@@ -393,4 +393,31 @@ describe('resolveLonghand', () => {
|
|
|
393
393
|
expect(resolveLonghand('textDecorationLine', values)).toBe('overline')
|
|
394
394
|
})
|
|
395
395
|
})
|
|
396
|
+
|
|
397
|
+
describe('flexDirection extraction from flex-flow shorthand', () => {
|
|
398
|
+
it('extracts the lone direction keyword', () => {
|
|
399
|
+
expect(resolveLonghand('flexDirection', new Map([['flexFlow', 'column']]))).toBe('column')
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
it('ignores token order — direction keyword can appear anywhere', () => {
|
|
403
|
+
expect(resolveLonghand('flexDirection', new Map([['flexFlow', 'wrap column-reverse']]))).toBe('column-reverse')
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
it('defaults to row when the shorthand carries only a wrap keyword', () => {
|
|
407
|
+
expect(resolveLonghand('flexDirection', new Map([['flexFlow', 'wrap']]))).toBe('row')
|
|
408
|
+
expect(resolveLonghand('flexDirection', new Map([['flexFlow', 'nowrap']]))).toBe('row')
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
it('returns undefined when flexFlow is absent', () => {
|
|
412
|
+
expect(resolveLonghand('flexDirection', new Map())).toBeUndefined()
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
it('prefers literal flexDirection over extracting from shorthand', () => {
|
|
416
|
+
const values = new Map([
|
|
417
|
+
['flexDirection', 'row-reverse'],
|
|
418
|
+
['flexFlow', 'column wrap'],
|
|
419
|
+
])
|
|
420
|
+
expect(resolveLonghand('flexDirection', values)).toBe('row-reverse')
|
|
421
|
+
})
|
|
422
|
+
})
|
|
396
423
|
})
|
|
@@ -217,14 +217,20 @@ const fromTextDecorationLine: Fallback = (values) => {
|
|
|
217
217
|
|
|
218
218
|
/**
|
|
219
219
|
* `flex-flow: <flex-direction> || <flex-wrap>` — order is free and either
|
|
220
|
-
* part may be omitted. Pick out
|
|
220
|
+
* part may be omitted. Pick out the direction keyword for the schema, or the
|
|
221
|
+
* spec's default (`row`) when the developer only wrote a wrap keyword, e.g.
|
|
222
|
+
* `flex-flow: wrap`.
|
|
221
223
|
*/
|
|
222
224
|
const FLEX_DIRECTION_KEYWORDS = new Set(['row', 'row-reverse', 'column', 'column-reverse'])
|
|
225
|
+
const DEFAULT_FLEX_DIRECTION = 'row'
|
|
223
226
|
|
|
224
227
|
const fromFlexFlowDirection: Fallback = (values) => {
|
|
225
228
|
const shorthand = values.get('flexFlow')
|
|
226
229
|
if (shorthand === undefined) return undefined
|
|
227
|
-
|
|
230
|
+
const directionToken = splitTopLevelTokens(shorthand).find((token) =>
|
|
231
|
+
FLEX_DIRECTION_KEYWORDS.has(token.toLowerCase()),
|
|
232
|
+
)
|
|
233
|
+
return directionToken ?? DEFAULT_FLEX_DIRECTION
|
|
228
234
|
}
|
|
229
235
|
|
|
230
236
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -6,6 +6,7 @@ import type { ExtractedElement } from './core/tree-builder'
|
|
|
6
6
|
import {
|
|
7
7
|
enrichContainerProperties,
|
|
8
8
|
enrichFlexProperties,
|
|
9
|
+
enrichMarginProperties,
|
|
9
10
|
getCssPropertiesForTag,
|
|
10
11
|
getDefaultDisplayForTag,
|
|
11
12
|
hasContainerLikeDisplay,
|
|
@@ -541,3 +542,71 @@ describe('enrichContainerProperties', () => {
|
|
|
541
542
|
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.paddingTop)
|
|
542
543
|
})
|
|
543
544
|
})
|
|
545
|
+
|
|
546
|
+
describe('enrichMarginProperties', () => {
|
|
547
|
+
it('adds the block-axis margins to a non-replaced inline element whose matched CSS changes display to block', () => {
|
|
548
|
+
const elements = [createElementWithCssProperties('span', 'display: block')]
|
|
549
|
+
|
|
550
|
+
const [enrichedElement] = enrichMarginProperties(elements)
|
|
551
|
+
const cssData = enrichedElement.extractorData.get('css-properties') as { relevant: string[] }
|
|
552
|
+
|
|
553
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginTop)
|
|
554
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginBottom)
|
|
555
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginInlineStart)
|
|
556
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginInlineEnd)
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
it('adds the full margin family to a non-replaced inline element whose matched CSS changes display to inline-flex', () => {
|
|
560
|
+
const elements = [createElementWithCssProperties('span', 'display: inline-flex')]
|
|
561
|
+
|
|
562
|
+
const [enrichedElement] = enrichMarginProperties(elements)
|
|
563
|
+
const cssData = enrichedElement.extractorData.get('css-properties') as { relevant: string[] }
|
|
564
|
+
|
|
565
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginTop)
|
|
566
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginBottom)
|
|
567
|
+
})
|
|
568
|
+
|
|
569
|
+
it('keeps only the horizontal margins when a span stays inline', () => {
|
|
570
|
+
const elements = [createElementWithCssProperties('span', 'display: inline')]
|
|
571
|
+
|
|
572
|
+
const [enrichedElement] = enrichMarginProperties(elements)
|
|
573
|
+
const cssData = enrichedElement.extractorData.get('css-properties') as { relevant: string[] }
|
|
574
|
+
|
|
575
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginInlineStart)
|
|
576
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginInlineEnd)
|
|
577
|
+
expect(cssData.relevant).not.toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginTop)
|
|
578
|
+
expect(cssData.relevant).not.toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginBottom)
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
it('removes all margin from an element whose matched CSS changes display to an internal table value', () => {
|
|
582
|
+
const elements = [createElementWithCssProperties('div', 'display: table-cell')]
|
|
583
|
+
|
|
584
|
+
const [enrichedElement] = enrichMarginProperties(elements)
|
|
585
|
+
const cssData = enrichedElement.extractorData.get('css-properties') as { relevant: string[] }
|
|
586
|
+
|
|
587
|
+
expect(cssData.relevant).not.toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginTop)
|
|
588
|
+
expect(cssData.relevant).not.toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginBottom)
|
|
589
|
+
expect(cssData.relevant).not.toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginInlineStart)
|
|
590
|
+
expect(cssData.relevant).not.toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginInlineEnd)
|
|
591
|
+
})
|
|
592
|
+
|
|
593
|
+
it('leaves the tag-default margin guess alone when no CSS declares display', () => {
|
|
594
|
+
const elements = [createElementWithCssProperties('span', '')]
|
|
595
|
+
|
|
596
|
+
const [enrichedElement] = enrichMarginProperties(elements)
|
|
597
|
+
const cssData = enrichedElement.extractorData.get('css-properties') as { relevant: string[] }
|
|
598
|
+
|
|
599
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginInlineStart)
|
|
600
|
+
expect(cssData.relevant).not.toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginTop)
|
|
601
|
+
})
|
|
602
|
+
|
|
603
|
+
it('corrects margin via the --display root convention, not just a literal display declaration', () => {
|
|
604
|
+
const elements = [createElementWithCssProperties('span', '--display: block')]
|
|
605
|
+
|
|
606
|
+
const [enrichedElement] = enrichMarginProperties(elements)
|
|
607
|
+
const cssData = enrichedElement.extractorData.get('css-properties') as { relevant: string[] }
|
|
608
|
+
|
|
609
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginTop)
|
|
610
|
+
expect(cssData.relevant).toContain(CSS_PROPERTIES.CSS_PROPERTY_TYPE.marginBottom)
|
|
611
|
+
})
|
|
612
|
+
})
|
|
@@ -135,26 +135,35 @@ const MARGIN_UNSUPPORTED_DISPLAY_VALUES = new Set([
|
|
|
135
135
|
])
|
|
136
136
|
|
|
137
137
|
/**
|
|
138
|
-
* Margin properties relevant to a
|
|
138
|
+
* Margin properties relevant to a given `display` value. Internal table
|
|
139
139
|
* display values (`tr`, `thead`/`tbody`/`tfoot`, `col`/`colgroup`, `td`/`th`)
|
|
140
140
|
* don't honor margin at all. Non-replaced inline elements (`span`, `a`, …)
|
|
141
141
|
* only honor the horizontal (inline) margins — `margin-top`/`margin-bottom`
|
|
142
142
|
* have no effect on them. Replaced inline elements (`img`, `video`, …) honor
|
|
143
143
|
* margin on every side, same as a block box.
|
|
144
144
|
*/
|
|
145
|
-
function
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (MARGIN_UNSUPPORTED_DISPLAY_VALUES.has(defaultDisplay)) {
|
|
145
|
+
function getMarginPropertiesForDisplay(displayValue: string, isReplacedElement: boolean): string[] {
|
|
146
|
+
const normalizedDisplayValue = normalizeDisplayValue(displayValue)
|
|
147
|
+
if (MARGIN_UNSUPPORTED_DISPLAY_VALUES.has(normalizedDisplayValue)) {
|
|
150
148
|
return []
|
|
151
149
|
}
|
|
152
|
-
if (
|
|
150
|
+
if (normalizedDisplayValue === 'inline' && !isReplacedElement) {
|
|
153
151
|
return HORIZONTAL_MARGIN_CSS_PROPERTIES
|
|
154
152
|
}
|
|
155
153
|
return MARGIN_CSS_PROPERTIES
|
|
156
154
|
}
|
|
157
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Margin properties relevant to a tag's default display, used as the
|
|
158
|
+
* best-effort guess at element creation time, before CSS matching has run.
|
|
159
|
+
* `enrichMarginProperties` corrects this once the effective display —
|
|
160
|
+
* matched CSS, including the `--display` root convention — is known.
|
|
161
|
+
*/
|
|
162
|
+
function getMarginPropertiesForTag(tag: string): string[] {
|
|
163
|
+
const normalizedTag = tag.toLowerCase()
|
|
164
|
+
return getMarginPropertiesForDisplay(getDefaultDisplayForTag(normalizedTag), MEDIA_TAGS.has(normalizedTag))
|
|
165
|
+
}
|
|
166
|
+
|
|
158
167
|
/**
|
|
159
168
|
* Child-layout controls for flex/grid containers, added post-hoc by
|
|
160
169
|
* `enrichFlexProperties` once the element's resolved `display` is known.
|
|
@@ -654,6 +663,49 @@ export function enrichContainerProperties(elements: ExtractedElement[]): Extract
|
|
|
654
663
|
})
|
|
655
664
|
}
|
|
656
665
|
|
|
666
|
+
/**
|
|
667
|
+
* Replaces whatever margin properties are currently in `existing` with the
|
|
668
|
+
* ones relevant to `marginProperties` — used by `enrichMarginProperties` to
|
|
669
|
+
* correct the tag-default guess once the effective display is known.
|
|
670
|
+
*/
|
|
671
|
+
function withMarginProperties(existing: string[], marginProperties: string[]): string[] {
|
|
672
|
+
const withoutMargin = existing.filter((property) => !(MARGIN_CSS_PROPERTIES as string[]).includes(property))
|
|
673
|
+
return [...withoutMargin, ...marginProperties]
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Walks the element tree and corrects margin properties from the tag-default
|
|
678
|
+
* guess made at creation time to the element's effective display — matched
|
|
679
|
+
* CSS, including the `--display` root convention. A non-replaced inline
|
|
680
|
+
* element (e.g. `<span>`) whose matched CSS changes display to `block` or
|
|
681
|
+
* `flex` gains the block-axis margins it was missing; conversely, an element
|
|
682
|
+
* whose effective display becomes an internal table value loses margin
|
|
683
|
+
* entirely. Must be called after CSS selector matching (requires
|
|
684
|
+
* css-matcher data).
|
|
685
|
+
*/
|
|
686
|
+
export function enrichMarginProperties(elements: ExtractedElement[]): ExtractedElement[] {
|
|
687
|
+
return elements.map((element) => {
|
|
688
|
+
const matcherData = element.extractorData.get('css-matcher') as MatchedCssData | undefined
|
|
689
|
+
const cssData = element.extractorData.get('css-properties') as CssPropertiesData | undefined
|
|
690
|
+
|
|
691
|
+
if (cssData && matcherData && hasEffectiveDisplayDeclaration(matcherData)) {
|
|
692
|
+
const effectiveDisplay = resolveEffectiveDisplayValue(matcherData)
|
|
693
|
+
if (effectiveDisplay !== undefined) {
|
|
694
|
+
const isReplacedElement = MEDIA_TAGS.has(element.tag.toLowerCase())
|
|
695
|
+
const marginProperties = getMarginPropertiesForDisplay(effectiveDisplay, isReplacedElement)
|
|
696
|
+
element.extractorData.set('css-properties', {
|
|
697
|
+
relevant: withMarginProperties(cssData.relevant, marginProperties),
|
|
698
|
+
})
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return {
|
|
703
|
+
...element,
|
|
704
|
+
children: enrichMarginProperties(element.children),
|
|
705
|
+
}
|
|
706
|
+
})
|
|
707
|
+
}
|
|
708
|
+
|
|
657
709
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
658
710
|
// Factory
|
|
659
711
|
// ─────────────────────────────────────────────────────────────────────────────
|
package/src/manifest-pipeline.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
enrichContainerProperties,
|
|
13
13
|
enrichFlexProperties,
|
|
14
14
|
enrichGapProperties,
|
|
15
|
+
enrichMarginProperties,
|
|
15
16
|
runExtractors,
|
|
16
17
|
} from './information-extractors/react'
|
|
17
18
|
import type { CoupledComponentInfo, CoupledProp, DOMBinding, TrackingStores } from './information-extractors/react'
|
|
@@ -150,7 +151,8 @@ export function processComponent(
|
|
|
150
151
|
if (html && extractedElements.length > 0 && css.length > 0) {
|
|
151
152
|
try {
|
|
152
153
|
const matchResult = matchCssSelectors(html, extractedElements, css)
|
|
153
|
-
const
|
|
154
|
+
const marginEnrichedElements = enrichMarginProperties(matchResult.elements)
|
|
155
|
+
const containerEnrichedElements = enrichContainerProperties(marginEnrichedElements)
|
|
154
156
|
const gapEnrichedElements = enrichGapProperties(containerEnrichedElements)
|
|
155
157
|
const flexEnrichedElements = enrichFlexProperties(gapEnrichedElements)
|
|
156
158
|
enhancedInfo = {
|