json-q
Version:
Retrieves values from JSON objects (and JavaScript objects) by css-selector-like query (includes attribute filters and array flattening).
144 lines (127 loc) • 3.96 kB
JavaScript
var fs = require('fs');
var path = require('path');
var requireRelative = require('require-relative');
var normalizePreset = require('./normalize-preset');
var join = path.join;
var dirname = path.dirname;
var relative = path.relative;
function getModulePath(filepath) {
return filepath.replace(/(.*([\\/]node_modules|\.\.)[\\/](@[^\\/]+[\\/])?[^\\/]+)([\\/].*)?$/g, '$1')
}
// Attempt to require a module, returning false on error
function req(name) {
try {
return require(name);
} catch (err) {
return false;
}
}
// Attempt to resolve a module, returning `undefined` on error
function resolve(name, relativeTo) {
var path = false;
try {
path = requireRelative.resolve(name, relativeTo);
} catch (err) {
console.log('resolve failed for "'+name+'": '+err);
}
return path;
}
// fast npm always use symlink
// and it resulted in module duplicated
// or alias
function fillAliasMap(path, list, map) {
return list.reduce(function (symlinkedList, mod) {
var realPath = relative(path, fs.realpathSync(join(path, mod)));
if (realPath !== mod) {
symlinkedList[realPath] = (mod);
}
return symlinkedList;
}, map || {});
}
// Get a list of child module names for the given module path
function getChildren(path, type, alias) {
var modules;
try {
modules = fs.readdirSync(join(path, 'node_modules'));
} catch (err) {
path = path.replace(/([\\/]node_modules)([\\/].*)?$/g, '$1');
modules = fs.readdirSync(path);
}
var children = (modules || [])
.filter( realFile )
.sort( reverseSorter(type==='plugin' ? isPlugin : isPreset) );
fillAliasMap(path, children, alias);
return children;
}
// is a filename an actual file
function realFile(f) {
return f && f.charAt(0)!=='.';
}
// ascending sort based on the truthiness of a function
function reverseSorter(comparison) {
return function(a, b) {
var ca = comparison(a),
cb = comparison(b);
return ca===cb ? 0 : (ca ? 1 : cb ? -1 : 0);
}
}
function isPreset(name) { return name && name.match(/^babel\-preset\-/g); }
function isPlugin(name) { return name && name.match(/^babel\-plugin\-/g); }
// find the matching module *instance* in a list of module paths, remove and return it
function findAndRemove(preset, path, list) {
for (var i=list.length; i--; ) {
var p = resolve(list[i], path),
v = p && req(p);
if (v && v===preset) {
list.splice(i, 1);
return p;
}
}
}
/** Resolve & serialize a Babel preset to a filename-based representation.
* Nested filepaths are relative to `relativeTo` if specified.
* Presets referenced as Strings (uncommon) are treated as dependencies of the preset that returned them.
*/
function loadPreset(name, opts, relativeTo) {
var path = resolve(name, relativeTo),
mod = normalizePreset(path && req(path), null, opts.options);
if (!mod) throw new Error('Preset "'+name+'" not found.');
path = dirname(path);
var out = {
alias: {}
};
if (mod.presets) {
var availablePresets = getChildren(path, 'preset', out.alias);
out.presets = mod.presets.map(function(preset) {
if (typeof preset!=='string') {
preset = findAndRemove(preset, path, availablePresets);
}
return loadPreset(preset, opts, path);
});
}
if (mod.plugins) {
var availablePlugins = getChildren(path, 'plugin', out.alias);
out.plugins = mod.plugins.map(function(plugin) {
var name = Array.isArray(plugin) ? plugin[0] : plugin;
if (typeof name!=='string') {
if (name._original_name) {
// console.log('using _original_name: ', name._original_name);
name = name._original_name;
}
else {
name = findAndRemove(name, path, availablePlugins);
}
}
if (!name) return plugin;
name = resolve(name, path);
name = getModulePath(name);
if (opts) {
if (opts.cwd) name = relative(opts.cwd, name);
if (opts.transform) name = opts.transform(name);
}
return Array.isArray(plugin) ? [name].concat(plugin.slice(1)) : name;
});
}
return out;
}
module.exports = loadPreset;