UNPKG

react-native-asset

Version:

Linking and unlinking of assets in your react-native app, works for fonts and sounds

268 lines (267 loc) 11.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.linkAssets = void 0; const dntShim = __importStar(require("./_dnt.shims.js")); const path = __importStar(require("./deps/jsr.io/@std/path/1.1.4/mod.js")); const get_config_js_1 = require("./get-config.js"); const ios_js_1 = __importDefault(require("./copy-assets/ios.js")); const ios_js_2 = __importDefault(require("./clean-assets/ios.js")); const android_js_1 = __importDefault(require("./copy-assets/android.js")); const android_js_2 = __importDefault(require("./clean-assets/android.js")); const index_js_1 = __importDefault(require("./manifest/index.js")); const linkAssets = async ({ rootPath, platforms, shouldUnlink = true, }) => { const cwd = dntShim.Deno.cwd(); const clearDuplicated = (files) => Array.from(new Map(files.map((f) => [path.parse(f.path).base + "|" + f.sha1, f])) .values()); const filesToIgnore = [ ".DS_Store", "Thumbs.db", ]; const filterFilesToIgnore = ({ path: asset }) => filesToIgnore.indexOf(path.basename(asset)) === -1; const getAbsolute = ({ filePath, dirPath }) => (path.isAbsolute(filePath) ? filePath : path.resolve(dirPath, filePath)); const getRelative = ({ filePath, dirPath }) => (path.isAbsolute(filePath) ? path.relative(dirPath, filePath) : filePath); const filterFileByFilesWhichNotExists = (files, { normalizeAbsolutePathsTo }) => (file) => { const { path: filePath, sha1: fileSha1 } = file; const relativeFilePath = getRelative({ filePath, dirPath: normalizeAbsolutePathsTo, }); return files .map((otherFile) => ({ ...otherFile, path: getRelative({ filePath: otherFile.path, dirPath: normalizeAbsolutePathsTo, }), })) .findIndex((otherFile) => { const { path: otherFileRelativePath, sha1: otherFileSha1 } = otherFile; return (relativeFilePath === otherFileRelativePath && fileSha1 === otherFileSha1); }) === -1; }; const computeSha1 = async (filePath) => { const data = await dntShim.Deno.readFile(filePath); const hashBuffer = await crypto.subtle.digest("SHA-1", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); }; const absoluteRootPath = path.resolve(cwd, rootPath); console.log(`Linking assets in ${absoluteRootPath}`); // basic validation const st = await dntShim.Deno.lstat(rootPath); if (!st.isDirectory) { throw new Error(`'rootPath' must be a valid path, got ${rootPath}`); } const st2 = await dntShim.Deno.lstat(absoluteRootPath); if (!st2.isDirectory) { throw new Error(`'rootPath' must be a valid path, got ${absoluteRootPath}`); } if (typeof shouldUnlink !== "boolean") { throw new Error(`'shouldUnlink' must be a boolean, got ${typeof shouldUnlink}`); } if ([platforms.ios, platforms.android].find(({ assets }) => !Array.isArray(assets))) { throw new Error("'platforms[\"platform\"].assets' must be an array"); } const finalRootPath = path.isAbsolute(rootPath) ? rootPath : path.resolve(cwd, rootPath); // build platforms defaults const mergedPlatforms = { ios: { enabled: platforms.ios.enabled, assets: platforms.ios.assets, }, android: { enabled: platforms.android.enabled, assets: platforms.android.assets, }, }; // helper modules are statically imported at the top of this file const config = await (0, get_config_js_1.getConfig)({ rootPath: finalRootPath }); const { android: { path: androidPath }, ios: { path: iosPath }, } = config; const linkOptionsPerExt = { ...["otf", "ttf"].reduce((result, fontType) => ({ ...result, [fontType]: { android: { path: path.resolve(androidPath, "app", "src", "main", "assets", "fonts"), }, ios: { addFont: true, }, }, }), {}), ...["png", "jpg", "gif"].reduce((result, imageType) => ({ ...result, [imageType]: { android: { path: path.resolve(androidPath, "app", "src", "main", "res", "drawable"), }, ios: { addFont: false, }, }, }), {}), mp3: { android: { path: path.resolve(androidPath, "app", "src", "main", "res", "raw"), }, ios: { addFont: false, }, }, }; const otherLinkOptions = { android: { path: path.resolve(androidPath, "app", "src", "main", "assets", "custom"), }, ios: { addFont: false, }, }; const linkPlatform = ({ rootPath: rp, shouldUnlink: su }) => async ({ name, manifest, config: platformConfig, linkOptionsPerExt: lopExt, otherLinkOptions: otherOptions, cleanAssets, copyAssets, assets: assetsPaths, }) => { const prevRelativeAssets = await manifest.read(); let assets = []; const loadAsset = async (assetMightNotAbsolute) => { const asset = getAbsolute({ filePath: assetMightNotAbsolute, dirPath: rp, }); const stats = await dntShim.Deno.lstat(asset); if (stats.isDirectory) { for await (const dirent of dntShim.Deno.readDir(asset)) { await loadAsset(path.resolve(asset, dirent.name)); } } else { const sha1 = await computeSha1(asset); assets = assets.concat({ path: asset, sha1 }); } }; const loadAll = async () => { await Promise.all(assetsPaths.map((p) => loadAsset(p))); assets = clearDuplicated(assets); }; // run loading synchronously for simplicity // (keeps behavior similar to original) await loadAll(); const fileFilters = [] .concat(Object.keys(lopExt).map((fileExt) => ({ name: fileExt, filter: ({ path: filePath }) => path.extname(filePath) === `.${fileExt}`, options: lopExt[fileExt], }))) .concat({ name: "custom", filter: ({ path: filePath }) => Object.keys(lopExt).indexOf(path.extname(filePath).substr(1)) === -1, options: otherOptions, }); for (const { name: fileConfigName, filter: fileConfigFilter, options } of fileFilters) { const prevRelativeAssetsWithExt = prevRelativeAssets .filter(fileConfigFilter) .filter(filterFileByFilesWhichNotExists(assets, { normalizeAbsolutePathsTo: rp, })); const assetsWithExt = assets .filter(fileConfigFilter) .filter(filterFileByFilesWhichNotExists(prevRelativeAssets, { normalizeAbsolutePathsTo: rp, })) .filter(filterFilesToIgnore); if (su && prevRelativeAssetsWithExt.length > 0) { console.info(`Cleaning previously linked ${fileConfigName} assets from ${name} project, prevRelativeAssetsWithExt: ${prevRelativeAssetsWithExt.map((x) => x.path)}`); // deno-lint-ignore no-await-in-loop -- sequential read/write to same plist file await cleanAssets(prevRelativeAssetsWithExt.map(({ path: filePath }) => getAbsolute({ filePath, dirPath: rp })), platformConfig, options); } if (assetsWithExt.length > 0) { console.info(`Linking ${fileConfigName} assets to ${name} project`); // deno-lint-ignore no-await-in-loop -- sequential read/write to same plist file await copyAssets(assetsWithExt.map(({ path: assetPath }) => assetPath), platformConfig, options); } } await manifest.write(assets .filter(filterFilesToIgnore) .map((asset) => ({ ...asset, path: path.relative(rp, asset.path).split(path.SEPARATOR).join("/"), })) .sort((a, b) => a.path.localeCompare(b.path, "en"))); }; const platformsArray = [ { name: "iOS", enabled: mergedPlatforms.ios.enabled, assets: mergedPlatforms.ios.assets, manifest: (0, index_js_1.default)(iosPath), config: config.ios, cleanAssets: ios_js_2.default, copyAssets: ios_js_1.default, linkOptionsPerExt: { otf: linkOptionsPerExt.otf.ios, ttf: linkOptionsPerExt.ttf.ios, mp3: linkOptionsPerExt.mp3.ios, }, otherLinkOptions: otherLinkOptions.ios, }, { name: "Android", enabled: mergedPlatforms.android.enabled, assets: mergedPlatforms.android.assets, manifest: (0, index_js_1.default)(androidPath), config: config.android, cleanAssets: android_js_2.default, copyAssets: android_js_1.default, linkOptionsPerExt: { otf: linkOptionsPerExt.otf.android, ttf: linkOptionsPerExt.ttf.android, png: linkOptionsPerExt.png.android, jpg: linkOptionsPerExt.jpg.android, gif: linkOptionsPerExt.gif.android, mp3: linkOptionsPerExt.mp3.android, }, otherLinkOptions: otherLinkOptions.android, }, ]; await Promise.all(platformsArray .filter(({ enabled, config: platformConfig }) => enabled && platformConfig.exists) .map((p) => linkPlatform({ rootPath: finalRootPath, shouldUnlink })(p))); }; exports.linkAssets = linkAssets;