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.
Files changed (98) hide show
  1. package/dist/bin-fix-mismatches/fix-mismatches.d.ts +2 -2
  2. package/dist/bin-fix-mismatches/fix-mismatches.js +13 -8
  3. package/dist/bin-fix-mismatches/index.js +1 -32
  4. package/dist/bin-format/format.d.ts +2 -2
  5. package/dist/bin-format/format.js +7 -5
  6. package/dist/bin-format/index.js +1 -26
  7. package/dist/bin-lint/index.js +1 -22
  8. package/dist/bin-lint/lint.d.ts +1 -1
  9. package/dist/bin-lint/lint.js +23 -23
  10. package/dist/bin-lint-semver-ranges/index.js +1 -36
  11. package/dist/bin-lint-semver-ranges/lint-semver-ranges.d.ts +2 -2
  12. package/dist/bin-lint-semver-ranges/lint-semver-ranges.js +5 -4
  13. package/dist/bin-list/index.js +1 -31
  14. package/dist/bin-list/list.d.ts +1 -1
  15. package/dist/bin-list/list.js +9 -5
  16. package/dist/bin-list-mismatches/index.js +1 -31
  17. package/dist/bin-list-mismatches/list-mismatches.d.ts +2 -2
  18. package/dist/bin-list-mismatches/list-mismatches.js +15 -9
  19. package/dist/bin-prompt/index.js +1 -33
  20. package/dist/bin-prompt/prompt.d.ts +2 -2
  21. package/dist/bin-prompt/prompt.js +13 -11
  22. package/dist/bin-set-semver-ranges/index.js +1 -38
  23. package/dist/bin-set-semver-ranges/set-semver-ranges.d.ts +2 -2
  24. package/dist/bin-set-semver-ranges/set-semver-ranges.js +8 -5
  25. package/dist/bin-update/effects.js +43 -28
  26. package/dist/bin-update/index.js +1 -31
  27. package/dist/bin-update/update.d.ts +1 -1
  28. package/dist/bin-update/update.js +4 -4
  29. package/dist/bin.js +3 -3
  30. package/dist/config/get-custom-types.js +20 -13
  31. package/dist/config/get-enabled-types.js +27 -12
  32. package/dist/config/get-sort-exports.js +2 -1
  33. package/dist/error-handlers/default-error-handlers.js +2 -2
  34. package/dist/get-context/index.d.ts +2 -2
  35. package/dist/get-context/index.js +1 -1
  36. package/dist/get-instances/index.js +6 -6
  37. package/dist/get-instances/instance.js +6 -2
  38. package/dist/get-package-json-files/get-patterns/get-lerna-patterns.js +4 -2
  39. package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.d.ts +1 -1
  40. package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.js +2 -2
  41. package/dist/get-package-json-files/get-patterns/get-yarn-patterns.js +2 -2
  42. package/dist/get-package-json-files/get-patterns/index.js +3 -3
  43. package/dist/get-package-json-files/index.js +1 -1
  44. package/dist/get-package-json-files/package-json-file.d.ts +7 -0
  45. package/dist/get-package-json-files/package-json-file.js +18 -3
  46. package/dist/guards/can-add-to-group.js +15 -9
  47. package/dist/guards/is-semver.js +3 -1
  48. package/dist/io/ask-for-choice.js +3 -3
  49. package/dist/io/ask-for-input.js +2 -2
  50. package/dist/io/exit-if-invalid.js +1 -1
  51. package/dist/io/glob-sync.js +1 -1
  52. package/dist/io/index.d.ts +1 -1
  53. package/dist/io/index.js +1 -1
  54. package/dist/io/read-config-file.js +5 -3
  55. package/dist/io/read-file-sync.js +1 -1
  56. package/dist/io/read-json-file-sync.d.ts +2 -1
  57. package/dist/io/read-json-file-sync.js +9 -5
  58. package/dist/io/read-yaml-file-sync.js +1 -1
  59. package/dist/io/{to-json.d.ts → to-formatted-json.d.ts} +1 -1
  60. package/dist/io/{to-json.js → to-formatted-json.js} +11 -8
  61. package/dist/io/write-file-sync.js +2 -2
  62. package/dist/io/write-if-changed.js +3 -4
  63. package/dist/lib/format-repository-url.js +8 -5
  64. package/dist/lib/get-group-header.js +3 -1
  65. package/dist/lib/get.js +20 -12
  66. package/dist/lib/ring-buffer.js +1 -1
  67. package/dist/lib/set-semver-range.js +8 -4
  68. package/dist/lib/with-logger.js +1 -2
  69. package/dist/option.js +4 -1
  70. package/dist/semver-group/create-semver-groups.js +7 -3
  71. package/dist/semver-group/disabled.js +1 -1
  72. package/dist/semver-group/filtered-out.js +1 -1
  73. package/dist/semver-group/ignored.js +1 -1
  74. package/dist/semver-group/with-range.js +3 -3
  75. package/dist/specifier/alias.js +3 -2
  76. package/dist/specifier/exact.js +1 -1
  77. package/dist/specifier/hosted-git.js +5 -3
  78. package/dist/specifier/index.js +27 -15
  79. package/dist/specifier/latest.js +1 -1
  80. package/dist/specifier/lib/parse-specifier.js +3 -1
  81. package/dist/specifier/range.js +1 -1
  82. package/dist/specifier/workspace-protocol.js +2 -1
  83. package/dist/strategy/lib/get-non-empty-string-prop.js +1 -1
  84. package/dist/strategy/name-and-version-props.js +7 -7
  85. package/dist/strategy/named-version-string.js +11 -8
  86. package/dist/strategy/unnamed-version-string.js +6 -6
  87. package/dist/strategy/versions-by-name.js +4 -2
  88. package/dist/version-group/banned.js +1 -1
  89. package/dist/version-group/create-version-groups.js +11 -7
  90. package/dist/version-group/filtered-out.js +1 -1
  91. package/dist/version-group/ignored.js +1 -1
  92. package/dist/version-group/lib/get-preferred-version.js +22 -13
  93. package/dist/version-group/lib/get-range-score.js +3 -1
  94. package/dist/version-group/pinned.js +2 -2
  95. package/dist/version-group/same-range.js +6 -6
  96. package/dist/version-group/snapped-to.js +7 -5
  97. package/dist/version-group/standard.js +19 -16
  98. package/package.json +22 -25
package/dist/lib/get.js CHANGED
@@ -3,34 +3,42 @@ import { isFunction } from 'tightrope/guard/is-function.js';
3
3
  import { isPrimitive } from 'tightrope/guard/is-primitive.js';
4
4
  import { isReadable } from 'tightrope/guard/is-readable.js';
5
5
  export function get(origin, ...props) {
6
- return isReadable(origin) ? props.reduce(getChild, origin) : ERR_UNREADABLE_ORIGIN(props, origin);
6
+ return isReadable(origin)
7
+ ? props.reduce(getChild, origin)
8
+ : errUnreadableOrigin(props, origin);
7
9
  }
8
10
  /** Used internally by get to retrieve a single child property from a parent object. */
9
11
  function getChild(parent, prop) {
10
12
  // quit if any ancestor was already not found
11
- if (Either.isEither(parent) && Either.isLeft(parent))
13
+ if (Either.isEither(parent) && Either.isLeft(parent)) {
12
14
  return parent;
15
+ }
13
16
  // ensure we have a plain value and not an Ok
14
- const value = Either.isEither(parent) && Either.isRight(parent) ? Either.getOrThrow(parent) : parent;
17
+ const value = Either.isEither(parent) && Either.isRight(parent)
18
+ ? Either.getOrThrow(parent)
19
+ : parent;
15
20
  // quit if we can't read properties of value (eg value.likeThis)
16
- if (!isReadable(value))
17
- return ERR_UNREADABLE_CHILD(prop, value);
21
+ if (!isReadable(value)) {
22
+ return errUnreadableChild(prop, value);
23
+ }
18
24
  // quit if value is object/array/function etc but the child is not found
19
- if (!isPrimitive(value) && prop in value === false)
20
- return ERR_NOT_FOUND(prop, value);
25
+ if (!isPrimitive(value) && prop in value === false) {
26
+ return errNotFound(prop, value);
27
+ }
21
28
  // quit if eg true.toFixed, 12.toUpperCase
22
- if (isPrimitive(value) && value[prop] === undefined)
23
- return ERR_NOT_FOUND(prop, value);
29
+ if (isPrimitive(value) && value[prop] === undefined) {
30
+ return errNotFound(prop, value);
31
+ }
24
32
  // the value is present, return it
25
33
  const child = value[prop];
26
34
  return Either.right(isFunction(child) ? child.bind(value) : child);
27
35
  }
28
- function ERR_UNREADABLE_CHILD(child, value) {
36
+ function errUnreadableChild(child, value) {
29
37
  return Either.left(new Error(`Cannot read "${child}" from unreadable value: ${value}`));
30
38
  }
31
- function ERR_NOT_FOUND(child, value) {
39
+ function errNotFound(child, value) {
32
40
  return Either.left(new Error(`Property "${child}" not found on value: ${value}`));
33
41
  }
34
- function ERR_UNREADABLE_ORIGIN(props, origin) {
42
+ function errUnreadableOrigin(props, origin) {
35
43
  return Either.left(new Error(`Cannot read "${props.join('.')}" from unreadable value: ${origin}`));
36
44
  }
@@ -11,7 +11,7 @@ export class RingBuffer extends Array {
11
11
  this.fixedLength = fixedLength;
12
12
  }
13
13
  push(...values) {
14
- values.forEach((value) => {
14
+ values.forEach(value => {
15
15
  this[this.cursor++] = value;
16
16
  this.cursor %= this.length;
17
17
  });
@@ -4,11 +4,15 @@ import { isSemver } from '../guards/is-semver.js';
4
4
  import { isValidSemverRange } from '../guards/is-valid-semver-range.js';
5
5
  /** @deprecated migrate to make better use of npm-package-arg */
6
6
  export function setSemverRange(semverRange, version) {
7
- if (!isSemver(version) || !isValidSemverRange(semverRange))
7
+ if (!(isSemver(version) && isValidSemverRange(semverRange))) {
8
8
  return version;
9
- if (semverRange === '*')
9
+ }
10
+ if (semverRange === '*') {
10
11
  return semverRange;
11
- const nextVersion = isLooseSemver(version) ? version.replace(/\.x/g, '.0') : version;
12
+ }
13
+ const nextVersion = isLooseSemver(version)
14
+ ? version.replace(/\.x/g, '.0')
15
+ : version;
12
16
  const from1stNumber = nextVersion.search(/[0-9]/);
13
17
  const from1stDot = nextVersion.indexOf('.');
14
18
  return semverRange === RANGE.LOOSE
@@ -16,5 +20,5 @@ export function setSemverRange(semverRange, version) {
16
20
  : `${semverRange}${nextVersion.slice(from1stNumber)}`;
17
21
  }
18
22
  function isLooseSemver(version) {
19
- return isString(version) && isSemver(version) && version.search(/\.x(\.|$)/) !== -1;
23
+ return (isString(version) && isSemver(version) && version.search(/\.x(\.|$)/) !== -1);
20
24
  }
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk-template';
2
- import { Effect, Logger, LogLevel } from 'effect';
2
+ import { Effect, LogLevel, Logger } from 'effect';
3
3
  export function withLogger(program) {
4
4
  const logger = Logger.make(({ logLevel, message }) => {
5
5
  const args = Array.isArray(message) ? message : [message];
@@ -16,7 +16,6 @@ export function withLogger(program) {
16
16
  globalThis.console.warn(chalk `{yellow ! %s}`, ...args);
17
17
  }
18
18
  else {
19
- globalThis.console.log(chalk `{cyan [%s] %s}`, logLevel, ...args);
20
19
  }
21
20
  });
22
21
  const layer = Logger.replace(Logger.defaultLogger, logger);
package/dist/option.js CHANGED
@@ -6,7 +6,10 @@ export const option = {
6
6
  '-f, --filter [pattern]',
7
7
  chalk `only include dependencies whose {yellow name} matches this regex`,
8
8
  ],
9
- indent: ['-i, --indent [value]', `override indentation. defaults to "${DEFAULT_CONFIG.indent}"`],
9
+ indent: [
10
+ '-i, --indent [value]',
11
+ `override indentation. defaults to "${DEFAULT_CONFIG.indent}"`,
12
+ ],
10
13
  source: [
11
14
  '-s, --source [pattern]',
12
15
  'glob pattern for package.json files to read from',
@@ -29,7 +29,7 @@ export function createSemverGroups(ctx) {
29
29
  error: 'config is not an object',
30
30
  })));
31
31
  }
32
- const mutuallyExclusiveProps = ['isIgnored', 'range'].filter((prop) => Boolean(config[prop]));
32
+ const mutuallyExclusiveProps = ['isIgnored', 'range'].filter(prop => Boolean(config[prop]));
33
33
  if (mutuallyExclusiveProps.length > 1) {
34
34
  return semverGroups.push(Effect.fail(new SemverGroup.ConfigError({
35
35
  config,
@@ -40,8 +40,12 @@ export function createSemverGroups(ctx) {
40
40
  const dependencyTypes = isArrayOfStrings(config.dependencyTypes)
41
41
  ? config.dependencyTypes
42
42
  : ['**'];
43
- const dependencies = isArrayOfStrings(config.dependencies) ? config.dependencies : ['**'];
44
- const packages = isArrayOfStrings(config.packages) ? config.packages : ['**'];
43
+ const dependencies = isArrayOfStrings(config.dependencies)
44
+ ? config.dependencies
45
+ : ['**'];
46
+ const packages = isArrayOfStrings(config.packages)
47
+ ? config.packages
48
+ : ['**'];
45
49
  const specifierTypes = isArrayOfStrings(config.specifierTypes)
46
50
  ? config.specifierTypes
47
51
  : ['**'];
@@ -20,7 +20,7 @@ export class DisabledSemverGroup extends Data.TaggedClass('Disabled') {
20
20
  return Effect.succeed(specifier);
21
21
  }
22
22
  inspectAll() {
23
- return Effect.all(this.instances.map((instance) => this.inspect(instance)));
23
+ return Effect.all(this.instances.map(instance => this.inspect(instance)));
24
24
  }
25
25
  inspect(instance) {
26
26
  return Effect.succeed(new Report.Disabled(instance));
@@ -26,7 +26,7 @@ export class FilteredOutSemverGroup extends Data.TaggedClass('FilteredOut') {
26
26
  return Effect.succeed(specifier);
27
27
  }
28
28
  inspectAll() {
29
- return Effect.all(this.instances.map((instance) => this.inspect(instance)));
29
+ return Effect.all(this.instances.map(instance => this.inspect(instance)));
30
30
  }
31
31
  inspect(instance) {
32
32
  return Effect.succeed(new Report.FilteredOut(instance));
@@ -16,7 +16,7 @@ export class IgnoredSemverGroup extends Data.TaggedClass('Ignored') {
16
16
  return Effect.succeed(specifier);
17
17
  }
18
18
  inspectAll() {
19
- return Effect.all(this.instances.map((instance) => this.inspect(instance)));
19
+ return Effect.all(this.instances.map(instance => this.inspect(instance)));
20
20
  }
21
21
  inspect(instance) {
22
22
  return Effect.succeed(new Report.Ignored(instance));
@@ -16,16 +16,16 @@ export class WithRangeSemverGroup extends Data.TaggedClass('WithRange') {
16
16
  return true;
17
17
  }
18
18
  getFixed(specifier) {
19
- return pipe(specifier.getSemver(), Effect.map((semver) => setSemverRange(this.config.range, semver)), Effect.flatMap((nextSemver) => specifier.setSemver(nextSemver)));
19
+ return pipe(specifier.getSemver(), Effect.map(semver => setSemverRange(this.config.range, semver)), Effect.flatMap(nextSemver => specifier.setSemver(nextSemver)));
20
20
  }
21
21
  inspectAll() {
22
- return Effect.all(this.instances.map((instance) => this.inspect(instance)));
22
+ return Effect.all(this.instances.map(instance => this.inspect(instance)));
23
23
  }
24
24
  inspect(instance) {
25
25
  const current = Specifier.create(instance, instance.rawSpecifier.raw);
26
26
  return pipe(this.getFixed(current), Effect.match({
27
27
  // if range is fixable
28
- onSuccess: (valid) =>
28
+ onSuccess: valid =>
29
29
  // if it is pinned and matches its pin
30
30
  instance.versionGroup._tag === 'Pinned' &&
31
31
  instance.rawSpecifier.raw === instance.versionGroup.config.pinVersion
@@ -9,12 +9,13 @@ export class AliasSpecifier extends BaseSpecifier {
9
9
  name = 'alias';
10
10
  /** Return the version portion if it is valid semver */
11
11
  getSemver() {
12
- return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map((parsed) => parsed.subSpec), Effect.flatMap((subSpec) => ['range', 'version'].includes(subSpec.type) && subSpec.fetchSpec !== null
12
+ return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map(parsed => parsed.subSpec), Effect.flatMap(subSpec => ['range', 'version'].includes(subSpec.type) &&
13
+ subSpec.fetchSpec !== null
13
14
  ? Effect.succeed(subSpec.fetchSpec)
14
15
  : NonSemverError.asEffect(this)));
15
16
  }
16
17
  /** Get a new `Specifier` from the given semver version applied to this one */
17
18
  setSemver(version) {
18
- return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map((parsed) => parsed.subSpec), Effect.map((subSpec) => subSpec.name || ''), Effect.map((name) => `npm:${name}@${version}`), Effect.map((raw) => Specifier.create(this.instance, raw)));
19
+ return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map(parsed => parsed.subSpec), Effect.map(subSpec => subSpec.name || ''), Effect.map(name => `npm:${name}@${version}`), Effect.map(raw => Specifier.create(this.instance, raw)));
19
20
  }
20
21
  }
@@ -12,7 +12,7 @@ export class ExactSpecifier extends BaseSpecifier {
12
12
  name = 'exact';
13
13
  /** Return the semver version */
14
14
  getSemver() {
15
- return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map((parsed) => parsed.fetchSpec));
15
+ return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map(parsed => parsed.fetchSpec));
16
16
  }
17
17
  /** Get a new `Specifier` from the given semver version applied to this one */
18
18
  setSemver(version) {
@@ -10,13 +10,15 @@ export class HostedGitSpecifier extends BaseSpecifier {
10
10
  name = 'hosted-git';
11
11
  /** Return the git tag if it is valid semver */
12
12
  getSemver() {
13
- return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map((parsed) => parsed.gitCommittish || ''), Effect.flatMap((gitCommittish) => isSemver(gitCommittish) ? Effect.succeed(gitCommittish) : NonSemverError.asEffect(this)));
13
+ return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map(parsed => parsed.gitCommittish || ''), Effect.flatMap(gitCommittish => isSemver(gitCommittish)
14
+ ? Effect.succeed(gitCommittish)
15
+ : NonSemverError.asEffect(this)));
14
16
  }
15
17
  /** Get a new `Specifier` from the given semver version applied to this one */
16
18
  setSemver(version) {
17
- return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map((parsed) => ({
19
+ return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map(parsed => ({
18
20
  gitCommittish: parsed.gitCommittish || '',
19
21
  rawSpec: parsed.rawSpec || '',
20
- })), Effect.map(({ gitCommittish, rawSpec }) => rawSpec.replace(gitCommittish, version)), Effect.map((raw) => Specifier.create(this.instance, raw)));
22
+ })), Effect.map(({ gitCommittish, rawSpec }) => rawSpec.replace(gitCommittish, version)), Effect.map(raw => Specifier.create(this.instance, raw)));
21
23
  }
22
24
  }
@@ -25,34 +25,46 @@ export var Specifier;
25
25
  Specifier.Url = UrlSpecifier;
26
26
  Specifier.WorkspaceProtocol = WorkspaceProtocolSpecifier;
27
27
  function create(instance, raw) {
28
- if (raw === DELETE)
28
+ if (raw === DELETE) {
29
29
  return new Specifier.Delete({ instance, raw });
30
- if (!raw)
30
+ }
31
+ if (!raw) {
31
32
  return new Specifier.Unsupported({ instance, raw });
33
+ }
32
34
  try {
33
- if (raw === 'latest')
34
- raw = '*';
35
- const parsed = parseSpecifier(instance.name, raw, instance.packageJsonFile);
35
+ const data = {
36
+ instance,
37
+ raw: raw === 'latest' ? '*' : raw,
38
+ };
39
+ const parsed = parseSpecifier(instance.name, data.raw, instance.packageJsonFile);
36
40
  const type = parsed.type;
37
- const data = { instance, raw };
38
- if (raw === '*')
41
+ if (data.raw === '*') {
39
42
  return new Specifier.Latest(data);
40
- if (type === 'version')
43
+ }
44
+ if (type === 'version') {
41
45
  return new Specifier.Exact(data);
42
- if (type === 'range')
46
+ }
47
+ if (type === 'range') {
43
48
  return new Specifier.Range(data);
44
- if (type === 'workspaceProtocol')
49
+ }
50
+ if (type === 'workspaceProtocol') {
45
51
  return new Specifier.WorkspaceProtocol(data);
46
- if (type === 'alias')
52
+ }
53
+ if (type === 'alias') {
47
54
  return new Specifier.Alias(data);
48
- if (type === 'file' || type === 'directory')
55
+ }
56
+ if (type === 'file' || type === 'directory') {
49
57
  return new Specifier.File(data);
50
- if (type === 'remote')
58
+ }
59
+ if (type === 'remote') {
51
60
  return new Specifier.Url(data);
52
- if (type === 'git')
61
+ }
62
+ if (type === 'git') {
53
63
  return new Specifier.HostedGit(data);
54
- if (type === 'tag')
64
+ }
65
+ if (type === 'tag') {
55
66
  return new Specifier.Tag(data);
67
+ }
56
68
  return new Specifier.Unsupported(data);
57
69
  }
58
70
  catch {
@@ -11,7 +11,7 @@ export class LatestSpecifier extends BaseSpecifier {
11
11
  name = 'latest';
12
12
  /** Return the semver version including the range */
13
13
  getSemver() {
14
- return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map((parsed) => parsed.fetchSpec));
14
+ return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map(parsed => parsed.fetchSpec));
15
15
  }
16
16
  /** Get a new `Specifier` from the given semver version applied to this one */
17
17
  setSemver(version) {
@@ -1,6 +1,8 @@
1
1
  import npa from 'npm-package-arg';
2
2
  export function parseSpecifier(name, specifier, packageJsonFile) {
3
- if (specifier === 'workspace:*' || specifier === 'workspace:~' || specifier === 'workspace:^') {
3
+ if (specifier === 'workspace:*' ||
4
+ specifier === 'workspace:~' ||
5
+ specifier === 'workspace:^') {
4
6
  const parsed = npa.resolve(name, packageJsonFile.jsonFile.dirPath, specifier.replace('workspace:', 'file:'));
5
7
  return {
6
8
  escapedName: parsed.escapedName,
@@ -11,7 +11,7 @@ export class RangeSpecifier extends BaseSpecifier {
11
11
  name = 'range';
12
12
  /** Return the semver version including the range */
13
13
  getSemver() {
14
- return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map((parsed) => parsed.fetchSpec));
14
+ return pipe(this.parse(), Effect.mapError(() => new NonSemverError({ specifier: this })), Effect.map(parsed => parsed.fetchSpec));
15
15
  }
16
16
  /** Get a new `Specifier` from the given semver version applied to this one */
17
17
  setSemver(version) {
@@ -19,8 +19,9 @@ export class WorkspaceProtocolSpecifier extends BaseSpecifier {
19
19
  const range = this.raw.replace('workspace:', '');
20
20
  const local = ctx.packageJsonFilesByName[this.instance.name];
21
21
  const version = local?.jsonFile?.contents?.version;
22
- if (version)
22
+ if (version) {
23
23
  return Effect.succeed(`${range}${version}`);
24
+ }
24
25
  }
25
26
  return Effect.succeed('0.0.0');
26
27
  }
@@ -3,5 +3,5 @@ import { isNonEmptyString } from 'tightrope/guard/is-non-empty-string.js';
3
3
  import { get } from '../../lib/get.js';
4
4
  const getOptionOfNonEmptyString = Option.liftPredicate(isNonEmptyString);
5
5
  export function getNonEmptyStringProp(propPath, file) {
6
- return pipe(get(file.jsonFile.contents, ...propPath.split('.')), Effect.flatMap((value) => getOptionOfNonEmptyString(value)), Effect.tapError(() => Effect.logDebug(`<${file.jsonFile.shortPath}>.${propPath} is not a non-empty string`)));
6
+ return pipe(get(file.jsonFile.contents, ...propPath.split('.')), Effect.flatMap(value => getOptionOfNonEmptyString(value)), Effect.tapError(() => Effect.logDebug(`<${file.jsonFile.shortPath}>.${propPath} is not a non-empty string`)));
7
7
  }
@@ -1,4 +1,4 @@
1
- import { Effect, identity, Option, pipe } from 'effect';
1
+ import { Effect, Option, identity, pipe } from 'effect';
2
2
  import { isObject } from 'tightrope/guard/is-object.js';
3
3
  import { get } from '../lib/get.js';
4
4
  import { DELETE } from '../version-group/lib/delete.js';
@@ -47,14 +47,14 @@ export class NameAndVersionPropsStrategy {
47
47
  const fullPath = path.split('.');
48
48
  const pathToParent = fullPath.slice(0, fullPath.length - 1).join('.');
49
49
  const key = fullPath.slice(-1).join('');
50
- return pipe(get(contents, ...pathToParent.split('.')), Effect.flatMap(getOptionOfObject), Effect.flatMap((parent) => Effect.try(() => {
50
+ return pipe(get(contents, ...pathToParent.split('.')), Effect.flatMap(getOptionOfObject), Effect.flatMap(parent => Effect.try(() => {
51
51
  parent[key] = nextValue;
52
+ file.applyEdit(fullPath, nextValue);
52
53
  })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
53
54
  }
54
- else {
55
- return pipe(getOptionOfObject(contents), Effect.flatMap((parent) => Effect.try(() => {
56
- parent[this.path] = nextValue;
57
- })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
58
- }
55
+ return pipe(getOptionOfObject(contents), Effect.flatMap(parent => Effect.try(() => {
56
+ parent[this.path] = nextValue;
57
+ file.applyEdit([this.path], nextValue);
58
+ })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
59
59
  }
60
60
  }
@@ -20,9 +20,12 @@ export class NamedVersionStringStrategy {
20
20
  // get version prop
21
21
  getNonEmptyStringProp(path, file),
22
22
  // if it is a non empty string, we can read it
23
- Effect.map((value) => value.split(/@(.*)/)),
23
+ Effect.map(value => value.split(/@(.*)/)),
24
24
  // check the string was properly formed
25
- Effect.flatMap(([name, version]) => Effect.all([getOptionOfNonEmptyString(name), getOptionOfNonEmptyString(version)])),
25
+ Effect.flatMap(([name, version]) => Effect.all([
26
+ getOptionOfNonEmptyString(name),
27
+ getOptionOfNonEmptyString(version),
28
+ ])),
26
29
  // return an array of one entry if valid
27
30
  Effect.map(([name, version]) => [[name, version]]), Effect.tapError(() => Effect.logDebug(`NamedVersionStringStrategy#${this.name} found nothing at <${file.jsonFile.shortPath}>.${this.path}`)),
28
31
  // if value is invalid, default to empty
@@ -36,14 +39,14 @@ export class NamedVersionStringStrategy {
36
39
  const fullPath = this.path.split('.');
37
40
  const pathToParent = fullPath.slice(0, fullPath.length - 1).join('.');
38
41
  const key = fullPath.slice(-1).join('');
39
- return pipe(get(contents, ...pathToParent.split('.')), Effect.flatMap(getOptionOfNonEmptyObject), Effect.flatMap((parent) => Effect.try(() => {
42
+ return pipe(get(contents, ...pathToParent.split('.')), Effect.flatMap(getOptionOfNonEmptyObject), Effect.flatMap(parent => Effect.try(() => {
40
43
  parent[key] = nextValue;
44
+ file.applyEdit(fullPath, nextValue);
41
45
  })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
42
46
  }
43
- else {
44
- return pipe(getOptionOfNonEmptyObject(contents), Effect.flatMap((parent) => Effect.try(() => {
45
- parent[this.path] = nextValue;
46
- })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
47
- }
47
+ return pipe(getOptionOfNonEmptyObject(contents), Effect.flatMap(parent => Effect.try(() => {
48
+ parent[this.path] = nextValue;
49
+ file.applyEdit([this.path], nextValue);
50
+ })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
48
51
  }
49
52
  }
@@ -32,14 +32,14 @@ export class UnnamedVersionStringStrategy {
32
32
  const fullPath = this.path.split('.');
33
33
  const pathToParent = fullPath.slice(0, fullPath.length - 1).join('.');
34
34
  const key = fullPath.slice(-1).join('');
35
- return pipe(get(contents, ...pathToParent.split('.')), Effect.flatMap(getOptionOfNonEmptyObject), Effect.flatMap((parent) => Effect.try(() => {
35
+ return pipe(get(contents, ...pathToParent.split('.')), Effect.flatMap(getOptionOfNonEmptyObject), Effect.flatMap(parent => Effect.try(() => {
36
36
  parent[key] = nextValue;
37
+ file.applyEdit(fullPath, nextValue);
37
38
  })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
38
39
  }
39
- else {
40
- return pipe(getOptionOfNonEmptyObject(contents), Effect.flatMap((parent) => Effect.try(() => {
41
- parent[this.path] = nextValue;
42
- })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
43
- }
40
+ return pipe(getOptionOfNonEmptyObject(contents), Effect.flatMap(parent => Effect.try(() => {
41
+ parent[this.path] = nextValue;
42
+ file.applyEdit([this.path], nextValue);
43
+ })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
44
44
  }
45
45
  }
@@ -12,14 +12,16 @@ export class VersionsByNameStrategy {
12
12
  this.path = path;
13
13
  }
14
14
  read(file) {
15
- return pipe(get(file.jsonFile.contents, ...this.path.split('.')), Effect.flatMap((value) => getOptionOfNonEmptyObject(value)), Effect.map((obj) => Object.entries(obj)), Effect.tapError(() => Effect.logDebug(`VersionsByNameStrategy#${this.name} found nothing at <${file.jsonFile.shortPath}>.${this.path}`)),
15
+ return pipe(get(file.jsonFile.contents, ...this.path.split('.')), Effect.flatMap(value => getOptionOfNonEmptyObject(value)), Effect.map(obj => Object.entries(obj)), Effect.tapError(() => Effect.logDebug(`VersionsByNameStrategy#${this.name} found nothing at <${file.jsonFile.shortPath}>.${this.path}`)),
16
16
  // if value is invalid, default to empty
17
17
  Effect.catchAll(() => Effect.succeed([])));
18
18
  }
19
19
  write(file, [name, version]) {
20
20
  const nextValue = version === DELETE ? undefined : version;
21
- return pipe(get(file.jsonFile.contents, ...this.path.split('.')), Effect.flatMap(getOptionOfNonEmptyObject), Effect.flatMap((parent) => Effect.try(() => {
21
+ const fullPath = this.path.split('.');
22
+ return pipe(get(file.jsonFile.contents, ...fullPath), Effect.flatMap(getOptionOfNonEmptyObject), Effect.flatMap(parent => Effect.try(() => {
22
23
  parent[name] = nextValue;
24
+ file.applyEdit(fullPath.concat(name), nextValue);
23
25
  })), Effect.tapError(() => Effect.logDebug(`strategy ${this._tag} with name ${this.name} failed to write to <${file.jsonFile.shortPath}>.${this.path}.${name}`)), Effect.catchAll(() => Effect.succeed(file)), Effect.map(() => file));
24
26
  }
25
27
  }
@@ -17,7 +17,7 @@ export class BannedVersionGroup extends Data.TaggedClass('Banned') {
17
17
  inspectAll() {
18
18
  return Effect.succeed(Object.entries(groupBy('name', this.instances)).map(([name, instances]) => ({
19
19
  name,
20
- reports: instances.map((instance) =>
20
+ reports: instances.map(instance =>
21
21
  // ✘ package should not be used
22
22
  // ✓ is a mismatch we can auto-fix
23
23
  new Report.Banned(Specifier.create(instance, DELETE))),
@@ -13,9 +13,7 @@ import { SnappedToVersionGroup } from './snapped-to.js';
13
13
  import { StandardVersionGroup } from './standard.js';
14
14
  export function createVersionGroups(ctx) {
15
15
  const { rcFile } = ctx.config;
16
- const versionGroups = [
17
- Effect.succeed(new FilteredOutVersionGroup(ctx)),
18
- ];
16
+ const versionGroups = [Effect.succeed(new FilteredOutVersionGroup(ctx))];
19
17
  if (isNonEmptyArray(rcFile.versionGroups)) {
20
18
  rcFile.versionGroups.forEach((config) => {
21
19
  if (!isObject(config)) {
@@ -24,7 +22,7 @@ export function createVersionGroups(ctx) {
24
22
  error: 'config is not an object',
25
23
  })));
26
24
  }
27
- const mutuallyExclusiveProps = ['isBanned', 'isIgnored', 'pinVersion', 'snapTo', 'policy'].filter((prop) => Boolean(config[prop]));
25
+ const mutuallyExclusiveProps = ['isBanned', 'isIgnored', 'pinVersion', 'snapTo', 'policy'].filter(prop => Boolean(config[prop]));
28
26
  if (mutuallyExclusiveProps.length > 1) {
29
27
  return versionGroups.push(Effect.fail(new VersionGroup.ConfigError({
30
28
  config,
@@ -35,8 +33,12 @@ export function createVersionGroups(ctx) {
35
33
  const dependencyTypes = isArrayOfStrings(config.dependencyTypes)
36
34
  ? config.dependencyTypes
37
35
  : ['**'];
38
- const dependencies = isArrayOfStrings(config.dependencies) ? config.dependencies : ['**'];
39
- const packages = isArrayOfStrings(config.packages) ? config.packages : ['**'];
36
+ const dependencies = isArrayOfStrings(config.dependencies)
37
+ ? config.dependencies
38
+ : ['**'];
39
+ const packages = isArrayOfStrings(config.packages)
40
+ ? config.packages
41
+ : ['**'];
40
42
  const specifierTypes = isArrayOfStrings(config.specifierTypes)
41
43
  ? config.specifierTypes
42
44
  : ['**'];
@@ -97,7 +99,9 @@ export function createVersionGroups(ctx) {
97
99
  specifierTypes,
98
100
  label,
99
101
  packages,
100
- preferVersion: config.preferVersion === 'lowestSemver' ? 'lowestSemver' : 'highestSemver',
102
+ preferVersion: config.preferVersion === 'lowestSemver'
103
+ ? 'lowestSemver'
104
+ : 'highestSemver',
101
105
  })));
102
106
  }
103
107
  });
@@ -22,7 +22,7 @@ export class FilteredOutVersionGroup extends Data.TaggedClass('FilteredOut') {
22
22
  inspectAll() {
23
23
  return Effect.succeed(Object.entries(groupBy('name', this.instances)).map(([name, instances]) => ({
24
24
  name,
25
- reports: instances.map((instance) =>
25
+ reports: instances.map(instance =>
26
26
  // ✓ is ignored and dismissed as valid
27
27
  new Report.FilteredOut(instance)),
28
28
  })));
@@ -15,7 +15,7 @@ export class IgnoredVersionGroup extends Data.TaggedClass('Ignored') {
15
15
  inspectAll() {
16
16
  return Effect.succeed(Object.entries(groupBy('name', this.instances)).map(([name, instances]) => ({
17
17
  name,
18
- reports: instances.map((instance) =>
18
+ reports: instances.map(instance =>
19
19
  // ✓ is ignored and dismissed as valid
20
20
  new Report.Ignored(instance)),
21
21
  })));
@@ -6,39 +6,48 @@ import { getRangeScore } from './get-range-score.js';
6
6
  export function getPreferredVersion(preferVersion, specifiers) {
7
7
  return pipe(
8
8
  // every instance must have a semver version
9
- Effect.all(specifiers.map((specifier) => pipe(specifier.getSemver(), Effect.map((semver) => ({ semver, specifier }))))),
9
+ Effect.all(specifiers.map(specifier => pipe(specifier.getSemver(), Effect.map(semver => ({ semver, specifier }))))),
10
10
  // comparing semver can error on some loose ranges, all must succeed
11
- Effect.map((semvers) => semvers.sort((a, b) => compareSemver(a.semver, b.semver))),
11
+ Effect.map(semvers => semvers.sort((a, b) => compareSemver(a.semver, b.semver))),
12
12
  // get the preferred value from the list
13
- Effect.map((sorted) => sorted[preferVersion === 'lowestSemver' ? 0 : sorted.length - 1]),
13
+ Effect.map(sorted => sorted[preferVersion === 'lowestSemver' ? 0 : sorted.length - 1]),
14
14
  // return just the specifier
15
- Effect.map((preferred) => preferred?.specifier));
15
+ Effect.map(preferred => preferred?.specifier));
16
16
  }
17
17
  const EQ = 0;
18
18
  const LT = -1;
19
19
  const GT = 1;
20
20
  function compareSemver(a, b) {
21
- if (a.startsWith('workspace:'))
21
+ if (a.startsWith('workspace:')) {
22
22
  return LT;
23
- if (b.startsWith('workspace:'))
23
+ }
24
+ if (b.startsWith('workspace:')) {
24
25
  return GT;
25
- if (a === b)
26
+ }
27
+ if (a === b) {
26
28
  return EQ;
27
- if (a === '*')
29
+ }
30
+ if (a === '*') {
28
31
  return GT;
29
- if (b === '*')
32
+ }
33
+ if (b === '*') {
30
34
  return LT;
35
+ }
31
36
  const cleanA = clean(a);
32
37
  const cleanB = clean(b);
33
- if (gt(cleanA, cleanB))
38
+ if (gt(cleanA, cleanB)) {
34
39
  return GT;
35
- if (lt(cleanA, cleanB))
40
+ }
41
+ if (lt(cleanA, cleanB)) {
36
42
  return LT;
43
+ }
37
44
  const scoreA = getRangeScore(a);
38
45
  const scoreB = getRangeScore(b);
39
- if (scoreA < scoreB)
46
+ if (scoreA < scoreB) {
40
47
  return LT;
41
- if (scoreA > scoreB)
48
+ }
49
+ if (scoreA > scoreB) {
42
50
  return GT;
51
+ }
43
52
  return EQ;
44
53
  }
@@ -13,6 +13,8 @@ const scoresByRange = {
13
13
  };
14
14
  /** Rank a Semver Range according to its greediness */
15
15
  export function getRangeScore(version) {
16
- const range = version.indexOf('.x') !== -1 ? RANGE.LOOSE : version.slice(0, version.search(/[0-9]/));
16
+ const range = version.indexOf('.x') !== -1
17
+ ? RANGE.LOOSE
18
+ : version.slice(0, version.search(/[0-9]/));
17
19
  return scoresByRange[range] || 0;
18
20
  }