mirror of https://github.com/webpack/webpack.git
184 lines
4.5 KiB
JavaScript
184 lines
4.5 KiB
JavaScript
/*
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
Author Tobias Koppers @sokra
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const { join, dirname, readJson } = require("../util/fs");
|
|
|
|
/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
|
|
|
|
/**
|
|
* @param {string} version version as string
|
|
* @returns {(number|string)[]} version as array
|
|
*/
|
|
exports.parseRequiredVersion = version => {
|
|
if (version === "*") return [];
|
|
let fuzzyStart = Infinity;
|
|
if (version.startsWith(">=")) {
|
|
fuzzyStart = 0;
|
|
version = version.slice(2);
|
|
} else if (version.startsWith("^")) {
|
|
fuzzyStart = 1;
|
|
version = version.slice(1);
|
|
} else if (version.startsWith("~")) {
|
|
fuzzyStart = 2;
|
|
version = version.slice(1);
|
|
}
|
|
return version
|
|
.split(".")
|
|
.map((x, i) => (i >= fuzzyStart && `${+x}` === x ? +x : x));
|
|
};
|
|
|
|
/**
|
|
* @param {string} version version as string
|
|
* @returns {(number|string)[]} version as array
|
|
*/
|
|
exports.parseVersion = version => {
|
|
return version.split(".").map(x => (`${+x}` === x ? +x : x));
|
|
};
|
|
|
|
/**
|
|
* @param {(number|string)[]} version version
|
|
* @returns {string} version as string
|
|
*/
|
|
exports.versionToString = version => {
|
|
if (!version) return "(unknown)";
|
|
if (version.length === 0) return "*";
|
|
const info = version.map(value =>
|
|
typeof value !== "string"
|
|
? {
|
|
type: "min",
|
|
value: `${value}`
|
|
}
|
|
: `${+value}` === value
|
|
? {
|
|
type: "exact",
|
|
value
|
|
}
|
|
: {
|
|
type: "tag",
|
|
value
|
|
}
|
|
);
|
|
switch (`${info[0].type}.${info.length > 1 ? info[1].type : "undefined"}`) {
|
|
case "exact.min":
|
|
case "tag.min":
|
|
if (!info.slice(2).some(i => i.type === "exact"))
|
|
return `^${version.join(".")}`;
|
|
break;
|
|
|
|
case "exact.exact":
|
|
case "exact.tag":
|
|
case "tag.exact":
|
|
case "tag.tag":
|
|
if (!info.slice(2).some(i => i.type === "exact"))
|
|
return `~${version.join(".")}`;
|
|
else if (!info.slice(2).some(i => i.type === "min"))
|
|
return version.join(".");
|
|
break;
|
|
|
|
case "min.min":
|
|
case "min.tag":
|
|
if (!info.slice(2).some(i => i.type === "exact"))
|
|
return `>=${version.join(".")}`;
|
|
break;
|
|
|
|
case "min.undefined":
|
|
return `>=${version.join(".")}`;
|
|
|
|
case "exact.undefined":
|
|
case "tag.undefined":
|
|
return version.join(".");
|
|
}
|
|
return info
|
|
.map(i => (i.type === "exact" ? i.value : `[>=${i.value}]`))
|
|
.join(".");
|
|
};
|
|
|
|
/**
|
|
* @param {string} str maybe required version
|
|
* @returns {boolean} true, if it looks like a version
|
|
*/
|
|
exports.isRequiredVersion = str => {
|
|
if (str === "*") return true;
|
|
if (/&&|\|\|/.test(str)) return false;
|
|
if (str.startsWith("^")) return true;
|
|
if (str.startsWith("~")) return true;
|
|
if (str.startsWith(">=")) return true;
|
|
return /^\d/.test(str);
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @param {InputFileSystem} fs file system
|
|
* @param {string} directory directory to start looking into
|
|
* @param {string[]} descriptionFiles possible description filenames
|
|
* @param {function(Error=, {data: object, path: string}=): void} callback callback
|
|
*/
|
|
const getDescriptionFile = (fs, directory, descriptionFiles, callback) => {
|
|
let i = 0;
|
|
const tryLoadCurrent = () => {
|
|
if (i >= descriptionFiles.length) {
|
|
const parentDirectory = dirname(fs, directory);
|
|
if (!parentDirectory || parentDirectory === directory) return callback();
|
|
return getDescriptionFile(
|
|
fs,
|
|
parentDirectory,
|
|
descriptionFiles,
|
|
callback
|
|
);
|
|
}
|
|
const filePath = join(fs, directory, descriptionFiles[i]);
|
|
readJson(fs, filePath, (err, data) => {
|
|
if (err) {
|
|
if ("code" in err && err.code === "ENOENT") {
|
|
i++;
|
|
return tryLoadCurrent();
|
|
}
|
|
return callback(err);
|
|
}
|
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
return callback(
|
|
new Error(`Description file ${filePath} is not an object`)
|
|
);
|
|
}
|
|
callback(null, { data, path: filePath });
|
|
});
|
|
};
|
|
tryLoadCurrent();
|
|
};
|
|
exports.getDescriptionFile = getDescriptionFile;
|
|
|
|
exports.getRequiredVersionFromDescriptionFile = (data, packageName) => {
|
|
if (
|
|
data.optionalDependencies &&
|
|
typeof data.optionalDependencies === "object" &&
|
|
packageName in data.optionalDependencies
|
|
) {
|
|
return data.optionalDependencies[packageName];
|
|
}
|
|
if (
|
|
data.dependencies &&
|
|
typeof data.dependencies === "object" &&
|
|
packageName in data.dependencies
|
|
) {
|
|
return data.dependencies[packageName];
|
|
}
|
|
if (
|
|
data.peerDependencies &&
|
|
typeof data.peerDependencies === "object" &&
|
|
packageName in data.peerDependencies
|
|
) {
|
|
return data.peerDependencies[packageName];
|
|
}
|
|
if (
|
|
data.devDependencies &&
|
|
typeof data.devDependencies === "object" &&
|
|
packageName in data.devDependencies
|
|
) {
|
|
return data.devDependencies[packageName];
|
|
}
|
|
};
|