"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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __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.urlToBuiltUrl = exports.getAssetHash = exports.assetFileNamesToFileName = exports.getAssetFilename = exports.fileToUrl = exports.checkPublicFile = exports.registerAssetToChunk = exports.assetPlugin = exports.chunkToEmittedAssetsMap = exports.assetUrlRE = void 0; const path_1 = __importDefault(require("path")); const url_1 = require("url"); const lite_1 = __importDefault(require("mime/lite")); const fs_1 = __importStar(require("fs")); const magic_string_1 = __importDefault(require("magic-string")); const crypto_1 = require("crypto"); const utils_1 = require("../utils"); const utils_2 = require("../../../../vite/utils/utils"); const shared_1 = require("@vue/shared"); exports.assetUrlRE = /__VITE_ASSET__([a-z\d]{8})__(?:\$_(.*?)__)?/g; // urls in JS must be quoted as strings, so when replacing them we need // a different regex const assetUrlQuotedRE = /"__VITE_ASSET__([a-z\d]{8})__(?:\$_(.*?)__)?"/g; const rawRE = /(\?|&)raw(?:&|$)/; const urlRE = /(\?|&)url(?:&|$)/; exports.chunkToEmittedAssetsMap = new WeakMap(); const assetCache = new WeakMap(); const assetHashToFilenameMap = new WeakMap(); // save hashes of the files that has been emitted in build watch const emittedHashMap = new WeakMap(); /** * Also supports loading plain strings with import text from './foo.txt?raw' */ function assetPlugin(config) { // assetHashToFilenameMap initialization in buildStart causes getAssetFilename to return undefined assetHashToFilenameMap.set(config, new Map()); return { name: 'vite:asset', buildStart() { assetCache.set(config, new Map()); emittedHashMap.set(config, new Set()); }, resolveId(id) { if (!config.assetsInclude((0, utils_1.cleanUrl)(id))) { return; } // imports to absolute urls pointing to files in /public // will fail to resolve in the main resolver. handle them here. const publicFile = checkPublicFile(id, config); if (publicFile) { return id; } }, async load(id) { if (id.startsWith('\0')) { // Rollup convention, this id should be handled by the // plugin that marked it with \0 return; } // raw requests, read from disk if (rawRE.test(id)) { const file = checkPublicFile(id, config) || (0, utils_1.cleanUrl)(id); // raw query, read file and return as string return `export default ${JSON.stringify(await fs_1.promises.readFile(file, 'utf-8'))}`; } if (!config.assetsInclude((0, utils_1.cleanUrl)(id)) && !urlRE.test(id)) { return; } id = id.replace(urlRE, '$1').replace(/[\?&]$/, ''); const url = await fileToUrl(id, config, this); return `export default ${JSON.stringify(url)}`; }, renderChunk(code, chunk) { let match; let s; while ((match = assetUrlQuotedRE.exec(code))) { s = s || (s = new magic_string_1.default(code)); const [full, hash, postfix = ''] = match; // some internal plugins may still need to emit chunks (e.g. worker) so // fallback to this.getFileName for that. const file = getAssetFilename(hash, config) || this.getFileName(hash); registerAssetToChunk(chunk, file); const outputFilepath = config.base + file + postfix; s.overwrite(match.index, match.index + full.length, JSON.stringify(outputFilepath)); } if (s) { return { code: s.toString(), map: (0, utils_2.withSourcemap)(config) ? s.generateMap({ hires: true }) : null, }; } else { return null; } }, }; } exports.assetPlugin = assetPlugin; function registerAssetToChunk(chunk, file) { let emitted = exports.chunkToEmittedAssetsMap.get(chunk); if (!emitted) { emitted = new Set(); exports.chunkToEmittedAssetsMap.set(chunk, emitted); } emitted.add((0, utils_1.cleanUrl)(file)); } exports.registerAssetToChunk = registerAssetToChunk; function checkPublicFile(url, { publicDir }) { // note if the file is in /public, the resolver would have returned it // as-is so it's not going to be a fully resolved path. if (!publicDir || !url.startsWith('/')) { return; } const publicFile = path_1.default.join(publicDir, (0, utils_1.cleanUrl)(url)); if (fs_1.default.existsSync(publicFile)) { return publicFile; } else { return; } } exports.checkPublicFile = checkPublicFile; function fileToUrl(id, config, ctx, canInline = false) { return fileToBuiltUrl(id, config, ctx, false, canInline); } exports.fileToUrl = fileToUrl; function getAssetFilename(hash, config) { var _a; return (_a = assetHashToFilenameMap.get(config)) === null || _a === void 0 ? void 0 : _a.get(hash); } exports.getAssetFilename = getAssetFilename; /** * converts the source filepath of the asset to the output filename based on the assetFileNames option. \ * this function imitates the behavior of rollup.js. \ * https://rollupjs.org/guide/en/#outputassetfilenames * * @example * ```ts * const content = Buffer.from('text'); * const fileName = assetFileNamesToFileName( * 'assets/[name].[hash][extname]', * '/path/to/file.txt', * getAssetHash(content), * content * ) * // fileName: 'assets/file.982d9e3e.txt' * ``` * * @param assetFileNames filename pattern. e.g. `'assets/[name].[hash][extname]'` * @param file filepath of the asset * @param contentHash hash of the asset. used for `'[hash]'` placeholder * @param content content of the asset. passed to `assetFileNames` if `assetFileNames` is a function * @returns output filename */ function assetFileNamesToFileName(assetFileNames, file, contentHash, content) { const basename = path_1.default.basename(file); // placeholders for `assetFileNames` // `hash` is slightly different from the rollup's one const extname = path_1.default.extname(basename); const ext = extname.substring(1); const name = basename.slice(0, -extname.length); const hash = contentHash; if ((0, shared_1.isFunction)(assetFileNames)) { assetFileNames = assetFileNames({ name: file, source: content, type: 'asset', }); if (!(0, shared_1.isString)(assetFileNames)) { throw new TypeError('assetFileNames must return a string'); } } else if (!(0, shared_1.isString)(assetFileNames)) { throw new TypeError('assetFileNames must be a string or a function'); } const fileName = assetFileNames.replace(/\[\w+\]/g, (placeholder) => { switch (placeholder) { case '[ext]': return ext; case '[extname]': return extname; case '[hash]': return hash; case '[name]': return sanitizeFileName(name); } throw new Error(`invalid placeholder ${placeholder} in assetFileNames "${assetFileNames}"`); }); return fileName; } exports.assetFileNamesToFileName = assetFileNamesToFileName; // taken from https://github.com/rollup/rollup/blob/a8647dac0fe46c86183be8596ef7de25bc5b4e4b/src/utils/sanitizeFileName.ts // https://datatracker.ietf.org/doc/html/rfc2396 // eslint-disable-next-line no-control-regex const INVALID_CHAR_REGEX = /[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g; const DRIVE_LETTER_REGEX = /^[a-z]:/i; function sanitizeFileName(name) { const match = DRIVE_LETTER_REGEX.exec(name); const driveLetter = match ? match[0] : ''; // A `:` is only allowed as part of a windows drive letter (ex: C:\foo) // Otherwise, avoid them because they can refer to NTFS alternate data streams. return (driveLetter + name.substring(driveLetter.length).replace(INVALID_CHAR_REGEX, '_')); } /** * Register an asset to be emitted as part of the bundle (if necessary) * and returns the resolved public URL */ function fileToBuiltUrl(id, config, pluginContext, skipPublicCheck = false, canInline = false) { if (!skipPublicCheck && checkPublicFile(id, config)) { return config.base + id.slice(1); } const cache = assetCache.get(config); const cached = cache.get(id); if (cached) { return cached; } const file = (0, utils_1.cleanUrl)(id); const content = fs_1.default.readFileSync(file); let url; if (canInline && content.length < Number(config.build.assetsInlineLimit)) { // base64 inlined as a string url = `data:${lite_1.default.getType(file)};base64,${content.toString('base64')}`; } else { const map = assetHashToFilenameMap.get(config); const contentHash = getAssetHash(content); const { search, hash } = (0, url_1.parse)(id); const postfix = (search || '') + (hash || ''); const inputDir = (0, utils_1.normalizePath)(process.env.UNI_INPUT_DIR); let fileName = file.startsWith(inputDir) ? path_1.default.posix.relative(inputDir, file) : assetFileNamesToFileName(path_1.default.posix.join(config.build.assetsDir, '[name].[hash][extname]'), file, contentHash, content); if (!map.has(contentHash)) { map.set(contentHash, fileName); } if (!fileName.includes('/static/')) { const emittedSet = emittedHashMap.get(config); if (!emittedSet.has(contentHash)) { pluginContext.emitFile({ name: fileName, fileName, type: 'asset', source: content, }); emittedSet.add(contentHash); } } url = `__VITE_ASSET__${contentHash}__${postfix ? `$_${postfix}__` : ``}`; } cache.set(id, url); return url; } function getAssetHash(content) { return (0, crypto_1.createHash)('sha256').update(content).digest('hex').slice(0, 8); } exports.getAssetHash = getAssetHash; function urlToBuiltUrl(url, importer, config, pluginContext) { if (checkPublicFile(url, config)) { return config.base + url.slice(1); } const file = url.startsWith('/') ? path_1.default.join(config.root, url) : path_1.default.join(path_1.default.dirname(importer), url); return fileToBuiltUrl(file, config, pluginContext, // skip public check since we just did it above true); } exports.urlToBuiltUrl = urlToBuiltUrl;