syncpack 12.4.0 → 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.
- package/dist/bin-fix-mismatches/fix-mismatches.d.ts +2 -2
- package/dist/bin-fix-mismatches/fix-mismatches.js +13 -8
- package/dist/bin-fix-mismatches/index.js +1 -32
- package/dist/bin-format/format.d.ts +2 -2
- package/dist/bin-format/format.js +7 -5
- package/dist/bin-format/index.js +1 -26
- package/dist/bin-lint/index.js +1 -22
- package/dist/bin-lint/lint.d.ts +1 -1
- package/dist/bin-lint/lint.js +23 -23
- package/dist/bin-lint-semver-ranges/index.js +1 -36
- package/dist/bin-lint-semver-ranges/lint-semver-ranges.d.ts +2 -2
- package/dist/bin-lint-semver-ranges/lint-semver-ranges.js +5 -4
- package/dist/bin-list/index.js +1 -31
- package/dist/bin-list/list.d.ts +1 -1
- package/dist/bin-list/list.js +9 -5
- package/dist/bin-list-mismatches/index.js +1 -31
- package/dist/bin-list-mismatches/list-mismatches.d.ts +2 -2
- package/dist/bin-list-mismatches/list-mismatches.js +15 -9
- package/dist/bin-prompt/index.js +1 -33
- package/dist/bin-prompt/prompt.d.ts +2 -2
- package/dist/bin-prompt/prompt.js +13 -11
- package/dist/bin-set-semver-ranges/index.js +1 -38
- package/dist/bin-set-semver-ranges/set-semver-ranges.d.ts +2 -2
- package/dist/bin-set-semver-ranges/set-semver-ranges.js +8 -5
- package/dist/bin-update/effects.js +43 -28
- package/dist/bin-update/index.js +1 -31
- package/dist/bin-update/update.d.ts +1 -1
- package/dist/bin-update/update.js +4 -4
- package/dist/bin.js +3 -3
- package/dist/config/get-custom-types.js +20 -13
- package/dist/config/get-enabled-types.js +27 -12
- package/dist/config/get-sort-exports.js +2 -1
- package/dist/error-handlers/default-error-handlers.js +2 -2
- package/dist/get-context/index.d.ts +2 -2
- package/dist/get-context/index.js +1 -1
- package/dist/get-instances/index.js +6 -6
- package/dist/get-instances/instance.js +6 -2
- package/dist/get-package-json-files/get-patterns/get-lerna-patterns.js +4 -2
- package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.d.ts +1 -1
- package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.js +2 -2
- package/dist/get-package-json-files/get-patterns/get-yarn-patterns.js +2 -2
- package/dist/get-package-json-files/get-patterns/index.js +3 -3
- package/dist/get-package-json-files/index.js +1 -1
- package/dist/get-package-json-files/package-json-file.d.ts +7 -0
- package/dist/get-package-json-files/package-json-file.js +18 -3
- package/dist/guards/can-add-to-group.js +15 -9
- package/dist/guards/is-semver.js +3 -1
- package/dist/io/ask-for-choice.js +3 -3
- package/dist/io/ask-for-input.js +2 -2
- package/dist/io/exit-if-invalid.js +1 -1
- package/dist/io/glob-sync.js +1 -1
- package/dist/io/index.d.ts +1 -1
- package/dist/io/index.js +1 -1
- package/dist/io/read-config-file.js +5 -3
- package/dist/io/read-file-sync.js +1 -1
- package/dist/io/read-json-file-sync.d.ts +2 -1
- package/dist/io/read-json-file-sync.js +9 -5
- package/dist/io/read-yaml-file-sync.js +1 -1
- package/dist/io/{to-json.d.ts → to-formatted-json.d.ts} +1 -1
- package/dist/io/{to-json.js → to-formatted-json.js} +11 -8
- package/dist/io/write-file-sync.js +2 -2
- package/dist/io/write-if-changed.js +3 -4
- package/dist/lib/format-repository-url.js +8 -5
- package/dist/lib/get-group-header.js +3 -1
- package/dist/lib/get.js +20 -12
- package/dist/lib/ring-buffer.js +1 -1
- package/dist/lib/set-semver-range.js +8 -4
- package/dist/lib/with-logger.js +1 -2
- package/dist/option.js +4 -1
- package/dist/semver-group/create-semver-groups.js +7 -3
- package/dist/semver-group/disabled.js +1 -1
- package/dist/semver-group/filtered-out.js +1 -1
- package/dist/semver-group/ignored.js +1 -1
- package/dist/semver-group/with-range.js +3 -3
- package/dist/specifier/alias.js +3 -2
- package/dist/specifier/exact.js +1 -1
- package/dist/specifier/hosted-git.js +5 -3
- package/dist/specifier/index.js +27 -15
- package/dist/specifier/latest.js +1 -1
- package/dist/specifier/lib/parse-specifier.js +3 -1
- package/dist/specifier/range.js +1 -1
- package/dist/specifier/workspace-protocol.js +2 -1
- package/dist/strategy/lib/get-non-empty-string-prop.js +1 -1
- package/dist/strategy/name-and-version-props.js +7 -7
- package/dist/strategy/named-version-string.js +11 -8
- package/dist/strategy/unnamed-version-string.js +6 -6
- package/dist/strategy/versions-by-name.js +4 -2
- package/dist/version-group/banned.js +1 -1
- package/dist/version-group/create-version-groups.js +11 -7
- package/dist/version-group/filtered-out.js +1 -1
- package/dist/version-group/ignored.js +1 -1
- package/dist/version-group/lib/get-preferred-version.js +22 -13
- package/dist/version-group/lib/get-range-score.js +3 -1
- package/dist/version-group/pinned.js +2 -2
- package/dist/version-group/same-range.js +6 -6
- package/dist/version-group/snapped-to.js +7 -5
- package/dist/version-group/standard.js +19 -16
- package/package.json +22 -25
package/dist/bin-prompt/index.js
CHANGED
|
@@ -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 {
|
|
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(
|
|
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(
|
|
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
|
|
71
|
-
const
|
|
72
|
-
const
|
|
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,
|
|
76
|
+
choices: [...choices, other, skip, quit],
|
|
77
77
|
}));
|
|
78
|
-
if (choice ===
|
|
78
|
+
if (choice === skip) {
|
|
79
79
|
return;
|
|
80
|
+
}
|
|
80
81
|
// @TODO: Learn https://www.effect.website/docs/data-types/exit
|
|
81
|
-
if (choice ===
|
|
82
|
+
if (choice === quit) {
|
|
82
83
|
return process.exit(0);
|
|
83
|
-
|
|
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(
|
|
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 {
|
|
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(
|
|
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
|
-
|
|
47
|
+
}
|
|
48
|
+
if (fixedCount) {
|
|
48
49
|
yield* $(logFixedSize(fixedCount));
|
|
49
|
-
|
|
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(() => {
|
|
@@ -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([
|
|
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}`;
|
|
@@ -92,8 +96,9 @@ export const updateEffects = {
|
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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(
|
|
113
|
-
const rawRepoUrl = typeof struct.repository === 'object'
|
|
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(
|
|
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({
|
|
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(
|
|
134
|
-
.map(
|
|
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(
|
|
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',
|
|
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(
|
|
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(
|
|
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,12 +185,14 @@ 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(
|
|
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 })
|
|
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
|
: '';
|
|
@@ -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(
|
|
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(
|
|
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,
|
|
261
|
+
.get(url, res => {
|
|
251
262
|
let body = '';
|
|
252
263
|
res.setEncoding('utf8');
|
|
253
|
-
res.on('data',
|
|
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',
|
|
261
|
-
resume(Effect.fail(new HttpError({
|
|
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(
|
|
276
|
+
}), Effect.flatMap(body => Effect.try({
|
|
264
277
|
try: () => JSON.parse(body),
|
|
265
|
-
catch: () => new NpmRegistryError({
|
|
278
|
+
catch: () => new NpmRegistryError({
|
|
279
|
+
error: `JSON.parse threw on response from ${url}`,
|
|
280
|
+
}),
|
|
266
281
|
})));
|
|
267
282
|
}
|
package/dist/bin-update/index.js
CHANGED
|
@@ -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 {
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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,
|
|
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,
|
|
50
|
+
return createError(config, errStrategy);
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
}));
|
|
@@ -16,9 +16,9 @@ export function getEnabledTypes({ cli, rcFile, }) {
|
|
|
16
16
|
return pipe(
|
|
17
17
|
// Look for dependency types defined using the old `{ prod: true }` syntax
|
|
18
18
|
// deprecated in syncpack@9.0.0
|
|
19
|
-
Effect.succeed(INTERNAL_TYPES.filter(
|
|
19
|
+
Effect.succeed(INTERNAL_TYPES.filter(key => isBoolean(rcFile[key]))),
|
|
20
20
|
// Short-circuit and quit if deprecated config is used
|
|
21
|
-
Effect.flatMap(
|
|
21
|
+
Effect.flatMap(deprecatedTypeProps => deprecatedTypeProps.length > 0
|
|
22
22
|
? Effect.fail(new DeprecatedTypesError({ types: deprecatedTypeProps }))
|
|
23
23
|
: Effect.void), Effect.flatMap(() => pipe(Effect.Do,
|
|
24
24
|
// Get index of every available strategy, keyed by their names as
|
|
@@ -30,13 +30,28 @@ export function getEnabledTypes({ cli, rcFile, }) {
|
|
|
30
30
|
// Combine them with the default/internal dependency types
|
|
31
31
|
Effect.map((customTypes) => Object.fromEntries([
|
|
32
32
|
['dev', new VersionsByNameStrategy('dev', 'devDependencies')],
|
|
33
|
-
[
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
[
|
|
34
|
+
'local',
|
|
35
|
+
new NameAndVersionPropsStrategy('local', 'version', 'name'),
|
|
36
|
+
],
|
|
37
|
+
[
|
|
38
|
+
'overrides',
|
|
39
|
+
new VersionsByNameStrategy('overrides', 'overrides'),
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
'peer',
|
|
43
|
+
new VersionsByNameStrategy('peer', 'peerDependencies'),
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
'pnpmOverrides',
|
|
47
|
+
new VersionsByNameStrategy('pnpmOverrides', 'pnpm.overrides'),
|
|
48
|
+
],
|
|
37
49
|
['prod', new VersionsByNameStrategy('prod', 'dependencies')],
|
|
38
|
-
[
|
|
39
|
-
|
|
50
|
+
[
|
|
51
|
+
'resolutions',
|
|
52
|
+
new VersionsByNameStrategy('resolutions', 'resolutions'),
|
|
53
|
+
],
|
|
54
|
+
...customTypes.map(type => [type.name, type]),
|
|
40
55
|
])))),
|
|
41
56
|
// The names of every available strategy
|
|
42
57
|
Effect.bind('allStrategyNames', ({ allStrategiesByName }) => Effect.succeed(Object.keys(allStrategiesByName))),
|
|
@@ -61,7 +76,7 @@ export function getEnabledTypes({ cli, rcFile, }) {
|
|
|
61
76
|
strategyNamesByStatus.provided.join('') === '**') {
|
|
62
77
|
return Effect.succeed(allStrategyNames.map(getStrategyByName));
|
|
63
78
|
}
|
|
64
|
-
strategyNamesByStatus.provided.forEach(
|
|
79
|
+
strategyNamesByStatus.provided.forEach(name => {
|
|
65
80
|
if (name.startsWith('!')) {
|
|
66
81
|
strategyNamesByStatus.negative.push(name.replace('!', ''));
|
|
67
82
|
}
|
|
@@ -70,14 +85,14 @@ export function getEnabledTypes({ cli, rcFile, }) {
|
|
|
70
85
|
}
|
|
71
86
|
});
|
|
72
87
|
if (isNonEmptyArray(strategyNamesByStatus.negative)) {
|
|
73
|
-
allStrategyNames.forEach(
|
|
88
|
+
allStrategyNames.forEach(name => {
|
|
74
89
|
if (!strategyNamesByStatus.negative.includes(name)) {
|
|
75
90
|
strategyNamesByStatus.enabled.push(name);
|
|
76
91
|
}
|
|
77
92
|
});
|
|
78
93
|
}
|
|
79
94
|
if (isNonEmptyArray(strategyNamesByStatus.positive)) {
|
|
80
|
-
strategyNamesByStatus.positive.forEach(
|
|
95
|
+
strategyNamesByStatus.positive.forEach(name => {
|
|
81
96
|
if (!strategyNamesByStatus.enabled.includes(name)) {
|
|
82
97
|
strategyNamesByStatus.enabled.push(name);
|
|
83
98
|
}
|
|
@@ -90,5 +105,5 @@ export function getEnabledTypes({ cli, rcFile, }) {
|
|
|
90
105
|
function getStrategyByName(type) {
|
|
91
106
|
return allStrategiesByName[type];
|
|
92
107
|
}
|
|
93
|
-
}), Effect.tap(
|
|
108
|
+
}), Effect.tap(enabledTypes => Effect.logDebug(`enabled dependency types determined to be: ${JSON.stringify(enabledTypes)}`)));
|
|
94
109
|
}
|
|
@@ -2,7 +2,8 @@ import { isArrayOfStrings } from 'tightrope/guard/is-array-of-strings.js';
|
|
|
2
2
|
import { isEmptyArray } from 'tightrope/guard/is-empty-array.js';
|
|
3
3
|
import { DEFAULT_CONFIG } from '../constants.js';
|
|
4
4
|
export function getSortExports({ rcFile }) {
|
|
5
|
-
return isArrayOfStrings(rcFile.sortExports) ||
|
|
5
|
+
return isArrayOfStrings(rcFile.sortExports) ||
|
|
6
|
+
isEmptyArray(rcFile.sortExports)
|
|
6
7
|
? rcFile.sortExports
|
|
7
8
|
: DEFAULT_CONFIG.sortExports;
|
|
8
9
|
}
|