syncpack 13.0.1 → 14.0.0-alpha.2

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 (233) hide show
  1. package/README.md +0 -3
  2. package/index.js +48 -0
  3. package/package.json +16 -73
  4. package/schema.json +917 -0
  5. package/syncpack.d.ts +122 -0
  6. package/LICENSE +0 -20
  7. package/dist/bin-fix-mismatches/fix-mismatches.d.ts +0 -16
  8. package/dist/bin-fix-mismatches/fix-mismatches.js +0 -115
  9. package/dist/bin-fix-mismatches/index.d.ts +0 -2
  10. package/dist/bin-fix-mismatches/index.js +0 -33
  11. package/dist/bin-format/format.d.ts +0 -13
  12. package/dist/bin-format/format.js +0 -92
  13. package/dist/bin-format/index.d.ts +0 -2
  14. package/dist/bin-format/index.js +0 -28
  15. package/dist/bin-lint/index.d.ts +0 -2
  16. package/dist/bin-lint/index.js +0 -17
  17. package/dist/bin-lint/lint.d.ts +0 -11
  18. package/dist/bin-lint/lint.js +0 -52
  19. package/dist/bin-lint-semver-ranges/index.d.ts +0 -2
  20. package/dist/bin-lint-semver-ranges/index.js +0 -30
  21. package/dist/bin-lint-semver-ranges/lint-semver-ranges.d.ts +0 -16
  22. package/dist/bin-lint-semver-ranges/lint-semver-ranges.js +0 -92
  23. package/dist/bin-list/index.d.ts +0 -2
  24. package/dist/bin-list/index.js +0 -27
  25. package/dist/bin-list/list.d.ts +0 -14
  26. package/dist/bin-list/list.js +0 -151
  27. package/dist/bin-list-mismatches/index.d.ts +0 -2
  28. package/dist/bin-list-mismatches/index.js +0 -29
  29. package/dist/bin-list-mismatches/list-mismatches.d.ts +0 -18
  30. package/dist/bin-list-mismatches/list-mismatches.js +0 -224
  31. package/dist/bin-prompt/index.d.ts +0 -2
  32. package/dist/bin-prompt/index.js +0 -29
  33. package/dist/bin-prompt/prompt.d.ts +0 -11
  34. package/dist/bin-prompt/prompt.js +0 -95
  35. package/dist/bin-set-semver-ranges/index.d.ts +0 -2
  36. package/dist/bin-set-semver-ranges/index.js +0 -32
  37. package/dist/bin-set-semver-ranges/set-semver-ranges.d.ts +0 -11
  38. package/dist/bin-set-semver-ranges/set-semver-ranges.js +0 -61
  39. package/dist/bin-update/effects.d.ts +0 -52
  40. package/dist/bin-update/effects.js +0 -282
  41. package/dist/bin-update/index.d.ts +0 -2
  42. package/dist/bin-update/index.js +0 -24
  43. package/dist/bin-update/update.d.ts +0 -6
  44. package/dist/bin-update/update.js +0 -59
  45. package/dist/bin.d.ts +0 -2
  46. package/dist/bin.js +0 -37
  47. package/dist/config/get-custom-types.d.ts +0 -19
  48. package/dist/config/get-custom-types.js +0 -57
  49. package/dist/config/get-enabled-types.d.ts +0 -17
  50. package/dist/config/get-enabled-types.js +0 -109
  51. package/dist/config/get-filter.d.ts +0 -2
  52. package/dist/config/get-filter.js +0 -10
  53. package/dist/config/get-indent.d.ts +0 -2
  54. package/dist/config/get-indent.js +0 -9
  55. package/dist/config/get-sort-az.d.ts +0 -2
  56. package/dist/config/get-sort-az.js +0 -8
  57. package/dist/config/get-sort-exports.d.ts +0 -2
  58. package/dist/config/get-sort-exports.js +0 -9
  59. package/dist/config/get-sort-first.d.ts +0 -2
  60. package/dist/config/get-sort-first.js +0 -8
  61. package/dist/config/get-source.d.ts +0 -2
  62. package/dist/config/get-source.js +0 -8
  63. package/dist/config/tag.d.ts +0 -3
  64. package/dist/config/tag.js +0 -2
  65. package/dist/config/types.d.ts +0 -134
  66. package/dist/config/types.js +0 -1
  67. package/dist/constants.d.ts +0 -106
  68. package/dist/constants.js +0 -103
  69. package/dist/error-handlers/default-error-handlers.d.ts +0 -25
  70. package/dist/error-handlers/default-error-handlers.js +0 -80
  71. package/dist/get-context/index.d.ts +0 -23
  72. package/dist/get-context/index.js +0 -18
  73. package/dist/get-context/lib/key-by.d.ts +0 -6
  74. package/dist/get-context/lib/key-by.js +0 -12
  75. package/dist/get-instances/index.d.ts +0 -14
  76. package/dist/get-instances/index.js +0 -42
  77. package/dist/get-instances/instance.d.ts +0 -26
  78. package/dist/get-instances/instance.js +0 -35
  79. package/dist/get-package-json-files/get-file-paths.d.ts +0 -21
  80. package/dist/get-package-json-files/get-file-paths.js +0 -22
  81. package/dist/get-package-json-files/get-patterns/get-lerna-patterns.d.ts +0 -3
  82. package/dist/get-package-json-files/get-patterns/get-lerna-patterns.js +0 -12
  83. package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.d.ts +0 -3
  84. package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.js +0 -14
  85. package/dist/get-package-json-files/get-patterns/get-yarn-patterns.d.ts +0 -3
  86. package/dist/get-package-json-files/get-patterns/get-yarn-patterns.js +0 -16
  87. package/dist/get-package-json-files/get-patterns/index.d.ts +0 -8
  88. package/dist/get-package-json-files/get-patterns/index.js +0 -23
  89. package/dist/get-package-json-files/index.d.ts +0 -10
  90. package/dist/get-package-json-files/index.js +0 -8
  91. package/dist/get-package-json-files/package-json-file.d.ts +0 -54
  92. package/dist/get-package-json-files/package-json-file.js +0 -44
  93. package/dist/guards/can-add-to-group.d.ts +0 -5
  94. package/dist/guards/can-add-to-group.js +0 -58
  95. package/dist/guards/is-semver.d.ts +0 -2
  96. package/dist/guards/is-semver.js +0 -15
  97. package/dist/guards/is-valid-semver-range.d.ts +0 -3
  98. package/dist/guards/is-valid-semver-range.js +0 -14
  99. package/dist/index.d.ts +0 -2
  100. package/dist/index.js +0 -1
  101. package/dist/io/ask-for-choice.d.ts +0 -14
  102. package/dist/io/ask-for-choice.js +0 -17
  103. package/dist/io/ask-for-input.d.ts +0 -13
  104. package/dist/io/ask-for-input.js +0 -14
  105. package/dist/io/exit-if-invalid.d.ts +0 -4
  106. package/dist/io/exit-if-invalid.js +0 -9
  107. package/dist/io/glob-sync.d.ts +0 -11
  108. package/dist/io/glob-sync.js +0 -14
  109. package/dist/io/index.d.ts +0 -27
  110. package/dist/io/index.js +0 -26
  111. package/dist/io/read-config-file.d.ts +0 -7
  112. package/dist/io/read-config-file.js +0 -24
  113. package/dist/io/read-file-sync.d.ts +0 -12
  114. package/dist/io/read-file-sync.js +0 -9
  115. package/dist/io/read-json-file-sync.d.ts +0 -31
  116. package/dist/io/read-json-file-sync.js +0 -23
  117. package/dist/io/read-yaml-file-sync.d.ts +0 -12
  118. package/dist/io/read-yaml-file-sync.js +0 -9
  119. package/dist/io/to-formatted-json.d.ts +0 -9
  120. package/dist/io/to-formatted-json.js +0 -32
  121. package/dist/io/write-file-sync.d.ts +0 -12
  122. package/dist/io/write-file-sync.js +0 -10
  123. package/dist/io/write-if-changed.d.ts +0 -5
  124. package/dist/io/write-if-changed.js +0 -9
  125. package/dist/lib/format-repository-url.d.ts +0 -1
  126. package/dist/lib/format-repository-url.js +0 -40
  127. package/dist/lib/get-group-header.d.ts +0 -10
  128. package/dist/lib/get-group-header.js +0 -25
  129. package/dist/lib/get.d.ts +0 -11
  130. package/dist/lib/get.js +0 -44
  131. package/dist/lib/pad-start.d.ts +0 -1
  132. package/dist/lib/pad-start.js +0 -3
  133. package/dist/lib/ring-buffer.d.ts +0 -10
  134. package/dist/lib/ring-buffer.js +0 -20
  135. package/dist/lib/set-semver-range.d.ts +0 -3
  136. package/dist/lib/set-semver-range.js +0 -24
  137. package/dist/lib/show-help-on-error.d.ts +0 -2
  138. package/dist/lib/show-help-on-error.js +0 -32
  139. package/dist/lib/sort-by-name.d.ts +0 -5
  140. package/dist/lib/sort-by-name.js +0 -9
  141. package/dist/lib/with-logger.d.ts +0 -2
  142. package/dist/lib/with-logger.js +0 -28
  143. package/dist/option.d.ts +0 -10
  144. package/dist/option.js +0 -30
  145. package/dist/report.d.ts +0 -131
  146. package/dist/report.js +0 -129
  147. package/dist/schema.json +0 -614
  148. package/dist/semver-group/create-semver-groups.d.ts +0 -4
  149. package/dist/semver-group/create-semver-groups.js +0 -83
  150. package/dist/semver-group/disabled.d.ts +0 -26
  151. package/dist/semver-group/disabled.js +0 -28
  152. package/dist/semver-group/filtered-out.d.ts +0 -27
  153. package/dist/semver-group/filtered-out.js +0 -34
  154. package/dist/semver-group/ignored.d.ts +0 -22
  155. package/dist/semver-group/ignored.js +0 -24
  156. package/dist/semver-group/index.d.ts +0 -20
  157. package/dist/semver-group/index.js +0 -7
  158. package/dist/semver-group/with-range.d.ts +0 -22
  159. package/dist/semver-group/with-range.js +0 -45
  160. package/dist/specifier/alias.d.ts +0 -17
  161. package/dist/specifier/alias.js +0 -21
  162. package/dist/specifier/base.d.ts +0 -41
  163. package/dist/specifier/base.js +0 -54
  164. package/dist/specifier/delete.d.ts +0 -17
  165. package/dist/specifier/delete.js +0 -16
  166. package/dist/specifier/exact.d.ts +0 -20
  167. package/dist/specifier/exact.js +0 -21
  168. package/dist/specifier/file.d.ts +0 -8
  169. package/dist/specifier/file.js +0 -7
  170. package/dist/specifier/hosted-git.d.ts +0 -15
  171. package/dist/specifier/hosted-git.js +0 -24
  172. package/dist/specifier/index.d.ts +0 -28
  173. package/dist/specifier/index.js +0 -75
  174. package/dist/specifier/latest.d.ts +0 -19
  175. package/dist/specifier/latest.js +0 -20
  176. package/dist/specifier/lib/non-semver-error.d.ts +0 -11
  177. package/dist/specifier/lib/non-semver-error.js +0 -6
  178. package/dist/specifier/lib/parse-specifier.d.ts +0 -14
  179. package/dist/specifier/lib/parse-specifier.js +0 -18
  180. package/dist/specifier/lib/specific-registry-result.d.ts +0 -9
  181. package/dist/specifier/lib/specific-registry-result.js +0 -1
  182. package/dist/specifier/range.d.ts +0 -19
  183. package/dist/specifier/range.js +0 -20
  184. package/dist/specifier/tag.d.ts +0 -11
  185. package/dist/specifier/tag.js +0 -10
  186. package/dist/specifier/unsupported.d.ts +0 -7
  187. package/dist/specifier/unsupported.js +0 -7
  188. package/dist/specifier/url.d.ts +0 -8
  189. package/dist/specifier/url.js +0 -7
  190. package/dist/specifier/workspace-protocol.d.ts +0 -19
  191. package/dist/specifier/workspace-protocol.js +0 -35
  192. package/dist/strategy/lib/get-non-empty-string-prop.d.ts +0 -3
  193. package/dist/strategy/lib/get-non-empty-string-prop.js +0 -7
  194. package/dist/strategy/name-and-version-props.d.ts +0 -12
  195. package/dist/strategy/name-and-version-props.js +0 -60
  196. package/dist/strategy/named-version-string.d.ts +0 -11
  197. package/dist/strategy/named-version-string.js +0 -52
  198. package/dist/strategy/unnamed-version-string.d.ts +0 -11
  199. package/dist/strategy/unnamed-version-string.js +0 -45
  200. package/dist/strategy/versions-by-name.d.ts +0 -11
  201. package/dist/strategy/versions-by-name.js +0 -27
  202. package/dist/version-group/banned.d.ts +0 -17
  203. package/dist/version-group/banned.js +0 -26
  204. package/dist/version-group/create-version-groups.d.ts +0 -4
  205. package/dist/version-group/create-version-groups.js +0 -118
  206. package/dist/version-group/filtered-out.d.ts +0 -19
  207. package/dist/version-group/filtered-out.js +0 -30
  208. package/dist/version-group/ignored.d.ts +0 -17
  209. package/dist/version-group/ignored.js +0 -23
  210. package/dist/version-group/index.d.ts +0 -26
  211. package/dist/version-group/index.js +0 -7
  212. package/dist/version-group/lib/clean.d.ts +0 -2
  213. package/dist/version-group/lib/clean.js +0 -6
  214. package/dist/version-group/lib/delete.d.ts +0 -2
  215. package/dist/version-group/lib/delete.js +0 -1
  216. package/dist/version-group/lib/get-highest-version.d.ts +0 -6
  217. package/dist/version-group/lib/get-highest-version.js +0 -8
  218. package/dist/version-group/lib/get-lowest-version.d.ts +0 -6
  219. package/dist/version-group/lib/get-lowest-version.js +0 -8
  220. package/dist/version-group/lib/get-preferred-version.d.ts +0 -5
  221. package/dist/version-group/lib/get-preferred-version.js +0 -53
  222. package/dist/version-group/lib/get-range-score.d.ts +0 -2
  223. package/dist/version-group/lib/get-range-score.js +0 -20
  224. package/dist/version-group/lib/group-by.d.ts +0 -5
  225. package/dist/version-group/lib/group-by.js +0 -11
  226. package/dist/version-group/pinned.d.ts +0 -17
  227. package/dist/version-group/pinned.js +0 -26
  228. package/dist/version-group/same-range.d.ts +0 -19
  229. package/dist/version-group/same-range.js +0 -96
  230. package/dist/version-group/snapped-to.d.ts +0 -17
  231. package/dist/version-group/snapped-to.js +0 -71
  232. package/dist/version-group/standard.d.ts +0 -18
  233. package/dist/version-group/standard.js +0 -119
@@ -1,95 +0,0 @@
1
- import chalk from 'chalk-template';
2
- import { Context, Effect, flow, pipe } from 'effect';
3
- import { uniq } from 'tightrope/array/uniq.js';
4
- import { isString } from 'tightrope/guard/is-string.js';
5
- import { logOtherCommands } from '../bin-list/list.js';
6
- import { CliConfigTag } from '../config/tag.js';
7
- import { ICON } from '../constants.js';
8
- import { defaultErrorHandlers } from '../error-handlers/default-error-handlers.js';
9
- import { getContext } from '../get-context/index.js';
10
- import { getInstances } from '../get-instances/index.js';
11
- import { askForChoice } from '../io/ask-for-choice.js';
12
- import { askForInput } from '../io/ask-for-input.js';
13
- import { exitIfInvalid } from '../io/exit-if-invalid.js';
14
- import { IoTag } from '../io/index.js';
15
- import { writeIfChanged } from '../io/write-if-changed.js';
16
- import { getVersionGroupHeader } from '../lib/get-group-header.js';
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* ($) {
20
- const { versionGroups } = yield* $(getInstances(ctx, io, errorHandlers));
21
- let unfixableCount = 0;
22
- let index = 0;
23
- for (const group of versionGroups) {
24
- const unfixable = [];
25
- for (const groupReport of yield* $(group.inspectAll())) {
26
- for (const report of groupReport.reports) {
27
- if (isUnfixable(report)) {
28
- unfixable.push(report);
29
- }
30
- }
31
- if (unfixable.length > 0) {
32
- unfixableCount += unfixable.length;
33
- Effect.logInfo(getVersionGroupHeader({ group, index }));
34
- yield* $(askForNextVersion(groupReport, unfixable));
35
- }
36
- }
37
- index++;
38
- }
39
- if (unfixableCount) {
40
- yield* $(writeIfChanged(ctx));
41
- }
42
- else {
43
- const msg = chalk `{green ${ICON.tick}} no issues which syncpack cannot fix automatically`;
44
- yield* $(Effect.logInfo(msg));
45
- yield* $(logOtherCommands());
46
- }
47
- return ctx;
48
- }), Effect.catchTags({
49
- WriteFileError: flow(errorHandlers.WriteFileError, Effect.map(() => {
50
- ctx.isInvalid = true;
51
- return ctx;
52
- })),
53
- }), Effect.flatMap(exitIfInvalid))), Effect.provide(pipe(Context.empty(), Context.add(CliConfigTag, cli), Context.add(IoTag, io))), withLogger);
54
- }
55
- function isUnfixable(report) {
56
- return (report._tag === 'MissingLocalVersion' ||
57
- report._tag === 'MissingSnappedToMismatch' ||
58
- report._tag === 'SameRangeMismatch' ||
59
- report._tag === 'UnsupportedMismatch');
60
- }
61
- function askForNextVersion(groupReport, unfixable) {
62
- return pipe(Effect.gen(function* ($) {
63
- const choices = uniq(groupReport.reports.map(report => report._tagGroup === 'Fixable'
64
- ? report.fixable.raw
65
- : report._tagGroup === 'Unfixable'
66
- ? report.unfixable.rawSpecifier
67
- : report._tagGroup === 'Valid'
68
- ? report.specifier.raw
69
- : null)).filter(isString);
70
- const other = chalk `{dim Other}`;
71
- const skip = chalk `{dim Skip}`;
72
- const quit = chalk `{dim Quit}`;
73
- // Ask user to choose a version to align on
74
- const choice = yield* $(askForChoice({
75
- message: groupReport.name,
76
- choices: [...choices, other, skip, quit],
77
- }));
78
- if (choice === skip) {
79
- return;
80
- }
81
- // @TODO: Learn https://www.effect.website/docs/data-types/exit
82
- if (choice === quit) {
83
- return process.exit(0);
84
- }
85
- const nextVersion = choice === other
86
- ? yield* $(askForInput({
87
- message: chalk `${groupReport.name} {dim Enter a replacement version}`,
88
- }))
89
- : choice;
90
- yield* $(pipe(unfixable, Effect.forEach(report => report.unfixable.write(nextVersion))));
91
- }), Effect.catchTags({
92
- AskForChoiceError: Effect.logDebug,
93
- AskForInputError: Effect.logDebug,
94
- }));
95
- }
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env node
2
- import chalk from 'chalk-template';
3
- import { program } from 'commander';
4
- import { Effect } from 'effect';
5
- import { io } from '../io/index.js';
6
- import { showHelpOnError } from '../lib/show-help-on-error.js';
7
- import { option } from '../option.js';
8
- import { setSemverRanges } from './set-semver-ranges.js';
9
- program.description(chalk `
10
- Ensure dependency versions within {yellow dependencies}, {yellow devDependencies},
11
- {yellow peerDependencies}, {yellow overrides}, and {yellow resolutions} follow a consistent format.`.replace(/^\n/, ''));
12
- program.on('--help', () => { });
13
- showHelpOnError(program);
14
- program
15
- .option(...option.source)
16
- .option(...option.filter)
17
- .option(...option.config)
18
- .option(...option.specs)
19
- .option(...option.types)
20
- .option(...option.indent)
21
- .parse(process.argv);
22
- Effect.runPromise(setSemverRanges({
23
- io,
24
- cli: {
25
- configPath: program.opts().config,
26
- filter: program.opts().filter,
27
- indent: program.opts().indent,
28
- source: program.opts().source,
29
- specs: program.opts().specs,
30
- types: program.opts().types,
31
- },
32
- }));
@@ -1,11 +0,0 @@
1
- import { Effect } from 'effect';
2
- import type { CliConfig } from '../config/types.js';
3
- import type { ErrorHandlers } from '../error-handlers/default-error-handlers.js';
4
- import type { Io } from '../io/index.js';
5
- interface Input {
6
- io: Io;
7
- cli: Partial<CliConfig>;
8
- errorHandlers?: ErrorHandlers;
9
- }
10
- export declare function setSemverRanges({ io, cli, errorHandlers, }: Input): Effect.Effect<unknown, never, never>;
11
- export {};
@@ -1,61 +0,0 @@
1
- import { Context, Effect, flow, pipe } from 'effect';
2
- import { isNonEmptyArray } from 'tightrope/guard/is-non-empty-array.js';
3
- import { fixMismatch, logAlreadyValidSize, logFixedSize, logUnfixableSize, } from '../bin-fix-mismatches/fix-mismatches.js';
4
- import { logSemverGroupsDisabledWarning } from '../bin-lint-semver-ranges/lint-semver-ranges.js';
5
- import { logUnsupportedMismatch } from '../bin-list-mismatches/list-mismatches.js';
6
- import { CliConfigTag } from '../config/tag.js';
7
- import { defaultErrorHandlers } from '../error-handlers/default-error-handlers.js';
8
- import { getContext } from '../get-context/index.js';
9
- import { getInstances } from '../get-instances/index.js';
10
- import { exitIfInvalid } from '../io/exit-if-invalid.js';
11
- import { IoTag } from '../io/index.js';
12
- import { writeIfChanged } from '../io/write-if-changed.js';
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* ($) {
16
- // no semver groups have been configured, they are disabled by default
17
- if (!isNonEmptyArray(ctx.config.rcFile.semverGroups)) {
18
- ctx.isInvalid = true;
19
- yield* $(logSemverGroupsDisabledWarning());
20
- return ctx;
21
- }
22
- const { semverGroups } = yield* $(getInstances(ctx, io, errorHandlers));
23
- let fixedCount = 0;
24
- let unfixableCount = 0;
25
- let validCount = 0;
26
- for (const group of semverGroups) {
27
- if (group._tag === 'WithRange') {
28
- for (const instance of group.instances) {
29
- const report = yield* $(group.inspect(instance));
30
- const _tag = report._tag;
31
- if (_tag === 'SemverRangeMismatch') {
32
- yield* $(fixMismatch(report));
33
- fixedCount++;
34
- }
35
- else if (_tag === 'UnsupportedMismatch') {
36
- yield* $(logUnsupportedMismatch(report));
37
- unfixableCount++;
38
- }
39
- else {
40
- validCount++;
41
- }
42
- }
43
- }
44
- }
45
- if (validCount) {
46
- yield* $(logAlreadyValidSize(validCount));
47
- }
48
- if (fixedCount) {
49
- yield* $(logFixedSize(fixedCount));
50
- }
51
- if (unfixableCount) {
52
- yield* $(logUnfixableSize(unfixableCount));
53
- }
54
- return ctx;
55
- }), Effect.flatMap(writeIfChanged), Effect.catchTags({
56
- WriteFileError: flow(errorHandlers.WriteFileError, Effect.map(() => {
57
- ctx.isInvalid = true;
58
- return ctx;
59
- })),
60
- }), Effect.flatMap(exitIfInvalid))), Effect.provide(pipe(Context.empty(), Context.add(CliConfigTag, cli), Context.add(IoTag, io))), withLogger);
61
- }
@@ -1,52 +0,0 @@
1
- import { Effect } from 'effect';
2
- import type { Instance } from '../get-instances/instance.js';
3
- declare const Releases_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => Readonly<A> & {
4
- readonly _tag: "Releases";
5
- };
6
- /** full release history from the npm registry for a given package */
7
- declare class Releases extends Releases_base<{
8
- instance: Instance;
9
- versions: {
10
- all: string[];
11
- latest: string;
12
- };
13
- repoUrl: string | undefined;
14
- }> {
15
- }
16
- declare const PromptCancelled_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => Readonly<A> & {
17
- readonly _tag: "PromptCancelled";
18
- };
19
- declare class PromptCancelled extends PromptCancelled_base<{
20
- name: string;
21
- }> {
22
- }
23
- declare const HttpError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => Readonly<A> & {
24
- readonly _tag: "HttpError";
25
- };
26
- declare class HttpError extends HttpError_base<{
27
- error: string;
28
- }> {
29
- }
30
- declare const NpmRegistryError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => Readonly<A> & {
31
- readonly _tag: "NpmRegistryError";
32
- };
33
- declare class NpmRegistryError extends NpmRegistryError_base<{
34
- error: string;
35
- }> {
36
- }
37
- export declare const updateEffects: {
38
- onFetchAllStart(): Effect.Effect<void, never, never>;
39
- onFetchStart(instance: Instance, totalCount: number): Effect.Effect<void, never, never>;
40
- onFetchEnd(instance: Instance, versions?: Releases["versions"]): Effect.Effect<void, never, never>;
41
- /** After checking the registry, store this instance known to be up to date */
42
- onUpToDate(instance: Instance): Effect.Effect<void, never, never>;
43
- /** After checking the registry, store this instance known to have newer versions available */
44
- onOutdated(instance: Instance, latest: string): Effect.Effect<void, never, never>;
45
- /** As the last request completes, remove the progress information */
46
- onFetchAllEnd(): Effect.Effect<void, never, never>;
47
- /** Fetch available versions for a given package from the npm registry */
48
- fetchLatestVersions(instance: Instance): Effect.Effect<Releases, HttpError | NpmRegistryError>;
49
- /** Given responses from npm, ask the user which they want */
50
- promptForUpdates(outdated: Releases[]): Effect.Effect<void, PromptCancelled>;
51
- };
52
- export {};
@@ -1,282 +0,0 @@
1
- import https from 'node:https';
2
- import { EOL } from 'node:os';
3
- import * as Schema from '@effect/schema/Schema';
4
- import chalk from 'chalk-template';
5
- import { Data, Effect, identity, pipe } from 'effect';
6
- import ora from 'ora';
7
- import prompts from 'prompts';
8
- import { diff } from 'semver';
9
- import gtr from 'semver/ranges/gtr.js';
10
- import { isArray } from 'tightrope/guard/is-array.js';
11
- import { isEmptyObject } from 'tightrope/guard/is-empty-object.js';
12
- import { ICON } from '../constants.js';
13
- import { formatRepositoryUrl } from '../lib/format-repository-url.js';
14
- import { RingBuffer } from '../lib/ring-buffer.js';
15
- import { setSemverRange } from '../lib/set-semver-range.js';
16
- import { Specifier } from '../specifier/index.js';
17
- /** full release history from the npm registry for a given package */
18
- class Releases extends Data.TaggedClass('Releases') {
19
- }
20
- // https://github.com/terkelg/prompts?tab=readme-ov-file#prompts
21
- class PromptCancelled extends Data.TaggedClass('PromptCancelled') {
22
- }
23
- class HttpError extends Data.TaggedClass('HttpError') {
24
- }
25
- class NpmRegistryError extends Data.TaggedClass('NpmRegistryError') {
26
- }
27
- /** the API client for the terminal spinner */
28
- let spinner = null;
29
- /** how many HTTP requests have been sent */
30
- let fetchedCount = 0;
31
- /** how many instances have updates available */
32
- let outdatedCount = 0;
33
- /** names of instances currently being fetched from npm */
34
- const inFlight = new Set();
35
- /** names of instances most recently finished being fetched from npm */
36
- const mostRecent = new RingBuffer(5);
37
- /** page size when prompting */
38
- const optionsPerPage = 50;
39
- /** instance names in `inFlight` are formatted for display */
40
- function format(instance) {
41
- return chalk `{gray ${instance.name}}`;
42
- }
43
- /** we need to remove colours when sorting loading status output */
44
- function stripAnsi(str) {
45
- // eslint-disable-next-line no-control-regex
46
- const ansiChars = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
47
- return str.replace(ansiChars, '');
48
- }
49
- export const updateEffects = {
50
- onFetchAllStart() {
51
- if (!spinner) {
52
- spinner = ora().start();
53
- }
54
- fetchedCount = 0;
55
- return Effect.void;
56
- },
57
- onFetchStart(instance, totalCount) {
58
- inFlight.add(format(instance));
59
- fetchedCount++;
60
- if (spinner) {
61
- const indent = `${EOL} `;
62
- const progress = new Set([
63
- ...mostRecent.filter(Boolean),
64
- ...inFlight.values(),
65
- ]);
66
- const sortedProgress = Array.from(progress).sort((a, b) => stripAnsi(a).localeCompare(stripAnsi(b)));
67
- const suffixText = sortedProgress.join(indent);
68
- spinner.text = chalk `${outdatedCount} updates found in ${fetchedCount}/${totalCount} dependencies${indent}${suffixText}`;
69
- }
70
- return Effect.void;
71
- },
72
- onFetchEnd(instance, versions) {
73
- inFlight.delete(format(instance));
74
- const latest = versions?.latest;
75
- if (latest) {
76
- if (gtr(latest, String(instance.rawSpecifier.raw), true)) {
77
- outdatedCount++;
78
- mostRecent.push(chalk `${instance.name} {gray {red ${String(instance.rawSpecifier.raw)}} ${ICON.rightArrow}} {green ${latest}}`);
79
- }
80
- else {
81
- mostRecent.push(chalk `{green ${instance.name}}`);
82
- }
83
- }
84
- return Effect.void;
85
- },
86
- /** After checking the registry, store this instance known to be up to date */
87
- onUpToDate(instance) {
88
- mostRecent.push(chalk `{green ${instance.name}}`);
89
- return Effect.void;
90
- },
91
- /** After checking the registry, store this instance known to have newer versions available */
92
- onOutdated(instance, latest) {
93
- outdatedCount++;
94
- mostRecent.push(chalk `${instance.name} {gray {red ${String(instance.rawSpecifier.raw)}} ${ICON.rightArrow}} {green ${latest}}`);
95
- return Effect.void;
96
- },
97
- /** As the last request completes, remove the progress information */
98
- onFetchAllEnd() {
99
- if (spinner) {
100
- spinner.stop();
101
- }
102
- spinner = null;
103
- fetchedCount = 0;
104
- return Effect.void;
105
- },
106
- /** Fetch available versions for a given package from the npm registry */
107
- fetchLatestVersions(instance) {
108
- return pipe(fetchJson(`https://registry.npmjs.org/${instance.name}`),
109
- // parse and validate the specific data we expect
110
- Effect.flatMap(Schema.decodeUnknownEither(Schema.Struct({
111
- 'dist-tags': Schema.Struct({ latest: 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) }))),
115
- }))),
116
- // transform it into something more appropriate
117
- Effect.map(struct => {
118
- const rawRepoUrl = typeof struct.repository === 'object'
119
- ? struct.repository.url
120
- : struct.repository;
121
- return new Releases({
122
- instance,
123
- versions: {
124
- all: Object.keys(struct.time).filter(key => key !== 'modified' && key !== 'created'),
125
- latest: struct['dist-tags'].latest,
126
- },
127
- repoUrl: formatRepositoryUrl(rawRepoUrl),
128
- });
129
- }),
130
- // hide ParseErrors and just treat them as another kind of NpmRegistryError
131
- Effect.catchTags({
132
- ParseError: () => Effect.fail(new NpmRegistryError({
133
- error: `Invalid response for ${instance.name}`,
134
- })),
135
- }));
136
- },
137
- /** Given responses from npm, ask the user which they want */
138
- promptForUpdates(outdated) {
139
- return pipe(Effect.Do, Effect.bind('releasesByType', () => groupByReleaseType(outdated)),
140
- // Create choices to ask if they want major, minor, patch etc
141
- Effect.bind('releaseTypeQuestions', ({ releasesByType }) => Effect.succeed(Object.keys(releasesByType)
142
- .filter(type => releasesByType[type].length > 0)
143
- .map(type => ({
144
- title: chalk `${releasesByType[type].length} ${type}`,
145
- selected: true,
146
- value: type,
147
- })))),
148
- // Ask which release types (major, minor, patch etc) they want
149
- Effect.bind('releaseTypeAnswers', ({ releaseTypeQuestions }) => releaseTypeQuestions.length > 0
150
- ? pipe(Effect.tryPromise({
151
- try: () => prompts({
152
- name: 'releaseTypeAnswers',
153
- type: 'multiselect',
154
- instructions: true,
155
- message: `${outdated.length} updates are available`,
156
- choices: releaseTypeQuestions,
157
- }).then(res => res?.releaseTypeAnswers || []),
158
- catch: identity,
159
- }), Effect.catchAll(() => pipe(Effect.logError('Error when prompting for releaseTypeAnswers'), Effect.map(() => []))))
160
- : Effect.succeed([])),
161
- // For each chosen release type, list the available updates to choose from
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)),
163
- /** Apply every update to the package.json files */
164
- Effect.flatMap(doState => pipe([
165
- ...doState.prepatchAnswers,
166
- ...doState.patchAnswers,
167
- ...doState.preminorAnswers,
168
- ...doState.minorAnswers,
169
- ...doState.premajorAnswers,
170
- ...doState.majorAnswers,
171
- ...doState.prereleaseAnswers,
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))));
173
- },
174
- };
175
- function promptForReleaseType(releaseType, doState) {
176
- const { releasesByType, releaseTypeAnswers } = doState;
177
- const prop = `${releaseType}Answers`;
178
- const releases = releasesByType[releaseType];
179
- return releaseTypeAnswers.includes(releaseType)
180
- ? pipe(Effect.tryPromise({
181
- try: () => prompts({
182
- name: prop,
183
- type: 'multiselect',
184
- instructions: false,
185
- // @ts-expect-error optionsPerPage *does* exist https://github.com/terkelg/prompts#options-7
186
- optionsPerPage,
187
- message: `${releases.length} ${releaseType} updates`,
188
- choices: releases.map(updateable => {
189
- const spacingValue = 50 -
190
- updateable.instance.name.length -
191
- String(updateable.instance.rawSpecifier).length -
192
- updateable.versions.latest.length;
193
- const spacing = Array.from({ length: spacingValue })
194
- .fill(' ')
195
- .join('');
196
- const repoUrl = updateable.repoUrl
197
- ? chalk `${spacing} {white - ${updateable.repoUrl}}`
198
- : '';
199
- return {
200
- title: chalk `${updateable.instance.name} {gray ${String(updateable.instance.rawSpecifier.raw)} ${ICON.rightArrow}} {green ${updateable.versions.latest}} ${repoUrl}`,
201
- selected: true,
202
- value: updateable,
203
- };
204
- }),
205
- }),
206
- catch: identity,
207
- }),
208
- // Paper over errors in terkelg/prompts for now
209
- Effect.catchAll(() => pipe(Effect.logError(`terkelg/prompts errored while prompting for ${prop}`), Effect.map(() => ({ [prop]: [] })))),
210
- // In terkelg/prompts, an empty object means that the user cancelled via
211
- // ctrl+c or the escape key etc. Handle this case so we can skip any
212
- // remaining steps.
213
- Effect.flatMap(res => isEmptyObject(res)
214
- ? Effect.fail(new PromptCancelled({ name: releaseType }))
215
- : Effect.succeed(isArray(res?.[prop]) ? res?.[prop] : [])))
216
- : Effect.succeed([]);
217
- }
218
- function groupByReleaseType(releases) {
219
- return Effect.succeed(releases.reduce((releasesByType, release) => {
220
- const previous = setSemverRange('', String(release.instance.rawSpecifier.raw));
221
- const latest = release.versions.latest;
222
- try {
223
- const type = diff(previous, latest);
224
- if (type && releasesByType[type]) {
225
- releasesByType[type].push(release);
226
- }
227
- }
228
- catch {
229
- //
230
- }
231
- return releasesByType;
232
- }, {
233
- prepatch: [],
234
- patch: [],
235
- preminor: [],
236
- minor: [],
237
- premajor: [],
238
- major: [],
239
- prerelease: [],
240
- }));
241
- }
242
- // @TODO: add a cache with a short TTL on disk in $TMPDIR
243
- function fetchJson(url) {
244
- return pipe(Effect.async(resume => {
245
- // setTimeout(
246
- // () => {
247
- // resume(
248
- // Effect.succeed(
249
- // JSON.stringify({
250
- // 'dist-tags': { latest: '3.1.1' },
251
- // 'time': {
252
- // '0.3.1': new Date().toJSON(),
253
- // },
254
- // }),
255
- // ),
256
- // );
257
- // },
258
- // Math.floor(Math.random() * 500) + 1,
259
- // );
260
- https
261
- .get(url, res => {
262
- let body = '';
263
- res.setEncoding('utf8');
264
- res.on('data', chunk => {
265
- body = `${body}${chunk}`;
266
- });
267
- res.on('end', () => {
268
- resume(Effect.succeed(body));
269
- });
270
- })
271
- .on('error', err => {
272
- resume(Effect.fail(new HttpError({
273
- error: `Node https threw on ${url}: ${String(err)}`,
274
- })));
275
- });
276
- }), Effect.flatMap(body => Effect.try({
277
- try: () => JSON.parse(body),
278
- catch: () => new NpmRegistryError({
279
- error: `JSON.parse threw on response from ${url}`,
280
- }),
281
- })));
282
- }
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env node
2
- import { program } from 'commander';
3
- import { Effect } from 'effect';
4
- import { io } from '../io/index.js';
5
- import { showHelpOnError } from '../lib/show-help-on-error.js';
6
- import { option } from '../option.js';
7
- import { update } from './update.js';
8
- program.description(' Update to the latest versions on the npm registry.');
9
- program.on('--help', () => { });
10
- showHelpOnError(program);
11
- program
12
- .option(...option.source)
13
- .option(...option.filter)
14
- .option(...option.config)
15
- .option(...option.specs)
16
- .option(...option.types)
17
- .parse(process.argv);
18
- Effect.runPromise(update(io, {
19
- configPath: program.opts().config,
20
- filter: program.opts().filter,
21
- source: program.opts().source,
22
- specs: program.opts().specs,
23
- types: program.opts().types,
24
- }));
@@ -1,6 +0,0 @@
1
- import { Effect } from 'effect';
2
- import type { CliConfig } from '../config/types.js';
3
- import type { ErrorHandlers } from '../error-handlers/default-error-handlers.js';
4
- import type { Io } from '../io/index.js';
5
- import { updateEffects } from './effects.js';
6
- export declare function update(io: Io, cli: Partial<CliConfig>, effects?: typeof updateEffects, errorHandlers?: ErrorHandlers): Effect.Effect<unknown, never, never>;
@@ -1,59 +0,0 @@
1
- import chalk from 'chalk-template';
2
- import { Context, Effect, flow, pipe } from 'effect';
3
- import { gtr } from 'semver';
4
- import { CliConfigTag } from '../config/tag.js';
5
- import { ICON } from '../constants.js';
6
- import { defaultErrorHandlers } from '../error-handlers/default-error-handlers.js';
7
- import { getContext } from '../get-context/index.js';
8
- import { getInstances } from '../get-instances/index.js';
9
- import { exitIfInvalid } from '../io/exit-if-invalid.js';
10
- import { IoTag } from '../io/index.js';
11
- import { writeIfChanged } from '../io/write-if-changed.js';
12
- import { withLogger } from '../lib/with-logger.js';
13
- import { Specifier } from '../specifier/index.js';
14
- import { updateEffects } from './effects.js';
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 => {
17
- const isVisitedByName = {};
18
- const updateable = [];
19
- instances.forEach(instance => {
20
- if (!isVisitedByName[instance.name] &&
21
- (instance.versionGroup._tag === 'SameRange' ||
22
- instance.versionGroup._tag === 'Standard')) {
23
- const specifier = Specifier.create(instance, instance.rawSpecifier.raw);
24
- if (specifier._tag === 'Range' || specifier._tag === 'Exact') {
25
- isVisitedByName[instance.name] = true;
26
- updateable.push(instance);
27
- }
28
- }
29
- });
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({
32
- onFailure: () => updateEffects.onFetchEnd(instance),
33
- onSuccess: ({ versions }) => updateEffects.onFetchEnd(instance, versions),
34
- }),
35
- // move up to date dependencies to error channel
36
- Effect.flatMap(updateable => gtr(updateable.versions.latest, String(instance.rawSpecifier.raw))
37
- ? pipe(updateEffects.onOutdated(instance, updateable.versions.latest), Effect.map(() => updateable))
38
- : pipe(updateEffects.onUpToDate(instance), Effect.flatMap(() => Effect.fail(updateable)))),
39
- // log error but don't catch it
40
- Effect.tapErrorTag('HttpError', ({ error }) => Effect.logError(chalk `{red ${ICON.cross} ${error}}`)),
41
- // log error but don't catch it
42
- Effect.tapErrorTag('NpmRegistryError', ({ error }) => Effect.logError(chalk `{red ${ICON.cross} ${error}}`))), { concurrency: 10 }),
43
- // discard errors and up to date dependencies
44
- Effect.flatMap(([_, outOfDate]) => Effect.succeed(outOfDate)))),
45
- // always remove the spinner when we're done
46
- Effect.tapBoth({
47
- onFailure: updateEffects.onFetchAllEnd,
48
- onSuccess: updateEffects.onFetchAllEnd,
49
- }),
50
- // ask the user which updates they want
51
- Effect.flatMap(updateEffects.promptForUpdates),
52
- // if we think the user cancelled, say so
53
- Effect.catchTag('PromptCancelled', () => Effect.logInfo(chalk `{red ${ICON.panic}} aborting after {blue syncpack update} was cancelled`)))), Effect.flatMap(({ ctx }) => pipe(writeIfChanged(ctx), Effect.catchTags({
54
- WriteFileError: flow(errorHandlers.WriteFileError, Effect.map(() => {
55
- ctx.isInvalid = true;
56
- return ctx;
57
- })),
58
- }))), Effect.flatMap(exitIfInvalid), Effect.withConcurrency(10), Effect.provide(pipe(Context.empty(), Context.add(CliConfigTag, cli), Context.add(IoTag, io))), withLogger);
59
- }
package/dist/bin.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};