@wix/zero-config-implementation 1.101.0 → 1.102.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
@@ -82737,10 +82737,10 @@ ${n}`, {
82737
82737
  props: { phase: "conversion" }
82738
82738
  });
82739
82739
  }
82740
- function xL(t, e) {
82740
+ function xL(t, e, r = /* @__PURE__ */ new Set()) {
82741
82741
  return [
82742
82742
  ...Ame(t.cssCustomProperties, e),
82743
- ...Eme(t.elements, e)
82743
+ ...Eme(t.elements, e, r)
82744
82744
  ];
82745
82745
  }
82746
82746
  function Ame(t, e) {
@@ -82752,14 +82752,19 @@ function Ame(t, e) {
82752
82752
  }
82753
82753
  return r;
82754
82754
  }
82755
- function Eme(t, e) {
82755
+ function Eme(t, e, r = /* @__PURE__ */ new Set()) {
82756
82756
  if (!t) return [];
82757
- const r = [];
82758
- for (const [n, i] of Object.entries(t)) {
82759
- const s = `${e}.elements.${n}`, a = gy.ELEMENT_TYPE.UNKNOWN_ElementType;
82760
- (!i.elementType || i.elementType === a) && r.push(`${s}: elementType is not set or UNKNOWN`), i.inlineElement && r.push(...xL(i.inlineElement, `${s}.inlineElement`));
82757
+ const n = [];
82758
+ for (const [i, s] of Object.entries(t)) {
82759
+ const a = `${e}.elements.${i}`, o = gy.ELEMENT_TYPE.UNKNOWN_ElementType;
82760
+ if ((!s.elementType || s.elementType === o) && n.push(`${a}: elementType is not set or UNKNOWN`), r.has(i) && n.push(`${a}: part name "${i}" is already used by an ancestor element`), s.inlineElement) {
82761
+ const u = new Set(r);
82762
+ u.add(i), n.push(
82763
+ ...xL(s.inlineElement, `${a}.inlineElement`, u)
82764
+ );
82765
+ }
82761
82766
  }
82762
- return r;
82767
+ return n;
82763
82768
  }
82764
82769
  const Fme = Ire;
82765
82770
  function Sme(t, e, r) {
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "registry": "https://registry.npmjs.org/",
5
5
  "access": "public"
6
6
  },
7
- "version": "1.101.0",
7
+ "version": "1.102.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": "7aa5841bf5ff6a0fa0800fc3d71a267d6e96dbe084125f5fd56fc333"
109
+ "falconPackageHash": "96d9e739c8567fd3813b698d6e9d84d175e3def2393dbaec37e6a9e7"
110
110
  }
@@ -139,4 +139,95 @@ describe('validateEditorElement', () => {
139
139
  })
140
140
  expect(() => validateEditorElement(editorElement, 'MyButton')).toThrow('MyButton')
141
141
  })
142
+
143
+ it('throws ValidationError when a part name is reused on a direct child element', () => {
144
+ const editorElement = buildMinimalEditorElement({
145
+ elements: {
146
+ element1: buildInlineElementItem({
147
+ inlineElement: {
148
+ selector: '.element1',
149
+ displayName: 'Element1',
150
+ elements: {
151
+ element1: buildInlineElementItem(),
152
+ },
153
+ },
154
+ }),
155
+ },
156
+ })
157
+ expect(() => validateEditorElement(editorElement, 'TestComponent')).toThrow(
158
+ 'editorElement.elements.element1.inlineElement.elements.element1: part name "element1" is already used by an ancestor element',
159
+ )
160
+ })
161
+
162
+ it('throws ValidationError when a part name is reused on a grandchild, not just a direct child', () => {
163
+ const editorElement = buildMinimalEditorElement({
164
+ elements: {
165
+ outer: buildInlineElementItem({
166
+ inlineElement: {
167
+ selector: '.outer',
168
+ displayName: 'Outer',
169
+ elements: {
170
+ middle: buildInlineElementItem({
171
+ inlineElement: {
172
+ selector: '.middle',
173
+ displayName: 'Middle',
174
+ elements: {
175
+ outer: buildInlineElementItem(),
176
+ },
177
+ },
178
+ }),
179
+ },
180
+ },
181
+ }),
182
+ },
183
+ })
184
+ expect(() => validateEditorElement(editorElement, 'TestComponent')).toThrow(
185
+ 'editorElement.elements.outer.inlineElement.elements.middle.inlineElement.elements.outer: part name "outer" is already used by an ancestor element',
186
+ )
187
+ })
188
+
189
+ it('does not throw when the same part name is reused across unrelated sibling subtrees', () => {
190
+ const editorElement = buildMinimalEditorElement({
191
+ elements: {
192
+ left: buildInlineElementItem({
193
+ inlineElement: {
194
+ selector: '.left',
195
+ displayName: 'Left',
196
+ elements: { shared: buildInlineElementItem() },
197
+ },
198
+ }),
199
+ right: buildInlineElementItem({
200
+ inlineElement: {
201
+ selector: '.right',
202
+ displayName: 'Right',
203
+ elements: { shared: buildInlineElementItem() },
204
+ },
205
+ }),
206
+ },
207
+ })
208
+ expect(() => validateEditorElement(editorElement, 'TestComponent')).not.toThrow()
209
+ })
210
+
211
+ it('does not throw for a deeply nested tree with all-unique part names', () => {
212
+ const editorElement = buildMinimalEditorElement({
213
+ elements: {
214
+ outer: buildInlineElementItem({
215
+ inlineElement: {
216
+ selector: '.outer',
217
+ displayName: 'Outer',
218
+ elements: {
219
+ middle: buildInlineElementItem({
220
+ inlineElement: {
221
+ selector: '.middle',
222
+ displayName: 'Middle',
223
+ elements: { inner: buildInlineElementItem() },
224
+ },
225
+ }),
226
+ },
227
+ },
228
+ }),
229
+ },
230
+ })
231
+ expect(() => validateEditorElement(editorElement, 'TestComponent')).not.toThrow()
232
+ })
142
233
  })
@@ -21,10 +21,14 @@ export function validateEditorElement(editorElement: RawEditorElement, component
21
21
  })
22
22
  }
23
23
 
24
- function collectElementViolations(element: AnyElement, elementPath: string): string[] {
24
+ function collectElementViolations(
25
+ element: AnyElement,
26
+ elementPath: string,
27
+ ancestorNames: ReadonlySet<string> = new Set(),
28
+ ): string[] {
25
29
  return [
26
30
  ...validateCssCustomProperties(element.cssCustomProperties, elementPath),
27
- ...validateElementsMap(element.elements, elementPath),
31
+ ...validateElementsMap(element.elements, elementPath, ancestorNames),
28
32
  ]
29
33
  }
30
34
 
@@ -44,7 +48,11 @@ function validateCssCustomProperties(
44
48
  return violations
45
49
  }
46
50
 
47
- function validateElementsMap(elements: Record<string, ElementItem> | undefined, elementPath: string): string[] {
51
+ function validateElementsMap(
52
+ elements: Record<string, ElementItem> | undefined,
53
+ elementPath: string,
54
+ ancestorNames: ReadonlySet<string> = new Set(),
55
+ ): string[] {
48
56
  if (!elements) return []
49
57
 
50
58
  const violations: string[] = []
@@ -56,8 +64,16 @@ function validateElementsMap(elements: Record<string, ElementItem> | undefined,
56
64
  violations.push(`${itemPath}: elementType is not set or UNKNOWN`)
57
65
  }
58
66
 
67
+ if (ancestorNames.has(elementKey)) {
68
+ violations.push(`${itemPath}: part name "${elementKey}" is already used by an ancestor element`)
69
+ }
70
+
59
71
  if (elementItem.inlineElement) {
60
- violations.push(...collectElementViolations(elementItem.inlineElement, `${itemPath}.inlineElement`))
72
+ const descendantAncestorNames = new Set(ancestorNames)
73
+ descendantAncestorNames.add(elementKey)
74
+ violations.push(
75
+ ...collectElementViolations(elementItem.inlineElement, `${itemPath}.inlineElement`, descendantAncestorNames),
76
+ )
61
77
  }
62
78
  }
63
79
  return violations