syncpack 12.3.3 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +1 -2
  2. package/dist/bin-fix-mismatches/fix-mismatches.d.ts +2 -2
  3. package/dist/bin-fix-mismatches/fix-mismatches.js +13 -8
  4. package/dist/bin-fix-mismatches/index.js +1 -32
  5. package/dist/bin-format/format.d.ts +2 -2
  6. package/dist/bin-format/format.js +10 -7
  7. package/dist/bin-format/index.js +1 -26
  8. package/dist/bin-lint/index.js +1 -22
  9. package/dist/bin-lint/lint.d.ts +1 -1
  10. package/dist/bin-lint/lint.js +23 -23
  11. package/dist/bin-lint-semver-ranges/index.js +1 -36
  12. package/dist/bin-lint-semver-ranges/lint-semver-ranges.d.ts +2 -2
  13. package/dist/bin-lint-semver-ranges/lint-semver-ranges.js +5 -4
  14. package/dist/bin-list/index.js +1 -31
  15. package/dist/bin-list/list.d.ts +1 -1
  16. package/dist/bin-list/list.js +9 -5
  17. package/dist/bin-list-mismatches/index.js +1 -31
  18. package/dist/bin-list-mismatches/list-mismatches.d.ts +2 -2
  19. package/dist/bin-list-mismatches/list-mismatches.js +15 -9
  20. package/dist/bin-prompt/index.js +1 -33
  21. package/dist/bin-prompt/prompt.d.ts +2 -2
  22. package/dist/bin-prompt/prompt.js +13 -11
  23. package/dist/bin-set-semver-ranges/index.js +1 -38
  24. package/dist/bin-set-semver-ranges/set-semver-ranges.d.ts +2 -2
  25. package/dist/bin-set-semver-ranges/set-semver-ranges.js +8 -5
  26. package/dist/bin-update/effects.d.ts +1 -1
  27. package/dist/bin-update/effects.js +46 -31
  28. package/dist/bin-update/index.js +1 -31
  29. package/dist/bin-update/update.d.ts +1 -1
  30. package/dist/bin-update/update.js +4 -4
  31. package/dist/bin.js +3 -3
  32. package/dist/config/get-custom-types.js +20 -13
  33. package/dist/config/get-enabled-types.js +27 -12
  34. package/dist/config/get-sort-exports.js +2 -1
  35. package/dist/config/types.d.ts +2 -0
  36. package/dist/error-handlers/default-error-handlers.js +2 -2
  37. package/dist/get-context/index.d.ts +2 -2
  38. package/dist/get-context/index.js +1 -1
  39. package/dist/get-instances/index.js +6 -6
  40. package/dist/get-instances/instance.js +6 -2
  41. package/dist/get-package-json-files/get-patterns/get-lerna-patterns.js +4 -2
  42. package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.d.ts +1 -1
  43. package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.js +2 -2
  44. package/dist/get-package-json-files/get-patterns/get-yarn-patterns.js +2 -2
  45. package/dist/get-package-json-files/get-patterns/index.js +3 -3
  46. package/dist/get-package-json-files/index.js +1 -1
  47. package/dist/get-package-json-files/package-json-file.d.ts +7 -0
  48. package/dist/get-package-json-files/package-json-file.js +18 -3
  49. package/dist/guards/can-add-to-group.js +19 -13
  50. package/dist/guards/is-semver.js +3 -1
  51. package/dist/io/ask-for-choice.js +3 -3
  52. package/dist/io/ask-for-input.js +2 -2
  53. package/dist/io/exit-if-invalid.js +1 -1
  54. package/dist/io/glob-sync.js +1 -1
  55. package/dist/io/index.d.ts +1 -2
  56. package/dist/io/index.js +1 -1
  57. package/dist/io/read-config-file.js +5 -3
  58. package/dist/io/read-file-sync.js +1 -1
  59. package/dist/io/read-json-file-sync.d.ts +2 -1
  60. package/dist/io/read-json-file-sync.js +9 -5
  61. package/dist/io/read-yaml-file-sync.js +1 -1
  62. package/dist/io/{to-json.d.ts → to-formatted-json.d.ts} +1 -1
  63. package/dist/io/{to-json.js → to-formatted-json.js} +11 -8
  64. package/dist/io/write-file-sync.js +2 -2
  65. package/dist/io/write-if-changed.js +3 -4
  66. package/dist/lib/format-repository-url.js +8 -5
  67. package/dist/lib/get-group-header.js +3 -1
  68. package/dist/lib/get.js +20 -12
  69. package/dist/lib/ring-buffer.js +1 -1
  70. package/dist/lib/set-semver-range.js +8 -4
  71. package/dist/lib/with-logger.js +6 -6
  72. package/dist/option.js +4 -1
  73. package/dist/schema.json +3 -0
  74. package/dist/semver-group/create-semver-groups.js +7 -3
  75. package/dist/semver-group/disabled.js +1 -1
  76. package/dist/semver-group/filtered-out.js +1 -1
  77. package/dist/semver-group/ignored.js +1 -1
  78. package/dist/semver-group/with-range.js +3 -3
  79. package/dist/specifier/alias.js +3 -2
  80. package/dist/specifier/delete.d.ts +2 -2
  81. package/dist/specifier/exact.js +1 -1
  82. package/dist/specifier/hosted-git.js +5 -3
  83. package/dist/specifier/index.js +27 -15
  84. package/dist/specifier/latest.js +1 -1
  85. package/dist/specifier/lib/parse-specifier.js +3 -1
  86. package/dist/specifier/range.js +1 -1
  87. package/dist/specifier/workspace-protocol.js +2 -1
  88. package/dist/strategy/lib/get-non-empty-string-prop.js +1 -1
  89. package/dist/strategy/name-and-version-props.js +7 -7
  90. package/dist/strategy/named-version-string.js +11 -8
  91. package/dist/strategy/unnamed-version-string.js +6 -6
  92. package/dist/strategy/versions-by-name.js +4 -2
  93. package/dist/version-group/banned.js +1 -1
  94. package/dist/version-group/create-version-groups.js +11 -7
  95. package/dist/version-group/filtered-out.js +1 -1
  96. package/dist/version-group/ignored.js +1 -1
  97. package/dist/version-group/lib/get-preferred-version.js +22 -13
  98. package/dist/version-group/lib/get-range-score.js +3 -1
  99. package/dist/version-group/pinned.js +2 -2
  100. package/dist/version-group/same-range.js +6 -6
  101. package/dist/version-group/snapped-to.js +7 -5
  102. package/dist/version-group/standard.js +19 -16
  103. package/package.json +41 -33
@@ -1,6 +1,6 @@
1
+ import { EOL } from 'node:os';
1
2
  import chalk from 'chalk-template';
2
3
  import { Context, Effect, pipe } from 'effect';
3
- import { EOL } from 'os';
4
4
  import { CliConfigTag } from '../config/tag.js';
5
5
  import { ICON } from '../constants.js';
6
6
  import { defaultErrorHandlers } from '../error-handlers/default-error-handlers.js';
@@ -11,8 +11,8 @@ import { IoTag } from '../io/index.js';
11
11
  import { getVersionGroupHeader } from '../lib/get-group-header.js';
12
12
  import { padStart } from '../lib/pad-start.js';
13
13
  import { withLogger } from '../lib/with-logger.js';
14
- export function listMismatches({ io, cli, errorHandlers = defaultErrorHandlers }) {
15
- return pipe(getContext({ io, cli, errorHandlers }), Effect.flatMap((ctx) => pipeline(ctx, io, errorHandlers)), Effect.flatMap(exitIfInvalid), Effect.provide(pipe(Context.empty(), Context.add(CliConfigTag, cli), Context.add(IoTag, io))), withLogger);
14
+ export function listMismatches({ io, cli, errorHandlers = defaultErrorHandlers, }) {
15
+ return pipe(getContext({ io, cli, errorHandlers }), Effect.flatMap(ctx => pipeline(ctx, io, errorHandlers)), Effect.flatMap(exitIfInvalid), Effect.provide(pipe(Context.empty(), Context.add(CliConfigTag, cli), Context.add(IoTag, io))), withLogger);
16
16
  }
17
17
  /** Exported to be reused by `syncpack lint` */
18
18
  export function pipeline(ctx, io, errorHandlers) {
@@ -30,11 +30,13 @@ export function pipeline(ctx, io, errorHandlers) {
30
30
  for (const groupReport of yield* $(group.inspectAll())) {
31
31
  for (const report of groupReport.reports) {
32
32
  countByReportGroup[report._tagGroup]++;
33
- if (report.isInvalid)
33
+ if (report.isInvalid) {
34
34
  ctx.isInvalid = true;
35
+ }
35
36
  const logReport = onReportTag[report._tag];
36
- if (logReport)
37
+ if (logReport) {
37
38
  yield* $(logReport(report));
39
+ }
38
40
  }
39
41
  }
40
42
  yield* $(onReportGroup.Valid(countByReportGroup.Valid));
@@ -48,26 +50,30 @@ export function pipeline(ctx, io, errorHandlers) {
48
50
  }
49
51
  const onReportGroup = {
50
52
  Excluded(amount) {
51
- if (amount === 0)
53
+ if (amount === 0) {
52
54
  return Effect.void;
55
+ }
53
56
  const msg = chalk `{gray ${padStart(amount)} ${ICON.rightArrow} ignored}`;
54
57
  return Effect.logInfo(msg);
55
58
  },
56
59
  Fixable(amount) {
57
- if (amount === 0)
60
+ if (amount === 0) {
58
61
  return Effect.void;
62
+ }
59
63
  const msg = chalk `${padStart(amount)} {green ${ICON.tick}} can be auto-fixed`;
60
64
  return Effect.logInfo(msg);
61
65
  },
62
66
  Unfixable(amount) {
63
- if (amount === 0)
67
+ if (amount === 0) {
64
68
  return Effect.void;
69
+ }
65
70
  const msg = chalk `{red ${padStart(amount)} ${ICON.panic} can be fixed manually using} {blue syncpack prompt}`;
66
71
  return Effect.logInfo(msg);
67
72
  },
68
73
  Valid(amount) {
69
- if (amount === 0)
74
+ if (amount === 0) {
70
75
  return Effect.void;
76
+ }
71
77
  const msg = chalk `${padStart(amount)} {green ${ICON.tick}} already valid`;
72
78
  return Effect.logInfo(msg);
73
79
  },
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import chalk from 'chalk-template';
3
2
  import { program } from 'commander';
4
3
  import { Effect } from 'effect';
5
4
  import { io } from '../io/index.js';
@@ -7,38 +6,7 @@ import { showHelpOnError } from '../lib/show-help-on-error.js';
7
6
  import { option } from '../option.js';
8
7
  import { prompt } from './prompt.js';
9
8
  program.description(' displays a series of prompts to fix mismatches which syncpack cannot fix automatically');
10
- program.on('--help', () => {
11
- console.log(chalk `
12
- Examples:
13
- {dim # uses defaults for resolving packages}
14
- syncpack prompt
15
- {dim # uses packages defined by --source when provided}
16
- syncpack prompt --source {yellow "apps/*/package.json"}
17
- {dim # multiple globs can be provided like this}
18
- syncpack prompt --source {yellow "apps/*/package.json"} --source {yellow "core/*/package.json"}
19
- {dim # uses dependencies regular expression defined by --filter when provided}
20
- syncpack prompt --filter {yellow "typescript|tslint"}
21
- {dim # only inspect "devDependencies"}
22
- syncpack prompt --types dev
23
- {dim # only inspect "devDependencies" and "peerDependencies"}
24
- syncpack prompt --types dev,peer
25
- {dim # indent package.json with 4 spaces instead of 2}
26
- syncpack prompt --indent {yellow " "}
27
-
28
- Resolving Packages:
29
- 1. If {yellow --source} globs are provided, use those.
30
- 2. If using Pnpm Workspaces, read {yellow packages} from {yellow pnpm-workspace.yaml} in the root of the project.
31
- 3. If using Yarn Workspaces, read {yellow workspaces} from {yellow package.json}.
32
- 4. If using Lerna, read {yellow packages} from {yellow lerna.json}.
33
- 5. Default to {yellow "package.json"} and {yellow "packages/*/package.json"}.
34
-
35
- Reference:
36
- globs {blue.underline https://github.com/isaacs/node-glob#glob-primer}
37
- lerna.json {blue.underline https://github.com/lerna/lerna#lernajson}
38
- Yarn Workspaces {blue.underline https://yarnpkg.com/lang/en/docs/workspaces}
39
- Pnpm Workspaces {blue.underline https://pnpm.js.org/en/workspaces}
40
- `);
41
- });
9
+ program.on('--help', () => { });
42
10
  showHelpOnError(program);
43
11
  program
44
12
  .option(...option.source)
@@ -1,5 +1,5 @@
1
1
  import { Effect } from 'effect';
2
- import { type CliConfig } from '../config/types.js';
2
+ import type { CliConfig } from '../config/types.js';
3
3
  import type { ErrorHandlers } from '../error-handlers/default-error-handlers.js';
4
4
  import type { Io } from '../io/index.js';
5
5
  interface Input {
@@ -7,5 +7,5 @@ interface Input {
7
7
  cli: Partial<CliConfig>;
8
8
  errorHandlers?: ErrorHandlers;
9
9
  }
10
- export declare function prompt({ io, cli, errorHandlers }: Input): Effect.Effect<unknown, never, never>;
10
+ export declare function prompt({ io, cli, errorHandlers, }: Input): Effect.Effect<unknown, never, never>;
11
11
  export {};
@@ -15,8 +15,8 @@ import { IoTag } from '../io/index.js';
15
15
  import { writeIfChanged } from '../io/write-if-changed.js';
16
16
  import { getVersionGroupHeader } from '../lib/get-group-header.js';
17
17
  import { withLogger } from '../lib/with-logger.js';
18
- export function prompt({ io, cli, errorHandlers = defaultErrorHandlers }) {
19
- return pipe(getContext({ io, cli, errorHandlers }), Effect.flatMap((ctx) => pipe(Effect.gen(function* ($) {
18
+ export function prompt({ io, cli, errorHandlers = defaultErrorHandlers, }) {
19
+ return pipe(getContext({ io, cli, errorHandlers }), Effect.flatMap(ctx => pipe(Effect.gen(function* ($) {
20
20
  const { versionGroups } = yield* $(getInstances(ctx, io, errorHandlers));
21
21
  let unfixableCount = 0;
22
22
  let index = 0;
@@ -60,32 +60,34 @@ function isUnfixable(report) {
60
60
  }
61
61
  function askForNextVersion(groupReport, unfixable) {
62
62
  return pipe(Effect.gen(function* ($) {
63
- const choices = uniq(groupReport.reports.map((report) => report._tagGroup === 'Fixable'
63
+ const choices = uniq(groupReport.reports.map(report => report._tagGroup === 'Fixable'
64
64
  ? report.fixable.raw
65
65
  : report._tagGroup === 'Unfixable'
66
66
  ? report.unfixable.rawSpecifier
67
67
  : report._tagGroup === 'Valid'
68
68
  ? report.specifier.raw
69
69
  : null)).filter(isString);
70
- const OTHER = chalk `{dim Other}`;
71
- const SKIP = chalk `{dim Skip}`;
72
- const QUIT = chalk `{dim Quit}`;
70
+ const other = chalk `{dim Other}`;
71
+ const skip = chalk `{dim Skip}`;
72
+ const quit = chalk `{dim Quit}`;
73
73
  // Ask user to choose a version to align on
74
74
  const choice = yield* $(askForChoice({
75
75
  message: groupReport.name,
76
- choices: [...choices, OTHER, SKIP, QUIT],
76
+ choices: [...choices, other, skip, quit],
77
77
  }));
78
- if (choice === SKIP)
78
+ if (choice === skip) {
79
79
  return;
80
+ }
80
81
  // @TODO: Learn https://www.effect.website/docs/data-types/exit
81
- if (choice === QUIT)
82
+ if (choice === quit) {
82
83
  return process.exit(0);
83
- const nextVersion = choice === OTHER
84
+ }
85
+ const nextVersion = choice === other
84
86
  ? yield* $(askForInput({
85
87
  message: chalk `${groupReport.name} {dim Enter a replacement version}`,
86
88
  }))
87
89
  : choice;
88
- yield* $(pipe(unfixable, Effect.forEach((report) => report.unfixable.write(nextVersion))));
90
+ yield* $(pipe(unfixable, Effect.forEach(report => report.unfixable.write(nextVersion))));
89
91
  }), Effect.catchTags({
90
92
  AskForChoiceError: Effect.logDebug,
91
93
  AskForInputError: Effect.logDebug,
@@ -9,44 +9,7 @@ import { setSemverRanges } from './set-semver-ranges.js';
9
9
  program.description(chalk `
10
10
  Ensure dependency versions within {yellow dependencies}, {yellow devDependencies},
11
11
  {yellow peerDependencies}, {yellow overrides}, and {yellow resolutions} follow a consistent format.`.replace(/^\n/, ''));
12
- program.on('--help', () => {
13
- console.log(chalk `
14
- Examples:
15
- {dim # uses defaults for resolving packages}
16
- syncpack set-semver-ranges
17
- {dim # uses packages defined by --source when provided}
18
- syncpack set-semver-ranges --source {yellow "apps/*/package.json"}
19
- {dim # multiple globs can be provided like this}
20
- syncpack set-semver-ranges --source {yellow "apps/*/package.json"} --source {yellow "core/*/package.json"}
21
- {dim # uses dependencies regular expression defined by --filter when provided}
22
- syncpack set-semver-ranges --filter {yellow "typescript|tslint"}
23
- {dim # indent package.json with 4 spaces instead of 2}
24
- syncpack set-semver-ranges --indent {yellow " "}
25
-
26
- Supported Ranges:
27
- < {dim <1.4.2}
28
- <= {dim <=1.4.2}
29
- "" {dim 1.4.2}
30
- ~ {dim ~1.4.2}
31
- ^ {dim ^1.4.2}
32
- >= {dim >=1.4.2}
33
- > {dim >1.4.2}
34
- * {dim *}
35
-
36
- Resolving Packages:
37
- 1. If {yellow --source} globs are provided, use those.
38
- 2. If using Pnpm Workspaces, read {yellow packages} from {yellow pnpm-workspace.yaml} in the root of the project.
39
- 3. If using Yarn Workspaces, read {yellow workspaces} from {yellow package.json}.
40
- 4. If using Lerna, read {yellow packages} from {yellow lerna.json}.
41
- 5. Default to {yellow "package.json"} and {yellow "packages/*/package.json"}.
42
-
43
- Reference:
44
- globs {blue.underline https://github.com/isaacs/node-glob#glob-primer}
45
- lerna.json {blue.underline https://github.com/lerna/lerna#lernajson}
46
- Yarn Workspaces {blue.underline https://yarnpkg.com/lang/en/docs/workspaces}
47
- Pnpm Workspaces {blue.underline https://pnpm.js.org/en/workspaces}
48
- `);
49
- });
12
+ program.on('--help', () => { });
50
13
  showHelpOnError(program);
51
14
  program
52
15
  .option(...option.source)
@@ -1,5 +1,5 @@
1
1
  import { Effect } from 'effect';
2
- import { type CliConfig } from '../config/types.js';
2
+ import type { CliConfig } from '../config/types.js';
3
3
  import type { ErrorHandlers } from '../error-handlers/default-error-handlers.js';
4
4
  import type { Io } from '../io/index.js';
5
5
  interface Input {
@@ -7,5 +7,5 @@ interface Input {
7
7
  cli: Partial<CliConfig>;
8
8
  errorHandlers?: ErrorHandlers;
9
9
  }
10
- export declare function setSemverRanges({ io, cli, errorHandlers }: Input): Effect.Effect<unknown, never, never>;
10
+ export declare function setSemverRanges({ io, cli, errorHandlers, }: Input): Effect.Effect<unknown, never, never>;
11
11
  export {};
@@ -11,8 +11,8 @@ import { exitIfInvalid } from '../io/exit-if-invalid.js';
11
11
  import { IoTag } from '../io/index.js';
12
12
  import { writeIfChanged } from '../io/write-if-changed.js';
13
13
  import { withLogger } from '../lib/with-logger.js';
14
- export function setSemverRanges({ io, cli, errorHandlers = defaultErrorHandlers }) {
15
- return pipe(getContext({ io, cli, errorHandlers }), Effect.flatMap((ctx) => pipe(Effect.gen(function* ($) {
14
+ export function setSemverRanges({ io, cli, errorHandlers = defaultErrorHandlers, }) {
15
+ return pipe(getContext({ io, cli, errorHandlers }), Effect.flatMap(ctx => pipe(Effect.gen(function* ($) {
16
16
  // no semver groups have been configured, they are disabled by default
17
17
  if (!isNonEmptyArray(ctx.config.rcFile.semverGroups)) {
18
18
  ctx.isInvalid = true;
@@ -42,12 +42,15 @@ export function setSemverRanges({ io, cli, errorHandlers = defaultErrorHandlers
42
42
  }
43
43
  }
44
44
  }
45
- if (validCount)
45
+ if (validCount) {
46
46
  yield* $(logAlreadyValidSize(validCount));
47
- if (fixedCount)
47
+ }
48
+ if (fixedCount) {
48
49
  yield* $(logFixedSize(fixedCount));
49
- if (unfixableCount)
50
+ }
51
+ if (unfixableCount) {
50
52
  yield* $(logUnfixableSize(unfixableCount));
53
+ }
51
54
  return ctx;
52
55
  }), Effect.flatMap(writeIfChanged), Effect.catchTags({
53
56
  WriteFileError: flow(errorHandlers.WriteFileError, Effect.map(() => {
@@ -37,7 +37,7 @@ declare class NpmRegistryError extends NpmRegistryError_base<{
37
37
  export declare const updateEffects: {
38
38
  onFetchAllStart(): Effect.Effect<void, never, never>;
39
39
  onFetchStart(instance: Instance, totalCount: number): Effect.Effect<void, never, never>;
40
- onFetchEnd(instance: Instance, versions?: Releases['versions']): Effect.Effect<void, never, never>;
40
+ onFetchEnd(instance: Instance, versions?: Releases["versions"]): Effect.Effect<void, never, never>;
41
41
  /** After checking the registry, store this instance known to be up to date */
42
42
  onUpToDate(instance: Instance): Effect.Effect<void, never, never>;
43
43
  /** After checking the registry, store this instance known to have newer versions available */
@@ -1,9 +1,9 @@
1
+ import https from 'node:https';
2
+ import { EOL } from 'node:os';
1
3
  import * as Schema from '@effect/schema/Schema';
2
4
  import chalk from 'chalk-template';
3
5
  import { Data, Effect, identity, pipe } from 'effect';
4
- import https from 'https';
5
6
  import ora from 'ora';
6
- import { EOL } from 'os';
7
7
  import prompts from 'prompts';
8
8
  import { diff } from 'semver';
9
9
  import gtr from 'semver/ranges/gtr.js';
@@ -48,8 +48,9 @@ function stripAnsi(str) {
48
48
  }
49
49
  export const updateEffects = {
50
50
  onFetchAllStart() {
51
- if (!spinner)
51
+ if (!spinner) {
52
52
  spinner = ora().start();
53
+ }
53
54
  fetchedCount = 0;
54
55
  return Effect.void;
55
56
  },
@@ -58,7 +59,10 @@ export const updateEffects = {
58
59
  fetchedCount++;
59
60
  if (spinner) {
60
61
  const indent = `${EOL} `;
61
- const progress = new Set([...mostRecent.filter(Boolean), ...inFlight.values()]);
62
+ const progress = new Set([
63
+ ...mostRecent.filter(Boolean),
64
+ ...inFlight.values(),
65
+ ]);
62
66
  const sortedProgress = Array.from(progress).sort((a, b) => stripAnsi(a).localeCompare(stripAnsi(b)));
63
67
  const suffixText = sortedProgress.join(indent);
64
68
  spinner.text = chalk `${outdatedCount} updates found in ${fetchedCount}/${totalCount} dependencies${indent}${suffixText}`;
@@ -71,7 +75,7 @@ export const updateEffects = {
71
75
  if (latest) {
72
76
  if (gtr(latest, String(instance.rawSpecifier.raw), true)) {
73
77
  outdatedCount++;
74
- mostRecent.push(chalk `${instance.name} {gray {red ${instance.rawSpecifier.raw}} ${ICON.rightArrow}} {green ${latest}}`);
78
+ mostRecent.push(chalk `${instance.name} {gray {red ${String(instance.rawSpecifier.raw)}} ${ICON.rightArrow}} {green ${latest}}`);
75
79
  }
76
80
  else {
77
81
  mostRecent.push(chalk `{green ${instance.name}}`);
@@ -87,13 +91,14 @@ export const updateEffects = {
87
91
  /** After checking the registry, store this instance known to have newer versions available */
88
92
  onOutdated(instance, latest) {
89
93
  outdatedCount++;
90
- mostRecent.push(chalk `${instance.name} {gray {red ${instance.rawSpecifier.raw}} ${ICON.rightArrow}} {green ${latest}}`);
94
+ mostRecent.push(chalk `${instance.name} {gray {red ${String(instance.rawSpecifier.raw)}} ${ICON.rightArrow}} {green ${latest}}`);
91
95
  return Effect.void;
92
96
  },
93
97
  /** As the last request completes, remove the progress information */
94
98
  onFetchAllEnd() {
95
- if (spinner)
99
+ if (spinner) {
96
100
  spinner.stop();
101
+ }
97
102
  spinner = null;
98
103
  fetchedCount = 0;
99
104
  return Effect.void;
@@ -104,17 +109,19 @@ export const updateEffects = {
104
109
  // parse and validate the specific data we expect
105
110
  Effect.flatMap(Schema.decodeUnknownEither(Schema.Struct({
106
111
  'dist-tags': Schema.Struct({ latest: Schema.String }),
107
- 'time': Schema.Record(Schema.String, Schema.String),
108
- 'homepage': Schema.optional(Schema.String),
109
- 'repository': Schema.optional(Schema.Union(Schema.String, Schema.Struct({ url: Schema.optional(Schema.String) }))),
112
+ time: Schema.Record({ key: Schema.String, value: Schema.String }),
113
+ homepage: Schema.optional(Schema.String),
114
+ repository: Schema.optional(Schema.Union(Schema.String, Schema.Struct({ url: Schema.optional(Schema.String) }))),
110
115
  }))),
111
116
  // transform it into something more appropriate
112
- Effect.map((struct) => {
113
- const rawRepoUrl = typeof struct.repository === 'object' ? struct.repository.url : struct.repository;
117
+ Effect.map(struct => {
118
+ const rawRepoUrl = typeof struct.repository === 'object'
119
+ ? struct.repository.url
120
+ : struct.repository;
114
121
  return new Releases({
115
122
  instance,
116
123
  versions: {
117
- all: Object.keys(struct.time).filter((key) => key !== 'modified' && key !== 'created'),
124
+ all: Object.keys(struct.time).filter(key => key !== 'modified' && key !== 'created'),
118
125
  latest: struct['dist-tags'].latest,
119
126
  },
120
127
  repoUrl: formatRepositoryUrl(rawRepoUrl),
@@ -122,7 +129,9 @@ export const updateEffects = {
122
129
  }),
123
130
  // hide ParseErrors and just treat them as another kind of NpmRegistryError
124
131
  Effect.catchTags({
125
- ParseError: () => Effect.fail(new NpmRegistryError({ error: `Invalid response for ${instance.name}` })),
132
+ ParseError: () => Effect.fail(new NpmRegistryError({
133
+ error: `Invalid response for ${instance.name}`,
134
+ })),
126
135
  }));
127
136
  },
128
137
  /** Given responses from npm, ask the user which they want */
@@ -130,8 +139,8 @@ export const updateEffects = {
130
139
  return pipe(Effect.Do, Effect.bind('releasesByType', () => groupByReleaseType(outdated)),
131
140
  // Create choices to ask if they want major, minor, patch etc
132
141
  Effect.bind('releaseTypeQuestions', ({ releasesByType }) => Effect.succeed(Object.keys(releasesByType)
133
- .filter((type) => releasesByType[type].length > 0)
134
- .map((type) => ({
142
+ .filter(type => releasesByType[type].length > 0)
143
+ .map(type => ({
135
144
  title: chalk `${releasesByType[type].length} ${type}`,
136
145
  selected: true,
137
146
  value: type,
@@ -145,14 +154,14 @@ export const updateEffects = {
145
154
  instructions: true,
146
155
  message: `${outdated.length} updates are available`,
147
156
  choices: releaseTypeQuestions,
148
- }).then((res) => res?.releaseTypeAnswers || []),
157
+ }).then(res => res?.releaseTypeAnswers || []),
149
158
  catch: identity,
150
159
  }), Effect.catchAll(() => pipe(Effect.logError('Error when prompting for releaseTypeAnswers'), Effect.map(() => []))))
151
160
  : Effect.succeed([])),
152
161
  // For each chosen release type, list the available updates to choose from
153
- Effect.bind('prepatchAnswers', (doState) => promptForReleaseType('prepatch', doState)), Effect.bind('patchAnswers', (doState) => promptForReleaseType('patch', doState)), Effect.bind('preminorAnswers', (doState) => promptForReleaseType('preminor', doState)), Effect.bind('minorAnswers', (doState) => promptForReleaseType('minor', doState)), Effect.bind('premajorAnswers', (doState) => promptForReleaseType('premajor', doState)), Effect.bind('majorAnswers', (doState) => promptForReleaseType('major', doState)), Effect.bind('prereleaseAnswers', (doState) => promptForReleaseType('prerelease', doState)),
162
+ Effect.bind('prepatchAnswers', doState => promptForReleaseType('prepatch', doState)), Effect.bind('patchAnswers', doState => promptForReleaseType('patch', doState)), Effect.bind('preminorAnswers', doState => promptForReleaseType('preminor', doState)), Effect.bind('minorAnswers', doState => promptForReleaseType('minor', doState)), Effect.bind('premajorAnswers', doState => promptForReleaseType('premajor', doState)), Effect.bind('majorAnswers', doState => promptForReleaseType('major', doState)), Effect.bind('prereleaseAnswers', doState => promptForReleaseType('prerelease', doState)),
154
163
  /** Apply every update to the package.json files */
155
- Effect.flatMap((doState) => pipe([
164
+ Effect.flatMap(doState => pipe([
156
165
  ...doState.prepatchAnswers,
157
166
  ...doState.patchAnswers,
158
167
  ...doState.preminorAnswers,
@@ -160,7 +169,7 @@ export const updateEffects = {
160
169
  ...doState.premajorAnswers,
161
170
  ...doState.majorAnswers,
162
171
  ...doState.prereleaseAnswers,
163
- ], Effect.forEach(({ instance, versions }) => pipe(instance.semverGroup.getFixed(Specifier.create(instance, versions.latest)), Effect.flatMap((latestWithRange) => instance.write(latestWithRange.raw)), Effect.catchTag('NonSemverError', Effect.logError))), Effect.flatMap(() => Effect.void))));
172
+ ], Effect.forEach(({ instance, versions }) => pipe(instance.semverGroup.getFixed(Specifier.create(instance, versions.latest)), Effect.flatMap(latestWithRange => instance.write(latestWithRange.raw)), Effect.catchTag('NonSemverError', Effect.logError))), Effect.flatMap(() => Effect.void))));
164
173
  },
165
174
  };
166
175
  function promptForReleaseType(releaseType, doState) {
@@ -176,17 +185,19 @@ function promptForReleaseType(releaseType, doState) {
176
185
  // @ts-expect-error optionsPerPage *does* exist https://github.com/terkelg/prompts#options-7
177
186
  optionsPerPage,
178
187
  message: `${releases.length} ${releaseType} updates`,
179
- choices: releases.map((updateable) => {
188
+ choices: releases.map(updateable => {
180
189
  const spacingValue = 50 -
181
190
  updateable.instance.name.length -
182
191
  String(updateable.instance.rawSpecifier).length -
183
192
  updateable.versions.latest.length;
184
- const spacing = Array.from({ length: spacingValue }).fill(' ').join('');
193
+ const spacing = Array.from({ length: spacingValue })
194
+ .fill(' ')
195
+ .join('');
185
196
  const repoUrl = updateable.repoUrl
186
197
  ? chalk `${spacing} {white - ${updateable.repoUrl}}`
187
198
  : '';
188
199
  return {
189
- title: chalk `${updateable.instance.name} {gray ${updateable.instance.rawSpecifier.raw} ${ICON.rightArrow}} {green ${updateable.versions.latest}} ${repoUrl}`,
200
+ title: chalk `${updateable.instance.name} {gray ${String(updateable.instance.rawSpecifier.raw)} ${ICON.rightArrow}} {green ${updateable.versions.latest}} ${repoUrl}`,
190
201
  selected: true,
191
202
  value: updateable,
192
203
  };
@@ -199,7 +210,7 @@ function promptForReleaseType(releaseType, doState) {
199
210
  // In terkelg/prompts, an empty object means that the user cancelled via
200
211
  // ctrl+c or the escape key etc. Handle this case so we can skip any
201
212
  // remaining steps.
202
- Effect.flatMap((res) => isEmptyObject(res)
213
+ Effect.flatMap(res => isEmptyObject(res)
203
214
  ? Effect.fail(new PromptCancelled({ name: releaseType }))
204
215
  : Effect.succeed(isArray(res?.[prop]) ? res?.[prop] : [])))
205
216
  : Effect.succeed([]);
@@ -230,7 +241,7 @@ function groupByReleaseType(releases) {
230
241
  }
231
242
  // @TODO: add a cache with a short TTL on disk in $TMPDIR
232
243
  function fetchJson(url) {
233
- return pipe(Effect.async((resume) => {
244
+ return pipe(Effect.async(resume => {
234
245
  // setTimeout(
235
246
  // () => {
236
247
  // resume(
@@ -247,21 +258,25 @@ function fetchJson(url) {
247
258
  // Math.floor(Math.random() * 500) + 1,
248
259
  // );
249
260
  https
250
- .get(url, (res) => {
261
+ .get(url, res => {
251
262
  let body = '';
252
263
  res.setEncoding('utf8');
253
- res.on('data', (chunk) => {
264
+ res.on('data', chunk => {
254
265
  body = `${body}${chunk}`;
255
266
  });
256
267
  res.on('end', () => {
257
268
  resume(Effect.succeed(body));
258
269
  });
259
270
  })
260
- .on('error', (err) => {
261
- resume(Effect.fail(new HttpError({ error: `Node https threw on ${url}: ${String(err)}` })));
271
+ .on('error', err => {
272
+ resume(Effect.fail(new HttpError({
273
+ error: `Node https threw on ${url}: ${String(err)}`,
274
+ })));
262
275
  });
263
- }), Effect.flatMap((body) => Effect.try({
276
+ }), Effect.flatMap(body => Effect.try({
264
277
  try: () => JSON.parse(body),
265
- catch: () => new NpmRegistryError({ error: `JSON.parse threw on response from ${url}` }),
278
+ catch: () => new NpmRegistryError({
279
+ error: `JSON.parse threw on response from ${url}`,
280
+ }),
266
281
  })));
267
282
  }
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import chalk from 'chalk-template';
3
2
  import { program } from 'commander';
4
3
  import { Effect } from 'effect';
5
4
  import { io } from '../io/index.js';
@@ -7,36 +6,7 @@ import { showHelpOnError } from '../lib/show-help-on-error.js';
7
6
  import { option } from '../option.js';
8
7
  import { update } from './update.js';
9
8
  program.description(' Update to the latest versions on the npm registry.');
10
- program.on('--help', () => {
11
- console.log(chalk `
12
- Examples:
13
- {dim # uses defaults for resolving packages}
14
- syncpack update
15
- {dim # uses packages defined by --source when provided}
16
- syncpack update --source {yellow "apps/*/package.json"}
17
- {dim # multiple globs can be provided like this}
18
- syncpack update --source {yellow "apps/*/package.json"} --source {yellow "core/*/package.json"}
19
- {dim # uses dependencies regular expression defined by --filter when provided}
20
- syncpack update --filter {yellow "typescript|tslint"}
21
- {dim # only inspect "devDependencies"}
22
- syncpack update --types dev
23
- {dim # only inspect "devDependencies" and "peerDependencies"}
24
- syncpack update --types dev,peer
25
-
26
- Resolving Packages:
27
- 1. If {yellow --source} globs are provided, use those.
28
- 2. If using Pnpm Workspaces, read {yellow packages} from {yellow pnpm-workspace.yaml} in the root of the project.
29
- 3. If using Yarn Workspaces, read {yellow workspaces} from {yellow package.json}.
30
- 4. If using Lerna, read {yellow packages} from {yellow lerna.json}.
31
- 5. Default to {yellow "package.json"} and {yellow "packages/*/package.json"}.
32
-
33
- Reference:
34
- globs {blue.underline https://github.com/isaacs/node-glob#glob-primer}
35
- lerna.json {blue.underline https://github.com/lerna/lerna#lernajson}
36
- Yarn Workspaces {blue.underline https://yarnpkg.com/lang/en/docs/workspaces}
37
- Pnpm Workspaces {blue.underline https://pnpm.js.org/en/workspaces}
38
- `);
39
- });
9
+ program.on('--help', () => { });
40
10
  showHelpOnError(program);
41
11
  program
42
12
  .option(...option.source)
@@ -1,5 +1,5 @@
1
1
  import { Effect } from 'effect';
2
- import { type CliConfig } from '../config/types.js';
2
+ import type { CliConfig } from '../config/types.js';
3
3
  import type { ErrorHandlers } from '../error-handlers/default-error-handlers.js';
4
4
  import type { Io } from '../io/index.js';
5
5
  import { updateEffects } from './effects.js';
@@ -13,10 +13,10 @@ import { withLogger } from '../lib/with-logger.js';
13
13
  import { Specifier } from '../specifier/index.js';
14
14
  import { updateEffects } from './effects.js';
15
15
  export function update(io, cli, effects = updateEffects, errorHandlers = defaultErrorHandlers) {
16
- return pipe(Effect.Do, Effect.bind('ctx', () => getContext({ io, cli, errorHandlers })), Effect.bind('instances', ({ ctx }) => getInstances(ctx, io, errorHandlers)), Effect.bind('update', ({ instances }) => pipe(Effect.succeed(instances.all), Effect.map((instances) => {
16
+ return pipe(Effect.Do, Effect.bind('ctx', () => getContext({ io, cli, errorHandlers })), Effect.bind('instances', ({ ctx }) => getInstances(ctx, io, errorHandlers)), Effect.bind('update', ({ instances }) => pipe(Effect.succeed(instances.all), Effect.map(instances => {
17
17
  const isVisitedByName = {};
18
18
  const updateable = [];
19
- instances.forEach((instance) => {
19
+ instances.forEach(instance => {
20
20
  if (!isVisitedByName[instance.name] &&
21
21
  (instance.versionGroup._tag === 'SameRange' ||
22
22
  instance.versionGroup._tag === 'Standard')) {
@@ -28,12 +28,12 @@ export function update(io, cli, effects = updateEffects, errorHandlers = default
28
28
  }
29
29
  });
30
30
  return updateable;
31
- }), Effect.tap(updateEffects.onFetchAllStart), Effect.flatMap((instances) => pipe(instances, Effect.partition((instance) => pipe(Effect.succeed(instance), Effect.tap(() => updateEffects.onFetchStart(instance, instances.length)), Effect.flatMap(effects.fetchLatestVersions), Effect.tapBoth({
31
+ }), Effect.tap(updateEffects.onFetchAllStart), Effect.flatMap(instances => pipe(instances, Effect.partition(instance => pipe(Effect.succeed(instance), Effect.tap(() => updateEffects.onFetchStart(instance, instances.length)), Effect.flatMap(effects.fetchLatestVersions), Effect.tapBoth({
32
32
  onFailure: () => updateEffects.onFetchEnd(instance),
33
33
  onSuccess: ({ versions }) => updateEffects.onFetchEnd(instance, versions),
34
34
  }),
35
35
  // move up to date dependencies to error channel
36
- Effect.flatMap((updateable) => gtr(updateable.versions.latest, String(instance.rawSpecifier.raw))
36
+ Effect.flatMap(updateable => gtr(updateable.versions.latest, String(instance.rawSpecifier.raw))
37
37
  ? pipe(updateEffects.onOutdated(instance, updateable.versions.latest), Effect.map(() => updateable))
38
38
  : pipe(updateEffects.onUpToDate(instance), Effect.flatMap(() => Effect.fail(updateable)))),
39
39
  // log error but don't catch it
package/dist/bin.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
2
5
  import { program } from 'commander';
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
  program
@@ -10,24 +10,31 @@ import { VersionsByNameStrategy } from '../strategy/versions-by-name.js';
10
10
  export class InvalidCustomTypeError extends Data.TaggedClass('InvalidCustomTypeError') {
11
11
  }
12
12
  export function getCustomTypes({ rcFile, }) {
13
- if (!isNonEmptyObject(rcFile.customTypes))
13
+ if (!isNonEmptyObject(rcFile.customTypes)) {
14
14
  return Effect.succeed([]);
15
- return Effect.all([...Object.entries(rcFile.customTypes), ...Object.entries(DEFAULT_CONFIG.customTypes)].map(([name, config]) => {
16
- const ERR_OBJ = 'Invalid customType';
17
- const ERR_PATH = 'Invalid customType.path';
18
- const ERR_NAME_PATH = 'Invalid customType.namePath';
19
- const ERR_STRATEGY = 'Invalid customType.strategy';
20
- if (!isObject(config))
21
- return createError(config, ERR_OBJ);
22
- if (!isNonEmptyString(config.path))
23
- return createError(config, ERR_PATH);
15
+ }
16
+ return Effect.all([
17
+ ...Object.entries(rcFile.customTypes),
18
+ ...Object.entries(DEFAULT_CONFIG.customTypes),
19
+ ].map(([name, config]) => {
20
+ const errObj = 'Invalid customType';
21
+ const errPath = 'Invalid customType.path';
22
+ const errNamePath = 'Invalid customType.namePath';
23
+ const errStrategy = 'Invalid customType.strategy';
24
+ if (!isObject(config)) {
25
+ return createError(config, errObj);
26
+ }
27
+ if (!isNonEmptyString(config.path)) {
28
+ return createError(config, errPath);
29
+ }
24
30
  const path = config.path;
25
31
  const strategy = config.strategy;
26
32
  switch (strategy) {
27
33
  case 'name~version': {
28
34
  const namePath = config.namePath;
29
- if (!isNonEmptyString(namePath))
30
- return createError(config, ERR_NAME_PATH);
35
+ if (!isNonEmptyString(namePath)) {
36
+ return createError(config, errNamePath);
37
+ }
31
38
  return Effect.succeed(new NameAndVersionPropsStrategy(name, path, namePath));
32
39
  }
33
40
  case 'name@version': {
@@ -40,7 +47,7 @@ export function getCustomTypes({ rcFile, }) {
40
47
  return Effect.succeed(new VersionsByNameStrategy(name, path));
41
48
  }
42
49
  default: {
43
- return createError(config, ERR_STRATEGY);
50
+ return createError(config, errStrategy);
44
51
  }
45
52
  }
46
53
  }));