syncpack 12.4.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin-fix-mismatches/fix-mismatches.d.ts +2 -2
- package/dist/bin-fix-mismatches/fix-mismatches.js +13 -8
- package/dist/bin-fix-mismatches/index.js +1 -32
- package/dist/bin-format/format.d.ts +2 -2
- package/dist/bin-format/format.js +7 -5
- package/dist/bin-format/index.js +1 -26
- package/dist/bin-lint/index.js +1 -22
- package/dist/bin-lint/lint.d.ts +1 -1
- package/dist/bin-lint/lint.js +23 -23
- package/dist/bin-lint-semver-ranges/index.js +1 -36
- package/dist/bin-lint-semver-ranges/lint-semver-ranges.d.ts +2 -2
- package/dist/bin-lint-semver-ranges/lint-semver-ranges.js +5 -4
- package/dist/bin-list/index.js +1 -31
- package/dist/bin-list/list.d.ts +1 -1
- package/dist/bin-list/list.js +9 -5
- package/dist/bin-list-mismatches/index.js +1 -31
- package/dist/bin-list-mismatches/list-mismatches.d.ts +2 -2
- package/dist/bin-list-mismatches/list-mismatches.js +15 -9
- package/dist/bin-prompt/index.js +1 -33
- package/dist/bin-prompt/prompt.d.ts +2 -2
- package/dist/bin-prompt/prompt.js +13 -11
- package/dist/bin-set-semver-ranges/index.js +1 -38
- package/dist/bin-set-semver-ranges/set-semver-ranges.d.ts +2 -2
- package/dist/bin-set-semver-ranges/set-semver-ranges.js +8 -5
- package/dist/bin-update/effects.js +43 -28
- package/dist/bin-update/index.js +1 -31
- package/dist/bin-update/update.d.ts +1 -1
- package/dist/bin-update/update.js +4 -4
- package/dist/bin.js +3 -3
- package/dist/config/get-custom-types.js +20 -13
- package/dist/config/get-enabled-types.js +27 -12
- package/dist/config/get-sort-exports.js +2 -1
- package/dist/error-handlers/default-error-handlers.js +2 -2
- package/dist/get-context/index.d.ts +2 -2
- package/dist/get-context/index.js +1 -1
- package/dist/get-instances/index.js +6 -6
- package/dist/get-instances/instance.js +6 -2
- package/dist/get-package-json-files/get-patterns/get-lerna-patterns.js +4 -2
- package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.d.ts +1 -1
- package/dist/get-package-json-files/get-patterns/get-pnpm-patterns.js +2 -2
- package/dist/get-package-json-files/get-patterns/get-yarn-patterns.js +2 -2
- package/dist/get-package-json-files/get-patterns/index.js +3 -3
- package/dist/get-package-json-files/index.js +1 -1
- package/dist/get-package-json-files/package-json-file.d.ts +7 -0
- package/dist/get-package-json-files/package-json-file.js +18 -3
- package/dist/guards/can-add-to-group.js +15 -9
- package/dist/guards/is-semver.js +3 -1
- package/dist/io/ask-for-choice.js +3 -3
- package/dist/io/ask-for-input.js +2 -2
- package/dist/io/exit-if-invalid.js +1 -1
- package/dist/io/glob-sync.js +1 -1
- package/dist/io/index.d.ts +1 -1
- package/dist/io/index.js +1 -1
- package/dist/io/read-config-file.js +5 -3
- package/dist/io/read-file-sync.js +1 -1
- package/dist/io/read-json-file-sync.d.ts +2 -1
- package/dist/io/read-json-file-sync.js +9 -5
- package/dist/io/read-yaml-file-sync.js +1 -1
- package/dist/io/{to-json.d.ts → to-formatted-json.d.ts} +1 -1
- package/dist/io/{to-json.js → to-formatted-json.js} +11 -8
- package/dist/io/write-file-sync.js +2 -2
- package/dist/io/write-if-changed.js +3 -4
- package/dist/lib/format-repository-url.js +8 -5
- package/dist/lib/get-group-header.js +3 -1
- package/dist/lib/get.js +20 -12
- package/dist/lib/ring-buffer.js +1 -1
- package/dist/lib/set-semver-range.js +8 -4
- package/dist/lib/with-logger.js +1 -2
- package/dist/option.js +4 -1
- package/dist/semver-group/create-semver-groups.js +7 -3
- package/dist/semver-group/disabled.js +1 -1
- package/dist/semver-group/filtered-out.js +1 -1
- package/dist/semver-group/ignored.js +1 -1
- package/dist/semver-group/with-range.js +3 -3
- package/dist/specifier/alias.js +3 -2
- package/dist/specifier/exact.js +1 -1
- package/dist/specifier/hosted-git.js +5 -3
- package/dist/specifier/index.js +27 -15
- package/dist/specifier/latest.js +1 -1
- package/dist/specifier/lib/parse-specifier.js +3 -1
- package/dist/specifier/range.js +1 -1
- package/dist/specifier/workspace-protocol.js +2 -1
- package/dist/strategy/lib/get-non-empty-string-prop.js +1 -1
- package/dist/strategy/name-and-version-props.js +7 -7
- package/dist/strategy/named-version-string.js +11 -8
- package/dist/strategy/unnamed-version-string.js +6 -6
- package/dist/strategy/versions-by-name.js +4 -2
- package/dist/version-group/banned.js +1 -1
- package/dist/version-group/create-version-groups.js +11 -7
- package/dist/version-group/filtered-out.js +1 -1
- package/dist/version-group/ignored.js +1 -1
- package/dist/version-group/lib/get-preferred-version.js +22 -13
- package/dist/version-group/lib/get-range-score.js +3 -1
- package/dist/version-group/pinned.js +2 -2
- package/dist/version-group/same-range.js +6 -6
- package/dist/version-group/snapped-to.js +7 -5
- package/dist/version-group/standard.js +19 -16
- package/package.json +22 -25
package/dist/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)
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
36
|
+
function errUnreadableChild(child, value) {
|
|
29
37
|
return Either.left(new Error(`Cannot read "${child}" from unreadable value: ${value}`));
|
|
30
38
|
}
|
|
31
|
-
function
|
|
39
|
+
function errNotFound(child, value) {
|
|
32
40
|
return Either.left(new Error(`Property "${child}" not found on value: ${value}`));
|
|
33
41
|
}
|
|
34
|
-
function
|
|
42
|
+
function errUnreadableOrigin(props, origin) {
|
|
35
43
|
return Either.left(new Error(`Cannot read "${props.join('.')}" from unreadable value: ${origin}`));
|
|
36
44
|
}
|
package/dist/lib/ring-buffer.js
CHANGED
|
@@ -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)
|
|
7
|
+
if (!(isSemver(version) && isValidSemverRange(semverRange))) {
|
|
8
8
|
return version;
|
|
9
|
-
|
|
9
|
+
}
|
|
10
|
+
if (semverRange === '*') {
|
|
10
11
|
return semverRange;
|
|
11
|
-
|
|
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
|
}
|
package/dist/lib/with-logger.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk-template';
|
|
2
|
-
import { 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: [
|
|
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(
|
|
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)
|
|
44
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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:
|
|
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
|
package/dist/specifier/alias.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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
|
}
|
package/dist/specifier/exact.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
22
|
+
})), Effect.map(({ gitCommittish, rawSpec }) => rawSpec.replace(gitCommittish, version)), Effect.map(raw => Specifier.create(this.instance, raw)));
|
|
21
23
|
}
|
|
22
24
|
}
|
package/dist/specifier/index.js
CHANGED
|
@@ -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
|
-
|
|
30
|
+
}
|
|
31
|
+
if (!raw) {
|
|
31
32
|
return new Specifier.Unsupported({ instance, raw });
|
|
33
|
+
}
|
|
32
34
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
38
|
-
if (raw === '*')
|
|
41
|
+
if (data.raw === '*') {
|
|
39
42
|
return new Specifier.Latest(data);
|
|
40
|
-
|
|
43
|
+
}
|
|
44
|
+
if (type === 'version') {
|
|
41
45
|
return new Specifier.Exact(data);
|
|
42
|
-
|
|
46
|
+
}
|
|
47
|
+
if (type === 'range') {
|
|
43
48
|
return new Specifier.Range(data);
|
|
44
|
-
|
|
49
|
+
}
|
|
50
|
+
if (type === 'workspaceProtocol') {
|
|
45
51
|
return new Specifier.WorkspaceProtocol(data);
|
|
46
|
-
|
|
52
|
+
}
|
|
53
|
+
if (type === 'alias') {
|
|
47
54
|
return new Specifier.Alias(data);
|
|
48
|
-
|
|
55
|
+
}
|
|
56
|
+
if (type === 'file' || type === 'directory') {
|
|
49
57
|
return new Specifier.File(data);
|
|
50
|
-
|
|
58
|
+
}
|
|
59
|
+
if (type === 'remote') {
|
|
51
60
|
return new Specifier.Url(data);
|
|
52
|
-
|
|
61
|
+
}
|
|
62
|
+
if (type === 'git') {
|
|
53
63
|
return new Specifier.HostedGit(data);
|
|
54
|
-
|
|
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 {
|
package/dist/specifier/latest.js
CHANGED
|
@@ -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(
|
|
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:*' ||
|
|
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,
|
package/dist/specifier/range.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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,
|
|
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(
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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(
|
|
23
|
+
Effect.map(value => value.split(/@(.*)/)),
|
|
24
24
|
// check the string was properly formed
|
|
25
|
-
Effect.flatMap(([name, version]) => Effect.all([
|
|
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(
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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(
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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)
|
|
39
|
-
|
|
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'
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
13
|
+
Effect.map(sorted => sorted[preferVersion === 'lowestSemver' ? 0 : sorted.length - 1]),
|
|
14
14
|
// return just the specifier
|
|
15
|
-
Effect.map(
|
|
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
|
-
|
|
23
|
+
}
|
|
24
|
+
if (b.startsWith('workspace:')) {
|
|
24
25
|
return GT;
|
|
25
|
-
|
|
26
|
+
}
|
|
27
|
+
if (a === b) {
|
|
26
28
|
return EQ;
|
|
27
|
-
|
|
29
|
+
}
|
|
30
|
+
if (a === '*') {
|
|
28
31
|
return GT;
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
}
|