Skip to content

@vltpkg/spec

spec

This is a library for parsing package specifiers.

Namings · Specifiers · Usage · Properties

Overview

Specifiers are primarily used in the following cases:

  • On the command line, like vlt add [email protected]
  • In manifests (such as package.json) where dependencies are listed, like "dependencies": { "foo": "1.x" }
  • Internally within vlt, such as lockfiles and so on.

Named vs Unnamed

A “named” specifier is one with the full name included, separated from the specifier by a @ character, such as [email protected] or @vltpkg/[email protected]. The name in these cases would be foo and @vltpkg/spec, respectively.

Note that it does not always correspond to the "name" in the manifest of the resolved package! For example, foo@npm:react@latest would resolve to the latest version of react, but would be named foo in the dependency graph, and loaded as import('foo').

Types of Specifiers

The following specifier types are supported:

  • workspace:... - Provide a semver range, or one of ~, *, or ^ to match against a dependency that exists in a workspace project of a monorepo. The package name must exist as a workspace project in the monorepo. If a semver range is provided, then it must match the referenced workspace package version. Otherwise:

    • * - Fill in whatever version is in the workspace, without any prefix. So, if ./packages/foo depends on bar@workspace*, and bar is version 1.2.3, then foo will be published with { "dependencies": { "bar": "1.2.3" }}
    • ~ or ^ - Publish with the version found in the monorepo, prefixed by the character. So in the example above, it’d be bar@~1.2.3 or bar@^1.2.3, respectively.
  • semver range - A valid semver range (including the empty string or a single semver version). This is resolved against the default registry. If the spec is a valid semver range, then no further parsing is done.

  • git+ssh://<url>[selector] or git+https://<url>[selector] - A git+ssh or git+https url will be checked out by git. If no ‘git selector’ is provided, then it will attempt to install from the default version. The git selector can be:

    • #committish Any valid committish value will be checked out. So, shasum, branch, tag, etc., would all work.
    • #semver:<range> If a semver range is provided, it will select over all the tags that are valid semver versions, and pick the highest version number that satisfies the range.
    • Additional fields can be specified by a ::-separated series of key:value pairs. Currently only path:<path in repo> is supported, for referencing packages living below the root of the repository, as in a monorepo. For example, tcompare@github:tapjs/tapjs#bf457f24::path:src/tcompare
  • https://some-host.com/path/to/file.tgz - An https or http URL to a tarball will resolve to itself.

  • file:///path/to/file - A file URL will resolve to itself. If it is a directory, it will be reified as a symbolic link to the folder specified. If it is a file, it will be treated as a tarball that gets unpacked into place. Relative paths are resolved from the package with the dependency.

  • registry:<registry url>#<name>[@version range or dist-tag] - This will use the specified registry url, and look up the name and version on that registry.

  • If a registry shorthand is defined in the options, then you can use it as an alias for that registry. Currently, the only shorthand that is enabled by default is npm:<name>[@version-range] as a shorthand for registry:https://registry.npmjs.org/#<name>[@version-range].

  • If a git repository shorthand is defined in the options, then you can use that shorthand prefix as an alias for that git host. Currently, github:, bitbucket:, gitlab:, and gist: are supported by default.

  • Anything else will be treated as a dist-tag in the registry packument. For example, foo@latest or blah@legacy-v2

Usage

import { Spec, type SpecOptions } from '@vltpkg/spec'
// optional: create some registry shorthands
const opts: SpecOptions = {
registries: {
// internal company registry or something
acmereg: 'https://dev.acme.internal/npm',
},
gitHosts: {
github: 'git+ssh://[email protected]:$1/$2',
// the $# pieces here are replaced by the path-separated
// portions, so eg `github:user/project#whatever
acmegit: 'git+ssh://[email protected]/git/$1/$2/$3',
}
}
const lodash = Spec.parse('lodash@latest')
// which is the same as:
const lodash = Spec.parse('lodash@npm:lodash@latest')
// which is the same as:
const lodash = Spec.parse(
'lodash@registry:https://registry.npmjs.org/#lodash@latest'
)
// pull from github
const ghProject = Spec.parse('abbrev@github:npm/abbrev-js#main', opts)
// pull from our internal hosts using the acme shorthand names
const fooFromAcmeReg = Spec.parse('foo@acmereg:[email protected]', opts)
const fooFromAcmeReg = Spec.parse(
'foo@acmegit:department/team/monorepo#main;directory:packages/foo',
opts,
)

Properties

  • type - the type of spec that this is. One of 'registry', 'git', 'file', or 'remote'.
  • spec - the full named specifier passed to the constructor
  • options - options passed to the constructor, plus defaults
  • name - the name portion, so foo in [email protected]
  • bareSpec - just the part AFTER the name, so 1.x in [email protected]
  • when type === 'git':
    • gitRemote - git remote url
    • gitSelector - the ::-separated set of key:value fields
    • gitSelectorParsed - the gitSelector parsed into a Record object
    • gitCommittish - the commit sha, branch, or tag
    • namedGitHost - github, gitlab, bitbucket, etc.
    • remoteURL - when using a named git host with an archive url template, and a committish is provided, this is the url to download a tarball archive
    • semver - the semver range, if provided in the gitSelector
    • range - the parsed semver range, if valid
  • when type === 'registry':
    • registry - the registry to look up data from
    • namedRegistry - in the case of alias specs, the named registry
    • registrySpec - the semver range or dist-tag
    • semver - the semver range, if valid
    • range - the parsed semver range, if valid
    • distTag - the registrySpec when it is not a semver range
    • subspec - the parsed spec to to be resolved against the registry in question, if the spec is a named registry like npm:[email protected] or an explicit registry url like registry:https://registry.npmjs.org#[email protected].
  • when type === 'file':
    • file - the path on disk to find the package
  • when type === 'remote':
    • remoteURL - the url to the remote archive