UNPKG

yarn-frozen-dependencies

Version:

A yarn plugin who freeze the workspace dependencies to prevent undesired updates.

79 lines (63 loc) 3.71 kB
/** @C3-MONOREPO/YARN-PLUGIN-SEALED-DEPENDENCIES * This plugin allows marking dependencies as sealed in a workspace to prevent undesired changes. * When you use a yarn command to manage dependencies, the plugin will automatically check if the operation is permitted * and report a message otherwise. * * To configure a workspace as sealed, add the `sealed` property in package.json. Please see the `SealedOptions` type to * known more about the possible value of the `sealed` property. */ import type {Plugin, Workspace, Descriptor} from "@yarnpkg/core"; import {Operation, OperationReporter, OperationReporterOptions} from "./operation-reporters/operation-reporter"; import {ConfirmOperationReporter} from "./operation-reporters/confirm.operation-reporter"; import {WarnOperationReporter} from "./operation-reporters/warn.operation-reporter"; import {ErrorOperationReporter} from "./operation-reporters/error.operation-reporter"; const checkOperationIsPossible = (operation: Operation) => async (workspace: Workspace, target: string, descriptor: Descriptor, destinationDescriptor: Descriptor) => { const {manifest: {raw: {sealed: sealedEntry = false}}} = workspace; const operationReportersOptions: OperationReporterOptions = { operation, workspace, target, descriptor, destinationDescriptor }; const operationReporters: Record<string, OperationReporter> = { 'confirm': new ConfirmOperationReporter(operationReportersOptions), 'warn': new WarnOperationReporter(operationReportersOptions), 'error': new ErrorOperationReporter(operationReportersOptions), } if (!sealedEntry) { return; } const sealedOptions = resolveSealedOptions(sealedEntry); if (sealedOptions[target].includes(operation)) { await operationReporters[sealedOptions.level].reportOperation(); } } //////////////////////////////////////////////////////////////////////////////// // SEALED OPTIONS //////////////////////////////////////////////////////////////////////////////// type SealedOptions = boolean & { level?: 'error' | 'warn' | 'confirm', operations?: Array<Operation>, dependencies?: boolean | Array<Operation>, devDependencies?: boolean | Array<Operation>, peerDependencies?: boolean | Array<Operation> }; const resolveSealedOptions = (sealedEntry: SealedOptions) => ({ level: (sealedEntry === true && 'error') || (sealedEntry.level) || 'error', operations: (sealedEntry.operations instanceof Array && sealedEntry.operations) || ['add', 'remove', 'replace'], dependencies: (sealedEntry.dependencies instanceof Array && sealedEntry.dependencies) || (sealedEntry.dependencies === false && []) || sealedEntry.operations || ['add', 'remove', 'replace'], devDependencies: (sealedEntry.devDependencies instanceof Array && sealedEntry.devDependencies) || (sealedEntry.dependencies === false && []) || sealedEntry.operations || ['add', 'remove', 'replace'], peerDependencies: (sealedEntry.peerDependencies instanceof Array && sealedEntry.peerDependencies) || (sealedEntry.dependencies === false && []) || sealedEntry.operations || ['add', 'remove', 'replace'], }); //////////////////////////////////////////////////////////////////////////////// // PLUGIN DECLARATION AND EXPORT //////////////////////////////////////////////////////////////////////////////// const plugin: Plugin = { hooks: { afterWorkspaceDependencyAddition: checkOperationIsPossible('add'), afterWorkspaceDependencyRemoval: checkOperationIsPossible('remove'), afterWorkspaceDependencyReplacement: checkOperationIsPossible('replace'), }, }; export default plugin;