UNPKG

react-native-flip

Version:
237 lines 10.4 kB
"use strict"; /** * Copyright (c) 2021 Expo, Inc. * Copyright (c) 2021 Callstack, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * Based on https://github.com/callstack/repack/blob/3c1e059/packages/repack/src/webpack/plugins/AssetsPlugin/assetsLoader.ts */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.raw = void 0; const crypto_1 = __importDefault(require("crypto")); const image_size_1 = require("image-size"); const loader_utils_1 = __importDefault(require("loader-utils")); const path_1 = __importDefault(require("path")); const schema_utils_1 = require("schema-utils"); const util_1 = require("util"); const escapeStringRegexp_1 = require("../../utils/escapeStringRegexp"); const NativeAssetResolver_1 = require("./NativeAssetResolver"); function getOptions(loaderContext) { const options = loader_utils_1.default.getOptions(loaderContext) || {}; schema_utils_1.validate({ type: 'object', required: ['platforms', 'assetExtensions'], properties: { platforms: { type: 'array', items: { type: 'string', }, }, assetExtensions: { type: 'array', items: { type: 'string', }, }, persist: { type: 'boolean' }, publicPath: { type: 'string' }, }, }, options, { name: 'nativeAssetsLoader' }); return options; } exports.raw = true; function getAndroidResourceFolder({ name, contents, scale, scaleFilePath, }) { const testXml = /\.(xml)$/; const testImages = /\.(png|jpg|gif|webp)$/; const testFonts = /\.(ttf|otf|ttc)$/; if ( // found font family (testXml.test(name) && (contents === null || contents === void 0 ? void 0 : contents.includes('font-family'))) || // font extensions testFonts.test(name)) { return 'font'; } else if (testImages.test(name) || testXml.test(name)) { // images extensions switch (scale) { case '@0.75x': return 'drawable-ldpi'; case '@1x': return 'drawable-mdpi'; case '@1.5x': return 'drawable-hdpi'; case '@2x': return 'drawable-xhdpi'; case '@3x': return 'drawable-xxhdpi'; case '@4x': return 'drawable-xxxhdpi'; default: throw new Error(`Unknown scale ${scale} for ${scaleFilePath}`); } } // everything else is going to RAW return 'raw'; } async function nativeAssetsLoader() { this.cacheable(); const callback = this.async(); const logger = this.getLogger('nativeAssetsLoader'); const rootContext = this.rootContext; logger.debug('Processing:', this.resourcePath); try { const options = getOptions(this); const pathSeparatorPattern = new RegExp(`\\${path_1.default.sep}`, 'g'); const resourcePath = this.resourcePath; const dirname = path_1.default.dirname(resourcePath); // Relative path to rootContext without any ../ due to https://github.com/callstack/haul/issues/474 // Assets from from outside of rootContext, should still be placed inside bundle output directory. // Example: // resourcePath = monorepo/node_modules/my-module/image.png // dirname = monorepo/node_modules/my-module // rootContext = monorepo/packages/my-app/ // relativeDirname = ../../node_modules/my-module (original) // So when we calculate destination for the asset for iOS ('assets' + relativeDirname + filename), // it will end up outside of `assets` directory, so we have to make sure it's: // relativeDirname = node_modules/my-module (tweaked) const relativeDirname = path_1.default .relative(rootContext, dirname) .replace(new RegExp(`^[\\.\\${path_1.default.sep}]+`), ''); const type = path_1.default.extname(resourcePath).replace(/^\./, ''); const assetsPath = 'assets'; const suffix = `(@\\d+(\\.\\d+)?x)?(\\.(${options.platforms.join('|')}))?\\.${type}$`; const filename = path_1.default.basename(resourcePath).replace(new RegExp(suffix), ''); // Name with embedded relative dirname eg `node_modules_reactnative_libraries_newappscreen_components_logo.png` const normalizedName = `${(relativeDirname.length === 0 ? filename : `${relativeDirname.replace(pathSeparatorPattern, '_')}_${filename}`) .toLowerCase() .replace(/[^a-z0-9_]/g, '')}.${type}`; const files = await new Promise((resolve, reject) => this.fs.readdir(dirname, (error, results) => { var _a, _b; if (error) { reject(error); } else { resolve((_b = (_a = results) === null || _a === void 0 ? void 0 : _a.filter(result => typeof result === 'string')) !== null && _b !== void 0 ? _b : []); } })); const scales = NativeAssetResolver_1.NativeAssetResolver.collectScales(files, { name: filename, type, assetExtensions: options.assetExtensions, platforms: options.platforms, }); const scaleKeys = Object.keys(scales).sort((a, b) => parseInt(a.replace(/[^\d.]/g, ''), 10) - parseInt(b.replace(/[^\d.]/g, ''), 10)); const readFileAsync = util_1.promisify(this.fs.readFile.bind(this.fs)); const resolveAssetOutput = (results, scale, scaleFilePath) => { if (options.persist && options.platforms.includes('android')) { const destination = getAndroidResourceFolder({ name: normalizedName, scale, scaleFilePath, contents: results, }); return path_1.default.join(destination, normalizedName); } const name = `${filename}${scale === '@1x' ? '' : scale}.${type}`; return path_1.default.join(assetsPath, relativeDirname, name); }; const resolveScaleAsync = async (scale) => { const scaleFilePath = path_1.default.join(dirname, scales[scale].name); this.addDependency(scaleFilePath); const results = await readFileAsync(scaleFilePath); return { content: results, destination: resolveAssetOutput(results, scale, scaleFilePath), }; }; const assets = await Promise.all(scaleKeys.map(resolveScaleAsync)); assets.forEach(asset => { const { destination, content } = asset; logger.debug('Asset emitted:', destination); // Assets are emitted relatively to `output.path`. this.emitFile(destination, content !== null && content !== void 0 ? content : ''); }); let publicPath = path_1.default.join(assetsPath, relativeDirname).replace(pathSeparatorPattern, '/'); if (options.publicPath) { publicPath = path_1.default.join(options.publicPath, publicPath); } const hashes = assets.map(asset => { var _a, _b; return crypto_1.default .createHash('md5') .update((_b = (_a = asset.content) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : asset.destination, 'utf8') .digest('hex'); }); let info; try { info = image_size_1.imageSize(this.resourcePath); const match = path_1.default .basename(this.resourcePath) .match(new RegExp(`^${escapeStringRegexp_1.escapeStringRegexp(filename)}${suffix}`)); if (match === null || match === void 0 ? void 0 : match[1]) { const scale = Number(match[1].replace(/[^\d.]/g, '')); if (typeof scale === 'number' && Number.isFinite(scale)) { info.width && (info.width /= scale); info.height && (info.height /= scale); } } } catch { // Asset is not an image } logger.debug('Asset processed:', { resourcePath, platforms: options.platforms, rootContext, relativeDirname, type, assetsPath, filename, normalizedName, scales, assets: assets.map(asset => asset.destination), publicPath, width: info === null || info === void 0 ? void 0 : info.width, height: info === null || info === void 0 ? void 0 : info.height, }); callback === null || callback === void 0 ? void 0 : callback(null, createAssetCodeBlock({ persist: !!options.persist, scales, filename, type, hashes, httpServerLocation: publicPath, fileSystemLocation: dirname, ...(info || {}), })); } catch (error) { callback === null || callback === void 0 ? void 0 : callback(error); } } exports.default = nativeAssetsLoader; function createAssetCodeBlock({ persist, scales, filename, type, hashes, httpServerLocation, height, width, fileSystemLocation, }) { return [ `var AssetRegistry = require('react-native/Libraries/Image/AssetRegistry');`, `module.exports = AssetRegistry.registerAsset({`, ` __packager_asset: true,`, ` scales: ${JSON.stringify(scales)},`, ` name: ${JSON.stringify(filename)},`, ` type: ${JSON.stringify(type)},`, ` hash: ${JSON.stringify(hashes.join())},`, ` httpServerLocation: ${JSON.stringify(httpServerLocation)},`, ` ${persist ? '' : `fileSystemLocation: ${JSON.stringify(fileSystemLocation)},`}`, ` ${height != null ? `height: ${height},` : ''}`, ` ${width != null ? `width: ${width},` : ''}`, `});`, ].join('\n'); } //# sourceMappingURL=loader.js.map