silk.npm.config.
Read npm's configuration the way npm does: the built-in, global, user, and project .npmrc
files, npm_config_* environment variables, and command-line values, with ${VAR} expansion,
scoped registries, and registry credentials.
When to use#
Use NpmConfig.load in a tool that talks to an npm registry and must honor the user's
.npmrc files, such as a package manager or a publish script. Read a key with
NpmConfig.text, choose a registry for a package with NpmConfig.registryFor, and get the
credentials for a request URL with NpmConfig.credentialsFor. To parse one ini text without
layers, use silk.npm.ini.
Details#
A configuration is a list of layers. When two layers set a key, the one with the higher priority wins. From highest to lowest, the layers are:
NpmConfigSource.CommandLine: values the caller passes, such as parsed--key=valueoptions.NpmConfigSource.Environment: each variablenpm_config_<name>(any case) with a non-empty value. In<name>, each_after the first character becomes-and letters become lowercase, unless the name starts with//.NpmConfigSource.Project:.npmrcin the project directory. That is theprefixfrom the command line, or else the nearest directory, from the working directory up, that has apackage.jsonfile or anode_modulesdirectory. If a directory above it has apackage.jsonwhoseworkspacespatterns include it, that workspace root is used instead. The project file is skipped in global mode (globalistrueorlocationisglobal) and when it is the same file as the user file.NpmConfigSource.User: theuserconfigfile, by default~/.npmrc.NpmConfigSource.Global: theglobalconfigfile, by default<prefix>/etc/npmrc.NpmConfigSource.Builtin: thenpmrcfile in npm's own install directory, if the caller names it.
In every layer, ${NAME} in a key or a text value is replaced by the environment variable
NAME. An unset variable leaves ${NAME} as it is. A \ before $ stops the expansion, and
each pair of \ before it becomes one \. As in npm, the items of a key[] list are expanded
only for npm's own list options: ca, cidr, diff, include, noproxy, omit, package,
and workspace. A file that cannot be read is an empty layer, as in npm. Keys inside an ini
[section] are ignored, as npm does not read them.
Errors#
HostInputErrorif the environment or the working directory cannot be read.FileErrorif the working directory is not a valid absolute path.OutOfMemoryErrorif theAllocatorcannot supply the configuration.
Gotchas#
Values are not checked or converted with npm's table of option types: a value is text, a
boolean, a null, or a list, as the ini text gives it. npm's default values are not included,
except the default registry https://registry.npmjs.org/. npm finds its global prefix from the
path of the node program; here it comes from NpmConfigOptions, the PREFIX environment
variable, or a prefix key. Paths use the / form of silk.system.filesystem; on Windows pass
the paths in NpmConfigOptions.
Examples#
Find the registry and the token for a scoped package#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.core.option { Option }
import silk.collections.bytes { Bytes }
import silk.collections.list { List }
import silk.system.host_input { HostInput, HostInputError }
import silk.npm.config { NpmConfig, NpmConfigSource, NpmCredentials }
import silk.system.filesystem { Path }
struct NoEnvironment {}
effect fn argumentCount(self: &mut NoEnvironment) -> usize ! HostInputError { return 0 }
effect fn argument(self: &mut NoEnvironment, index: usize) -> Option<Bytes>
! HostInputError | OutOfMemoryError ? &mut Allocator {
return Option<Bytes>.none()
}
effect fn variable(self: &mut NoEnvironment, name: &[u8]) -> Option<Bytes>
! HostInputError | OutOfMemoryError ? &mut Allocator {
return Option<Bytes>.none()
}
effect fn variableNames(self: &mut NoEnvironment) -> List<Bytes>
! HostInputError | OutOfMemoryError ? &mut Allocator {
return List<Bytes>.make()
}
effect fn workingDirectory(self: &mut NoEnvironment) -> Bytes
! HostInputError | OutOfMemoryError ? &mut Allocator {
return run Bytes.copy(b"/")
}
impl HostInput for NoEnvironment {
argumentCount: NoEnvironment.argumentCount
argument: NoEnvironment.argument
variable: NoEnvironment.variable
variableNames: NoEnvironment.variableNames
workingDirectory: NoEnvironment.workingDirectory
}
effect fn check() -> bool ! HostInputError | OutOfMemoryError ? &mut HostInput | &mut Allocator {
let mut config = NpmConfig.make()
let text = b"@acme:registry=https://npm.acme.test/\n//npm.acme.test/:_authToken=secret\n"
let layer = run NpmConfig.parseLayer(NpmConfigSource.User, Option<Path>.none(), text)
run NpmConfig.addLayer(&mut config, move layer)
let registry = NpmConfig.registryFor(&config, "@acme/widgets")
let credentials = run NpmConfig.credentialsFor(&config, "https://npm.acme.test/@acme%2fwidgets", registry)
return match move credentials {
Option<NpmCredentials>.Some { value } => registry == "https://npm.acme.test/"
&& &NpmCredentials.token(&value) == &Option<string>.some("secret")
Option<NpmCredentials>.None => false
}
}
pub effect fn main() -> i32 ! HostInputError | OutOfMemoryError {
let mut allocator = Allocator.systemAllocatorProvider()
let mut environment = NoEnvironment {}
let found = run check() |> Effect.provideMut<HostInput>(&mut environment)
|> Effect.provideMut<Allocator>(&mut allocator)
if !found {
return 1
}
return 0
}Import as NpmConfig with import silk.npm.config { NpmConfig }.
Public declarations: 6.
DEFAULT_REGISTRY#
pub const DEFAULT_REGISTRY: string<'static>The registry npm uses when no registry key is set.
NpmConfigSource#
pub enum NpmConfigSourceWhere a layer of the configuration comes from. A later variant has a higher priority.
Builtin#
BuiltinThe npmrc file in npm's own install directory.
Global#
GlobalThe global file, globalconfig, by default <prefix>/etc/npmrc.
User#
UserThe user file, userconfig, by default ~/.npmrc.
Project#
ProjectThe .npmrc file in the project directory.
Environment#
EnvironmentThe npm_config_* environment variables.
CommandLine#
CommandLineValues the caller passes, such as options from the command line.
NpmConfigLayer#
pub struct NpmConfigLayerOne layer of the configuration: the entries from one file, the environment, or the caller.
Field source#
pub source: NpmConfigSourceWhere the layer comes from.
Field file#
pub file: Option<Path>The file of the layer, or None for the environment and command-line layers.
Field error#
pub error: Option<FileError>The error that stopped the file from being read, such as NotFound. The layer then has no
entries.
Field entries#
pub entries: List<NpmEntry>The entries, with ${NAME} expanded in keys and text values (for a list, only for npm's own
list options). Keys inside an ini [section] are left out. A key appears once.
NpmConfigOptions#
pub struct NpmConfigOptionsPaths and values for NpmConfig.load. Each field can be left out.
Field workingDirectory#
pub workingDirectory: Option<Path>The directory to start the project search from. By default, the working directory of
HostInput.
Field home#
pub home: Option<Path>The home directory, for ~/ in paths and the default user file ~/.npmrc. By default, the
HOME environment variable, or USERPROFILE if HOME is not set.
Field globalPrefix#
pub globalPrefix: Option<Path>The global prefix, for the default global file <prefix>/etc/npmrc. By default, the PREFIX
environment variable. A prefix key in a layer wins over both.
Field builtinFile#
pub builtinFile: Option<Path>npm's built-in npmrc file, in npm's install directory. It is not read if left out.
Field commandLine#
pub commandLine: Option<List<NpmEntry>>The command-line layer, such as NpmIni.parse(b"registry=https://example.test/\n").
NpmCredentials#
pub struct NpmCredentialsThe credentials that npm sends to a registry.
Details#
npm sends Authorization: Bearer <token> if there is a token, or else Authorization: Basic
<basic> if there is a basic value. NpmCredentials.authorization gives that header value.
A client certificate can come with either one, or alone.
Field registryKey#
pub registryKey: StringThe key prefix that had the credentials, such as //registry.npmjs.org/.
Field bearer#
pub bearer: Option<String>The value of <registryKey>:_authToken.
Field basic#
pub basic: Option<String>The Base64 text for basic authentication: <registryKey>:_auth as written, or else
<registryKey>:username and the Base64-decoded <registryKey>:_password joined by : and
encoded.
Field certificateFile#
pub certificateFile: Option<String>The value of <registryKey>:certfile, a path to a PEM client certificate. It is set only
together with NpmCredentials.keyFile.
Field keyFile#
pub keyFile: Option<String>The value of <registryKey>:keyfile, a path to the PEM key of the client certificate.
Implementation NpmCredentials#
impl NpmCredentialsMethod token#
pub fn token<'a>(self: &'a NpmCredentials) -> Option<string<'a>>Returns the bearer token, or None if the credentials have no token. The text borrows from
self.
Method authorization#
pub effect fn authorization(self: &NpmCredentials) -> Option<String>
! OutOfMemoryError
? &mut AllocatorReturns the value of the Authorization header npm sends: Bearer <token>, or else Basic
<basic>, or None if the credentials are only a client certificate.
Errors#
OutOfMemoryErrorif theAllocatorcannot supply the text.
NpmConfig#
pub struct NpmConfignpm's configuration: layers of keys, from the command line down to npm's built-in file.
When to use#
Use NpmConfig.load to read the configuration that npm would use in a directory. Use
NpmConfig.make, NpmConfig.parseLayer, and NpmConfig.addLayer to build one from your
own text, for example in a test.
Details#
When two layers set a key, the higher one wins. From highest to lowest: command line, environment, project, user, global, built-in.
Implementation NpmConfig#
impl NpmConfigAssociated function make#
pub fn make() -> NpmConfigReturns a configuration with no layers, no home directory, and no working directory.
Associated function load#
pub effect fn load(options: NpmConfigOptions) -> NpmConfig
! HostInputError | FileError | OutOfMemoryError
? &mut FileSystem | &mut HostInput | &mut AllocatorReads npm's configuration for the working directory, from all files, the environment, and
the command-line values in options.
Details#
The layers are read in npm's order: built-in file, command line, environment, project file, user file, global file. A later file is found with the layers before it:
The project directory is
prefixfrom the command line, or else the nearest directory, from the working directory up, with apackage.jsonfile or anode_modulesdirectory, or else the working directory. If a directory above it has apackage.jsonwhoseworkspacespatterns name it, that directory is used, unlessworkspacesisfalseon the command line. The project file is skipped in global mode (globalistrueorlocationisglobal), and when it is the user file.The user file is
userconfig, by default~/.npmrc.The global file is
globalconfig, by default<prefix>/etc/npmrc, whereprefixis the key or else the global prefix ofoptionsor thePREFIXenvironment variable.
A file that cannot be read, for any reason, is a layer with no entries, and its error is
kept in NpmConfigLayer.error. A user or global file that is the same path as a file read
before it is skipped; npm stops with an error in that case. Keys and text values have
${NAME} expanded.
Errors#
HostInputErrorif the environment or the working directory cannot be read.FileErrorwith reasonInvalidPathif the working directory ofHostInputis not an absolute/path. PassworkingDirectoryinoptionsto avoid it.OutOfMemoryErrorif theAllocatorcannot supply the configuration.
Associated function parseLayer#
pub effect fn parseLayer(
source: NpmConfigSource,
file: Option<Path>,
bytes: &[u8],
) -> NpmConfigLayer
! HostInputError | OutOfMemoryError
? &mut HostInput | &mut AllocatorReturns the layer for the ini text bytes, with ${NAME} expanded in keys and text values.
When to use#
Use it to add text that is not in a file, such as values from your own command line, or to
build a configuration in a test. Add the result with NpmConfig.addLayer.
Details#
The text is parsed with NpmIni.parse. Keys inside an ini [section] are left out. Keys
and text values have ${NAME} expanded with NpmConfig.expand; the items of a key[] list
are expanded only for npm's list options ca, cidr, diff, include, noproxy, omit,
package, and workspace, as in npm. If two keys are the same after expansion, the later one
wins. file is recorded in the layer as it is.
Errors#
HostInputErrorif an environment variable cannot be read.OutOfMemoryErrorif theAllocatorcannot supply the layer.
Associated function readLayer#
pub effect fn readLayer(source: NpmConfigSource, path: Path) -> NpmConfigLayer
! HostInputError | OutOfMemoryError
? &mut FileSystem | &mut HostInput | &mut AllocatorReads the file path as the layer source.
Details#
If the file cannot be read, for any reason, the layer has no entries and keeps the error in
NpmConfigLayer.error, as npm ignores such a file. Otherwise it is the same as
NpmConfig.parseLayer for the contents.
Errors#
HostInputErrorif an environment variable cannot be read.OutOfMemoryErrorif theAllocatorcannot supply the layer.
Associated function environmentLayer#
pub effect fn environmentLayer() -> NpmConfigLayer
! HostInputError | OutOfMemoryError
? &mut HostInput | &mut AllocatorReturns the environment layer: one entry for each variable npm_config_<name> with a
non-empty value.
Details#
The prefix npm_config_ matches in any case. Unless <name> starts with //, each _ after
its first character becomes - and ASCII letters become lowercase, so NPM_CONFIG_SAVE_EXACT
sets save-exact. The text true, false, and null become a boolean or a null. Keys and
text values have ${NAME} expanded. If two variables give the same key, the later one in the
order of the host wins.
Errors#
HostInputErrorif the environment cannot be read.OutOfMemoryErrorif theAllocatorcannot supply the layer.
Method addLayer#
pub effect fn addLayer(self: &mut NpmConfig, layer: NpmConfigLayer) -> ()
! OutOfMemoryError
? &mut AllocatorAdds layer to the configuration. A layer with the same source is replaced.
Errors#
OutOfMemoryErrorif theAllocatorcannot supply room for the layer.
Method layers#
pub fn layers<'a>(self: &'a NpmConfig) -> &'a [NpmConfigLayer]Returns the layers, from the lowest priority to the highest.
Method get#
pub fn get<'a>(self: &'a NpmConfig, key: string) -> Option<&'a NpmEntry>Returns the entry for key from the layer with the highest priority that sets it, or None
if no layer sets it.
Details#
key is compared byte for byte, after ${NAME} expansion of the keys in the layers. For a
list, leave out the [].
Method text#
pub fn text<'a>(self: &'a NpmConfig, key: string) -> Option<string<'a>>Returns the text of the first value of key, from the layer with the highest priority that
sets it.
Details#
Returns None if no layer sets key, or if the winning value is a boolean or a null. The text
borrows from self.
Method flag#
pub fn flag(self: &NpmConfig, key: string) -> Option<bool>Returns the boolean value of key, from the layer with the highest priority that sets it.
Returns None if no layer sets key, or if the winning value is not true or false.
Method path#
pub effect fn path(self: &NpmConfig, key: string) -> Option<Path>
! FileError | OutOfMemoryError
? &mut AllocatorReturns the text value of key as a path, as npm reads its path options.
Details#
A value that starts with ~/ is resolved in the home directory. Any other relative value is
resolved in the working directory, and an absolute value is normalized. Returns None if no
layer sets key as text, or if the value needs a home or working directory that the
configuration does not have.
Errors#
FileErrorwith reasonInvalidPathif the value has a NUL byte or goes above the root.OutOfMemoryErrorif theAllocatorcannot supply the path.
Method userFile#
pub effect fn userFile(self: &NpmConfig) -> Option<Path>
! FileError | OutOfMemoryError
? &mut AllocatorReturns the user file: the userconfig path, or else .npmrc in the home directory, or
None if neither is known.
Errors#
FileErrorwith reasonInvalidPathifuserconfighas a NUL byte or goes above the root.OutOfMemoryErrorif theAllocatorcannot supply the path.
Method globalFile#
pub effect fn globalFile(self: &NpmConfig, globalPrefix: Option<Path>) -> Option<Path>
! HostInputError | FileError | OutOfMemoryError
? &mut HostInput | &mut AllocatorReturns the global file: the globalconfig path, or else etc/npmrc in the global prefix.
Details#
The global prefix is the prefix path, or else globalPrefix, or else the PREFIX
environment variable. Returns None if none of them is known.
Errors#
HostInputErrorif the environment cannot be read.FileErrorwith reasonInvalidPathif a path has a NUL byte or goes above the root.OutOfMemoryErrorif theAllocatorcannot supply the path.
Method registryFor#
pub fn registryFor<'a>(self: &'a NpmConfig, name: string) -> string<'a>Returns the registry URL for the package name, as npm chooses it.
Details#
For a scoped name such as @acme/widgets, it is the text of @acme:registry if that is set
and not empty. Otherwise it is the text of registry, or DEFAULT_REGISTRY. name can
also be a spec such as @acme/widgets@^2; only the scope before the first / is read. The
text borrows from self.
Method registry#
pub fn registry<'a>(self: &'a NpmConfig) -> string<'a>Returns the text of registry, or DEFAULT_REGISTRY if it is not set or empty. The text
borrows from self.
Method credentialsFor#
pub effect fn credentialsFor(self: &NpmConfig, url: string, registry: string) -> Option<
NpmCredentials
>
! OutOfMemoryError
? &mut AllocatorReturns the credentials npm would send with a request to url, or None if there are none.
Details#
The lookup starts with the key prefix //<host>/<path> of url, without the scheme, the user,
the query, and the fragment, and with a default port left out. While the prefix is longer than
//, it checks <prefix>:_authToken, then <prefix>:_auth, then <prefix>:username with
<prefix>:_password, then <prefix>:certfile with <prefix>:keyfile, and stops at the first
prefix that has one of them set to a non-empty value. Otherwise it removes the last path name
or the last / and tries again. So //npm.test/team/:_authToken covers
https://npm.test/team/pkg.
If no prefix has credentials, and registry is a different URL on the same host and port as
url, the credentials of registry are used, as npm does for tarball URLs. Pass the result of
NpmConfig.registryFor for the package as registry.
Credentials only for a host-wide key, such as an _authToken with no //host/ prefix, are not
used, as npm 9 and later refuse them.
Errors#
OutOfMemoryErrorif theAllocatorcannot supply the credentials.
Gotchas#
It returns None if url is not a valid absolute URL.
Associated function nerfDart#
pub effect fn nerfDart(url: string) -> Option<String>
! OutOfMemoryError
? &mut AllocatorReturns the key prefix npm uses for the credentials of url, such as //registry.npmjs.org/
for https://registry.npmjs.org/some/pkg.
Details#
It is //, the host with a port that is not the default, and the path up to and with its
last /. The scheme, the user, the query, and the fragment are left out. Returns None if
url is not a valid absolute URL.
Errors#
OutOfMemoryErrorif theAllocatorcannot supply the text.
Associated function expand#
pub effect fn expand(text: string) -> String
! HostInputError | OutOfMemoryError
? &mut HostInput | &mut AllocatorReturns text with each ${NAME} replaced by the value of the environment variable NAME,
as npm expands .npmrc keys and values.
Details#
NAME is one or more characters other than $, {, and }. An unset variable leaves
${NAME} as it is; a variable set to empty text gives empty text. For k backslashes right
before $: if k is even, k / 2 backslashes stay and the variable is expanded; if k is
odd, (k + 1) / 2 backslashes are removed and ${NAME} stays.
Errors#
HostInputErrorif an environment variable cannot be read.OutOfMemoryErrorif theAllocatorcannot supply the text.
Category: Data formats.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.