• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facebook / react-native / af585971-f736-432c-90fc-8c3de5e01da3

pending completion
af585971-f736-432c-90fc-8c3de5e01da3

push

CircleCI

Facebook GitHub Bot
ESM ActivityIndicator

3633 of 26411 branches covered (13.76%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 1 file covered. (100.0%)

7424 of 44591 relevant lines covered (16.65%)

241.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Libraries/ReactNative/getNativeComponentAttributes.js
1
/**
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 *
7
 * @flow
8
 * @format
9
 */
10

11
'use strict';
12

13
const ReactNativeStyleAttributes = require('../Components/View/ReactNativeStyleAttributes');
14
const resolveAssetSource = require('../Image/resolveAssetSource');
15
import processColor from '../StyleSheet/processColor';
×
16
const processColorArray = require('../StyleSheet/processColorArray');
17
const insetsDiffer = require('../Utilities/differ/insetsDiffer');
18
const matricesDiffer = require('../Utilities/differ/matricesDiffer');
19
const pointsDiffer = require('../Utilities/differ/pointsDiffer');
20
const sizesDiffer = require('../Utilities/differ/sizesDiffer');
21
const UIManager = require('./UIManager');
22
const invariant = require('invariant');
23

24
function getNativeComponentAttributes(uiViewClassName: string): any {
25
  const viewConfig = UIManager.getViewManagerConfig(uiViewClassName);
×
26

27
  invariant(
×
28
    viewConfig != null && viewConfig.NativeProps != null,
×
29
    'requireNativeComponent: "%s" was not found in the UIManager.',
30
    uiViewClassName,
31
  );
32

33
  // TODO: This seems like a whole lot of runtime initialization for every
34
  // native component that can be either avoided or simplified.
35
  let {baseModuleName, bubblingEventTypes, directEventTypes} = viewConfig;
×
36
  let nativeProps = viewConfig.NativeProps;
×
37

38
  bubblingEventTypes = bubblingEventTypes ?? {};
×
39
  directEventTypes = directEventTypes ?? {};
×
40

41
  while (baseModuleName) {
×
42
    const baseModule = UIManager.getViewManagerConfig(baseModuleName);
×
43
    if (!baseModule) {
×
44
      baseModuleName = null;
×
45
    } else {
46
      bubblingEventTypes = {
×
47
        ...baseModule.bubblingEventTypes,
48
        ...bubblingEventTypes,
49
      };
50
      directEventTypes = {
×
51
        ...baseModule.directEventTypes,
52
        ...directEventTypes,
53
      };
54
      nativeProps = {
×
55
        ...baseModule.NativeProps,
56
        ...nativeProps,
57
      };
58
      baseModuleName = baseModule.baseModuleName;
×
59
    }
60
  }
61

62
  const validAttributes: {[string]: mixed} = {};
×
63

64
  for (const key in nativeProps) {
×
65
    const typeName = nativeProps[key];
×
66
    const diff = getDifferForType(typeName);
×
67
    const process = getProcessorForType(typeName);
×
68

69
    // If diff or process == null, omit the corresponding property from the Attribute
70
    // Why:
71
    //  1. Consistency with AttributeType flow type
72
    //  2. Consistency with Static View Configs, which omit the null properties
73
    validAttributes[key] =
×
74
      diff == null
×
75
        ? process == null
×
76
          ? true
77
          : {process}
78
        : process == null
×
79
        ? {diff}
80
        : {diff, process};
81
  }
82

83
  // Unfortunately, the current setup declares style properties as top-level
84
  // props. This makes it so we allow style properties in the `style` prop.
85
  // TODO: Move style properties into a `style` prop and disallow them as
86
  // top-level props on the native side.
87
  validAttributes.style = ReactNativeStyleAttributes;
×
88

89
  Object.assign(viewConfig, {
×
90
    uiViewClassName,
91
    validAttributes,
92
    bubblingEventTypes,
93
    directEventTypes,
94
  });
95

96
  attachDefaultEventTypes(viewConfig);
×
97

98
  return viewConfig;
×
99
}
100

101
function attachDefaultEventTypes(viewConfig: any) {
102
  // This is supported on UIManager platforms (ex: Android),
103
  // as lazy view managers are not implemented for all platforms.
104
  // See [UIManager] for details on constants and implementations.
105
  const constants = UIManager.getConstants();
×
106
  if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) {
×
107
    // Lazy view managers enabled.
108
    viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes());
×
109
  } else {
110
    viewConfig.bubblingEventTypes = merge(
×
111
      viewConfig.bubblingEventTypes,
112
      constants.genericBubblingEventTypes,
113
    );
114
    viewConfig.directEventTypes = merge(
×
115
      viewConfig.directEventTypes,
116
      constants.genericDirectEventTypes,
117
    );
118
  }
119
}
120

121
// TODO: Figure out how to avoid all this runtime initialization cost.
122
function merge(destination: ?Object, source: ?Object): ?Object {
123
  if (!source) {
×
124
    return destination;
×
125
  }
126
  if (!destination) {
×
127
    return source;
×
128
  }
129

130
  for (const key in source) {
×
131
    if (!source.hasOwnProperty(key)) {
×
132
      continue;
×
133
    }
134

135
    let sourceValue = source[key];
×
136
    if (destination.hasOwnProperty(key)) {
×
137
      const destinationValue = destination[key];
×
138
      if (
×
139
        typeof sourceValue === 'object' &&
×
140
        typeof destinationValue === 'object'
141
      ) {
142
        sourceValue = merge(destinationValue, sourceValue);
×
143
      }
144
    }
145
    destination[key] = sourceValue;
×
146
  }
147
  return destination;
×
148
}
149

150
function getDifferForType(
151
  typeName: string,
152
): ?(prevProp: any, nextProp: any) => boolean {
153
  switch (typeName) {
×
154
    // iOS Types
155
    case 'CATransform3D':
156
      return matricesDiffer;
×
157
    case 'CGPoint':
158
      return pointsDiffer;
×
159
    case 'CGSize':
160
      return sizesDiffer;
×
161
    case 'UIEdgeInsets':
162
      return insetsDiffer;
×
163
    // Android Types
164
    case 'Point':
165
      return pointsDiffer;
×
166
    case 'EdgeInsets':
167
      return insetsDiffer;
×
168
  }
169
  return null;
×
170
}
171

172
function getProcessorForType(typeName: string): ?(nextProp: any) => any {
173
  switch (typeName) {
×
174
    // iOS Types
175
    case 'CGColor':
176
    case 'UIColor':
177
      return processColor;
×
178
    case 'CGColorArray':
179
    case 'UIColorArray':
180
      return processColorArray;
×
181
    case 'CGImage':
182
    case 'UIImage':
183
    case 'RCTImageSource':
184
      return resolveAssetSource;
×
185
    // Android Types
186
    case 'Color':
187
      return processColor;
×
188
    case 'ColorArray':
189
      return processColorArray;
×
190
    case 'ImageSource':
191
      return resolveAssetSource;
×
192
  }
193
  return null;
×
194
}
195

196
module.exports = getNativeComponentAttributes;
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc