@wix/zero-config-implementation 1.30.0 → 1.31.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/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "registry": "https://registry.npmjs.org/",
5
5
  "access": "public"
6
6
  },
7
- "version": "1.30.0",
7
+ "version": "1.31.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",
@@ -83,5 +83,5 @@
83
83
  ]
84
84
  }
85
85
  },
86
- "falconPackageHash": "7c40209d1126d0b860d10bc39a13660c52b5a97620afd671085c8c41"
86
+ "falconPackageHash": "47671a9f6b5bba6b6a6a93ccf874198731eefd39404baf528141978b"
87
87
  }
@@ -5,7 +5,7 @@
5
5
  * Each element gets a semantic name computed by concatenating ancestor names.
6
6
  */
7
7
 
8
- import { pascalCase } from 'case-anything'
8
+ import { camelCase, pascalCase } from 'case-anything'
9
9
  import { type DefaultTreeAdapterMap, parseFragment } from 'parse5'
10
10
  import { TRACE_ATTR } from '../../../../component-renderer'
11
11
  import { findPreferredSemanticClass } from '../../../../utils/css-class'
@@ -34,59 +34,59 @@ export interface ExtractedElement {
34
34
  // ─────────────────────────────────────────────────────────────────────────────
35
35
 
36
36
  const TAG_NAMES: Record<string, string> = {
37
- a: 'Anchor',
38
- abbr: 'Abbreviation',
39
- article: 'Article',
40
- aside: 'Aside',
41
- button: 'Button',
42
- caption: 'Caption',
43
- col: 'TableColumn',
44
- colgroup: 'TableColumnGroup',
45
- dd: 'DescriptionDetails',
46
- details: 'Details',
47
- div: 'Div',
48
- dl: 'DescriptionList',
49
- dt: 'DescriptionTerm',
50
- fieldset: 'Fieldset',
51
- figcaption: 'FigureCaption',
52
- figure: 'Figure',
53
- footer: 'Footer',
54
- form: 'Form',
55
- h1: 'Heading1',
56
- h2: 'Heading2',
57
- h3: 'Heading3',
58
- h4: 'Heading4',
59
- h5: 'Heading5',
60
- h6: 'Heading6',
61
- header: 'Header',
62
- hr: 'HorizontalRule',
63
- img: 'Image',
64
- input: 'Input',
65
- label: 'Label',
66
- legend: 'Legend',
67
- li: 'ListItem',
68
- main: 'Main',
69
- nav: 'Navigation',
70
- ol: 'OrderedList',
71
- optgroup: 'OptionGroup',
72
- option: 'Option',
73
- p: 'Paragraph',
74
- pre: 'Preformatted',
75
- progress: 'Progress',
76
- section: 'Section',
77
- select: 'Select',
78
- span: 'Span',
79
- strong: 'Strong',
80
- summary: 'Summary',
81
- table: 'Table',
82
- tbody: 'TableBody',
83
- td: 'TableCell',
84
- textarea: 'TextArea',
85
- tfoot: 'TableFooter',
86
- th: 'TableHeader',
87
- thead: 'TableHead',
88
- tr: 'TableRow',
89
- ul: 'UnorderedList',
37
+ a: 'anchor',
38
+ abbr: 'abbreviation',
39
+ article: 'article',
40
+ aside: 'aside',
41
+ button: 'button',
42
+ caption: 'caption',
43
+ col: 'tableColumn',
44
+ colgroup: 'tableColumnGroup',
45
+ dd: 'descriptionDetails',
46
+ details: 'details',
47
+ div: 'div',
48
+ dl: 'descriptionList',
49
+ dt: 'descriptionTerm',
50
+ fieldset: 'fieldset',
51
+ figcaption: 'figureCaption',
52
+ figure: 'figure',
53
+ footer: 'footer',
54
+ form: 'form',
55
+ h1: 'heading1',
56
+ h2: 'heading2',
57
+ h3: 'heading3',
58
+ h4: 'heading4',
59
+ h5: 'heading5',
60
+ h6: 'heading6',
61
+ header: 'header',
62
+ hr: 'horizontalRule',
63
+ img: 'image',
64
+ input: 'input',
65
+ label: 'label',
66
+ legend: 'legend',
67
+ li: 'listItem',
68
+ main: 'main',
69
+ nav: 'navigation',
70
+ ol: 'orderedList',
71
+ optgroup: 'optionGroup',
72
+ option: 'option',
73
+ p: 'paragraph',
74
+ pre: 'preformatted',
75
+ progress: 'progress',
76
+ section: 'section',
77
+ select: 'select',
78
+ span: 'span',
79
+ strong: 'strong',
80
+ summary: 'summary',
81
+ table: 'table',
82
+ tbody: 'tableBody',
83
+ td: 'tableCell',
84
+ textarea: 'textArea',
85
+ tfoot: 'tableFooter',
86
+ th: 'tableHeader',
87
+ thead: 'tableHead',
88
+ tr: 'tableRow',
89
+ ul: 'unorderedList',
90
90
  }
91
91
 
92
92
  // ─────────────────────────────────────────────────────────────────────────────
@@ -118,10 +118,10 @@ const hasDirectTextContent = (element: Element): boolean =>
118
118
  element.childNodes.some((child) => isTextNode(child) && child.value.trim().length > 0)
119
119
 
120
120
  /**
121
- * Normalizes a tag name to its semantic PascalCase form
121
+ * Normalizes a tag name to its semantic camelCase form
122
122
  */
123
123
  function normalizeTagName(tag: string): string {
124
- return TAG_NAMES[tag.toLowerCase()] ?? pascalCase(tag)
124
+ return TAG_NAMES[tag.toLowerCase()] ?? camelCase(tag)
125
125
  }
126
126
 
127
127
  /**
@@ -148,16 +148,17 @@ function getTextContent(element: Element): string {
148
148
  * Priority: id > aria-label > aria-labelledby > normalized tag name
149
149
  */
150
150
  function getElementNamePart(element: Element, getElementById: (id: string) => Element | undefined): string {
151
+ let elementName: string | undefined
151
152
  const id = getAttribute(element, 'id')
152
153
  // Skip spy-instrumented ids (mock_propName_XXXXXX) — they are runtime mock values,
153
154
  // not semantic identifiers, and would produce garbage element names.
154
155
  if (id && !id.includes('mock_')) {
155
- return pascalCase(id)
156
+ elementName = id
156
157
  }
157
158
 
158
159
  const ariaLabel = getAttribute(element, 'aria-label')
159
160
  if (ariaLabel && !ariaLabel.startsWith('mock_')) {
160
- return pascalCase(ariaLabel)
161
+ elementName = ariaLabel
161
162
  }
162
163
 
163
164
  const ariaLabelledBy = getAttribute(element, 'aria-labelledby')
@@ -166,7 +167,7 @@ function getElementNamePart(element: Element, getElementById: (id: string) => El
166
167
  if (labelElement) {
167
168
  const labelText = getTextContent(labelElement)
168
169
  if (labelText) {
169
- return pascalCase(labelText)
170
+ elementName = labelText
170
171
  }
171
172
  }
172
173
  }
@@ -174,7 +175,11 @@ function getElementNamePart(element: Element, getElementById: (id: string) => El
174
175
  const classAttr = getAttribute(element, 'class')
175
176
  if (classAttr) {
176
177
  const semanticClass = findPreferredSemanticClass(classAttr.split(' '))
177
- if (semanticClass) return pascalCase(semanticClass)
178
+ if (semanticClass) elementName = semanticClass
179
+ }
180
+
181
+ if (elementName) {
182
+ return camelCase(elementName)
178
183
  }
179
184
 
180
185
  return normalizeTagName(element.tagName)
@@ -268,8 +273,10 @@ export function buildElementTree(html: string, store: ExtractorStore): Extracted
268
273
  // Compute this element's name part
269
274
  const namePart = isRoot ? 'root' : getElementNamePart(node, getElementById)
270
275
 
271
- // Full name is ancestor path + this element's name (no separator)
272
- const name = isRoot ? 'root' : ancestorPath + namePart
276
+ // Full name is ancestor path + this element's name (no separator).
277
+ // Use pascalCase on namePart when appending so that
278
+ // e.g. "mediaSection" + "vectorArt" → "mediaSectionVectorArt".
279
+ const name = isRoot ? 'root' : ancestorPath.length > 0 ? ancestorPath + pascalCase(namePart) : namePart
273
280
 
274
281
  // Check for text content
275
282
  const hasText = hasDirectTextContent(node)