UNPKG

syncpack

Version:

Consistent dependency versions in large JavaScript Monorepos

110 lines (109 loc) 5.14 kB
import { Data, Effect, pipe } from 'effect'; import { isArrayOfStrings } from 'tightrope/guard/is-array-of-strings.js'; import { isBoolean } from 'tightrope/guard/is-boolean.js'; import { isEmptyArray } from 'tightrope/guard/is-empty-array.js'; import { isNonEmptyArray } from 'tightrope/guard/is-non-empty-array.js'; import { isNonEmptyString } from 'tightrope/guard/is-non-empty-string.js'; import { INTERNAL_TYPES } from '../constants.js'; import { NameAndVersionPropsStrategy } from '../strategy/name-and-version-props.js'; import { VersionsByNameStrategy } from '../strategy/versions-by-name.js'; import { getCustomTypes } from './get-custom-types.js'; export class DeprecatedTypesError extends Data.TaggedClass('DeprecatedTypesError') { } export class RenamedWorkspaceTypeError extends Data.TaggedClass('RenamedWorkspaceTypeError') { } export function getEnabledTypes({ cli, rcFile, }) { return pipe( // Look for dependency types defined using the old `{ prod: true }` syntax // deprecated in syncpack@9.0.0 Effect.succeed(INTERNAL_TYPES.filter(key => isBoolean(rcFile[key]))), // Short-circuit and quit if deprecated config is used Effect.flatMap(deprecatedTypeProps => deprecatedTypeProps.length > 0 ? Effect.fail(new DeprecatedTypesError({ types: deprecatedTypeProps })) : Effect.void), Effect.flatMap(() => pipe(Effect.Do, // Get index of every available strategy, keyed by their names as // they're referred to in config Effect.bind('allStrategiesByName', () => pipe( // Get custom types if any are defined, short-circuit and quit if // any are invalid getCustomTypes({ cli, rcFile }), // Combine them with the default/internal dependency types Effect.map((customTypes) => Object.fromEntries([ ['dev', new VersionsByNameStrategy('dev', 'devDependencies')], [ 'local', new NameAndVersionPropsStrategy('local', 'version', 'name'), ], [ 'overrides', new VersionsByNameStrategy('overrides', 'overrides'), ], [ 'peer', new VersionsByNameStrategy('peer', 'peerDependencies'), ], [ 'pnpmOverrides', new VersionsByNameStrategy('pnpmOverrides', 'pnpm.overrides'), ], ['prod', new VersionsByNameStrategy('prod', 'dependencies')], [ 'resolutions', new VersionsByNameStrategy('resolutions', 'resolutions'), ], ...customTypes.map(type => [type.name, type]), ])))), // The names of every available strategy Effect.bind('allStrategyNames', ({ allStrategiesByName }) => Effect.succeed(Object.keys(allStrategiesByName))), // Create groupings to assign each provided dependencyType to Effect.bind('strategyNamesByStatus', () => Effect.succeed({ provided: (isNonEmptyString(cli.types) ? cli.types.split(',') : isArrayOfStrings(rcFile.dependencyTypes) ? rcFile.dependencyTypes : []).filter(isNonEmptyString), enabled: [], positive: [], negative: [], })))), Effect.tap(({ strategyNamesByStatus }) => Effect.logDebug(`dependency types provided by user: ${JSON.stringify(strategyNamesByStatus.provided)}`)), // Determine which dependencyTypes should be enabled based on: // * which are defined // * which were listed to be enabled // * which were listed but !negated // * etc. Effect.flatMap(({ allStrategiesByName, allStrategyNames, strategyNamesByStatus }) => { if (isEmptyArray(strategyNamesByStatus.provided) || strategyNamesByStatus.provided.join('') === '**') { return Effect.succeed(allStrategyNames.map(getStrategyByName)); } strategyNamesByStatus.provided.forEach(name => { if (name.startsWith('!')) { strategyNamesByStatus.negative.push(name.replace('!', '')); } else { strategyNamesByStatus.positive.push(name); } }); if (isNonEmptyArray(strategyNamesByStatus.negative)) { allStrategyNames.forEach(name => { if (!strategyNamesByStatus.negative.includes(name)) { strategyNamesByStatus.enabled.push(name); } }); } if (isNonEmptyArray(strategyNamesByStatus.positive)) { strategyNamesByStatus.positive.forEach(name => { if (!strategyNamesByStatus.enabled.includes(name)) { strategyNamesByStatus.enabled.push(name); } }); } if (strategyNamesByStatus.enabled.includes('workspace')) { return Effect.fail(new RenamedWorkspaceTypeError({})); } return Effect.succeed(strategyNamesByStatus.enabled.map(getStrategyByName)); function getStrategyByName(type) { return allStrategiesByName[type]; } }), Effect.tap(enabledTypes => Effect.logDebug(`enabled dependency types determined to be: ${JSON.stringify(enabledTypes)}`))); }