Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions packages/metro/src/Assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,29 +299,36 @@ export async function getAsset(
}

// NOTE: If fileExistsInFileMap is not provided, we fall back to pathBelongsToRoots for backward compatibility, as getAsset is part of the public API.
if (fileExistsInFileMap != null) {
if (!fileExistsInFileMap(absolutePath)) {
throw new Error(
`'${relativePath}' could not be found, because it is not within the projectRoot or watchFolders, or it is blocked via the resolver.blockList config`,
);
}
} else {
if (!pathBelongsToRoots(absolutePath, [projectRoot, ...watchFolders])) {
throw new Error(
`'${relativePath}' could not be found, because it cannot be found in the project root or any watch folder`,
);
}
if (
fileExistsInFileMap == null &&
!pathBelongsToRoots(absolutePath, [projectRoot, ...watchFolders])
) {
throw new Error(
`'${relativePath}' could not be found, because it cannot be found in the project root or any watch folder`,
);
}

const record = await getAbsoluteAssetRecord(absolutePath, platform ?? null);

for (let i = 0; i < record.scales.length; i++) {
if (record.scales[i] >= assetData.resolution) {
if (
fileExistsInFileMap != null &&
!fileExistsInFileMap(record.files[i])
) {
continue;
}
return fs.promises.readFile(record.files[i]);
}
}

return fs.promises.readFile(record.files[record.files.length - 1]);
const lastFile = record.files[record.files.length - 1];
if (fileExistsInFileMap != null && !fileExistsInFileMap(lastFile)) {
throw new Error(
`'${relativePath}' could not be found, because it is not within the projectRoot or watchFolders, or it is blocked via the resolver.blockList config`,
);
}
return fs.promises.readFile(lastFile);
}

function pathBelongsToRoots(
Expand Down
75 changes: 75 additions & 0 deletions packages/metro/src/__tests__/Assets-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,81 @@ describe('getAsset', () => {
getAssetStr('imgs/b.png', '/root', [], null, ['png'], () => false),
).rejects.toBeInstanceOf(Error);
});

test('should serve scale variant when only scale variants exist and fileExistsInFileMap is provided', async () => {
writeImages({
'b@2x.png': 'b2 image',
'b@3x.png': 'b3 image',
});

expect(
await getAssetStr(
'imgs/b@2x.png',
'/root',
[],
null,
['png'],
() => true,
),
).toBe('b2 image');
});

test('should throw when fileExistsInFileMap rejects the resolved scale variant', async () => {
writeImages({
'b@2x.png': 'b2 image',
'b@3x.png': 'b3 image',
});

await expect(
getAssetStr('imgs/b@2x.png', '/root', [], null, ['png'], () => false),
).rejects.toBeInstanceOf(Error);
});

test('should check fileExistsInFileMap against the resolved file, not the base path', async () => {
writeImages({
'b@2x.png': 'b2 image',
'b@3x.png': 'b3 image',
});

const checkedPaths = [];
const result = await getAssetStr(
'imgs/b@2x.png',
'/root',
[],
null,
['png'],
filePath => {
checkedPaths.push(filePath);
return true;
},
);

expect(result).toBe('b2 image');
expect(checkedPaths).toEqual(['/root/imgs/b@2x.png']);
});

test('should check fileExistsInFileMap for the fallback (highest scale) file', async () => {
writeImages({
'b@1x.png': 'b1 image',
'b@2x.png': 'b2 image',
});

const checkedPaths = [];
const result = await getAssetStr(
'imgs/b@3x.png',
'/root',
[],
null,
['png'],
filePath => {
checkedPaths.push(filePath);
return true;
},
);

expect(result).toBe('b2 image');
expect(checkedPaths).toEqual(['/root/imgs/b@2x.png']);
});
});

describe('getAssetData', () => {
Expand Down
Loading