• 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

94.0
/Libraries/Image/AssetSourceResolver.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
export type ResolvedAssetSource = {|
14
  +__packager_asset: boolean,
15
  +width: ?number,
16
  +height: ?number,
17
  +uri: string,
18
  +scale: number,
19
|};
20

21
import type {PackagerAsset} from '@react-native/assets-registry/registry';
22

23
import PixelRatio from '../Utilities/PixelRatio';
990✔
24

25
const Platform = require('../Utilities/Platform');
26
const {pickScale} = require('./AssetUtils');
27
const {
28
  getAndroidResourceFolderName,
29
  getAndroidResourceIdentifier,
30
  getBasePath,
31
} = require('@react-native/assets-registry/path-support');
32
const invariant = require('invariant');
33

34
/**
35
 * Returns a path like 'assets/AwesomeModule/icon@2x.png'
36
 */
37
function getScaledAssetPath(asset: PackagerAsset): string {
38
  const scale = pickScale(asset.scales, PixelRatio.get());
4✔
39
  const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
4✔
40
  const assetDir = getBasePath(asset);
4✔
41
  return assetDir + '/' + asset.name + scaleSuffix + '.' + asset.type;
4✔
42
}
43

44
/**
45
 * Returns a path like 'drawable-mdpi/icon.png'
46
 */
47
function getAssetPathInDrawableFolder(asset: PackagerAsset): string {
48
  const scale = pickScale(asset.scales, PixelRatio.get());
2✔
49
  const drawableFolder = getAndroidResourceFolderName(asset, scale);
2✔
50
  const fileName = getAndroidResourceIdentifier(asset);
2✔
51
  return drawableFolder + '/' + fileName + '.' + asset.type;
2✔
52
}
53

54
class AssetSourceResolver {
10✔
55
  serverUrl: ?string;
56
  // where the jsbundle is being run from
57
  jsbundleUrl: ?string;
58
  // the asset to resolve
59
  asset: PackagerAsset;
60

61
  constructor(serverUrl: ?string, jsbundleUrl: ?string, asset: PackagerAsset) {
10✔
62
    this.serverUrl = serverUrl;
10✔
63
    this.jsbundleUrl = jsbundleUrl;
10✔
64
    this.asset = asset;
10✔
65
  }
10✔
66

67
  isLoadedFromServer(): boolean {
68
    return !!this.serverUrl;
8✔
69
  }
70

71
  isLoadedFromFileSystem(): boolean {
72
    return !!(this.jsbundleUrl && this.jsbundleUrl.startsWith('file://'));
4✔
73
  }
74

75
  defaultAsset(): ResolvedAssetSource {
76
    if (this.isLoadedFromServer()) {
8✔
77
      return this.assetServerURL();
2✔
78
    }
79

80
    if (Platform.OS === 'android') {
6✔
81
      return this.isLoadedFromFileSystem()
4✔
82
        ? this.drawableFolderInBundle()
83
        : this.resourceIdentifierWithoutScale();
84
    } else {
85
      return this.scaledAssetURLNearBundle();
2✔
86
    }
87
  }
88

89
  /**
90
   * Returns an absolute URL which can be used to fetch the asset
91
   * from the devserver
92
   */
93
  assetServerURL(): ResolvedAssetSource {
94
    invariant(!!this.serverUrl, 'need server to load from');
2✔
95
    return this.fromSource(
2✔
96
      this.serverUrl +
97
        getScaledAssetPath(this.asset) +
98
        '?platform=' +
99
        Platform.OS +
100
        '&hash=' +
101
        this.asset.hash,
102
    );
103
  }
104

105
  /**
106
   * Resolves to just the scaled asset filename
107
   * E.g. 'assets/AwesomeModule/icon@2x.png'
108
   */
109
  scaledAssetPath(): ResolvedAssetSource {
110
    return this.fromSource(getScaledAssetPath(this.asset));
×
111
  }
112

113
  /**
114
   * Resolves to where the bundle is running from, with a scaled asset filename
115
   * E.g. 'file:///sdcard/bundle/assets/AwesomeModule/icon@2x.png'
116
   */
117
  scaledAssetURLNearBundle(): ResolvedAssetSource {
118
    const path = this.jsbundleUrl || 'file://';
2!
119
    return this.fromSource(
2✔
120
      // Assets can have relative paths outside of the project root.
121
      // When bundling them we replace `../` with `_` to make sure they
122
      // don't end up outside of the expected assets directory.
123
      path + getScaledAssetPath(this.asset).replace(/\.\.\//g, '_'),
124
    );
125
  }
126

127
  /**
128
   * The default location of assets bundled with the app, located by
129
   * resource identifier
130
   * The Android resource system picks the correct scale.
131
   * E.g. 'assets_awesomemodule_icon'
132
   */
133
  resourceIdentifierWithoutScale(): ResolvedAssetSource {
134
    invariant(
3✔
135
      Platform.OS === 'android',
136
      'resource identifiers work on Android',
137
    );
138
    return this.fromSource(getAndroidResourceIdentifier(this.asset));
3✔
139
  }
140

141
  /**
142
   * If the jsbundle is running from a sideload location, this resolves assets
143
   * relative to its location
144
   * E.g. 'file:///sdcard/AwesomeModule/drawable-mdpi/icon.png'
145
   */
146
  drawableFolderInBundle(): ResolvedAssetSource {
147
    const path = this.jsbundleUrl || 'file://';
2!
148
    return this.fromSource(path + getAssetPathInDrawableFolder(this.asset));
2✔
149
  }
150

151
  fromSource(source: string): ResolvedAssetSource {
152
    return {
10✔
153
      __packager_asset: true,
154
      width: this.asset.width,
155
      height: this.asset.height,
156
      uri: source,
157
      scale: pickScale(this.asset.scales, PixelRatio.get()),
158
    };
159
  }
10✔
160

161
  static pickScale: (scales: Array<number>, deviceScale?: number) => number =
162
    pickScale;
163
}
164

165
module.exports = AssetSourceResolver;
10✔
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

© 2026 Coveralls, Inc