@ui5/webcomponents-base 2.0.0-rc.6 → 2.0.1

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -4
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/UI5Element.d.ts +9 -8
  5. package/dist/UI5Element.js +111 -108
  6. package/dist/UI5Element.js.map +1 -1
  7. package/dist/UI5ElementMetadata.d.ts +6 -15
  8. package/dist/UI5ElementMetadata.js +3 -71
  9. package/dist/UI5ElementMetadata.js.map +1 -1
  10. package/dist/asset-registries/Icons.d.ts +1 -1
  11. package/dist/asset-registries/Icons.js.map +1 -1
  12. package/dist/converters/DOMReference.d.ts +5 -0
  13. package/dist/converters/DOMReference.js +13 -0
  14. package/dist/converters/DOMReference.js.map +1 -0
  15. package/dist/custom-elements-internal.json +15 -275
  16. package/dist/custom-elements.json +15 -269
  17. package/dist/decorators/property.js +1 -1
  18. package/dist/decorators/property.js.map +1 -1
  19. package/dist/delegate/ItemNavigation.d.ts +1 -1
  20. package/dist/delegate/ItemNavigation.js.map +1 -1
  21. package/dist/features/InputElementsFormSupport.d.ts +1 -1
  22. package/dist/features/InputElementsFormSupport.js.map +1 -1
  23. package/dist/features/OpenUI5Support.js +3 -0
  24. package/dist/features/OpenUI5Support.js.map +1 -1
  25. package/dist/generated/VersionInfo.js +4 -4
  26. package/dist/generated/VersionInfo.js.map +1 -1
  27. package/dist/prod/UI5Element.js +1 -1
  28. package/dist/prod/UI5Element.js.map +3 -3
  29. package/dist/prod/UI5ElementMetadata.js +1 -1
  30. package/dist/prod/UI5ElementMetadata.js.map +3 -3
  31. package/dist/prod/asset-registries/Icons.js +1 -1
  32. package/dist/prod/asset-registries/Icons.js.map +2 -2
  33. package/dist/prod/converters/DOMReference.js +2 -0
  34. package/dist/prod/converters/DOMReference.js.map +7 -0
  35. package/dist/prod/decorators/property.js +1 -1
  36. package/dist/prod/decorators/property.js.map +2 -2
  37. package/dist/prod/delegate/ItemNavigation.js.map +1 -1
  38. package/dist/prod/features/InputElementsFormSupport.js.map +1 -1
  39. package/dist/prod/features/OpenUI5Support.js +1 -1
  40. package/dist/prod/features/OpenUI5Support.js.map +2 -2
  41. package/dist/prod/generated/VersionInfo.js +1 -1
  42. package/dist/prod/generated/VersionInfo.js.map +2 -2
  43. package/dist/prod/util/AriaLabelHelper.js.map +1 -1
  44. package/dist/util/AriaLabelHelper.js.map +1 -1
  45. package/dist/util/getClassCopy.d.ts +5 -2
  46. package/package.json +3 -3
  47. package/dist/prod/types/CSSColor.js +0 -2
  48. package/dist/prod/types/CSSColor.js.map +0 -7
  49. package/dist/prod/types/CSSSize.js +0 -2
  50. package/dist/prod/types/CSSSize.js.map +0 -7
  51. package/dist/prod/types/DOMReference.js +0 -2
  52. package/dist/prod/types/DOMReference.js.map +0 -7
  53. package/dist/prod/types/DataType.js +0 -2
  54. package/dist/prod/types/DataType.js.map +0 -7
  55. package/dist/prod/types/Float.js +0 -2
  56. package/dist/prod/types/Float.js.map +0 -7
  57. package/dist/prod/types/Integer.js +0 -2
  58. package/dist/prod/types/Integer.js.map +0 -7
  59. package/dist/types/CSSColor.d.ts +0 -11
  60. package/dist/types/CSSColor.js +0 -14
  61. package/dist/types/CSSColor.js.map +0 -1
  62. package/dist/types/CSSSize.d.ts +0 -11
  63. package/dist/types/CSSSize.js +0 -14
  64. package/dist/types/CSSSize.js.map +0 -1
  65. package/dist/types/DOMReference.d.ts +0 -13
  66. package/dist/types/DOMReference.js +0 -21
  67. package/dist/types/DOMReference.js.map +0 -1
  68. package/dist/types/DataType.d.ts +0 -20
  69. package/dist/types/DataType.js +0 -39
  70. package/dist/types/DataType.js.map +0 -1
  71. package/dist/types/Float.d.ts +0 -14
  72. package/dist/types/Float.js +0 -18
  73. package/dist/types/Float.js.map +0 -1
  74. package/dist/types/Integer.d.ts +0 -14
  75. package/dist/types/Integer.js +0 -18
  76. package/dist/types/Integer.js.map +0 -1
@@ -54,7 +54,14 @@ declare abstract class UI5Element extends HTMLElement {
54
54
  static template?: TemplateFunction;
55
55
  static _metadata: UI5ElementMetadata;
56
56
  static renderer: Renderer;
57
+ initializedProperties: Map<string, unknown>;
58
+ _rendered: boolean;
57
59
  constructor();
60
+ _initShadowRoot(): void;
61
+ /**
62
+ * Note: this "slotchange" listener is for slots, rendered in the component's shadow root
63
+ */
64
+ _onShadowRootSlotChange(e: Event): void;
58
65
  /**
59
66
  * Returns a unique ID for this UI5 Element
60
67
  *
@@ -148,14 +155,6 @@ declare abstract class UI5Element extends HTMLElement {
148
155
  * @private
149
156
  */
150
157
  _updateAttribute(name: string, newValue: PropertyValue): void;
151
- /**
152
- * @private
153
- */
154
- _upgradeProperty(this: Record<string, any>, propertyName: string): void;
155
- /**
156
- * @private
157
- */
158
- _upgradeAllProperties(): void;
159
158
  /**
160
159
  * Returns a singleton event listener for the "change" event of a child in a given slot
161
160
  *
@@ -180,6 +179,7 @@ declare abstract class UI5Element extends HTMLElement {
180
179
  _detachSlotChange(child: HTMLSlotElement, slotName: string): void;
181
180
  /**
182
181
  * Whenever a slot element is slotted inside a UI5 Web Component, its slotchange event invalidates the component
182
+ * Note: this "slotchange" listener is for slots that are children of the component (in the light dom, as opposed to slots rendered by the component in the shadow root)
183
183
  *
184
184
  * @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
185
185
  * @private
@@ -213,6 +213,7 @@ declare abstract class UI5Element extends HTMLElement {
213
213
  * @public
214
214
  */
215
215
  onInvalidation(changeInfo: ChangeInfo): void;
216
+ updateAttributes(): void;
216
217
  /**
217
218
  * Do not call this method directly, only intended to be called by js
218
219
  * @protected
@@ -22,6 +22,31 @@ const DEV_MODE = true;
22
22
  let autoId = 0;
23
23
  const elementTimeouts = new Map();
24
24
  const uniqueDependenciesCache = new Map();
25
+ const defaultConverter = {
26
+ fromAttribute(value, type) {
27
+ if (type === Boolean) {
28
+ return value !== null;
29
+ }
30
+ if (type === Number) {
31
+ return value === null ? undefined : parseFloat(value);
32
+ }
33
+ return value;
34
+ },
35
+ toAttribute(value, type) {
36
+ if (type === Boolean) {
37
+ return value ? "" : null;
38
+ }
39
+ // don't set attributes for arrays and objects
40
+ if (type === Object || type === Array) {
41
+ return null;
42
+ }
43
+ // object, array, other
44
+ if (value === null || value === undefined) {
45
+ return null;
46
+ }
47
+ return String(value);
48
+ },
49
+ };
25
50
  /**
26
51
  * Triggers re-rendering of a UI5Element instance due to state change.
27
52
  * @param {ChangeInfo} changeInfo An object with information about the change that caused invalidation.
@@ -65,6 +90,10 @@ function getPropertyDescriptor(proto, name) {
65
90
  class UI5Element extends HTMLElement {
66
91
  constructor() {
67
92
  super();
93
+ // used to differentiate whether a setter is called from the constructor (from an initializer) or later
94
+ // setters from the constructor should not set attributes, this is delegated after the first rendering but is async
95
+ // setters after the constructor can set attributes synchronously for more convinient development
96
+ this._rendered = false;
68
97
  const ctor = this.constructor;
69
98
  this._changedState = []; // Filled on each invalidation, cleared on re-render (used for debugging)
70
99
  this._suppressInvalidation = true; // A flag telling whether all invalidations should be ignored. Initialized with "true" because a UI5Element can not be invalidated until it is rendered for the first time
@@ -82,10 +111,35 @@ class UI5Element extends HTMLElement {
82
111
  this._doNotSyncAttributes = new Set(); // attributes that are excluded from attributeChangedCallback synchronization
83
112
  this._slotsAssignedNodes = new WeakMap(); // map of all nodes, slotted (directly or transitively) per component slot
84
113
  this._state = { ...ctor.getMetadata().getInitialState() };
85
- this._upgradeAllProperties();
114
+ // save properties set before element is upgraded, as they will be overriden by the field initializers in the constructor
115
+ this.initializedProperties = new Map();
116
+ const allProps = this.constructor.getMetadata().getPropertiesList();
117
+ allProps.forEach(propertyName => {
118
+ if (this.hasOwnProperty(propertyName)) { // eslint-disable-line
119
+ const value = this[propertyName];
120
+ this.initializedProperties.set(propertyName, value);
121
+ }
122
+ });
123
+ this._initShadowRoot();
124
+ }
125
+ _initShadowRoot() {
126
+ const ctor = this.constructor;
86
127
  if (ctor._needsShadowDOM()) {
87
128
  const defaultOptions = { mode: "open" };
88
129
  this.attachShadow({ ...defaultOptions, ...ctor.getMetadata().getShadowRootOptions() });
130
+ const slotsAreManaged = ctor.getMetadata().slotsAreManaged();
131
+ if (slotsAreManaged) {
132
+ this.shadowRoot.addEventListener("slotchange", this._onShadowRootSlotChange.bind(this));
133
+ }
134
+ }
135
+ }
136
+ /**
137
+ * Note: this "slotchange" listener is for slots, rendered in the component's shadow root
138
+ */
139
+ _onShadowRootSlotChange(e) {
140
+ const targetShadowRoot = e.target?.getRootNode(); // the "slotchange" event target is always a slot element
141
+ if (targetShadowRoot === this.shadowRoot) { // only for slotchange events that originate from slots, belonging to the component's shadow root
142
+ this._processChildren();
89
143
  }
90
144
  }
91
145
  /**
@@ -124,7 +178,8 @@ class UI5Element extends HTMLElement {
124
178
  if (DEV_MODE) {
125
179
  const props = this.constructor.getMetadata().getProperties();
126
180
  for (const [prop, propData] of Object.entries(props)) { // eslint-disable-line
127
- if (Object.hasOwn(this, prop)) {
181
+ if (Object.hasOwn(this, prop) && !this.initializedProperties.has(prop)) {
182
+ // initialized properties should not trigger this error as they will be reassigned, only property initializers will trigger this in case unsupported TS mode
128
183
  // eslint-disable-next-line no-console
129
184
  console.error(`[UI5-FWK] ${this.constructor.getMetadata().getTag()} has a property [${prop}] that is shadowed by the instance. Updates to this property will not invalidate the component. Possible reason is TS target ES2022 or TS useDefineForClassFields`);
130
185
  }
@@ -199,10 +254,9 @@ class UI5Element extends HTMLElement {
199
254
  return;
200
255
  }
201
256
  const canSlotText = metadata.canSlotText();
202
- const hasClonedSlot = Object.keys(metadata.getSlots()).some(slotName => metadata.getSlots()[slotName].cloned);
203
257
  const mutationObserverOptions = {
204
258
  childList: true,
205
- subtree: canSlotText || hasClonedSlot,
259
+ subtree: canSlotText,
206
260
  characterData: canSlotText,
207
261
  };
208
262
  observeDOMNode(this, this._processChildren.bind(this), mutationObserverOptions);
@@ -301,6 +355,7 @@ class UI5Element extends HTMLElement {
301
355
  // not the order elements are defined.
302
356
  slottedChildrenMap.forEach((children, propertyName) => {
303
357
  this._state[propertyName] = children.sort((a, b) => a.idx - b.idx).map(_ => _.child);
358
+ this._state[kebabToCamelCase(propertyName)] = this._state[propertyName];
304
359
  });
305
360
  // Compare the content of each slot with the cached values and invalidate for the ones that changed
306
361
  let invalidated = false;
@@ -345,6 +400,7 @@ class UI5Element extends HTMLElement {
345
400
  }
346
401
  });
347
402
  this._state[propertyName] = [];
403
+ this._state[kebabToCamelCase(propertyName)] = this._state[propertyName];
348
404
  }
349
405
  /**
350
406
  * Attach a callback that will be executed whenever the component is invalidated
@@ -398,20 +454,8 @@ class UI5Element extends HTMLElement {
398
454
  const nameInCamelCase = kebabToCamelCase(realName);
399
455
  if (properties.hasOwnProperty(nameInCamelCase)) { // eslint-disable-line
400
456
  const propData = properties[nameInCamelCase];
401
- const propertyType = propData.type;
402
- let propertyValidator = propData.validator;
403
- if (propertyType && propertyType.isDataTypeClass) {
404
- propertyValidator = propertyType;
405
- }
406
- if (propertyValidator) {
407
- newPropertyValue = propertyValidator.attributeToProperty(newValue);
408
- }
409
- else if (propertyType === Boolean) {
410
- newPropertyValue = newValue !== null;
411
- }
412
- else {
413
- newPropertyValue = newValue;
414
- }
457
+ const converter = propData.converter ?? defaultConverter;
458
+ newPropertyValue = converter.fromAttribute(newValue, propData.type);
415
459
  this[nameInCamelCase] = newPropertyValue;
416
460
  }
417
461
  }
@@ -435,55 +479,29 @@ class UI5Element extends HTMLElement {
435
479
  }
436
480
  const properties = ctor.getMetadata().getProperties();
437
481
  const propData = properties[name];
438
- const propertyType = propData.type;
439
- let propertyValidator = propData.validator;
440
482
  const attrName = camelToKebabCase(name);
441
- const attrValue = this.getAttribute(attrName);
442
- if (propertyType && propertyType.isDataTypeClass) {
443
- propertyValidator = propertyType;
444
- }
445
- if (propertyValidator) {
446
- const newAttrValue = propertyValidator.propertyToAttribute(newValue);
447
- if (newAttrValue === null) { // null means there must be no attribute for the current value of the property
448
- this._doNotSyncAttributes.add(attrName); // skip the attributeChangedCallback call for this attribute
449
- this.removeAttribute(attrName); // remove the attribute safely (will not trigger synchronization to the property value due to the above line)
450
- this._doNotSyncAttributes.delete(attrName); // enable synchronization again for this attribute
483
+ const converter = propData.converter || defaultConverter;
484
+ if (DEV_MODE) {
485
+ const tag = this.constructor.getMetadata().getTag();
486
+ if (typeof newValue === "boolean" && propData.type !== Boolean) {
487
+ // eslint-disable-next-line
488
+ console.error(`[UI5-FWK] boolean value for property [${name}] of component [${tag}] is missing "{ type: Boolean }" in its property decorator. Attribute conversion will treat it as a string. If this is intended, pass the value converted to string, otherwise add the type to the property decorator`);
451
489
  }
452
- else {
453
- this.setAttribute(attrName, newAttrValue);
490
+ if (typeof newValue === "number" && propData.type !== Number) {
491
+ // eslint-disable-next-line
492
+ console.error(`[UI5-FWK] numeric value for property [${name}] of component [${tag}] is missing "{ type: Number }" in its property decorator. Attribute conversion will treat it as a string. If this is intended, pass the value converted to string, otherwise add the type to the property decorator`);
454
493
  }
455
494
  }
456
- else if (propertyType === Boolean) {
457
- if (newValue === true && attrValue === null) {
458
- this.setAttribute(attrName, "");
459
- }
460
- else if (newValue === false && attrValue !== null) {
461
- this.removeAttribute(attrName);
462
- }
495
+ const newAttrValue = converter.toAttribute(newValue, propData.type);
496
+ if (newAttrValue === null || newAttrValue === undefined) { // null means there must be no attribute for the current value of the property
497
+ this._doNotSyncAttributes.add(attrName); // skip the attributeChangedCallback call for this attribute
498
+ this.removeAttribute(attrName); // remove the attribute safely (will not trigger synchronization to the property value due to the above line)
499
+ this._doNotSyncAttributes.delete(attrName); // enable synchronization again for this attribute
463
500
  }
464
- else if (typeof newValue !== "object") {
465
- if (attrValue !== newValue) {
466
- this.setAttribute(attrName, newValue);
467
- }
468
- } // else { return; } // old object handling
469
- }
470
- /**
471
- * @private
472
- */
473
- _upgradeProperty(propertyName) {
474
- if (this.hasOwnProperty(propertyName)) { // eslint-disable-line
475
- const value = this[propertyName];
476
- delete this[propertyName];
477
- this[propertyName] = value;
501
+ else {
502
+ this.setAttribute(attrName, newAttrValue);
478
503
  }
479
504
  }
480
- /**
481
- * @private
482
- */
483
- _upgradeAllProperties() {
484
- const allProps = this.constructor.getMetadata().getPropertiesList();
485
- allProps.forEach(this._upgradeProperty.bind(this));
486
- }
487
505
  /**
488
506
  * Returns a singleton event listener for the "change" event of a child in a given slot
489
507
  *
@@ -546,6 +564,7 @@ class UI5Element extends HTMLElement {
546
564
  }
547
565
  /**
548
566
  * Whenever a slot element is slotted inside a UI5 Web Component, its slotchange event invalidates the component
567
+ * Note: this "slotchange" listener is for slots that are children of the component (in the light dom, as opposed to slots rendered by the component in the shadow root)
549
568
  *
550
569
  * @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
551
570
  * @private
@@ -585,6 +604,13 @@ class UI5Element extends HTMLElement {
585
604
  * @public
586
605
  */
587
606
  onInvalidation(changeInfo) { } // eslint-disable-line
607
+ updateAttributes() {
608
+ const ctor = this.constructor;
609
+ const props = ctor.getMetadata().getProperties();
610
+ for (const [prop, propData] of Object.entries(props)) { // eslint-disable-line
611
+ this._updateAttribute(prop, this[prop]);
612
+ }
613
+ }
588
614
  /**
589
615
  * Do not call this method directly, only intended to be called by js
590
616
  * @protected
@@ -592,9 +618,21 @@ class UI5Element extends HTMLElement {
592
618
  _render() {
593
619
  const ctor = this.constructor;
594
620
  const hasIndividualSlots = ctor.getMetadata().hasIndividualSlots();
621
+ // restore properties that were initialized before `define` by calling the setter
622
+ if (this.initializedProperties.size > 0) {
623
+ Array.from(this.initializedProperties.entries()).forEach(([prop, value]) => {
624
+ delete this[prop];
625
+ this[prop] = value;
626
+ });
627
+ this.initializedProperties.clear();
628
+ }
595
629
  // suppress invalidation to prevent state changes scheduling another rendering
596
630
  this._suppressInvalidation = true;
597
631
  this.onBeforeRendering();
632
+ if (!this._rendered) {
633
+ // first time rendering, previous setters might have been initializers from the constructor - update attributes here
634
+ this.updateAttributes();
635
+ }
598
636
  // Intended for framework usage only. Currently ItemNavigation updates tab indexes after the component has updated its state but before the template is rendered
599
637
  this._componentStateFinalizedEventProvider.fireEvent("componentStateFinalized");
600
638
  // resume normal invalidation handling
@@ -625,6 +663,7 @@ class UI5Element extends HTMLElement {
625
663
  if (ctor._needsShadowDOM()) {
626
664
  updateShadowRoot(this);
627
665
  }
666
+ this._rendered = true;
628
667
  // Safari requires that children get the slot attribute only after the slot tags have been rendered in the shadow DOM
629
668
  if (hasIndividualSlots) {
630
669
  this._assignIndividualSlotsToChildren();
@@ -822,18 +861,6 @@ class UI5Element extends HTMLElement {
822
861
  if (!isValidPropertyName(prop)) {
823
862
  console.warn(`"${prop}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
824
863
  }
825
- if (propData.type === Boolean && propData.defaultValue) {
826
- throw new Error(`Cannot set a default value for property "${prop}". All booleans are false by default.`);
827
- }
828
- if (propData.type === Array) {
829
- throw new Error(`Wrong type for property "${prop}". Properties cannot be of type Array - use "multiple: true" and set "type" to the single value type, such as "String", "Object", etc...`);
830
- }
831
- if (propData.type === Object && propData.defaultValue) {
832
- throw new Error(`Cannot set a default value for property "${prop}". All properties of type "Object" are empty objects by default.`);
833
- }
834
- if (propData.multiple && propData.defaultValue) {
835
- throw new Error(`Cannot set a default value for property "${prop}". All multiple properties are empty arrays by default.`);
836
- }
837
864
  const descriptor = getPropertyDescriptor(proto, prop);
838
865
  // if the decorator is on a setter, proxy the new setter to it
839
866
  let origSet;
@@ -853,43 +880,12 @@ class UI5Element extends HTMLElement {
853
880
  if (origGet) {
854
881
  return origGet.call(this);
855
882
  }
856
- if (this._state[prop] !== undefined) {
857
- return this._state[prop];
858
- }
859
- const propDefaultValue = propData.defaultValue;
860
- if (propData.type === Boolean) {
861
- return false;
862
- }
863
- else if (propData.type === String) { // eslint-disable-line
864
- return propDefaultValue;
865
- }
866
- else if (propData.multiple) { // eslint-disable-line
867
- return [];
868
- }
869
- else {
870
- return propDefaultValue;
871
- }
883
+ return this._state[prop];
872
884
  },
873
885
  set(value) {
874
- let isDifferent;
875
886
  const ctor = this.constructor;
876
- const metadataCtor = ctor.getMetadata().constructor;
877
- value = metadataCtor.validatePropertyValue(value, propData);
878
- const propertyType = propData.type;
879
- let propertyValidator = propData.validator;
880
887
  const oldState = origGet ? origGet.call(this) : this._state[prop];
881
- if (propertyType && propertyType.isDataTypeClass) {
882
- propertyValidator = propertyType;
883
- }
884
- if (propertyValidator) {
885
- isDifferent = !propertyValidator.valuesAreEqual(oldState, value);
886
- }
887
- else if (Array.isArray(oldState) && Array.isArray(value) && propData.multiple && propData.compareValues) { // compareValues is added for IE, test if needed now
888
- isDifferent = !arraysAreEqual(oldState, value);
889
- }
890
- else {
891
- isDifferent = oldState !== value;
892
- }
888
+ const isDifferent = oldState !== value;
893
889
  if (isDifferent) {
894
890
  // if the decorator is on a setter, use it for storage
895
891
  if (origSet) {
@@ -904,10 +900,13 @@ class UI5Element extends HTMLElement {
904
900
  newValue: value,
905
901
  oldValue: oldState,
906
902
  });
903
+ if (this._rendered) {
904
+ // is already rendered so it is not the constructor - can set the attribute synchronously
905
+ this._updateAttribute(prop, value);
906
+ }
907
907
  if (ctor.getMetadata().isFormAssociated()) {
908
908
  setFormValue(this);
909
909
  }
910
- this._updateAttribute(prop, value);
911
910
  }
912
911
  },
913
912
  });
@@ -920,7 +919,7 @@ class UI5Element extends HTMLElement {
920
919
  console.warn(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
921
920
  }
922
921
  const propertyName = slotData.propertyName || slotName;
923
- Object.defineProperty(proto, propertyName, {
922
+ const propertyDescriptor = {
924
923
  get() {
925
924
  if (this._state[propertyName] !== undefined) {
926
925
  return this._state[propertyName];
@@ -930,7 +929,11 @@ class UI5Element extends HTMLElement {
930
929
  set() {
931
930
  throw new Error("Cannot set slot content directly, use the DOM APIs (appendChild, removeChild, etc...)");
932
931
  },
933
- });
932
+ };
933
+ Object.defineProperty(proto, propertyName, propertyDescriptor);
934
+ if (propertyName !== kebabToCamelCase(propertyName)) {
935
+ Object.defineProperty(proto, kebabToCamelCase(propertyName), propertyDescriptor);
936
+ }
934
937
  }
935
938
  }
936
939
  }