react-native-svg-asset-plugin
Version:
Asset plugin for importing SVG images in React Native
105 lines (103 loc) • 4.86 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCacheStoragePath = getCacheStoragePath;
const node_path_1 = __importDefault(require("node:path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
/**
* Module-level Map to track ongoing symlink creation operations.
* Key: projectSymlink path, Value: Promise that resolves to the symlink path
*/
const symlinkOperations = new Map();
/**
* Returns the directory path where generated assets should be stored. Ensures
* that it exists.
*/
async function getCacheStoragePath(config, assetData) {
const projectSymlink = node_path_1.default.join(assetData.fileSystemLocation, config.cacheDir);
// Check if we're already processing this symlink
const existingOperation = symlinkOperations.get(projectSymlink);
if (existingOperation) {
return existingOperation;
}
// Create a new operation for this symlink
const operation = (async () => {
/* Store generated images in separate directories for each source image
directory. This makes it easier to validate the output of source files,
as well as makes the output directories smaller. */
// Calculate relative path from project root to the asset's directory
let subdirectoryPath = node_path_1.default.relative(config.projectRoot, assetData.fileSystemLocation);
/* Note that the httpServerLocation may not match the actual filesystem
location, as the metro server has multiple ways to specify the asset
path. See https://github.com/facebook/metro/blob/v0.83.3/packages/metro/src/Server.js#L517 */
/* All imported assets should reside within the project root as the metro
bundler doesn't allow importing files from outside. But things might
change, so it should be handled regardless.
On Windows, path.relative() returns an absolute path when paths are on
different drives, so we need to check for that as well. */
if (subdirectoryPath.startsWith("..") ||
node_path_1.default.isAbsolute(subdirectoryPath)) {
/* Note that directory collisions are not a concern, as all output files
have unique names based on their content hash. */
subdirectoryPath = "";
}
const cacheDir = node_path_1.default.join(config.cacheStorageDir, subdirectoryPath);
// Ensure the actual cache directory exists
await fs_extra_1.default.ensureDir(cacheDir);
// Ensure symlink points to the cache directory
const stats = await lstatIfExists(projectSymlink);
if (!stats) {
// Symlink doesn't exist, create it
await fs_extra_1.default.symlink(cacheDir, projectSymlink, "dir");
}
else if (stats.isSymbolicLink()) {
const currentTarget = await fs_extra_1.default.readlink(projectSymlink);
if (currentTarget !== cacheDir) {
// Replace incorrect symlink with correct one
await fs_extra_1.default.remove(projectSymlink);
await fs_extra_1.default.symlink(cacheDir, projectSymlink, "dir");
}
}
else if (stats.isDirectory()) {
// Migrate old cache directory to new location
for (const file of await fs_extra_1.default.readdir(projectSymlink)) {
try {
await fs_extra_1.default.move(node_path_1.default.join(projectSymlink, file), node_path_1.default.join(cacheDir, file), {
overwrite: true,
});
}
catch {
// Ignore errors as missing files can be regenerated
}
}
// Remove old directory and create symlink
await fs_extra_1.default.remove(projectSymlink);
await fs_extra_1.default.symlink(cacheDir, projectSymlink, "dir");
}
else {
// Remove file or other non-directory entry
await fs_extra_1.default.remove(projectSymlink);
await fs_extra_1.default.symlink(cacheDir, projectSymlink, "dir");
}
return projectSymlink;
})();
// Store the operation in the Map
symlinkOperations.set(projectSymlink, operation);
return operation;
}
/**
* Returns lstat for a path, or null if the path doesn't exist.
*/
async function lstatIfExists(filePath) {
try {
return await fs_extra_1.default.lstat(filePath);
}
catch (error) {
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
return null;
}
throw error;
}
}