Comparing version 9.0.2 to 9.1.2
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
exports.__esModule = true; | ||
@@ -29,30 +13,23 @@ exports.fixMismatches = void 0; | ||
invalidGroups.forEach(function (instanceGroup) { | ||
var nextVersion = instanceGroup.getExpectedVersion(); | ||
if (nextVersion === '') | ||
console.trace(instanceGroup); | ||
instanceGroup.instances.forEach(function (instance) { | ||
return instance.setVersion(nextVersion); | ||
}); | ||
if (!instanceGroup.hasUnsupportedVersion()) { | ||
var nextVersion_1 = instanceGroup.getExpectedVersion(); | ||
instanceGroup.instances.forEach(function (instance) { | ||
return instance.setVersion(nextVersion_1); | ||
}); | ||
} | ||
}); | ||
}); | ||
ctx.packageJsonFiles.forEach(function (file) { | ||
removeEmptyObjects(file.contents); | ||
/** Remove eg `{"dependencies": {}, "devDependencies": {}}` */ | ||
ctx.packageJsonFiles.forEach(function (packageJsonFile) { | ||
var contents = packageJsonFile.contents; | ||
Object.keys(contents).forEach(function (key) { | ||
var value = contents[key]; | ||
if ((0, expect_more_1.isObject)(value) && | ||
Object.values(value).every(expect_more_1.isUndefined)) { | ||
delete contents[key]; | ||
} | ||
}); | ||
}); | ||
return ctx; | ||
/** Remove eg { "dependencies": {}, "devDependencies": {} }` */ | ||
function removeEmptyObjects(parent) { | ||
if ((0, expect_more_1.isObject)(parent)) { | ||
Object.entries(parent).forEach(function (_a) { | ||
var _b = __read(_a, 2), key = _b[0], child = _b[1]; | ||
if ((0, expect_more_1.isObject)(child) && | ||
((0, expect_more_1.isEmptyObject)(child) || Object.values(child).every(expect_more_1.isUndefined))) { | ||
delete parent[key]; | ||
} | ||
else { | ||
removeEmptyObjects(child); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
exports.fixMismatches = fixMismatches; |
@@ -53,3 +53,2 @@ "use strict"; | ||
var log = __importStar(require("../lib/log")); | ||
var set_semver_range_1 = require("../lib/set-semver-range"); | ||
function lintSemverRanges(ctx) { | ||
@@ -73,5 +72,3 @@ ctx.semverGroups.reverse().forEach(function (semverGroup, i) { | ||
mismatches.forEach(function (instance) { | ||
if (!instance.hasRange(semverGroup.range)) { | ||
logSemverRangeMismatch(instance, semverGroup); | ||
} | ||
logSemverRangeMismatch(instance, semverGroup); | ||
}); | ||
@@ -87,5 +84,5 @@ }); | ||
var actual = instance.version; | ||
var expected = (0, set_semver_range_1.setSemverRange)(semverGroup.range, actual); | ||
var expected = semverGroup.getExpectedVersion(instance); | ||
console.log((0, chalk_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject([" {red ", "} ", " {green ", "} {dim in ", " of ", "}"], [" {red ", "} ", " {green ", "} {dim in ", " of ", "}"])), actual, constants_1.ICON.rightArrow, expected, path, shortPath)); | ||
} | ||
var templateObject_1; |
@@ -50,42 +50,65 @@ "use strict"; | ||
invalidGroups.forEach(function (instanceGroup) { | ||
var name = instanceGroup.name; | ||
var workspaceInstance = instanceGroup.getWorkspaceInstance(); | ||
var expected = instanceGroup.getExpectedVersion() || ''; | ||
var isBanned = versionGroup.isBanned; | ||
var isUnpinned = instanceGroup.isUnpinned; | ||
// Log the dependency name | ||
if (isBanned) { | ||
logBanned(name); | ||
if (versionGroup.isBanned()) | ||
return logBanned(instanceGroup); | ||
if (versionGroup.isUnpinned()) | ||
return logUnpinned(instanceGroup); | ||
if (instanceGroup.hasUnsupportedVersion()) | ||
return logUnsupportedMismatches(instanceGroup); | ||
if (instanceGroup.hasWorkspaceInstance()) { | ||
return logWorkspaceMismatch(instanceGroup); | ||
} | ||
else if (isUnpinned) { | ||
logPinVersionMismatch(name, versionGroup); | ||
} | ||
else if (workspaceInstance) { | ||
logWorkspaceMismatch(workspaceInstance, expected, name); | ||
} | ||
else { | ||
logHighestVersionMismatch(expected, name); | ||
} | ||
// Log each of the dependencies mismatches | ||
instanceGroup.instances.forEach(function (instance) { | ||
if (instance.version !== expected) { | ||
logVersionMismatch(instance); | ||
} | ||
}); | ||
logHighestVersionMismatch(instanceGroup); | ||
}); | ||
}); | ||
return ctx; | ||
function logBanned(name) { | ||
function logBanned(instanceGroup) { | ||
var name = instanceGroup.name; | ||
log.invalid(name, 'is banned in this version group'); | ||
// Log each of the dependencies mismatches | ||
instanceGroup.instances.forEach(function (instance) { | ||
logVersionMismatch(instance); | ||
}); | ||
} | ||
function logPinVersionMismatch(name, versionGroup) { | ||
var pinVersion = versionGroup.pinVersion; | ||
function logUnsupportedMismatches(instanceGroup) { | ||
var name = instanceGroup.name; | ||
log.invalid(name, 'has mismatched versions which syncpack cannot fix'); | ||
// Log each of the dependencies mismatches | ||
instanceGroup.instances.forEach(function (instance) { | ||
logUnsupportedVersionMismatch(instance); | ||
}); | ||
} | ||
function logUnpinned(instanceGroup) { | ||
var name = instanceGroup.name; | ||
var pinVersion = instanceGroup.versionGroup.getPinnedVersion(); | ||
log.invalid(name, (0, chalk_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject(["is pinned in this version group at {reset.green ", "}"], ["is pinned in this version group at {reset.green ", "}"])), pinVersion)); | ||
// Log each of the dependencies mismatches | ||
instanceGroup.instances.forEach(function (instance) { | ||
if (instance.version !== pinVersion) { | ||
logVersionMismatch(instance); | ||
} | ||
}); | ||
} | ||
function logWorkspaceMismatch(workspaceInstance, expected, name) { | ||
var shortPath = workspaceInstance.packageJsonFile.shortPath; | ||
function logWorkspaceMismatch(instanceGroup) { | ||
var name = instanceGroup.name; | ||
var workspaceInstance = instanceGroup.getWorkspaceInstance(); | ||
var shortPath = workspaceInstance === null || workspaceInstance === void 0 ? void 0 : workspaceInstance.packageJsonFile.shortPath; | ||
var expected = instanceGroup.getExpectedVersion(); | ||
log.invalid(name, (0, chalk_1["default"])(templateObject_2 || (templateObject_2 = __makeTemplateObject(["{reset.green ", "} {dim is developed in this repo at ", "}"], ["{reset.green ", "} {dim is developed in this repo at ", "}"])), expected, shortPath)); | ||
// Log each of the dependencies mismatches | ||
instanceGroup.instances.forEach(function (instance) { | ||
if (instance.version !== expected) { | ||
logVersionMismatch(instance); | ||
} | ||
}); | ||
} | ||
function logHighestVersionMismatch(expected, name) { | ||
function logHighestVersionMismatch(instanceGroup) { | ||
var name = instanceGroup.name; | ||
var expected = instanceGroup.getExpectedVersion(); | ||
log.invalid(name, (0, chalk_1["default"])(templateObject_3 || (templateObject_3 = __makeTemplateObject(["{reset.green ", "} {dim is the highest valid semver version in use}"], ["{reset.green ", "} {dim is the highest valid semver version in use}"])), expected)); | ||
// Log each of the dependencies mismatches | ||
instanceGroup.instances.forEach(function (instance) { | ||
if (instance.version !== expected) { | ||
logVersionMismatch(instance); | ||
} | ||
}); | ||
} | ||
@@ -98,4 +121,10 @@ function logVersionMismatch(instance) { | ||
} | ||
function logUnsupportedVersionMismatch(instance) { | ||
var type = instance.pathDef.path; | ||
var shortPath = instance.packageJsonFile.shortPath; | ||
var actual = instance.version; | ||
console.log((0, chalk_1["default"])(templateObject_5 || (templateObject_5 = __makeTemplateObject([" {yellow ", "} {dim in ", " of ", "}"], [" {yellow ", "} {dim in ", " of ", "}"])), actual, type, shortPath)); | ||
} | ||
} | ||
exports.listMismatches = listMismatches; | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4; | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5; |
@@ -42,26 +42,32 @@ "use strict"; | ||
log.versionGroupHeader(i); | ||
versionGroup.instanceGroups.forEach(function (instanceGroup) { | ||
var expected = instanceGroup.getExpectedVersion(); | ||
var uniques = instanceGroup.uniques; | ||
versionGroup.getAllInstanceGroups().forEach(function (instanceGroup) { | ||
// Record that this project has mismatches, so that eg. the CLI can exit | ||
// with the correct status code. | ||
if (instanceGroup.isInvalid) | ||
if (instanceGroup.isInvalid()) | ||
ctx.isInvalid = true; | ||
versionGroup.isBanned | ||
? logBanned(instanceGroup) | ||
: versionGroup.isIgnored | ||
? logIgnored(instanceGroup) | ||
: instanceGroup.hasMismatches | ||
? logVersionMismatch(instanceGroup, uniques, expected) | ||
: logVersionMatch(instanceGroup, uniques); | ||
if (versionGroup.isBanned()) | ||
return logBanned(instanceGroup); | ||
if (versionGroup.isIgnored()) | ||
return logIgnored(instanceGroup); | ||
if (versionGroup.isUnpinned()) | ||
return logUnpinned(instanceGroup); | ||
if (instanceGroup.hasMismatchingVersions()) { | ||
return instanceGroup.hasUnsupportedVersion() | ||
? logUnsupportedMismatches(instanceGroup) | ||
: logVersionMismatch(instanceGroup); | ||
} | ||
logVersionMatch(instanceGroup); | ||
}); | ||
}); | ||
return ctx; | ||
function logVersionMatch(instanceGroup, uniques) { | ||
console.log((0, chalk_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject(["{dim -} {white ", "} {dim ", "}"], ["{dim -} {white ", "} {dim ", "}"])), instanceGroup.name, uniques)); | ||
function logVersionMatch(instanceGroup) { | ||
console.log((0, chalk_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject(["{dim -} {white ", "} {dim ", "}"], ["{dim -} {white ", "} {dim ", "}"])), instanceGroup.name, instanceGroup.getUniqueVersions())); | ||
} | ||
function logVersionMismatch(instanceGroup, uniques, expected) { | ||
console.log((0, chalk_1["default"])(templateObject_2 || (templateObject_2 = __makeTemplateObject(["{red ", " ", "} ", ""], ["{red ", " ", "} ", ""])), constants_1.ICON.cross, instanceGroup.name, uniques | ||
function logVersionMismatch(instanceGroup) { | ||
console.log((0, chalk_1["default"])(templateObject_2 || (templateObject_2 = __makeTemplateObject(["{red ", " ", "} ", ""], ["{red ", " ", "} ", ""])), constants_1.ICON.cross, instanceGroup.name, instanceGroup | ||
.getUniqueVersions() | ||
.map(function (version) { | ||
return version === expected ? chalk_1["default"].green(version) : chalk_1["default"].red(version); | ||
return version === instanceGroup.getExpectedVersion() | ||
? chalk_1["default"].green(version) | ||
: chalk_1["default"].red(version); | ||
}) | ||
@@ -76,4 +82,14 @@ .join(chalk_1["default"].dim(', ')))); | ||
} | ||
function logUnpinned(instanceGroup) { | ||
var pinVersion = instanceGroup.versionGroup.getPinnedVersion(); | ||
console.log((0, chalk_1["default"])(templateObject_5 || (templateObject_5 = __makeTemplateObject(["{red ", " ", "} {dim.red is pinned to ", " in this version group}"], ["{red ", " ", "} {dim.red is pinned to ", " in this version group}"])), constants_1.ICON.cross, instanceGroup.name, pinVersion)); | ||
} | ||
function logUnsupportedMismatches(instanceGroup) { | ||
console.log((0, chalk_1["default"])(templateObject_6 || (templateObject_6 = __makeTemplateObject(["{red ", " ", "} {dim.red has mismatched versions which syncpack cannot fix: ", "}"], ["{red ", " ", "} {dim.red has mismatched versions which syncpack cannot fix: ", "}"])), constants_1.ICON.cross, instanceGroup.name, instanceGroup | ||
.getUniqueVersions() | ||
.map(function (version) { return chalk_1["default"].yellow(version); }) | ||
.join(chalk_1["default"].dim(', ')))); | ||
} | ||
} | ||
exports.list = list; | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4; | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6; |
@@ -7,3 +7,3 @@ "use strict"; | ||
semverGroup.instances.forEach(function (instance) { | ||
instance.setRange(semverGroup.range); | ||
instance.setVersion(semverGroup.getExpectedVersion(instance)); | ||
}); | ||
@@ -10,0 +10,0 @@ }); |
import type { Syncpack } from '../../../types'; | ||
import type { Instance } from '../../get-package-json-files/package-json-file/instance'; | ||
import type { InstanceGroup } from './instance-group'; | ||
export declare class VersionGroup { | ||
/** */ | ||
dependencies: string[]; | ||
/** Optionally limit this group to dependencies at these named paths */ | ||
dependencyTypes: Syncpack.TypeName[]; | ||
/** */ | ||
input: Syncpack.Config.Private; | ||
/** */ | ||
instanceGroups: InstanceGroup[]; | ||
/** */ | ||
instances: Instance[]; | ||
/** */ | ||
instancesByName: Record<string, Instance[]>; | ||
/** */ | ||
isBanned: boolean; | ||
/** */ | ||
isDefault: boolean; | ||
/** */ | ||
isIgnored: boolean; | ||
/** */ | ||
packages: string[]; | ||
/** Optionally force all dependencies in this group to have this version */ | ||
pinVersion?: string; | ||
constructor(input: Syncpack.Config.Private, versionGroup: Syncpack.Config.VersionGroup.Any); | ||
import { BaseGroup } from '../base-group'; | ||
import { InstanceGroup } from './instance-group'; | ||
export declare class VersionGroup extends BaseGroup<Syncpack.Config.VersionGroup.Any> { | ||
getAllInstanceGroups(): InstanceGroup[]; | ||
getInvalidInstanceGroups(): InstanceGroup[]; | ||
isBanned(): boolean; | ||
isIgnored(): boolean; | ||
hasPinnedVersion(): boolean; | ||
getPinnedVersion(): string; | ||
isUnpinned(): boolean; | ||
} |
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
if (typeof b !== "function" && b !== null) | ||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
exports.__esModule = true; | ||
exports.VersionGroup = void 0; | ||
var VersionGroup = /** @class */ (function () { | ||
function VersionGroup(input, versionGroup) { | ||
this.dependencies = versionGroup.dependencies; | ||
this.dependencyTypes = versionGroup.dependencyTypes; | ||
this.input = input; | ||
this.instanceGroups = []; | ||
this.instances = []; | ||
this.instancesByName = {}; | ||
this.isBanned = versionGroup.isBanned === true; | ||
this.isDefault = versionGroup === input.defaultVersionGroup; | ||
this.isIgnored = versionGroup.isIgnored === true; | ||
this.packages = versionGroup.packages; | ||
this.pinVersion = versionGroup.pinVersion; | ||
var expect_more_1 = require("expect-more"); | ||
var base_group_1 = require("../base-group"); | ||
var instance_group_1 = require("./instance-group"); | ||
var VersionGroup = /** @class */ (function (_super) { | ||
__extends(VersionGroup, _super); | ||
function VersionGroup() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
VersionGroup.prototype.getAllInstanceGroups = function () { | ||
var _this = this; | ||
return Object.entries(this.instancesByName).map(function (_a) { | ||
var _b = __read(_a, 2), name = _b[0], instances = _b[1]; | ||
return new instance_group_1.InstanceGroup(_this, name, instances); | ||
}); | ||
}; | ||
VersionGroup.prototype.getInvalidInstanceGroups = function () { | ||
return this.instanceGroups.filter(function (group) { return group.isInvalid; }); | ||
return this.getAllInstanceGroups().filter(function (group) { return group.isInvalid(); }); | ||
}; | ||
VersionGroup.prototype.isBanned = function () { | ||
return this.groupConfig.isBanned === true; | ||
}; | ||
VersionGroup.prototype.isIgnored = function () { | ||
return this.groupConfig.isIgnored === true; | ||
}; | ||
VersionGroup.prototype.hasPinnedVersion = function () { | ||
return (0, expect_more_1.isNonEmptyString)(this.getPinnedVersion()); | ||
}; | ||
VersionGroup.prototype.getPinnedVersion = function () { | ||
return this.groupConfig.pinVersion; | ||
}; | ||
VersionGroup.prototype.isUnpinned = function () { | ||
var pinVersion = this.groupConfig.pinVersion; | ||
return ((0, expect_more_1.isNonEmptyString)(pinVersion) && | ||
this.instances.some(function (_a) { | ||
var version = _a.version; | ||
return version !== pinVersion; | ||
})); | ||
}; | ||
return VersionGroup; | ||
}()); | ||
}(base_group_1.BaseGroup)); | ||
exports.VersionGroup = VersionGroup; |
@@ -5,31 +5,21 @@ import type { VersionGroup } from '..'; | ||
export declare class InstanceGroup { | ||
/** 1+ `Instance` has a version which does not follow the rules */ | ||
hasMismatches: boolean; | ||
/** Every package/pathName location where this dependency was found */ | ||
instances: Instance[]; | ||
/** */ | ||
hasWorkspaceInstance: boolean; | ||
/** Syncpack must report or fix this groups mismatches */ | ||
isInvalid: boolean; | ||
/** 1+ `Instance` has a version not matching `VersionGroup.pinVersion` */ | ||
isUnpinned: boolean; | ||
/** @example `"lodash"` */ | ||
name: string; | ||
/** All `Instance` versions, with duplicates removed */ | ||
uniques: string[]; | ||
/** The `VersionGroup` which this `InstanceGroup` belongs to */ | ||
versionGroup: VersionGroup; | ||
constructor(versionGroup: VersionGroup, name: string, instances: Instance[]); | ||
hasUnsupportedVersion(): boolean; | ||
getUniqueVersions(): string[]; | ||
hasMismatchingVersions(): boolean; | ||
isInvalid(): boolean; | ||
getExpectedVersion(): string | undefined; | ||
getPinnedVersion(): string; | ||
/** | ||
* If this dependency is a package developed locally, we should use its | ||
* version as the source of truth. | ||
*/ | ||
getWorkspaceVersion(): string; | ||
/** | ||
* Find instance of this dependency which is a package developed locally in | ||
* this monorepo. | ||
*/ | ||
getHighestVersion(): string; | ||
isUnpinned(): boolean; | ||
/** Get version of dependency which is developed in this monorepo */ | ||
getWorkspaceVersion(): string | undefined; | ||
/** Find instance of this dependency which is developed in this monorepo */ | ||
getWorkspaceInstance(): Instance | undefined; | ||
hasWorkspaceInstance(): boolean; | ||
} |
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
exports.__esModule = true; | ||
exports.InstanceGroup = void 0; | ||
var expect_more_1 = require("expect-more"); | ||
var error_1 = require("../../../../lib/error"); | ||
var is_semver_1 = require("../../../../lib/is-semver"); | ||
var print_strings_1 = require("../../../../lib/print-strings"); | ||
var get_highest_version_1 = require("./get-highest-version"); | ||
@@ -25,49 +11,56 @@ /** Every `Instance` of eg `"lodash"` for a given `VersionGroup` */ | ||
function InstanceGroup(versionGroup, name, instances) { | ||
var pinnedVersion = versionGroup.pinVersion; | ||
var isBanned = versionGroup.isBanned === true; | ||
var isIgnored = versionGroup.isIgnored === true; | ||
var hasPinnedVersion = (0, expect_more_1.isNonEmptyString)(pinnedVersion); | ||
var versions = instances.map(function (_a) { | ||
var version = _a.version; | ||
return version; | ||
}); | ||
var uniques = Array.from(new Set(versions)).sort(); | ||
var _a = __read(uniques, 1), version = _a[0]; | ||
var isUnpinned = hasPinnedVersion && version !== pinnedVersion; | ||
var hasMismatches = isBanned || isUnpinned || uniques.length > 1; | ||
var isInvalid = !isIgnored && hasMismatches; | ||
this.instances = instances; | ||
this.hasMismatches = hasMismatches; | ||
this.hasWorkspaceInstance = Boolean(this.getWorkspaceVersion()); | ||
this.isInvalid = isInvalid; | ||
this.isUnpinned = isUnpinned; | ||
this.name = name; | ||
this.uniques = uniques; | ||
this.versionGroup = versionGroup; | ||
} | ||
InstanceGroup.prototype.hasUnsupportedVersion = function () { | ||
return this.instances.some(function (obj) { return !(0, is_semver_1.isSemver)(obj.version); }); | ||
}; | ||
InstanceGroup.prototype.getUniqueVersions = function () { | ||
return Array.from(new Set(this.instances.map(function (obj) { return obj.version; }))).sort(); | ||
}; | ||
InstanceGroup.prototype.hasMismatchingVersions = function () { | ||
return this.getUniqueVersions().length > 1; | ||
}; | ||
InstanceGroup.prototype.isInvalid = function () { | ||
return this.versionGroup.isIgnored() | ||
? false | ||
: this.versionGroup.isBanned() || | ||
this.versionGroup.isUnpinned() || | ||
this.hasMismatchingVersions(); | ||
}; | ||
InstanceGroup.prototype.getExpectedVersion = function () { | ||
// remove this dependency | ||
if (this.versionGroup.isBanned) | ||
return undefined; | ||
if (this.isUnpinned) | ||
return this.getPinnedVersion(); | ||
if (this.hasWorkspaceInstance) | ||
var versionGroup = this.versionGroup; | ||
var REMOVE_DEPENDENCY = undefined; | ||
if (versionGroup.isBanned()) | ||
return REMOVE_DEPENDENCY; | ||
if (versionGroup.isUnpinned()) | ||
return versionGroup.getPinnedVersion(); | ||
if (this.hasWorkspaceInstance()) | ||
return this.getWorkspaceVersion(); | ||
return (0, get_highest_version_1.getHighestVersion)(this.uniques); | ||
if (this.hasUnsupportedVersion()) { | ||
throw new error_1.BaseError("".concat(this.name, " contains unsupported versions: ").concat((0, print_strings_1.printStrings)(this.getUniqueVersions()))); | ||
} | ||
return this.getHighestVersion(); | ||
}; | ||
InstanceGroup.prototype.getPinnedVersion = function () { | ||
return this.versionGroup.pinVersion || ''; | ||
InstanceGroup.prototype.getHighestVersion = function () { | ||
return (0, get_highest_version_1.getHighestVersion)(this.getUniqueVersions()); | ||
}; | ||
/** | ||
* If this dependency is a package developed locally, we should use its | ||
* version as the source of truth. | ||
*/ | ||
InstanceGroup.prototype.isUnpinned = function () { | ||
var _this = this; | ||
return (this.versionGroup.hasPinnedVersion() && | ||
this.instances.some(function (_a) { | ||
var version = _a.version; | ||
return version !== _this.versionGroup.getPinnedVersion(); | ||
})); | ||
}; | ||
/** Get version of dependency which is developed in this monorepo */ | ||
InstanceGroup.prototype.getWorkspaceVersion = function () { | ||
var _a; | ||
return ((_a = this.getWorkspaceInstance()) === null || _a === void 0 ? void 0 : _a.packageJsonFile.contents.version) || ''; | ||
if (this.hasWorkspaceInstance()) { | ||
return (_a = this.getWorkspaceInstance()) === null || _a === void 0 ? void 0 : _a.packageJsonFile.contents.version; | ||
} | ||
throw new error_1.BaseError('getWorkspaceVersion invoked when there is none'); | ||
}; | ||
/** | ||
* Find instance of this dependency which is a package developed locally in | ||
* this monorepo. | ||
*/ | ||
/** Find instance of this dependency which is developed in this monorepo */ | ||
InstanceGroup.prototype.getWorkspaceInstance = function () { | ||
@@ -79,4 +72,7 @@ return this.instances.find(function (_a) { | ||
}; | ||
InstanceGroup.prototype.hasWorkspaceInstance = function () { | ||
return this.getWorkspaceInstance() !== undefined; | ||
}; | ||
return InstanceGroup; | ||
}()); | ||
exports.InstanceGroup = InstanceGroup; |
@@ -8,2 +8,3 @@ "use strict"; | ||
var error_1 = require("../../lib/error"); | ||
var print_strings_1 = require("../../lib/print-strings"); | ||
var get_patterns_1 = require("./get-patterns"); | ||
@@ -20,3 +21,3 @@ /** | ||
function resolvePatterns(patterns) { | ||
var quoted = patterns.map(function (p) { return "\"".concat(p, "\""); }).join(', '); | ||
var quoted = (0, print_strings_1.printStrings)(patterns); | ||
var ERR_NO_MATCH = "No package.json files matched the patterns: ".concat(quoted); | ||
@@ -23,0 +24,0 @@ return (0, ts_belt_1.pipe)(patterns, _R_1.$R.onlyOk(resolvePattern), ts_belt_1.R.mapError(error_1.BaseError.map(ERR_NO_MATCH)), ts_belt_1.R.map((0, ts_belt_1.flow)(ts_belt_1.A.flat, ts_belt_1.A.uniq, removeReadonlyType))); |
@@ -60,4 +60,5 @@ "use strict"; | ||
var pathDef = instance.pathDef, name = instance.name, version = instance.version; | ||
if (name.search(new RegExp(_this.config.filter)) === -1) { | ||
(0, log_1.verbose)('skip instance, name does not match filter', instance); | ||
var filter = _this.config.filter; | ||
if (name.search(new RegExp(filter)) === -1) { | ||
(0, log_1.verbose)("skip, name \"".concat(name, "\" does not match filter \"").concat(filter, "\"")); | ||
return false; | ||
@@ -64,0 +65,0 @@ } |
import type { PackageJsonFile } from '.'; | ||
import type { Syncpack } from '../../../types'; | ||
import type { SemverGroup } from '../../get-groups/semver-group'; | ||
import type { VersionGroup } from '../../get-groups/version-group'; | ||
export declare class Instance { | ||
@@ -17,4 +15,4 @@ /** the name of this dependency */ | ||
constructor(pathDef: Syncpack.PathDefinition, name: string, packageJsonFile: PackageJsonFile, version: string); | ||
hasRange(range: Syncpack.Config.SemverRange.Value): boolean; | ||
setRange(range: Syncpack.Config.SemverRange.Value): void; | ||
/** Is this instance the package.json file of this package developed in this repo? */ | ||
isWorkspace(): boolean; | ||
/** | ||
@@ -25,3 +23,2 @@ * In the case of banned dependencies, their version is set to `undefined`, | ||
setVersion(version: string | undefined): void; | ||
matchesGroup(group: SemverGroup | VersionGroup): boolean; | ||
} |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
exports.__esModule = true; | ||
exports.Instance = void 0; | ||
var ts_belt_1 = require("@mobily/ts-belt"); | ||
var expect_more_1 = require("expect-more"); | ||
var minimatch_1 = __importDefault(require("minimatch")); | ||
var _R_1 = require("../../$R"); | ||
var set_semver_range_1 = require("../../../lib/set-semver-range"); | ||
var path_strategy_1 = require("../../get-config/path-strategy"); | ||
@@ -21,12 +15,6 @@ var Instance = /** @class */ (function () { | ||
} | ||
Instance.prototype.hasRange = function (range) { | ||
if (this.pathDef.name === 'workspace') { | ||
// version property of package.json must always be exact | ||
return this.version === (0, set_semver_range_1.setSemverRange)('', this.version); | ||
} | ||
return this.version === (0, set_semver_range_1.setSemverRange)(range, this.version); | ||
/** Is this instance the package.json file of this package developed in this repo? */ | ||
Instance.prototype.isWorkspace = function () { | ||
return this.pathDef.name === 'workspace'; | ||
}; | ||
Instance.prototype.setRange = function (range) { | ||
this.setVersion((0, set_semver_range_1.setSemverRange)(range, this.version)); | ||
}; | ||
/** | ||
@@ -57,11 +45,4 @@ * In the case of banned dependencies, their version is set to `undefined`, | ||
}; | ||
Instance.prototype.matchesGroup = function (group) { | ||
var _this = this; | ||
return (group.packages.some(function (pattern) { return (0, minimatch_1["default"])(_this.pkgName, pattern); }) && | ||
group.dependencies.some(function (pattern) { return (0, minimatch_1["default"])(_this.name, pattern); }) && | ||
(!(0, expect_more_1.isNonEmptyArray)(group.dependencyTypes) || | ||
group.dependencyTypes.includes(this.pathDef.name))); | ||
}; | ||
return Instance; | ||
}()); | ||
exports.Instance = Instance; |
@@ -16,7 +16,5 @@ "use strict"; | ||
var disk_1 = require("../lib/disk"); | ||
var log_1 = require("../lib/log"); | ||
var get_all_instances_1 = require("./get-all-instances"); | ||
var get_config_1 = require("./get-config"); | ||
var get_semver_groups_1 = require("./get-groups/get-semver-groups"); | ||
var get_version_groups_1 = require("./get-groups/get-version-groups"); | ||
var get_groups_1 = require("./get-groups"); | ||
var get_package_json_files_1 = require("./get-package-json-files"); | ||
@@ -36,8 +34,5 @@ /** | ||
var instances = (0, get_all_instances_1.getAllInstances)(packageJsonFiles); | ||
var semverGroups = (0, get_semver_groups_1.getSemverGroups)(config, instances); | ||
var versionGroups = (0, get_version_groups_1.getVersionGroups)(config, instances); | ||
var ctx = __assign(__assign({}, config), { disk: disk, isInvalid: false, packageJsonFiles: packageJsonFiles, semverGroups: semverGroups, versionGroups: versionGroups }); | ||
(0, log_1.verbose)('final context:', ctx); | ||
return ctx; | ||
var _a = (0, get_groups_1.getGroups)(config, instances), semverGroups = _a.semverGroups, versionGroups = _a.versionGroups; | ||
return __assign(__assign({}, config), { disk: disk, isInvalid: false, packageJsonFiles: packageJsonFiles, semverGroups: semverGroups, versionGroups: versionGroups }); | ||
} | ||
exports.getContext = getContext; |
{ | ||
"name": "syncpack", | ||
"description": "Manage multiple package.json files, such as in Lerna Monorepos and Yarn/Pnpm Workspaces", | ||
"version": "9.0.2", | ||
"version": "9.1.2", | ||
"author": "Jamie Mason <jamie@foldleft.io> (https://github.com/JamieMason)", | ||
@@ -51,2 +51,3 @@ "bin": { | ||
"eslint-plugin-import": "2.27.5", | ||
"eslint-plugin-jest": "27.2.1", | ||
"expect-more-jest": "5.5.0", | ||
@@ -53,0 +54,0 @@ "jest": "29.4.1", |
788
README.md
# syncpack | ||
> Manage multiple package.json files, such as in Lerna Monorepos and Yarn/Pnpm | ||
> Workspaces | ||
> Consistent dependency versions in large JavaScript Monorepos. | ||
[![NPM version](http://img.shields.io/npm/v/syncpack.svg?style=flat-square)](https://www.npmjs.com/package/syncpack) | ||
[![NPM downloads](http://img.shields.io/npm/dm/syncpack.svg?style=flat-square)](https://www.npmjs.com/package/syncpack) | ||
[![Build Status](https://img.shields.io/github/actions/workflow/status/JamieMason/syncpack/ci.yaml?branch=master)](https://github.com/JamieMason/syncpack/actions) | ||
[![Maintainability](https://api.codeclimate.com/v1/badges/516439365fdd0e3c6526/maintainability)](https://codeclimate.com/github/JamieMason/syncpack/maintainability) | ||
## Installation | ||
@@ -17,18 +11,10 @@ | ||
> ### Breaking Changes | ||
> | ||
> Version [9.0.0](https://github.com/JamieMason/syncpack/releases/tag/9.0.0) | ||
> required some breaking API changes to add support for a new | ||
> [`customTypes`](#customtypes) feature, but they are very simple to make. | ||
> | ||
> ### GitHub Action | ||
> | ||
> As of May 2022 there is now a | ||
> [Syncpack GitHub Action](https://github.com/marketplace/actions/syncpack-synchronise-monorepo-dependency-versions). | ||
> It is new and less stable than syncpack itself, but please give it a try and | ||
> [give your feedback](https://github.com/JamieMason/syncpack-github-action/issues/new). | ||
## Documentation | ||
Full information can be found in the documentation at | ||
https://jamiemason.github.io/syncpack/. | ||
## Commands | ||
### fix-mismatches | ||
### [fix-mismatches](https://jamiemason.github.io/syncpack/fix-mismatches) | ||
@@ -39,42 +25,4 @@ Ensure that multiple packages requiring the same dependency define the same | ||
See [`versionGroups`](#versiongroups) if you have advanced requirements. | ||
### [format](https://jamiemason.github.io/syncpack/format) | ||
<details> | ||
<summary>Options</summary> | ||
``` | ||
-s, --source [pattern] glob pattern for package.json files to read from | ||
-f, --filter [pattern] only include dependencies whose name matches this regex | ||
-t, --types <names> only include dependencies matching these types (eg. types=dev,prod,myCustomType) | ||
-c, --config <path> path to a syncpack config file | ||
-i, --indent [value] override indentation. defaults to " " | ||
-h, --help display help for command | ||
``` | ||
</details> | ||
<details> | ||
<summary>Examples</summary> | ||
```bash | ||
# uses defaults for resolving packages | ||
syncpack fix-mismatches | ||
# uses packages defined by --source when provided | ||
syncpack fix-mismatches --source "apps/*/package.json" | ||
# multiple globs can be provided like this | ||
syncpack fix-mismatches --source "apps/*/package.json" --source "core/*/package.json" | ||
# uses dependencies regular expression defined by --filter when provided | ||
syncpack fix-mismatches --filter "typescript|tslint" | ||
# only inspect "devDependencies" | ||
syncpack fix-mismatches --types dev | ||
# only inspect "devDependencies" and "peerDependencies" | ||
syncpack fix-mismatches --types dev,peer | ||
# indent package.json with 4 spaces instead of 2 | ||
syncpack fix-mismatches --indent " " | ||
``` | ||
</details> | ||
### format | ||
Organise package.json files according to a conventional format, where fields | ||
@@ -85,721 +33,33 @@ appear in a predictable order and nested fields are ordered alphabetically. | ||
<details> | ||
<summary>Options</summary> | ||
### [lint-semver-ranges](https://jamiemason.github.io/syncpack/lint-semver-ranges) | ||
``` | ||
-s, --source [pattern] glob pattern for package.json files to read from | ||
-c, --config <path> path to a syncpack config file | ||
-i, --indent [value] override indentation. defaults to " " | ||
-h, --help display help for command | ||
``` | ||
</details> | ||
<details> | ||
<summary>Examples</summary> | ||
```bash | ||
# uses defaults for resolving packages | ||
syncpack format | ||
# uses packages defined by --source when provided | ||
syncpack format --source "apps/*/package.json" | ||
# multiple globs can be provided like this | ||
syncpack format --source "apps/*/package.json" --source "core/*/package.json" | ||
# indent package.json with 4 spaces instead of 2 | ||
syncpack format --indent " " | ||
``` | ||
</details> | ||
### lint-semver-ranges | ||
Check whether dependency versions used within "dependencies", "devDependencies", | ||
and "peerDependencies" follow a consistent format. | ||
etc follow a consistent format. | ||
See [`semverGroups`](#semvergroups) if you have advanced requirements. | ||
### [list](https://jamiemason.github.io/syncpack/list) | ||
<details> | ||
<summary>Options</summary> | ||
``` | ||
-s, --source [pattern] glob pattern for package.json files to read from | ||
-f, --filter [pattern] only include dependencies whose name matches this regex | ||
-r, --semver-range <range> see supported ranges below. defaults to "" | ||
-c, --config <path> path to a syncpack config file | ||
-t, --types <names> only include dependencies matching these types (eg. types=dev,prod,myCustomType) | ||
-h, --help display help for command | ||
``` | ||
</details> | ||
<details> | ||
<summary>Examples</summary> | ||
```bash | ||
# uses defaults for resolving packages | ||
syncpack lint-semver-ranges | ||
# uses packages defined by --source when provided | ||
syncpack lint-semver-ranges --source "apps/*/package.json" | ||
# multiple globs can be provided like this | ||
syncpack lint-semver-ranges --source "apps/*/package.json" --source "core/*/package.json" | ||
# uses dependencies regular expression defined by --filter when provided | ||
syncpack lint-semver-ranges --filter "typescript|tslint" | ||
# use ~ range instead of default "" | ||
syncpack lint-semver-ranges --semver-range ~ | ||
# use ~ range in "devDependencies" | ||
syncpack lint-semver-ranges --types dev --semver-range ~ | ||
# use ~ range in "devDependencies" and "peerDependencies" | ||
syncpack lint-semver-ranges --types dev,peer semver-range ~ | ||
``` | ||
</details> | ||
### list | ||
List all dependencies required by your packages. | ||
<details> | ||
<summary>Options</summary> | ||
### [list-mismatches](https://jamiemason.github.io/syncpack/list-mismatches) | ||
``` | ||
-s, --source [pattern] glob pattern for package.json files to read from | ||
-f, --filter [pattern] only include dependencies whose name matches this regex | ||
-c, --config <path> path to a syncpack config file | ||
-t, --types <names> only include dependencies matching these types (eg. types=dev,prod,myCustomType) | ||
-h, --help display help for command | ||
``` | ||
</details> | ||
<details> | ||
<summary>Examples</summary> | ||
```bash | ||
# uses defaults for resolving packages | ||
syncpack list | ||
# uses packages defined by --source when provided | ||
syncpack list --source "apps/*/package.json" | ||
# multiple globs can be provided like this | ||
syncpack list --source "apps/*/package.json" --source "core/*/package.json" | ||
# uses dependencies regular expression defined by --filter when provided | ||
syncpack list --filter "typescript|tslint" | ||
# only inspect "devDependencies" | ||
syncpack list --types dev | ||
# only inspect "devDependencies" and "peerDependencies" | ||
syncpack list --types dev,peer | ||
``` | ||
</details> | ||
### list-mismatches | ||
List dependencies which are required by multiple packages, where the version is | ||
not the same across every package. | ||
See [`versionGroups`](#versiongroups) if you have advanced requirements. | ||
### [set-semver-ranges](https://jamiemason.github.io/syncpack/set-semver-ranges) | ||
<details> | ||
<summary>Options</summary> | ||
Ensure dependency versions used within `"dependencies"`, `"devDependencies"` etc | ||
follow a consistent format. | ||
``` | ||
-s, --source [pattern] glob pattern for package.json files to read from | ||
-f, --filter [pattern] only include dependencies whose name matches this regex | ||
-c, --config <path> path to a syncpack config file | ||
-t, --types <names> only include dependencies matching these types (eg. types=dev,prod,myCustomType) | ||
-h, --help display help for command | ||
``` | ||
## Breaking Changes | ||
</details> | ||
Version [9.0.0](https://github.com/JamieMason/syncpack/releases/tag/9.0.0) | ||
required some breaking API changes to add support for a new | ||
[`customTypes`](https://jamiemason.github.io/syncpack/config/custom-types) | ||
feature, but they are very simple to make. | ||
<details> | ||
<summary>Examples</summary> | ||
## Badges | ||
```bash | ||
# uses defaults for resolving packages | ||
syncpack list-mismatches | ||
# uses packages defined by --source when provided | ||
syncpack list-mismatches --source "apps/*/package.json" | ||
# multiple globs can be provided like this | ||
syncpack list-mismatches --source "apps/*/package.json" --source "core/*/package.json" | ||
# uses dependencies regular expression defined by --filter when provided | ||
syncpack list-mismatches --filter "typescript|tslint" | ||
# only inspect "devDependencies" | ||
syncpack list-mismatches --types dev | ||
# only inspect "devDependencies" and "peerDependencies" | ||
syncpack list-mismatches --types dev,peer | ||
``` | ||
</details> | ||
### set-semver-ranges | ||
Ensure dependency versions used within `"dependencies"`, `"devDependencies"`, | ||
and `"peerDependencies"` follow a consistent format. | ||
See [`semverGroups`](#semvergroups) if you have advanced requirements. | ||
<details> | ||
<summary>Options</summary> | ||
``` | ||
-s, --source [pattern] glob pattern for package.json files to read from | ||
-f, --filter [pattern] only include dependencies whose name matches this regex | ||
-c, --config <path> path to a syncpack config file | ||
-r, --semver-range <range> see supported ranges below. defaults to "" | ||
-t, --types <names> only include dependencies matching these types (eg. types=dev,prod,myCustomType) | ||
-i, --indent [value] override indentation. defaults to " " | ||
-h, --help display help for command | ||
``` | ||
</details> | ||
<details> | ||
<summary>Examples</summary> | ||
```bash | ||
# uses defaults for resolving packages | ||
syncpack set-semver-ranges | ||
# uses packages defined by --source when provided | ||
syncpack set-semver-ranges --source "apps/*/package.json" | ||
# multiple globs can be provided like this | ||
syncpack set-semver-ranges --source "apps/*/package.json" --source "core/*/package.json" | ||
# uses dependencies regular expression defined by --filter when provided | ||
syncpack set-semver-ranges --filter "typescript|tslint" | ||
# use ~ range instead of default "" | ||
syncpack set-semver-ranges --semver-range ~ | ||
# set ~ range in "devDependencies" | ||
syncpack set-semver-ranges --types dev --semver-range ~ | ||
# set ~ range in "devDependencies" and "peerDependencies" | ||
syncpack set-semver-ranges --types dev,peer --semver-range ~ | ||
# indent package.json with 4 spaces instead of 2 | ||
syncpack set-semver-ranges --indent " " | ||
``` | ||
</details> | ||
## Configuration File | ||
Creating a configuration file is optional, syncpack will search up the directory | ||
tree in the following places: | ||
- a `syncpack` property in `package.json` | ||
- a `.syncpackrc` file in JSON or YAML format | ||
- a `.syncpackrc.json`, `.syncpackrc.yaml`, `.syncpackrc.yml`, `.syncpackrc.js`, | ||
or `.syncpackrc.cjs` file | ||
- a `syncpack.config.js` or `syncpack.config.cjs` CommonJS module exporting an | ||
object | ||
- a `config.syncpack` property in `package.json` | ||
If you want to specify a path to a configuration file, overriding the discovered | ||
configuration file (if present), you can use the `--config` option. | ||
### Default Configuration | ||
```json | ||
{ | ||
"dependencyTypes": [ | ||
"dev", | ||
"overrides", | ||
"peer", | ||
"pnpmOverrides", | ||
"prod", | ||
"resolutions", | ||
"workspace" | ||
], | ||
"filter": ".", | ||
"indent": " ", | ||
"semverGroups": [], | ||
"semverRange": "", | ||
"sortAz": [ | ||
"contributors", | ||
"dependencies", | ||
"devDependencies", | ||
"keywords", | ||
"peerDependencies", | ||
"resolutions", | ||
"scripts" | ||
], | ||
"sortFirst": ["name", "description", "version", "author"], | ||
"source": [], | ||
"versionGroups": [] | ||
} | ||
``` | ||
### Configuration Options | ||
#### `--type` / `dependencyTypes` | ||
All of the properties in the table below are searched by default, but can be | ||
disabled via the `dependencyTypes` property of your config file or the `--types` | ||
option on the command line. | ||
- If `dependencyTypes` is unset or is an empty array, nothing is disabled. | ||
- If `dependencyTypes` is set, only those listed will be enabled. | ||
- If `--types` is set, it takes precedence and only its values will be used. | ||
In this example, only dependencies found in `dependencies` and `devDependencies` | ||
will be inspected by syncpack. | ||
```json | ||
{ | ||
"dependencyTypes": ["dev", "prod"] | ||
} | ||
``` | ||
| Value | Property in package.json | | ||
| --------------- | ------------------------ | | ||
| `dev` | `.devDependencies` | | ||
| `overrides` | `.overrides` | | ||
| `peer` | `.peerDependencies` | | ||
| `pnpmOverrides` | `.pnpm.overrides` | | ||
| `prod` | `.dependencies` | | ||
| `resolutions` | `.resolutions` | | ||
| `workspace` | `.version` | | ||
This list can be extended with your own `customTypes`, so you can find and fix | ||
versions found in other parts of your package.json files. | ||
##### The `workspace` type | ||
This option synchronises the versions of your dependencies with the `version` | ||
properties of the package.json files developed in your own local | ||
workspace/project, when they relate to eachother. | ||
Take this example, `@your-repo/fetch` is developed in your repo: | ||
```jsonc | ||
{ | ||
"name": "@your-repo/fetch", | ||
"version": "1.0.2" | ||
// ...rest of the file | ||
} | ||
``` | ||
and another package developed in your repo depends on it: | ||
```jsonc | ||
{ | ||
"name": "@your-repo/ui", | ||
// ...other stuff | ||
"dependencies": { | ||
"@your-repo/fetch": "0.9.4" | ||
} | ||
// ...rest of the file | ||
} | ||
``` | ||
When `workspace` is enabled, syncpack will fix `@your-repo/ui` so it depends on | ||
version `1.0.2` of `@your-repo/fetch`. | ||
#### `indent` | ||
The character(s) to be used to indent your package.json files when writing to | ||
disk. | ||
#### `semverRange` | ||
Defaulted to `""` to ensure that exact dependency versions are used instead of | ||
loose ranges, but this can be overridden in your config file or via the | ||
`--semver-range` command line option. | ||
##### Supported Ranges | ||
``` | ||
< <1.4.2 | ||
<= <=1.4.2 | ||
"" 1.4.2 | ||
~ ~1.4.2 | ||
^ ^1.4.2 | ||
>= >=1.4.2 | ||
> >1.4.2 | ||
* * | ||
``` | ||
#### `sortAz` | ||
When using the `format` command, determines which fields within package.json | ||
files should be sorted alphabetically. When the value is an Object, its keys are | ||
sorted alphabetically. When the value is an Array, its values are sorted | ||
alphabetically. There is no equivalent CLI Option for this configuration. | ||
#### `sortFirst` | ||
When using the `format` command, determines which fields within package.json | ||
files should appear at the top, and in what order. There is no equivalent CLI | ||
Option for this configuration. | ||
#### `source` | ||
Defaults to `["package.json", "packages/*/package.json"]` to match most Projects | ||
using Lerna or Yarn Workspaces, but this can be overridden in your config file | ||
or via multiple `--source` command line options. Supports any patterns supported | ||
by [glob](https://github.com/isaacs/node-glob). | ||
#### `customTypes` | ||
Extend syncpack to find and fix versions in your packages which are not | ||
available by default. Custom types behave like any other dependency, so can be | ||
included in [versionGroups](#versiongroups) or [semverGroups](#semvergroups) | ||
etc. | ||
The example below adds support for synchronising versions found in: | ||
1. The | ||
[`engines`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#engines) | ||
object. | ||
1. The [`packageManager`](https://nodejs.org/api/packages.html#packagemanager) | ||
string. | ||
```json | ||
{ | ||
"customTypes": { | ||
"engines": { | ||
"path": "engines", | ||
"strategy": "versionsByName" | ||
}, | ||
"packageManager": { | ||
"path": "packageManager", | ||
"strategy": "name@version" | ||
} | ||
} | ||
} | ||
``` | ||
##### `customTypes[name]` | ||
The key of each custom type is its name, this can be used in the following | ||
places to toggle when it is enabled: | ||
1. [`--type` / `dependencyTypes`](#--type--dependencytypes). | ||
1. [`versionGroup.dependencyTypes`](#versiongroupdependencytypes) | ||
1. [`semverGroup.dependencyTypes`](#semvergroupdependencytypes) | ||
##### `customTypes[name].path` | ||
Where the version can be found in each package.json file, such as `engines`, | ||
`packageManager` or `some.nested.property`. | ||
##### `customTypes[name].strategy` | ||
A strategy defines how syncpack needs to read and write dependency names and | ||
versions, there are 3 to choose from: | ||
| Name | Example | | ||
| ---------------- | -------------------------------------- | | ||
| `name@version` | `pnpm@7.27.0` | | ||
| `version` | `12.4.2` | | ||
| `versionsByName` | `{"pnpm":"7.27.0", "semver": "7.3.8"}` | | ||
#### `versionGroups` | ||
The most common use case for version groups is when some of the packages in your | ||
Monorepo are considered alpha (or legacy). Since those packages are much further | ||
ahead (or behind) the other packages, the dependencies within those packages | ||
need to be managed differently to the rest of the Monorepo. | ||
Your alpha packages might use unstable versions of some dependencies, while the | ||
rest of the repo might need to remain on stable versions. | ||
You don't want mismatches within your alpha packages, you don't want mismatches | ||
within the other packages, but you _do_ want those groups to use different | ||
versions _to each other_ and not have `syncpack` make them all the same. | ||
In the following example, 2 of our packages are using different versions of | ||
`react` and `react-dom` to the rest of the project. | ||
```json | ||
{ | ||
"versionGroups": [ | ||
{ | ||
"dependencies": ["react", "react-dom"], | ||
"packages": ["@alpha/server", "@alpha/ui"] | ||
} | ||
] | ||
} | ||
``` | ||
> 👋 The `dependencies` and `packages` fields are processed using | ||
> [minimatch](https://github.com/isaacs/minimatch), so the above example can | ||
> also be written as `"packages": ["@alpha/**"]`. | ||
`syncpack` will make ensure that: | ||
- The versions of `react` and `react-dom` are the same within `@alpha/server` | ||
and `@alpha/ui`. | ||
- The versions of `react` and `react-dom` are the same across every package | ||
except `@alpha/server` and `@alpha/ui`. | ||
- The versions of `react` and `react-dom` within `@alpha/server` and `@alpha/ui` | ||
can be different to the other packages in the monorepo. | ||
- The versions of every other dependency in the monorepo (eg `lodash`) are the | ||
same across every package including `@alpha/server` and `@alpha/ui`. | ||
Each dependency can only belong to one version group, the first rule which | ||
matches a given dependency and package will apply. | ||
You can be quite granular with these rules, so the partitioning doesn't _have_ | ||
to apply to an entire package: | ||
- A specific dependency in a specific package. | ||
- A specific dependency in some specific packages only. | ||
- Any dependency who name matches a pattern such as `@aws-sdk/**`. | ||
See [`semverGroups`](#semverGroups) for more examples, they work the same way. | ||
##### `versionGroup.dependencies` | ||
Required. An array of minimatch glob patterns which should match the key of | ||
dependencies defined in your package.json files. | ||
| Pattern | Matches | | ||
| ------------------------ | ---------------------------------------- | | ||
| `["**"]` | Any dependency | | ||
| `["@aws-sdk/**"]` | Any dependency with the scope `@aws-sdk` | | ||
| `["react", "react-dom"]` | Specific dependencies by name | | ||
##### `versionGroup.packages` | ||
Required. An array of minimatch glob patterns which should match the `name` | ||
property of packages developed within your monorepo. | ||
| Pattern | Matches | | ||
| ---------------------------- | ------------------------------------- | | ||
| `["**"]` | Any package | | ||
| `["@my-repo/**"]` | Any package with the scope `@my-repo` | | ||
| `["my-server", "my-client"]` | Specific packages by name | | ||
##### `versionGroup.dependencyTypes` | ||
Optional. If set, will result in only the dependency types included in that | ||
array being considered a match for this version group. | ||
In this example we define that all dependencies within `peerDependencies` in the | ||
repo must match, regardless of what versions of the same dependencies might be | ||
used in `dependencies` or `devDependencies`. | ||
```json | ||
{ | ||
"versionGroups": [ | ||
{ | ||
"dependencies": ["**"], | ||
"dependencyTypes": ["peerDependencies"], | ||
"packages": ["**"] | ||
} | ||
] | ||
} | ||
``` | ||
##### `versionGroup.isBanned` | ||
Remove dependencies which you've decided should never be allowed. | ||
```json | ||
{ | ||
"versionGroups": [ | ||
{ | ||
"dependencies": ["never-gonna"], | ||
"isBanned": true, | ||
"packages": ["**"] | ||
} | ||
] | ||
} | ||
``` | ||
##### `versionGroup.isIgnored` | ||
Have syncpack ignore these dependencies completely. | ||
```json | ||
{ | ||
"versionGroups": [ | ||
{ | ||
"dependencies": ["**"], | ||
"isIgnored": true, | ||
"packages": ["oops-moment", "workaround"] | ||
} | ||
] | ||
} | ||
``` | ||
##### `versionGroup.pinVersion` | ||
Pin the version of all dependencies in this group to match this specific version | ||
you've defined. | ||
```json | ||
{ | ||
"versionGroups": [ | ||
{ | ||
"dependencies": ["@aws-sdk/**"], | ||
"packages": ["**"], | ||
"pinVersion": "3.55.0" | ||
} | ||
] | ||
} | ||
``` | ||
#### `semverGroups` | ||
Allow some packages to have different semver range rules to the rest of your | ||
monorepo. Each dependency can only belong to one semver group, the first rule | ||
which matches a given dependency and package will apply. | ||
##### Example use cases | ||
1: Every dependency of `@myrepo/library` should have a semver range of `~`, | ||
regardless of what the rest of the monorepo uses: | ||
```json | ||
{ | ||
"semverGroups": [ | ||
{ | ||
"range": "~", | ||
"dependencies": ["**"], | ||
"packages": ["@myrepo/library"] | ||
} | ||
] | ||
} | ||
``` | ||
2: Every dependency of `@myrepo/library` whose name matches `@alpha/**` should | ||
have a semver range of `^`, regardless of what the rest of that package or the | ||
rest of the monorepo uses: | ||
```json | ||
{ | ||
"semverGroups": [ | ||
{ | ||
"range": "^", | ||
"dependencies": ["@alpha/**"], | ||
"packages": ["@myrepo/library"] | ||
} | ||
] | ||
} | ||
``` | ||
3: Every dependency in the monorepo whose name matches `@alpha/**` should have a | ||
semver range of `~`, regardless of what the rest of the monorepo uses: | ||
```json | ||
{ | ||
"semverGroups": [ | ||
{ | ||
"range": "~", | ||
"dependencies": ["@alpha/**"], | ||
"packages": ["**"] | ||
} | ||
] | ||
} | ||
``` | ||
3: Production dependencies should have fixed version numbers, but development | ||
and peer dependencies can be broader. | ||
```json | ||
{ | ||
"semverGroups": [ | ||
{ | ||
"range": "", | ||
"dependencyTypes": [ | ||
"dependencies", | ||
"resolutions", | ||
"overrides", | ||
"pnpmOverrides", | ||
"workspace" | ||
], | ||
"dependencies": ["**"], | ||
"packages": ["**"] | ||
}, | ||
{ | ||
"range": "~", | ||
"dependencyTypes": ["devDependencies"], | ||
"dependencies": ["**"], | ||
"packages": ["**"] | ||
}, | ||
{ | ||
"range": "^", | ||
"dependencyTypes": ["peerDependencies"], | ||
"dependencies": ["**"], | ||
"packages": ["**"] | ||
} | ||
] | ||
} | ||
``` | ||
##### `semverGroup.range` | ||
Which of the [Supported Ranges](#supported-ranges) this group should use. | ||
##### `semverGroup.dependencies` | ||
Works the same as [`versionGroup.dependencies`](#versiongroupdependencies). | ||
##### `semverGroup.isIgnored` | ||
Works the same as [`versionGroup.isIgnored`](#versiongroupisignored). | ||
##### `semverGroup.packages` | ||
Works the same as [`versionGroup.packages`](#versiongrouppackages). | ||
##### `semverGroup.dependencyTypes` | ||
Works the same as | ||
[`versionGroup.dependencyTypes`](#versiongroupdependencytypes). | ||
#### `filter` | ||
A string which will be passed to `new RegExp()` to match against package names | ||
that should be included. | ||
> ⚠️ `filter` was originally intended as a convenience to be used from the | ||
> command line to filter the output of `syncpack list`, **it is not recommended | ||
> to add this to your config file to manage your project more generally**. | ||
> | ||
> Instead use [`versionGroups`](#versiongroups) and/or | ||
> [`semverGroups`](#semvergroups). | ||
## Resolving Packages | ||
package.json files are resolved in this order of precendence: | ||
1. If `--source` | ||
[glob patterns](https://github.com/isaacs/node-glob#glob-primer) are | ||
provided, use those. | ||
2. If using [Yarn Workspaces](https://yarnpkg.com/lang/en/docs/workspaces/), | ||
read `workspaces` from `./package.json`. | ||
3. If using [Lerna](https://lerna.js.org/), read `packages` from | ||
`./lerna.json`. | ||
4. If using [Pnpm](https://pnpm.js.org/), read `packages` from | ||
`./pnpm-workspace.yaml`. | ||
5. Default to `'package.json'` and `'packages/*/package.json'`. | ||
> 👋 Always add quotes around your `--source` patterns | ||
> [[more info](https://github.com/JamieMason/syncpack/issues/66#issuecomment-1146011769)]. | ||
## Getting Help | ||
Get help with issues by creating a [Bug Report] or discuss ideas by opening a | ||
[Feature Request]. | ||
[bug report]: | ||
https://github.com/JamieMason/syncpack/issues/new?template=bug_report.md | ||
[feature request]: | ||
https://github.com/JamieMason/syncpack/issues/new?template=feature_request.md | ||
## Other Projects | ||
If you find my Open Source projects useful, please share them ❤️ | ||
- [**eslint-formatter-git-log**](https://github.com/JamieMason/eslint-formatter-git-log)<br>ESLint | ||
Formatter featuring Git Author, Date, and Hash | ||
- [**eslint-plugin-prefer-arrow-functions**](https://github.com/JamieMason/eslint-plugin-prefer-arrow-functions)<br>Convert | ||
functions to arrow functions | ||
- [**ImageOptim-CLI**](https://github.com/JamieMason/ImageOptim-CLI)<br>Automates | ||
ImageOptim, ImageAlpha, and JPEGmini for Mac to make batch optimisation of | ||
images part of your automated build process. | ||
- [**Jasmine-Matchers**](https://github.com/JamieMason/Jasmine-Matchers)<br>Write | ||
Beautiful Specs with Custom Matchers | ||
- [**karma-benchmark**](https://github.com/JamieMason/karma-benchmark)<br>Run | ||
Benchmark.js over multiple Browsers, with CI compatible output | ||
- [**self-help**](https://github.com/JamieMason/self-help#readme)<br>Interactive | ||
Q&A Guides for Web and the Command Line | ||
- [![NPM version](http://img.shields.io/npm/v/syncpack.svg?style=flat-square)](https://www.npmjs.com/package/syncpack) | ||
- [![NPM downloads](http://img.shields.io/npm/dm/syncpack.svg?style=flat-square)](https://www.npmjs.com/package/syncpack) | ||
- [![Build Status](https://img.shields.io/github/actions/workflow/status/JamieMason/syncpack/ci.yaml?branch=master)](https://github.com/JamieMason/syncpack/actions) | ||
- [![Maintainability](https://api.codeclimate.com/v1/badges/516439365fdd0e3c6526/maintainability)](https://codeclimate.com/github/JamieMason/syncpack/maintainability) |
145
5189
233343
17
63