@dependabot/yarn-lib
Version:
📦🐈 Fast, reliable, and secure dependency management.
616 lines (484 loc) • 19.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.integrityErrors = undefined;
var _extends2;
function _load_extends() {
return _extends2 = _interopRequireDefault(require('babel-runtime/helpers/extends'));
}
var _asyncToGenerator2;
function _load_asyncToGenerator() {
return _asyncToGenerator2 = _interopRequireDefault(require('babel-runtime/helpers/asyncToGenerator'));
}
var _constants;
function _load_constants() {
return _constants = _interopRequireWildcard(require('./constants.js'));
}
var _fs;
function _load_fs() {
return _fs = _interopRequireWildcard(require('./util/fs.js'));
}
var _misc;
function _load_misc() {
return _misc = require('./util/misc.js');
}
var _packageNameUtils;
function _load_packageNameUtils() {
return _packageNameUtils = require('./util/package-name-utils.js');
}
var _workspaceLayout;
function _load_workspaceLayout() {
return _workspaceLayout = _interopRequireDefault(require('./workspace-layout.js'));
}
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const invariant = require('invariant');
const path = require('path');
const integrityErrors = exports.integrityErrors = {
EXPECTED_IS_NOT_A_JSON: 'integrityFailedExpectedIsNotAJSON',
FILES_MISSING: 'integrityFailedFilesMissing',
LOCKFILE_DONT_MATCH: 'integrityLockfilesDontMatch',
FLAGS_DONT_MATCH: 'integrityFlagsDontMatch',
LINKED_MODULES_DONT_MATCH: 'integrityCheckLinkedModulesDontMatch',
PATTERNS_DONT_MATCH: 'integrityPatternsDontMatch',
MODULES_FOLDERS_MISSING: 'integrityModulesFoldersMissing',
SYSTEM_PARAMS_DONT_MATCH: 'integritySystemParamsDontMatch'
};
const INTEGRITY_FILE_DEFAULTS = () => ({
systemParams: (0, (_packageNameUtils || _load_packageNameUtils()).getSystemParams)(),
modulesFolders: [],
flags: [],
linkedModules: [],
topLevelPatterns: [],
lockfileEntries: {},
files: []
});
/**
*
*/
class InstallationIntegrityChecker {
constructor(config) {
this.config = config;
}
/**
* Get the common ancestor of every node_modules - it may be a node_modules directory itself, but isn't required to.
*/
_getModulesRootFolder() {
if (this.config.modulesFolder) {
return this.config.modulesFolder;
} else if (this.config.workspaceRootFolder) {
return this.config.workspaceRootFolder;
} else {
return path.join(this.config.lockfileFolder, (_constants || _load_constants()).NODE_MODULES_FOLDER);
}
}
/**
* Get the directory in which the yarn-integrity file should be written.
*/
_getIntegrityFileFolder() {
if (this.config.modulesFolder) {
return this.config.modulesFolder;
} else if (this.config.enableMetaFolder) {
return path.join(this.config.lockfileFolder, (_constants || _load_constants()).META_FOLDER);
} else {
return path.join(this.config.lockfileFolder, (_constants || _load_constants()).NODE_MODULES_FOLDER);
}
}
/**
* Get the full path of the yarn-integrity file.
*/
_getIntegrityFileLocation() {
var _this = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const locationFolder = _this._getIntegrityFileFolder();
const locationPath = path.join(locationFolder, (_constants || _load_constants()).INTEGRITY_FILENAME);
const exists = yield (_fs || _load_fs()).exists(locationPath);
return {
locationFolder,
locationPath,
exists
};
})();
}
/**
* Get the list of the directories that contain our modules (there might be multiple such folders b/c of workspaces).
*/
_getModulesFolders({ workspaceLayout } = {}) {
const locations = [];
if (this.config.modulesFolder) {
locations.push(this.config.modulesFolder);
} else {
locations.push(path.join(this.config.lockfileFolder, (_constants || _load_constants()).NODE_MODULES_FOLDER));
}
if (workspaceLayout) {
for (var _iterator = Object.keys(workspaceLayout.workspaces), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
const workspaceName = _ref;
const loc = workspaceLayout.workspaces[workspaceName].loc;
if (loc) {
locations.push(path.join(loc, (_constants || _load_constants()).NODE_MODULES_FOLDER));
}
}
}
return locations.sort((_misc || _load_misc()).sortAlpha);
}
/**
* Get a list of the files that are located inside our module folders.
*/
_getIntegrityListing({ workspaceLayout } = {}) {
var _this2 = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const files = [];
const recurse = (() => {
var _ref2 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir) {
for (var _iterator2 = yield (_fs || _load_fs()).readdir(dir), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref3;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref3 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref3 = _i2.value;
}
const file = _ref3;
const entry = path.join(dir, file);
const stat = yield (_fs || _load_fs()).lstat(entry);
if (stat.isDirectory()) {
yield recurse(entry);
} else {
files.push(entry);
}
}
});
return function recurse(_x) {
return _ref2.apply(this, arguments);
};
})();
for (var _iterator3 = _this2._getModulesFolders({ workspaceLayout }), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref4;
if (_isArray3) {
if (_i3 >= _iterator3.length) break;
_ref4 = _iterator3[_i3++];
} else {
_i3 = _iterator3.next();
if (_i3.done) break;
_ref4 = _i3.value;
}
const modulesFolder = _ref4;
if (yield (_fs || _load_fs()).exists(modulesFolder)) {
yield recurse(modulesFolder);
}
}
return files;
})();
}
/**
* Generate integrity hash of input lockfile.
*/
_generateIntegrityFile(lockfile, patterns, flags, workspaceLayout, artifacts) {
var _this3 = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const result = (0, (_extends2 || _load_extends()).default)({}, INTEGRITY_FILE_DEFAULTS(), {
artifacts
});
result.topLevelPatterns = patterns;
// If using workspaces, we also need to add the workspaces patterns to the top-level, so that we'll know if a
// dependency is added or removed into one of them. We must take care not to read the aggregator (if !loc).
//
// Also note that we can't use of workspaceLayout.workspaces[].manifest._reference.patterns, because when
// doing a "yarn check", the _reference property hasn't yet been properly initialized.
if (workspaceLayout) {
result.topLevelPatterns = result.topLevelPatterns.filter(function (p) {
// $FlowFixMe
return !workspaceLayout.getManifestByPattern(p);
});
for (var _iterator4 = Object.keys(workspaceLayout.workspaces), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
var _ref5;
if (_isArray4) {
if (_i4 >= _iterator4.length) break;
_ref5 = _iterator4[_i4++];
} else {
_i4 = _iterator4.next();
if (_i4.done) break;
_ref5 = _i4.value;
}
const name = _ref5;
if (!workspaceLayout.workspaces[name].loc) {
continue;
}
const manifest = workspaceLayout.workspaces[name].manifest;
if (manifest) {
for (var _iterator5 = (_constants || _load_constants()).DEPENDENCY_TYPES, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
var _ref6;
if (_isArray5) {
if (_i5 >= _iterator5.length) break;
_ref6 = _iterator5[_i5++];
} else {
_i5 = _iterator5.next();
if (_i5.done) break;
_ref6 = _i5.value;
}
const dependencyType = _ref6;
const dependencies = manifest[dependencyType];
if (!dependencies) {
continue;
}
for (var _iterator6 = Object.keys(dependencies), _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) {
var _ref7;
if (_isArray6) {
if (_i6 >= _iterator6.length) break;
_ref7 = _iterator6[_i6++];
} else {
_i6 = _iterator6.next();
if (_i6.done) break;
_ref7 = _i6.value;
}
const dep = _ref7;
result.topLevelPatterns.push(`${dep}@${dependencies[dep]}`);
}
}
}
}
}
result.topLevelPatterns.sort((_misc || _load_misc()).sortAlpha);
if (flags.checkFiles) {
result.flags.push('checkFiles');
}
if (flags.flat) {
result.flags.push('flat');
}
if (_this3.config.ignoreScripts) {
result.flags.push('ignoreScripts');
}
if (_this3.config.focus) {
result.flags.push('focus: ' + _this3.config.focusedWorkspaceName);
}
if (_this3.config.production) {
result.flags.push('production');
}
if (_this3.config.plugnplayEnabled) {
result.flags.push('plugnplay');
}
const linkedModules = _this3.config.linkedModules;
if (linkedModules.length) {
result.linkedModules = linkedModules.sort((_misc || _load_misc()).sortAlpha);
}
for (var _iterator7 = Object.keys(lockfile), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) {
var _ref8;
if (_isArray7) {
if (_i7 >= _iterator7.length) break;
_ref8 = _iterator7[_i7++];
} else {
_i7 = _iterator7.next();
if (_i7.done) break;
_ref8 = _i7.value;
}
const key = _ref8;
result.lockfileEntries[key] = lockfile[key].resolved || '';
}
for (var _iterator8 = _this3._getModulesFolders({ workspaceLayout }), _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) {
var _ref9;
if (_isArray8) {
if (_i8 >= _iterator8.length) break;
_ref9 = _iterator8[_i8++];
} else {
_i8 = _iterator8.next();
if (_i8.done) break;
_ref9 = _i8.value;
}
const modulesFolder = _ref9;
if (yield (_fs || _load_fs()).exists(modulesFolder)) {
result.modulesFolders.push(path.relative(_this3.config.lockfileFolder, modulesFolder));
}
}
if (flags.checkFiles) {
const modulesRoot = _this3._getModulesRootFolder();
result.files = (yield _this3._getIntegrityListing({ workspaceLayout })).map(function (entry) {
return path.relative(modulesRoot, entry);
}).sort((_misc || _load_misc()).sortAlpha);
}
return result;
})();
}
_getIntegrityFile(locationPath) {
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const expectedRaw = yield (_fs || _load_fs()).readFile(locationPath);
try {
return (0, (_extends2 || _load_extends()).default)({}, INTEGRITY_FILE_DEFAULTS(), JSON.parse(expectedRaw));
} catch (e) {
// ignore JSON parsing for legacy text integrity files compatibility
}
return null;
})();
}
_compareIntegrityFiles(actual, expected, checkFiles, workspaceLayout) {
if (!expected) {
return 'EXPECTED_IS_NOT_A_JSON';
}
if (!(0, (_misc || _load_misc()).compareSortedArrays)(actual.linkedModules, expected.linkedModules)) {
return 'LINKED_MODULES_DONT_MATCH';
}
if (actual.systemParams !== expected.systemParams) {
return 'SYSTEM_PARAMS_DONT_MATCH';
}
let relevantExpectedFlags = expected.flags.slice();
// If we run "yarn" after "yarn --check-files", we shouldn't fail the less strict validation
if (actual.flags.indexOf('checkFiles') === -1) {
relevantExpectedFlags = relevantExpectedFlags.filter(flag => flag !== 'checkFiles');
}
if (!(0, (_misc || _load_misc()).compareSortedArrays)(actual.flags, relevantExpectedFlags)) {
return 'FLAGS_DONT_MATCH';
}
if (!(0, (_misc || _load_misc()).compareSortedArrays)(actual.topLevelPatterns, expected.topLevelPatterns || [])) {
return 'PATTERNS_DONT_MATCH';
}
for (var _iterator9 = Object.keys(actual.lockfileEntries), _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) {
var _ref10;
if (_isArray9) {
if (_i9 >= _iterator9.length) break;
_ref10 = _iterator9[_i9++];
} else {
_i9 = _iterator9.next();
if (_i9.done) break;
_ref10 = _i9.value;
}
const key = _ref10;
if (actual.lockfileEntries[key] !== expected.lockfileEntries[key]) {
return 'LOCKFILE_DONT_MATCH';
}
}
for (var _iterator10 = Object.keys(expected.lockfileEntries), _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) {
var _ref11;
if (_isArray10) {
if (_i10 >= _iterator10.length) break;
_ref11 = _iterator10[_i10++];
} else {
_i10 = _iterator10.next();
if (_i10.done) break;
_ref11 = _i10.value;
}
const key = _ref11;
if (actual.lockfileEntries[key] !== expected.lockfileEntries[key]) {
return 'LOCKFILE_DONT_MATCH';
}
}
if (checkFiles) {
// Early bailout if we expect more files than what we have
if (expected.files.length > actual.files.length) {
return 'FILES_MISSING';
}
// Since we know the "files" array is sorted (alphabetically), we can optimize the thing
// Instead of storing the files in a Set, we can just iterate both arrays at once. O(n)!
for (let u = 0, v = 0; u < expected.files.length; ++u) {
// Index that, if reached, means that we won't have enough food to match the remaining expected entries anyway
const max = v + (actual.files.length - v) - (expected.files.length - u) + 1;
// Skip over files that have been added (ie not present in 'expected')
while (v < max && actual.files[v] !== expected.files[u]) {
v += 1;
}
// If we've reached the index defined above, the file is either missing or we can early exit
if (v === max) {
return 'FILES_MISSING';
}
}
}
return 'OK';
}
check(patterns, lockfile, flags, workspaceLayout) {
var _this4 = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
// check if patterns exist in lockfile
const missingPatterns = patterns.filter(function (p) {
return !lockfile[p] && (!workspaceLayout || !workspaceLayout.getManifestByPattern(p));
});
const loc = yield _this4._getIntegrityFileLocation();
if (missingPatterns.length || !loc.exists) {
return {
integrityFileMissing: !loc.exists,
missingPatterns
};
}
const actual = yield _this4._generateIntegrityFile(lockfile, patterns, flags, workspaceLayout);
const expected = yield _this4._getIntegrityFile(loc.locationPath);
let integrityMatches = _this4._compareIntegrityFiles(actual, expected, flags.checkFiles, workspaceLayout);
if (integrityMatches === 'OK') {
invariant(expected, "The integrity shouldn't pass without integrity file");
for (var _iterator11 = expected.modulesFolders, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) {
var _ref12;
if (_isArray11) {
if (_i11 >= _iterator11.length) break;
_ref12 = _iterator11[_i11++];
} else {
_i11 = _iterator11.next();
if (_i11.done) break;
_ref12 = _i11.value;
}
const modulesFolder = _ref12;
if (!(yield (_fs || _load_fs()).exists(path.join(_this4.config.lockfileFolder, modulesFolder)))) {
integrityMatches = 'MODULES_FOLDERS_MISSING';
}
}
}
return {
integrityFileMissing: false,
integrityMatches: integrityMatches === 'OK',
integrityError: integrityMatches === 'OK' ? undefined : integrityMatches,
missingPatterns,
hardRefreshRequired: integrityMatches === 'SYSTEM_PARAMS_DONT_MATCH'
};
})();
}
/**
* Get artifacts from integrity file if it exists.
*/
getArtifacts() {
var _this5 = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const loc = yield _this5._getIntegrityFileLocation();
if (!loc.exists) {
return null;
}
const expectedRaw = yield (_fs || _load_fs()).readFile(loc.locationPath);
let expected;
try {
expected = JSON.parse(expectedRaw);
} catch (e) {
// ignore JSON parsing for legacy text integrity files compatibility
}
return expected ? expected.artifacts : null;
})();
}
/**
* Write the integrity hash of the current install to disk.
*/
save(patterns, lockfile, flags, workspaceLayout, artifacts) {
var _this6 = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const integrityFile = yield _this6._generateIntegrityFile(lockfile, patterns, flags, workspaceLayout, artifacts);
const loc = yield _this6._getIntegrityFileLocation();
invariant(loc.locationPath, 'expected integrity hash location');
yield (_fs || _load_fs()).mkdirp(path.dirname(loc.locationPath));
yield (_fs || _load_fs()).writeFile(loc.locationPath, JSON.stringify(integrityFile, null, 2));
})();
}
removeIntegrityFile() {
var _this7 = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const loc = yield _this7._getIntegrityFileLocation();
if (loc.exists) {
yield (_fs || _load_fs()).unlink(loc.locationPath);
}
})();
}
}
exports.default = InstallationIntegrityChecker;