/** * Module that handles all vlt configuration needs * * Project-level configs are set in a `vlt.json` file in the local project * if present. This will override the user-level configs in the appropriate * XDG config path. * * Command-specific configuration can be specified by putting options in a * field in the `command` object. For example: * * ```json * { * "registry": "https://registry.npmjs.org/", * "command": { * "publish": { * "registry": "http://registry.internal" * } * } * } * ``` * @module */ import { PackageInfoClient } from '@vltpkg/package-info'; import { PackageJson } from '@vltpkg/package-json'; import type { SpecOptions } from '@vltpkg/spec'; import type { WhichConfig } from '@vltpkg/vlt-json'; import { Monorepo } from '@vltpkg/workspaces'; import type { Jack, OptionsResults, Unwrap } from 'jackspeak'; import { PathScurry } from 'path-scurry'; import type { Commands, RecordField } from './definition.ts'; import { commands, definition, isRecordField, recordFields } from './definition.ts'; export { commands, definition, isRecordField, recordFields, type Commands, }; export declare const kCustomInspect: unique symbol; export type RecordPairs = Record; export type RecordString = Record; export type PairsAsRecords = ConfigOptionsNoExtras & { command?: { [k in keyof Commands]?: ConfigOptionsNoExtras; }; }; export declare const pairsToRecords: (obj: NonNullable | OptionsResults) => PairsAsRecords; export declare const recordsToPairs: (obj: RecordPairs) => RecordPairs; export type ConfigDataNoCommand = { [k in keyof OptionsResults]?: OptionsResults[k]; }; /** * Config data can be any options, and also a 'command' field which * contains command names and override options for that command. */ export type ConfigData = ConfigDataNoCommand & { command?: { [k in keyof Commands]?: ConfigDataNoCommand; }; }; export type ConfigFileDataNoCommand = { [k in keyof ConfigDataNoCommand]: k extends (OptListKeys) ? RecordString | string[] : ConfigDataNoCommand[k]; }; /** * Config data as it appears in the config field of the vlt.json, with kv pair * lists stored as `Record` and */ export type ConfigFileData = ConfigFileDataNoCommand & { command?: { [k in keyof Commands]?: ConfigFileDataNoCommand; }; }; export type ConfigOptionsNoExtras = { [k in keyof OptionsResults]: k extends (RecordField) ? RecordString : k extends 'command' ? never : OptionsResults[k]; }; export type ConfigOptions = ConfigOptionsNoExtras & Pick & { packageJson: PackageJson; scurry: PathScurry; projectRoot: string; monorepo?: Monorepo; packageInfo: PackageInfoClient; }; /** * The base config definition set as a type */ export type ConfigDefinitions = Unwrap; export type StringListKeys = { [k in keyof O]: O[k] extends string[] | undefined ? k : never; }; export type OptListKeys = Exclude[keyof StringListKeys], undefined>; /** * Class that handles configuration for vlt. * * Call {@link Config.load} to get one of these. */ export declare class Config { #private; /** * The {@link https://npmjs.com/jackspeak | JackSpeak} object * representing vlt's configuration */ jack: Jack; /** * Parsed values in effect */ values?: OptionsResults; /** * Command-specific config values */ commandValues: { [cmd in Commands[keyof Commands]]?: ConfigData; }; /** * A flattened object of the parsed configuration */ get options(): ConfigOptions; /** * Reset the options value, optionally setting a new project root * to recalculate the options. */ resetOptions(projectRoot?: string): void; /** * positional arguments to the vlt process */ positionals?: string[]; /** * The root of the project where a vlt.json, vlt.json, * package.json, or .git was found. Not necessarily the `process.cwd()`, * though that is the default location. * * Never walks up as far as `$HOME`. So for example, if a project is in * `~/projects/xyz`, then the highest dir it will check is `~/projects` */ projectRoot: string; /** * `Record` to dereference command aliases. */ commands: Commands; /** * Which command name to use for overriding with command-specific values, * determined from the argv when parse() is called. */ command?: Commands[keyof Commands]; constructor(jack?: Jack, projectRoot?: string); /** * Parse the arguments and set configuration and positionals accordingly. */ parse(args?: string[]): this & ParsedConfig; /** * Get a `key=value` list option value as an object. * * For example, a list option with a vlaue of `['key=value', 'xyz=as=df' ]` * would be returned as `{key: 'value', xyz: 'as=df'}` * * Results are memoized, so subsequent calls for the same key will return the * same object. If new strings are added to the list, then the memoized value * is *not* updated, so only use once configurations have been fully loaded. * * If the config value is not set at all, an empty object is returned. */ getRecord(k: OptListKeys): RecordString; /** * Get a configuration value. * * Note: `key=value` pair configs are returned as a string array. To get them * as an object, use {@link Config#getRecord}. */ get>(k: K): OptionsResults[K]; /** * Write the config values to the user or project config file. */ writeConfigFile(this: LoadedConfig, which: WhichConfig, values: NonNullable): Promise; /** * Fold in the provided fields with the existing properties * in the config file. */ addConfigToFile(this: LoadedConfig, which: WhichConfig, values: NonNullable): Promise; /** * Deletes the specified config fields from the named file * Returns `true` if anything was changed. */ deleteConfigKeys(this: LoadedConfig, which: WhichConfig, fields: string[]): Promise; /** * Edit the user or project configuration file. * * If the file isn't present, then it starts with `{}` so the user has * something to work with. * * If the result is not valid, or no config settings are contained in the * file after editing, then it's restored to what it was before, which might * mean deleting the file. */ editConfigFile(this: LoadedConfig, which: WhichConfig, edit: (file: string) => Promise | void): Promise; /** * Find the local config file and load both it and the user-level config in * the XDG config home. */ loadConfigFile(): Promise; /** * Force a complete reload of config files from disk. * This clears all caches and re-reads config files. * Useful for long-running processes that need to pick up config changes. */ reloadFromDisk(): Promise; /** * Load the configuration and return a Promise to a * {@link Config} object */ static load(projectRoot?: string, argv?: string[], /** * only used in tests, resets the memoization * @internal */ reload?: boolean): Promise; } export type ParsedConfig = Config & { command: NonNullable; values: OptionsResults; positionals: string[]; }; /** * A fully loaded {@link Config} object */ export type LoadedConfig = ParsedConfig;