paths.js 3.96 KB
Newer Older
YazhouChen's avatar
YazhouChen committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
'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)
 */