114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const merge = require('lodash.merge');
|
|
|
|
const reExt = /\.(css|scss|sass)$/;
|
|
|
|
const defaults = {
|
|
prev: '',
|
|
includePaths: [],
|
|
nodeModules: './node_modules'
|
|
};
|
|
|
|
function isExternal(filePath) {
|
|
return filePath.startsWith('http://') || filePath.startsWith('https://') || filePath.startsWith('//') || filePath.startsWith('\\\\') || filePath.startsWith('url(');
|
|
}
|
|
|
|
function _resolve( options ) {
|
|
const opts = merge( {}, defaults, options );
|
|
const {
|
|
file,
|
|
prev,
|
|
nodeModules
|
|
} = opts;
|
|
let { includePaths } = opts;
|
|
|
|
let candidte;
|
|
let cwd = path.extname(prev) ? path.dirname(prev) : prev;
|
|
let meta = path.parse(file);
|
|
let matches = new Set();
|
|
|
|
// Skip external stylesheets
|
|
if (isExternal(file)) {
|
|
return [ file ];
|
|
}
|
|
|
|
// Absolute path
|
|
if (path.isAbsolute(file)) {
|
|
cwd = '';
|
|
includePaths = [];
|
|
}
|
|
|
|
// node_modules import
|
|
if (file.startsWith('~')) {
|
|
meta = path.parse(file.slice(1));
|
|
cwd = path.resolve(nodeModules);
|
|
includePaths = [];
|
|
}
|
|
|
|
// Import from parent
|
|
if (file.startsWith('.')) {
|
|
includePaths = [];
|
|
}
|
|
|
|
// Only unique paths
|
|
includePaths = new Set([ cwd, ...includePaths ]);
|
|
|
|
includePaths.forEach(( dir ) => {
|
|
candidte = path.resolve(dir, path.format(meta));
|
|
|
|
// Has extension
|
|
if ( reExt.test(candidte) ) {
|
|
matches.add(candidte);
|
|
} else {
|
|
// No extension
|
|
if (meta.base.startsWith('_')) {
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}.css`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}.scss`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}.sass`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/index.scss`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/index.sass`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/_index.scss`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/_index.sass`));
|
|
} else {
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}.css`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}.scss`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}.sass`));
|
|
matches.add(path.resolve(dir, meta.dir, `_${meta.base}.scss`));
|
|
matches.add(path.resolve(dir, meta.dir, `_${meta.base}.sass`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/index.scss`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/index.sass`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/_index.scss`));
|
|
matches.add(path.resolve(dir, meta.dir, `${meta.base}/_index.sass`));
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
return [ ...matches ];
|
|
|
|
}
|
|
|
|
function resolve( options ) {
|
|
|
|
let file = options.file;
|
|
let resolved = _resolve(options);
|
|
let existing = [];
|
|
|
|
if (resolved.length && isExternal(resolved[0])) {
|
|
return file;
|
|
}
|
|
|
|
resolved.forEach((candidate) => {
|
|
if (fs.existsSync(candidate)) {
|
|
existing.push(candidate);
|
|
}
|
|
});
|
|
|
|
return existing[0] || file;
|
|
}
|
|
|
|
|
|
module.exports.resolve = resolve;
|
|
module.exports._resolve = _resolve;
|