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.
- package/README.md +1 -2
- 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 +10 -7
- 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.d.ts +1 -1
- package/dist/bin-update/effects.js +46 -31
- 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/config/types.d.ts +2 -0
- 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 +19 -13
- 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 -2
- 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 +6 -6
- package/dist/option.js +4 -1
- package/dist/schema.json +3 -0
- 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/delete.d.ts +2 -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 +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(
|
|
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
|
},
|
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(() => {
|
|
@@ -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[
|
|
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([
|
|
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
|
-
|
|
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,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(
|
|
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
|
: '';
|
|
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(
|
|
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
|
}));
|