diff --git a/src/version-group/standard.spec.ts b/src/version-group/standard.spec.ts index 3888a843..3bfccb67 100644 --- a/src/version-group/standard.spec.ts +++ b/src/version-group/standard.spec.ts @@ -9,67 +9,133 @@ import { list } from '../bin-list/list'; describe('the "local" dependency type', () => { describe('when local package is missing a version property', () => { - const getScenario = createScenario({ - '.syncpackrc': { - dependencyTypes: ['local', 'prod'], - }, - 'package.json': { - name: 'foo', - }, - 'packages/a/package.json': { - name: 'a', - dependencies: { - foo: '0.2.0', + describe('when local package IS depended on', () => { + const getScenario = createScenario({ + '.syncpackrc': { + dependencyTypes: ['local', 'prod'], }, - }, - }); + 'package.json': { + name: 'foo', + }, + 'packages/a/package.json': { + name: 'a', + dependencies: { + foo: '0.2.0', + }, + }, + }); - describe('version report', () => { - it('is broken and unfixable', () => { - const reports = getScenario().getVersionReports(); - expect(reports).toHaveLength(2); - expect(reports).toHaveProperty('1.name', 'foo'); - expect(reports).toHaveProperty('0.reports.0._tag', 'MissingLocalVersion'); + describe('version report', () => { + it('is broken and unfixable', () => { + const reports = getScenario().getVersionReports(); + expect(reports).toHaveLength(2); + expect(reports).toHaveProperty('1.name', 'foo'); + expect(reports).toHaveProperty('1.reports.0._tag', 'MissingLocalVersion'); + expect(reports).toHaveProperty('1.reports.1._tag', 'MissingLocalVersion'); + }); }); - }); - describe('lint', () => { - it('exits 1', () => { - const scenario = getScenario(); - Effect.runSyncExit(lint(scenario)); - expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + describe('lint', () => { + it('exits 1', () => { + const scenario = getScenario(); + Effect.runSyncExit(lint(scenario)); + expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + }); }); - }); - describe('lintSemverRanges', () => { - it('exits 0', () => { - const scenario = getScenario(); - Effect.runSyncExit(lintSemverRanges(scenario)); - expect(scenario.io.process.exit).not.toHaveBeenCalled(); + describe('lintSemverRanges', () => { + it('exits 0', () => { + const scenario = getScenario(); + Effect.runSyncExit(lintSemverRanges(scenario)); + expect(scenario.io.process.exit).not.toHaveBeenCalled(); + }); }); - }); - describe('list', () => { - it('exits 1', () => { - const scenario = getScenario(); - Effect.runSyncExit(list(scenario)); - expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + describe('list', () => { + it('exits 1', () => { + const scenario = getScenario(); + Effect.runSyncExit(list(scenario)); + expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + }); }); - }); - describe('list-mismatches', () => { - it('exits 1', () => { - const scenario = getScenario(); - Effect.runSyncExit(listMismatches(scenario)); - expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + describe('list-mismatches', () => { + it('exits 1', () => { + const scenario = getScenario(); + Effect.runSyncExit(listMismatches(scenario)); + expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + }); + }); + + describe('fix-mismatches', () => { + it('exits 1', () => { + const scenario = getScenario(); + Effect.runSyncExit(fixMismatches(scenario)); + expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + }); }); }); - describe('fix-mismatches', () => { - it('exits 1', () => { - const scenario = getScenario(); - Effect.runSyncExit(fixMismatches(scenario)); - expect(scenario.io.process.exit).toHaveBeenCalledWith(1); + describe('when local package is NOT depended on', () => { + const getScenario = createScenario({ + '.syncpackrc': { + dependencyTypes: ['local', 'prod'], + }, + 'package.json': { + name: 'foo', + }, + 'packages/a/package.json': { + name: 'a', + }, + }); + + describe('version report', () => { + it('is valid', () => { + const reports = getScenario().getVersionReports(); + expect(reports).toHaveLength(2); + expect(reports).toHaveProperty('1.name', 'foo'); + expect(reports).toHaveProperty('1.reports.0._tag', 'Valid'); + }); + }); + + describe('lint', () => { + it('exits 0', () => { + const scenario = getScenario(); + Effect.runSyncExit(lint(scenario)); + expect(scenario.io.process.exit).not.toHaveBeenCalled(); + }); + }); + + describe('lintSemverRanges', () => { + it('exits 0', () => { + const scenario = getScenario(); + Effect.runSyncExit(lintSemverRanges(scenario)); + expect(scenario.io.process.exit).not.toHaveBeenCalled(); + }); + }); + + describe('list', () => { + it('exits 0', () => { + const scenario = getScenario(); + Effect.runSyncExit(list(scenario)); + expect(scenario.io.process.exit).not.toHaveBeenCalled(); + }); + }); + + describe('list-mismatches', () => { + it('exits 0', () => { + const scenario = getScenario(); + Effect.runSyncExit(listMismatches(scenario)); + expect(scenario.io.process.exit).not.toHaveBeenCalled(); + }); + }); + + describe('fix-mismatches', () => { + it('exits 0', () => { + const scenario = getScenario(); + Effect.runSyncExit(fixMismatches(scenario)); + expect(scenario.io.process.exit).not.toHaveBeenCalled(); + }); }); }); }); @@ -98,6 +164,8 @@ describe('the "local" dependency type', () => { expect(reports).toHaveProperty('1.name', 'foo'); expect(reports).toHaveProperty('1.reports.0._tag', 'MissingLocalVersion'); expect(reports).toHaveProperty('1.reports.0.unfixable.rawSpecifier', '~0.2.0'); + expect(reports).toHaveProperty('1.reports.1._tag', 'MissingLocalVersion'); + expect(reports).toHaveProperty('1.reports.1.unfixable.rawSpecifier', '~0.2.0'); }); }); diff --git a/src/version-group/standard.ts b/src/version-group/standard.ts index 2741e06d..131185cd 100644 --- a/src/version-group/standard.ts +++ b/src/version-group/standard.ts @@ -33,66 +33,66 @@ export class StandardVersionGroup extends Data.TaggedClass('Standard')<{ if (localInstance) { const localVersion = localInstance?.rawSpecifier; - return localVersion === 'PACKAGE_JSON_HAS_NO_VERSION' - ? Effect.succeed({ - name, - reports: instances.map( - (instance) => - // ! dependency is a package developed in this repo - // ✘ local package is missing a .version property - // ✘ is a mismatch we can't auto-fix - new Report.MissingLocalVersion(instance, localInstance), - ), - }) - : pipe( - Effect.succeed(Specifier.create(localInstance, localVersion)), - Effect.flatMap((local) => - Effect.all( - local._tag !== 'VersionSpecifier' - ? instances.map((instance) => - // ! dependency is a package developed in this repo - // ✘ local package has an invalid .version property - // ✘ is a mismatch we can't auto-fix - Effect.succeed(new Report.MissingLocalVersion(instance, localInstance)), - ) - : instances.flatMap((instance) => - pipe( - Effect.succeed(Specifier.create(instance, instance.rawSpecifier)), - Effect.flatMap((specifier) => - specifier.instance === localInstance - ? // ✓ this is the local package which the others should match - // ! its version must always remain as exact semver - // ! other instances need to be adjusted for their semver groups - Effect.succeed(new Report.Valid(specifier)) - : pipe( - specifier.replaceWith(local), - specifier.instance.semverGroup.getFixed, - Effect.match({ - onFailure: /* istanbul ignore next */ () => - // ! is not the local package instance - // ✘ local version is not fixable by this semver group - // ✘ is a mismatch we can't auto-fix - // ✘ this should be impossible - we already proved the local version is exact semver - new Report.UnsupportedMismatch(specifier.instance), - onSuccess: (valid) => - specifier.instance.rawSpecifier === valid.raw - ? // ! is not the local package instance - // ✓ local version matches this semver group - // ✓ current version matches local - new Report.Valid(specifier) - : // ! is not the local package instance - // ✓ local version matches this semver group - // ✘ current version mismatches local - new Report.LocalPackageMismatch(valid, localInstance), - }), - ), - ), - ), + return pipe( + Effect.succeed(Specifier.create(localInstance, localVersion)), + Effect.flatMap((local) => + Effect.all( + local._tag !== 'VersionSpecifier' && instances.length > 1 + ? instances.map((instance) => + // ! dependency is a package developed in this repo + // ✘ local package has an invalid .version property + // ✘ is a mismatch we can't auto-fix + Effect.succeed(new Report.MissingLocalVersion(instance, localInstance)), + ) + : instances.flatMap((instance) => + // instances.flatMap((instance) => + pipe( + Effect.succeed(Specifier.create(instance, instance.rawSpecifier)), + Effect.flatMap((specifier) => + specifier.instance === localInstance + ? // ✓ this is the local package which the others should match + // ! its version must always remain as exact semver + // ! other instances need to be adjusted for their semver groups + Effect.succeed(new Report.Valid(specifier)) + : pipe( + specifier.replaceWith(local), + specifier.instance.semverGroup.getFixed, + Effect.match({ + onFailure: /* istanbul ignore next */ () => + // ! is not the local package instance + // ✘ local version is not fixable by this semver group + // ✘ is a mismatch we can't auto-fix + // ✘ this should be impossible - we already proved the local version is exact semver + new Report.UnsupportedMismatch(specifier.instance), + onSuccess: (valid) => + specifier.instance.rawSpecifier === valid.raw + ? // ! is not the local package instance + // ✓ local version matches this semver group + // ✓ current version matches local + new Report.Valid(specifier) + : localVersion === 'PACKAGE_JSON_HAS_NO_VERSION' + ? // ! is not the local package instance + // ✘ local package has a version defined + // ✓ local version matches this semver group + // ✘ current version mismatches local + new Report.MissingLocalVersion( + specifier.instance, + localInstance, + ) + : // ! is not the local package instance + // ✓ local package has a version defined + // ✓ local version matches this semver group + // ✘ current version mismatches local + new Report.LocalPackageMismatch(valid, localInstance), + }), + ), ), - ), - ), - Effect.map((reports) => ({ name, reports })), - ); + ), + ), + ), + ), + Effect.map((reports) => ({ name, reports })), + ); } const PreferredMismatch =