@wix/zero-config-implementation 1.80.0 → 1.82.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 CHANGED
@@ -1,4 +1,4 @@
1
- import { B as t, D as e, E as o, I as n, N as c, P as l, R as i, a as p, V as E, b as m, c as x, d as f, e as d, f as u, h as C, i as I, j as k, k as y, l as A, m as D, n as P, o as R, p as h, q as B, r as M, s as T, t as b, w } from "./index-B8oF7hWg.js";
1
+ import { B as t, D as e, E as o, I as n, N as c, P as l, R as i, a as p, V as E, b as m, c as x, d as f, e as d, f as u, h as C, i as I, j as k, k as y, l as A, m as D, n as P, o as R, p as h, q as B, r as M, s as T, t as b, w } from "./index-tAvBvLbA.js";
2
2
  import "react";
3
3
  export {
4
4
  t as BaseError,
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "registry": "https://registry.npmjs.org/",
5
5
  "access": "public"
6
6
  },
7
- "version": "1.80.0",
7
+ "version": "1.82.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",
@@ -82,5 +82,5 @@
82
82
  ]
83
83
  }
84
84
  },
85
- "falconPackageHash": "9e634a5f6a97f802dcc3b2dbc92f56c3c9623790346ee5278ca65f03"
85
+ "falconPackageHash": "e0c2218f13619a2e924dab970b18c75b5745958f61951a3928964230"
86
86
  }
@@ -0,0 +1,2 @@
1
+ export const navigatorUserAgent = navigator.userAgent
2
+ export const elementPrototype = Element.prototype
@@ -0,0 +1,2 @@
1
+ export const navigatorUserAgent = navigator.userAgent
2
+ export const elementPrototype = Element.prototype
@@ -0,0 +1,2 @@
1
+ export const navigatorUserAgent = navigator.userAgent
2
+ export const elementPrototype = Element.prototype
@@ -0,0 +1,4 @@
1
+ void navigator.userAgent
2
+ void Element.prototype
3
+
4
+ throw new Error('browser-global fixture runtime failure')
@@ -54,6 +54,27 @@ function createComponent(rootElement: ExtractedElement): ComponentInfoWithCss {
54
54
  }
55
55
  }
56
56
 
57
+ function createSemanticElement({
58
+ traceId,
59
+ name,
60
+ className,
61
+ children = [],
62
+ }: {
63
+ traceId: string
64
+ name: string
65
+ className: string
66
+ children?: ExtractedElement[]
67
+ }): ExtractedElement {
68
+ return {
69
+ traceId,
70
+ name,
71
+ tag: 'div',
72
+ attributes: { class: className },
73
+ extractorData: new Map<string, unknown>(),
74
+ children,
75
+ }
76
+ }
77
+
57
78
  describe('toEditorReactComponent display conversion', () => {
58
79
  it('resolves local display fallback chains before emitting the manifest display value', () => {
59
80
  const rootElement = createElementWithDisplayMatcher(
@@ -85,6 +106,64 @@ describe('toEditorReactComponent display conversion', () => {
85
106
  },
86
107
  })
87
108
  })
109
+
110
+ it('omits the nearest matching ancestor class prefix from inner element display names', () => {
111
+ const rootElement = createSemanticElement({
112
+ traceId: 'trace-root',
113
+ name: 'root',
114
+ className: 'testimonials-slider',
115
+ children: [
116
+ createSemanticElement({
117
+ traceId: 'trace-play-pause-button',
118
+ name: 'playPauseButton',
119
+ className: 'play-pause-button',
120
+ }),
121
+ createSemanticElement({
122
+ traceId: 'trace-slide',
123
+ name: 'testimonialsSliderSlide',
124
+ className: 'testimonials-slider-slide',
125
+ children: [
126
+ createSemanticElement({
127
+ traceId: 'trace-quote',
128
+ name: 'testimonialsSliderQuote',
129
+ className: 'testimonials-slider-slide-quote',
130
+ }),
131
+ createSemanticElement({
132
+ traceId: 'trace-author',
133
+ name: 'testimonialsSliderAuthor',
134
+ className: 'testimonials-slider__author',
135
+ }),
136
+ ],
137
+ }),
138
+ ],
139
+ })
140
+
141
+ const elements = toEditorReactComponent({
142
+ ...createComponent(rootElement),
143
+ componentName: 'TestimonialsSlider',
144
+ }).editorElement?.elements
145
+
146
+ expect(elements?.playPauseButton?.inlineElement).toMatchObject({
147
+ selector: '.play-pause-button',
148
+ displayName: 'Play Pause Button',
149
+ })
150
+ expect(elements?.testimonialsSliderSlide?.inlineElement).toMatchObject({
151
+ selector: '.testimonials-slider-slide',
152
+ displayName: 'Slide',
153
+ })
154
+ expect(
155
+ elements?.testimonialsSliderSlide?.inlineElement?.elements?.testimonialsSliderQuote?.inlineElement,
156
+ ).toMatchObject({
157
+ selector: '.testimonials-slider-slide-quote',
158
+ displayName: 'Quote',
159
+ })
160
+ expect(
161
+ elements?.testimonialsSliderSlide?.inlineElement?.elements?.testimonialsSliderAuthor?.inlineElement,
162
+ ).toMatchObject({
163
+ selector: '.testimonials-slider__author',
164
+ displayName: 'Author',
165
+ })
166
+ })
88
167
  })
89
168
 
90
169
  function cssInfoFromStylesheet(cssString: string): ExtractedCssInfo {
@@ -75,6 +75,7 @@ function buildEditorElement(
75
75
  // class triggers don't (they carry the className verbatim and match the element
76
76
  // directly), so they're built even when the element resolves no semantic class.
77
77
  const rootSemanticClass = getSemanticBlockName(rootElement)
78
+ const rootSemanticClasses = rootSemanticClass ? [rootSemanticClass] : []
78
79
  const rootStates = rootElement
79
80
  ? mergeStates(
80
81
  rootSemanticClass ? buildStatesBlock(rootElement, rootSemanticClass) : undefined,
@@ -94,6 +95,7 @@ function buildEditorElement(
94
95
  childElements,
95
96
  nearestCommonAncestorCustomProps,
96
97
  customClassTriggers,
98
+ rootSemanticClasses,
97
99
  component.innerElementProps,
98
100
  component.propUsages,
99
101
  ),
@@ -116,6 +118,23 @@ function buildSelector(rootElement?: ExtractedElement): string {
116
118
  return rootElement?.tag ?? ''
117
119
  }
118
120
 
121
+ function buildInnerElementDisplayName(element: ExtractedElement, ancestorSemanticClasses: string[]): string {
122
+ const semanticClass = getSemanticBlockName(element)
123
+
124
+ if (semanticClass) {
125
+ for (const ancestorSemanticClass of [...ancestorSemanticClasses].reverse()) {
126
+ for (const separator of ['-', '__']) {
127
+ const ancestorPrefix = `${ancestorSemanticClass}${separator}`
128
+ if (semanticClass.startsWith(ancestorPrefix)) {
129
+ return formatDisplayName(semanticClass.slice(ancestorPrefix.length))
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ return formatDisplayName(element.name)
136
+ }
137
+
119
138
  function buildData(
120
139
  props: Record<string, CoupledProp>,
121
140
  propUsages: TrackingStores['propUsages'],
@@ -142,6 +161,7 @@ function buildElements(
142
161
  elements: ExtractedElement[],
143
162
  nearestCommonAncestorCustomProps: Map<string, Record<string, CssCustomPropertyItem>>,
144
163
  customClassTriggers: CustomClassTrigger[],
164
+ ancestorSemanticClasses: string[],
145
165
  innerElementProps?: CoupledComponentInfo['innerElementProps'],
146
166
  propUsages?: TrackingStores['propUsages'],
147
167
  parentElementPropsPath?: string,
@@ -180,7 +200,7 @@ function buildElements(
180
200
  elementType: ELEMENTS.ELEMENT_TYPE.inlineElement,
181
201
  inlineElement: {
182
202
  selector: buildSelector(element),
183
- displayName: formatDisplayName(element.name),
203
+ displayName: buildInnerElementDisplayName(element, ancestorSemanticClasses),
184
204
  behaviors: { removable: true, selectable: false },
185
205
  // Add data from inner element props if available
186
206
  ...(data && Object.keys(data).length > 0 && { data }),
@@ -196,6 +216,7 @@ function buildElements(
196
216
  element.children,
197
217
  nearestCommonAncestorCustomProps,
198
218
  customClassTriggers,
219
+ semanticClass ? [...ancestorSemanticClasses, semanticClass] : ancestorSemanticClasses,
199
220
  innerElementProps,
200
221
  propUsages,
201
222
  innerEntry?.elementPropsPath ?? parentElementPropsPath,
@@ -8,7 +8,170 @@ import { readLoaderPortRefStateForTests, readRegisteredRefElementModuleUrlsForTe
8
8
 
9
9
  const require = createRequire(import.meta.url)
10
10
 
11
+ const extractionGlobalPropertyNames = [
12
+ 'window',
13
+ 'document',
14
+ 'HTMLElement',
15
+ 'Element',
16
+ 'navigator',
17
+ 'customElements',
18
+ 'IntersectionObserver',
19
+ 'React',
20
+ 'ReactDOM',
21
+ ] as const
22
+
23
+ type ExtractionGlobalPropertyName = (typeof extractionGlobalPropertyNames)[number]
24
+
25
+ function snapshotExtractionGlobalDescriptors(): Map<ExtractionGlobalPropertyName, PropertyDescriptor | undefined> {
26
+ return new Map(
27
+ extractionGlobalPropertyNames.map((propertyName) => [
28
+ propertyName,
29
+ Object.getOwnPropertyDescriptor(globalThis, propertyName),
30
+ ]),
31
+ )
32
+ }
33
+
34
+ function clearExtractionGlobals(): void {
35
+ for (const propertyName of extractionGlobalPropertyNames) {
36
+ Reflect.deleteProperty(globalThis, propertyName)
37
+ }
38
+ }
39
+
40
+ function restoreExtractionGlobalDescriptors(
41
+ originalDescriptors: Map<ExtractionGlobalPropertyName, PropertyDescriptor | undefined>,
42
+ ): void {
43
+ clearExtractionGlobals()
44
+ for (const [propertyName, propertyDescriptor] of originalDescriptors) {
45
+ if (propertyDescriptor !== undefined) {
46
+ Object.defineProperty(globalThis, propertyName, propertyDescriptor)
47
+ }
48
+ }
49
+ }
50
+
11
51
  describe('module loading', () => {
52
+ it('loads an ESM entry that reads navigator and Element during module evaluation', async () => {
53
+ const originalDescriptors = snapshotExtractionGlobalDescriptors()
54
+ clearExtractionGlobals()
55
+
56
+ try {
57
+ const entryPath = path.resolve(__dirname, '__fixtures__/esm-browser-globals-entry.mjs')
58
+ const loadedModuleResult = await loadModuleForExtraction(entryPath)
59
+ const loadedModule = loadedModuleResult._unsafeUnwrap()
60
+ const globals = globalThis as Record<string, unknown>
61
+ const configuredWindow = globals.window as Record<string, unknown>
62
+
63
+ expect(loadedModule.moduleExports.navigatorUserAgent).toBe(
64
+ (configuredWindow.navigator as { userAgent: string }).userAgent,
65
+ )
66
+ expect(loadedModule.moduleExports.elementPrototype).toBe(
67
+ (configuredWindow.Element as { prototype: unknown }).prototype,
68
+ )
69
+ expect(globals.navigator).toBe(configuredWindow.navigator)
70
+ expect(globals.Element).toBe(configuredWindow.Element)
71
+
72
+ await loadedModule.cleanup()
73
+ } finally {
74
+ restoreExtractionGlobalDescriptors(originalDescriptors)
75
+ }
76
+ })
77
+
78
+ it('preserves caller-provided navigator and Element globals', async () => {
79
+ const originalDescriptors = snapshotExtractionGlobalDescriptors()
80
+ clearExtractionGlobals()
81
+
82
+ const callerNavigator = { userAgent: 'caller-provided navigator' }
83
+ class CallerProvidedElement {}
84
+
85
+ try {
86
+ Object.defineProperty(globalThis, 'navigator', {
87
+ configurable: true,
88
+ value: callerNavigator,
89
+ writable: true,
90
+ })
91
+ Object.defineProperty(globalThis, 'Element', {
92
+ configurable: true,
93
+ value: CallerProvidedElement,
94
+ writable: true,
95
+ })
96
+
97
+ const entryPath = path.resolve(__dirname, '__fixtures__/esm-browser-globals-preservation-entry.mjs')
98
+ const loadedModuleResult = await loadModuleForExtraction(entryPath)
99
+ const loadedModule = loadedModuleResult._unsafeUnwrap()
100
+ const globals = globalThis as Record<string, unknown>
101
+
102
+ expect(globals.navigator).toBe(callerNavigator)
103
+ expect(globals.Element).toBe(CallerProvidedElement)
104
+ expect(loadedModule.moduleExports.elementPrototype).toBe(CallerProvidedElement.prototype)
105
+
106
+ await loadedModule.cleanup()
107
+ } finally {
108
+ restoreExtractionGlobalDescriptors(originalDescriptors)
109
+ }
110
+ })
111
+
112
+ it('preserves an existing navigator while adding a missing Element global', async () => {
113
+ const originalDescriptors = snapshotExtractionGlobalDescriptors()
114
+ clearExtractionGlobals()
115
+
116
+ const existingNavigator = { userAgent: 'existing Node navigator' }
117
+
118
+ try {
119
+ Object.defineProperty(globalThis, 'navigator', {
120
+ configurable: true,
121
+ value: existingNavigator,
122
+ writable: true,
123
+ })
124
+
125
+ const entryPath = path.resolve(__dirname, '__fixtures__/esm-browser-globals-existing-navigator-entry.mjs')
126
+ const loadedModuleResult = await loadModuleForExtraction(entryPath)
127
+ const loadedModule = loadedModuleResult._unsafeUnwrap()
128
+ const globals = globalThis as Record<string, unknown>
129
+ const configuredWindow = globals.window as Record<string, unknown>
130
+
131
+ expect(loadedModule.moduleExports.navigatorUserAgent).toBe(existingNavigator.userAgent)
132
+ expect(loadedModule.moduleExports.elementPrototype).toBe(
133
+ (configuredWindow.Element as { prototype: unknown }).prototype,
134
+ )
135
+ expect(globals.navigator).toBe(existingNavigator)
136
+ expect(globals.Element).toBe(configuredWindow.Element)
137
+
138
+ await loadedModule.cleanup()
139
+ } finally {
140
+ restoreExtractionGlobalDescriptors(originalDescriptors)
141
+ }
142
+ })
143
+
144
+ it('keeps unrelated module-evaluation failures visible after browser-global setup', async () => {
145
+ const originalDescriptors = snapshotExtractionGlobalDescriptors()
146
+ clearExtractionGlobals()
147
+
148
+ const callerNavigator = { userAgent: 'caller-provided navigator' }
149
+ class CallerProvidedElement {}
150
+
151
+ try {
152
+ Object.defineProperty(globalThis, 'navigator', {
153
+ configurable: true,
154
+ value: callerNavigator,
155
+ writable: true,
156
+ })
157
+ Object.defineProperty(globalThis, 'Element', {
158
+ configurable: true,
159
+ value: CallerProvidedElement,
160
+ writable: true,
161
+ })
162
+
163
+ const entryPath = path.resolve(__dirname, '__fixtures__/esm-browser-globals-runtime-error-entry.mjs')
164
+ const loadedModuleResult = await loadModuleForExtraction(entryPath)
165
+
166
+ expect(loadedModuleResult.isErr()).toBe(true)
167
+ if (loadedModuleResult.isErr()) {
168
+ expect(loadedModuleResult.error.esmError?.message).toContain('browser-global fixture runtime failure')
169
+ }
170
+ } finally {
171
+ restoreExtractionGlobalDescriptors(originalDescriptors)
172
+ }
173
+ })
174
+
12
175
  it('temporarily tags ref-element modules in the CJS fallback and cleans them up afterwards', async () => {
13
176
  const entryPath = path.resolve(__dirname, '__fixtures__/cjs-ref-element-entry.cjs')
14
177
  const targetPath = path.resolve(__dirname, '__fixtures__/cjs-ref-element-target.cjs')
@@ -44,6 +44,8 @@ function setupWindowGlobals(): void {
44
44
  }
45
45
 
46
46
  const windowObj = globals.window as Record<string, unknown>
47
+ if (globals.navigator === undefined) globals.navigator = windowObj.navigator
48
+ if (globals.Element === undefined) globals.Element = windowObj.Element
47
49
  const intersectionObserver = windowObj.IntersectionObserver ?? NoopIntersectionObserver
48
50
  if (globals.IntersectionObserver === undefined) globals.IntersectionObserver = intersectionObserver
49
51
  if (windowObj.IntersectionObserver === undefined) windowObj.IntersectionObserver = intersectionObserver