'use strict'; const path = require('path'); const url = require('url'); /** * Normalazing result url, before replace decl value * * @param {String} assetUrl * @returns {String} */ const normalize = (assetUrl) => { assetUrl = path.normalize(assetUrl); return path.sep === '\\' ? assetUrl.replace(/\\/g, '\/') : assetUrl; }; /** * @param {String} assetUrl * @returns {Boolean} */ const isUrlWithoutPathname = (assetUrl) => { return assetUrl[0] === '#' || assetUrl.indexOf('%23') === 0 || assetUrl.indexOf('data:') === 0 || /^[a-z]+:\/\//.test(assetUrl) || /^\/\//.test(assetUrl); }; /** * Check if url is absolute, hash or data-uri * * @param {String} assetUrl * @param {PostcssUrl~Options} options * @returns {Boolean} */ const isUrlShouldBeIgnored = (assetUrl, options) => { const isAbsolutePath = assetUrl[0] === '/'; const isStartsWithTilde = assetUrl[0] === '~'; return isUrlWithoutPathname(assetUrl) || ((isAbsolutePath || isStartsWithTilde) && !options.basePath); }; /** * @param {String} baseDir - absolute target path * @param {String} assetsPath - extend asset path, can be absolute path * @param {String} relative - current relative asset path * @returns {String} */ const getAssetsPath = (baseDir, assetsPath, relative) => path.resolve(baseDir, assetsPath || '', relative || ''); /** * Target path, output base dir * * @param {Dir} dir * @returns {String} */ const getTargetDir = (dir) => dir.from !== dir.to ? dir.to : process.cwd(); /** * Stylesheet file path from decl * * @param {Decl} decl * @returns {String} */ const getPathDeclFile = (decl) => decl.source && decl.source.input && decl.source.input.file; /** * Stylesheet file dir from decl * * @param {Decl} decl * @returns {String} */ const getDirDeclFile = (decl) => { const filename = getPathDeclFile(decl); return filename ? path.dirname(filename) : process.cwd(); }; /** * Returns paths list, where we can find assets file * * @param {String[]|String} basePath - base paths where trying search to assets file * @param {Dir} dirFrom * @param {String} relPath - relative asset path * @returns {String[]} */ const getPathByBasePath = (basePath, dirFrom, relPath) => { if (relPath[0] === '/') { relPath = `.${relPath}`; } basePath = !Array.isArray(basePath) ? [basePath] : basePath; return basePath.map((pathItem) => getAssetsPath(dirFrom, pathItem, relPath) ); }; /** * Preparing asset paths and data * * @param {String} assetUrl * @param {PostcssUrl~Dir} dir * @param {Decl} decl * @returns {PostcssUrl~Asset} */ const prepareAsset = (assetUrl, dir, decl) => { const parsedUrl = url.parse(assetUrl); const pathname = !isUrlWithoutPathname(assetUrl) ? parsedUrl.pathname : null; const absolutePath = pathname ? path.resolve(path.join(dir.file, pathname)) : getPathDeclFile(decl); return { url: assetUrl, originUrl: assetUrl, pathname, absolutePath: absolutePath || dir.from, relativePath: absolutePath ? path.relative(dir.from, absolutePath) : '.', search: (parsedUrl.search || ''), hash: (parsedUrl.hash || '') }; }; module.exports = { normalize, prepareAsset, getAssetsPath, getDirDeclFile, getPathDeclFile, getTargetDir, getPathByBasePath, isUrlShouldBeIgnored }; /** * @typedef {Object} PostcssUrl~Asset * @property {String} url - origin asset url * @property {String} name - parsed asset filename * @property {String} absolutePath - absolute asset path * @property {String} relativePath - relative asset path (relative to target dir) * @property {String} search - search from url, ex. ?query=1 * @property {String} hash - hash from url */ /** * @typedef {Object} PostcssUrl~Dir * @property {String} from - dirname from postcss option 'from' * @property {String} to - dirname from postcss option 'to' * @property {String} file - decl file dirname (css file) */