diff --git a/src/specifier/index.spec.ts b/src/specifier/index.spec.ts index e7c0cf5d..46fb18f5 100644 --- a/src/specifier/index.spec.ts +++ b/src/specifier/index.spec.ts @@ -165,8 +165,8 @@ describe('supported version formats', () => { version: '~1.0.0', }, { - name: 'range', - expected: 'Range', + name: 'latest', + expected: 'Latest', version: '*', }, { diff --git a/src/specifier/index.ts b/src/specifier/index.ts index d6d93979..0e072332 100644 --- a/src/specifier/index.ts +++ b/src/specifier/index.ts @@ -5,6 +5,7 @@ import { DeleteSpecifier } from './delete'; import { ExactSpecifier } from './exact'; import { FileSpecifier } from './file'; import { HostedGitSpecifier } from './hosted-git'; +import { LatestSpecifier } from './latest'; import { parseSpecifier } from './lib/parse-specifier'; import { RangeSpecifier } from './range'; import { TagSpecifier } from './tag'; @@ -15,25 +16,27 @@ import { WorkspaceProtocolSpecifier } from './workspace-protocol'; export namespace Specifier { export const Alias = AliasSpecifier; export const Delete = DeleteSpecifier; + export const Exact = ExactSpecifier; export const File = FileSpecifier; export const HostedGit = HostedGitSpecifier; + export const Latest = LatestSpecifier; export const Range = RangeSpecifier; export const Tag = TagSpecifier; export const Unsupported = UnsupportedSpecifier; export const Url = UrlSpecifier; - export const Version = ExactSpecifier; export const WorkspaceProtocol = WorkspaceProtocolSpecifier; export type Any = | AliasSpecifier | DeleteSpecifier + | ExactSpecifier | FileSpecifier | HostedGitSpecifier + | LatestSpecifier | RangeSpecifier | TagSpecifier | UnsupportedSpecifier | UrlSpecifier - | ExactSpecifier | WorkspaceProtocolSpecifier; export function create(instance: Instance, raw: string | Delete): Specifier.Any { @@ -44,7 +47,8 @@ export namespace Specifier { const parsed = parseSpecifier(instance.name, raw, instance.packageJsonFile); const type = parsed.type; const data = { instance, raw }; - if (type === 'version') return new Specifier.Version(data); + if (raw === '*') return new Specifier.Latest(data); + if (type === 'version') return new Specifier.Exact(data); if (type === 'range') return new Specifier.Range(data); if (type === 'workspaceProtocol') return new Specifier.WorkspaceProtocol(data); if (type === 'alias') return new Specifier.Alias(data); diff --git a/src/specifier/latest.ts b/src/specifier/latest.ts new file mode 100644 index 00000000..1d0fbb52 --- /dev/null +++ b/src/specifier/latest.ts @@ -0,0 +1,28 @@ +import { Effect, pipe } from 'effect'; +import { Specifier } from '.'; +import { BaseSpecifier } from './base'; +import { NonSemverError } from './lib/non-semver-error'; +import type { SpecificRegistryResult } from './lib/specific-registry-result'; + +type T = SpecificRegistryResult<'range'>; + +/** + * @example "*" + */ +export class LatestSpecifier extends BaseSpecifier { + _tag = 'Latest' as const; + + /** Return the semver version including the range */ + getSemver(): Effect.Effect { + return pipe( + this.parse(), + Effect.mapError(() => new NonSemverError({ specifier: this })), + Effect.map((parsed) => parsed.fetchSpec), + ); + } + + /** Get a new `Specifier` from the given semver version applied to this one */ + setSemver(version: string): Effect.Effect { + return Effect.succeed(Specifier.create(this.instance, version)); + } +} diff --git a/src/specifier/range.ts b/src/specifier/range.ts index bfa4eac7..56921ff9 100644 --- a/src/specifier/range.ts +++ b/src/specifier/range.ts @@ -7,7 +7,6 @@ import type { SpecificRegistryResult } from './lib/specific-registry-result'; type T = SpecificRegistryResult<'range'>; /** - * @example "*" * @example "^1.2.3" */ export class RangeSpecifier extends BaseSpecifier {