UNPKG

@rushstack/heft-config-file

Version:

Configuration file loader for @rushstack/heft

504 lines (469 loc) 19.9 kB
/** * A library for loading config files for use with the * {@link https://rushstack.io/pages/heft/overview/ | Heft} build system. * * @packageDocumentation */ import type { IRigConfig } from '@rushstack/rig-package'; import type { ITerminal } from '@rushstack/terminal'; /** * @deprecated Use {@link ProjectConfigurationFile} instead. * @beta */ export declare const ConfigurationFile: typeof ProjectConfigurationFile; /** * @deprecated Use {@link ProjectConfigurationFile} instead. * @beta */ export declare type ConfigurationFile<TConfigurationFile> = ProjectConfigurationFile<TConfigurationFile>; /** * @beta */ export declare abstract class ConfigurationFileBase<TConfigurationFile, TExtraOptions extends {}> { private readonly _getSchema; private readonly _jsonPathMetadata; private readonly _propertyInheritanceTypes; private readonly _defaultPropertyInheritance; private readonly _customValidationFunction; private __schema; private get _schema(); private readonly _configCache; private readonly _configPromiseCache; constructor(options: IConfigurationFileOptions<TConfigurationFile, TExtraOptions>); /** * @internal */ static _formatPathForLogging: (path: string) => string; /** * Get the path to the source file that the referenced property was originally * loaded from. */ getObjectSourceFilePath<TObject extends object>(obj: TObject): string | undefined; /** * Get the value of the specified property on the specified object that was originally * loaded from a configuration file. */ getPropertyOriginalValue<TParentProperty extends object, TValue>(options: IOriginalValueOptions<TParentProperty>): TValue | undefined; /** * Get the original value of the `$schema` property from the original configuration file, it one was present. */ getSchemaPropertyOriginalValue<TObject extends object>(obj: TObject): string | undefined; protected _loadConfigurationFileInnerWithCache(terminal: ITerminal, resolvedConfigurationFilePath: string, projectFolderPath: string | undefined, onConfigurationFileNotFound?: IOnConfigurationFileNotFoundCallback): TConfigurationFile; protected _loadConfigurationFileInnerWithCacheAsync(terminal: ITerminal, resolvedConfigurationFilePath: string, projectFolderPath: string | undefined, onFileNotFound?: IOnConfigurationFileNotFoundCallback): Promise<TConfigurationFile>; private _loadConfigurationFileEntryWithCache; private _loadConfigurationFileEntryWithCacheAsync; /** * Parses the raw JSON-with-comments text of the configuration file. * @param fileText - The text of the configuration file * @param resolvedConfigurationFilePathForLogging - The path to the configuration file, formatted for logs * @returns The parsed configuration file */ private _parseConfigurationFile; /** * Resolves all path properties and annotates properties with their original values. * @param entry - The cache entry for the loaded configuration file * @param projectFolderPath - The project folder path, if applicable * @returns The configuration file with all path properties resolved */ private _contextualizeConfigurationFile; /** * Resolves all path properties and merges parent properties. * @param entry - The cache entry for the loaded configuration file * @param projectFolderPath - The project folder path, if applicable * @returns The flattened, unvalidated configuration file, with path properties resolved */ private _contextualizeAndFlattenConfigurationFile; /** * Resolves all path properties, merges parent properties, and validates the configuration file. * @param entry - The cache entry for the loaded configuration file * @param projectFolderPath - The project folder path, if applicable * @param terminal - The terminal to log validation messages to * @returns The finalized configuration file */ private _finalizeConfigurationFile; private _loadConfigurationFileEntry; private _loadConfigurationFileEntryAsync; private _annotateProperties; private _resolvePathProperty; private _mergeConfigurationFiles; private _mergeObjects; } /** * A function to invoke after schema validation to validate the configuration file. * If this function returns any value other than `true`, the configuration file API * will throw an error indicating that custom validation failed. If the function wishes * to provide its own error message, it may use any combination of the terminal and throwing * its own error. * @beta */ export declare type CustomValidationFunction<TConfigurationFile> = (configurationFile: TConfigurationFile, resolvedConfigurationFilePathForLogging: string, terminal: ITerminal) => boolean; /** * @beta */ export declare type IConfigurationFileOptions<TConfigurationFile, TExtraOptions extends object> = IConfigurationFileOptionsWithJsonSchemaFilePath<TConfigurationFile, TExtraOptions> | IConfigurationFileOptionsWithJsonSchemaObject<TConfigurationFile, TExtraOptions>; /** * @beta */ export declare interface IConfigurationFileOptionsBase<TConfigurationFile> { /** * Use this property to specify how JSON nodes are postprocessed. */ jsonPathMetadata?: IJsonPathsMetadata<TConfigurationFile>; /** * Use this property to control how root-level properties are handled between parent and child * configuration files. */ propertyInheritance?: IPropertiesInheritance<TConfigurationFile>; /** * Use this property to control how specific property types are handled between parent and child * configuration files. */ propertyInheritanceDefaults?: IPropertyInheritanceDefaults; /** * Use this property if you need to validate the configuration file in ways beyond what JSON schema can handle. * This function will be invoked after JSON schema validation. * * If the file is valid, this function should return `true`, otherwise `ConfigurationFile` will throw an error * indicating that custom validation failed. To suppress this error, the function may itself choose to throw. */ customValidationFunction?: CustomValidationFunction<TConfigurationFile>; } /** * @beta */ export declare type IConfigurationFileOptionsWithJsonSchemaFilePath<TConfigurationFile, TExtraOptions extends {}> = IConfigurationFileOptionsBase<TConfigurationFile> & TExtraOptions & { /** * The path to the schema for the configuration file. */ jsonSchemaPath: string; jsonSchemaObject?: never; }; /** * @beta */ export declare type IConfigurationFileOptionsWithJsonSchemaObject<TConfigurationFile, TExtraOptions extends {}> = IConfigurationFileOptionsBase<TConfigurationFile> & TExtraOptions & { /** * The schema for the configuration file. */ jsonSchemaObject: object; jsonSchemaPath?: never; }; /** * Used to specify how node(s) in a JSON object should be processed after being loaded. * * @beta */ export declare interface ICustomJsonPathMetadata<TConfigurationFile> { /** * If `ICustomJsonPathMetadata.pathResolutionMethod` is set to `PathResolutionMethod.custom`, * this property be used to resolve the path. */ customResolver?: (resolverOptions: IJsonPathMetadataResolverOptions<TConfigurationFile>) => string; /** * If this property describes a filesystem path, use this property to describe * how the path should be resolved. */ pathResolutionMethod?: PathResolutionMethod.custom; } /** * @beta */ export declare interface ICustomPropertyInheritance<TObject> extends IPropertyInheritance<InheritanceType.custom> { /** * Provides a custom inheritance function. This function takes two arguments: the first is the * child file's object, and the second is the parent file's object. The function should return * the resulting combined object. * This function will not be invoked if the current value is `null`, the property will simply be deleted. */ inheritanceFunction: PropertyInheritanceCustomFunction<TObject>; } /** * @beta */ export declare type IJsonPathMetadata<T> = ICustomJsonPathMetadata<T> | INonCustomJsonPathMetadata; /** * Options provided to the custom resolver specified in {@link ICustomJsonPathMetadata}. * * @beta */ export declare interface IJsonPathMetadataResolverOptions<TConfigurationFile> { /** * The name of the property being resolved. */ propertyName: string; /** * The value of the path property being resolved. */ propertyValue: string; /** * The path to the configuration file the property was obtained from. */ configurationFilePath: string; /** * The configuration file the property was obtained from. */ configurationFile: Partial<TConfigurationFile>; /** * If this is a project configuration file, the root folder of the project. */ projectFolderPath?: string; } /** * Keys in this object are JSONPaths {@link https://jsonpath.com/}, and values are objects * that describe how node(s) selected by the JSONPath are processed after loading. * * @beta */ export declare interface IJsonPathsMetadata<TConfigurationFile> { [jsonPath: string]: IJsonPathMetadata<TConfigurationFile>; } /** * @beta * * The set of possible mechanisms for merging properties from parent configuration files. * If a child configuration file sets a property value to `null`, that will always delete the value * specified in the parent configuration file, regardless of the inheritance type. */ export declare const InheritanceType: { /** * Append additional elements after elements from the parent file's property. Only applicable * for arrays. */ readonly append: "append"; /** * Perform a shallow merge of additional elements after elements from the parent file's property. * Only applicable for objects. */ readonly merge: "merge"; /** * Discard elements from the parent file's property */ readonly replace: "replace"; /** * Custom inheritance functionality */ readonly custom: "custom"; }; /** * @beta */ export declare type InheritanceType = (typeof InheritanceType)[keyof typeof InheritanceType]; /** * @beta */ export declare namespace InheritanceType { /** * Append additional elements after elements from the parent file's property. Only applicable * for arrays. */ export type append = typeof InheritanceType.append; /** * Perform a shallow merge of additional elements after elements from the parent file's property. * Only applicable for objects. */ export type merge = typeof InheritanceType.merge; /** * Discard elements from the parent file's property */ export type replace = typeof InheritanceType.replace; /** * Custom inheritance functionality */ export type custom = typeof InheritanceType.custom; } /** * Used to specify how node(s) in a JSON object should be processed after being loaded. * * @beta */ export declare interface INonCustomJsonPathMetadata { /** * If this property describes a filesystem path, use this property to describe * how the path should be resolved. */ pathResolutionMethod?: PathResolutionMethod.NodeResolve | PathResolutionMethod.nodeResolve | PathResolutionMethod.resolvePathRelativeToConfigurationFile | PathResolutionMethod.resolvePathRelativeToProjectRoot; } /** * Callback that returns a fallback configuration file path if the original configuration file was not found. * @beta */ export declare type IOnConfigurationFileNotFoundCallback = (resolvedConfigurationFilePathForLogging: string) => string | undefined; /** * @beta */ export declare interface IOriginalValueOptions<TParentProperty> { parentObject: Partial<TParentProperty>; propertyName: keyof TParentProperty; } /** * @beta */ export declare interface IProjectConfigurationFileOptions { /** * A project root-relative path to the configuration file that should be loaded. */ projectRelativeFilePath: string; } /** * Alias for the constructor type for {@link ProjectConfigurationFile}. * @beta */ export declare type IProjectConfigurationFileSpecification<TConfigFile> = IConfigurationFileOptions<TConfigFile, IProjectConfigurationFileOptions>; /** * @beta */ export declare type IPropertiesInheritance<TConfigurationFile> = { [propertyName in keyof TConfigurationFile]?: IPropertyInheritance<InheritanceType.append | InheritanceType.merge | InheritanceType.replace> | ICustomPropertyInheritance<TConfigurationFile[propertyName]>; }; /** * @beta */ export declare interface IPropertyInheritance<TInheritanceType extends InheritanceType> { inheritanceType: TInheritanceType; } /** * @beta */ export declare interface IPropertyInheritanceDefaults { array?: IPropertyInheritance<InheritanceType.append | InheritanceType.replace>; object?: IPropertyInheritance<InheritanceType.merge | InheritanceType.replace>; } /** * @beta */ export declare class NonProjectConfigurationFile<TConfigurationFile> extends ConfigurationFileBase<TConfigurationFile, {}> { /** * Load the configuration file at the specified absolute path, automatically resolving * `extends` properties. Will throw an error if the file cannot be found. */ loadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile; /** * Load the configuration file at the specified absolute path, automatically resolving * `extends` properties. Will throw an error if the file cannot be found. */ loadConfigurationFileAsync(terminal: ITerminal, filePath: string): Promise<TConfigurationFile>; /** * This function is identical to {@link NonProjectConfigurationFile.loadConfigurationFile}, except * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. */ tryLoadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile | undefined; /** * This function is identical to {@link NonProjectConfigurationFile.loadConfigurationFileAsync}, except * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. */ tryLoadConfigurationFileAsync(terminal: ITerminal, filePath: string): Promise<TConfigurationFile | undefined>; } /** * @beta * * The set of possible resolution methods for fields that refer to paths. */ export declare const PathResolutionMethod: { /** * Resolve a path relative to the configuration file */ readonly resolvePathRelativeToConfigurationFile: "resolvePathRelativeToConfigurationFile"; /** * Resolve a path relative to the root of the project containing the configuration file */ readonly resolvePathRelativeToProjectRoot: "resolvePathRelativeToProjectRoot"; /** * Treat the property as a NodeJS-style require/import reference and resolve using standard * NodeJS filesystem resolution * * @deprecated * Use {@link (PathResolutionMethod:variable).nodeResolve} instead */ readonly NodeResolve: "NodeResolve"; /** * Treat the property as a NodeJS-style require/import reference and resolve using standard * NodeJS filesystem resolution */ readonly nodeResolve: "nodeResolve"; /** * Resolve the property using a custom resolver. */ readonly custom: "custom"; }; /** * @beta */ export declare type PathResolutionMethod = (typeof PathResolutionMethod)[keyof typeof PathResolutionMethod]; /** * @beta */ export declare namespace PathResolutionMethod { /** * Resolve a path relative to the configuration file */ export type resolvePathRelativeToConfigurationFile = typeof PathResolutionMethod.resolvePathRelativeToConfigurationFile; /** * Resolve a path relative to the root of the project containing the configuration file */ export type resolvePathRelativeToProjectRoot = typeof PathResolutionMethod.resolvePathRelativeToProjectRoot; /** * Treat the property as a NodeJS-style require/import reference and resolve using standard * NodeJS filesystem resolution * * @deprecated * Use {@link (PathResolutionMethod:namespace).nodeResolve} instead */ export type NodeResolve = typeof PathResolutionMethod.NodeResolve; /** * Treat the property as a NodeJS-style require/import reference and resolve using standard * NodeJS filesystem resolution */ export type nodeResolve = typeof PathResolutionMethod.nodeResolve; /** * Resolve the property using a custom resolver. */ export type custom = typeof PathResolutionMethod.custom; } /** * @beta */ export declare class ProjectConfigurationFile<TConfigurationFile> extends ConfigurationFileBase<TConfigurationFile, IProjectConfigurationFileOptions> { /** {@inheritDoc IProjectConfigurationFileOptions.projectRelativeFilePath} */ readonly projectRelativeFilePath: string; constructor(options: IProjectConfigurationFileSpecification<TConfigurationFile>); /** * Find and return a configuration file for the specified project, automatically resolving * `extends` properties and handling rigged configuration files. Will throw an error if a configuration * file cannot be found in the rig or project config folder. */ loadConfigurationFileForProject(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): TConfigurationFile; /** * Find and return a configuration file for the specified project, automatically resolving * `extends` properties and handling rigged configuration files. Will throw an error if a configuration * file cannot be found in the rig or project config folder. */ loadConfigurationFileForProjectAsync(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): Promise<TConfigurationFile>; /** * This function is identical to {@link ProjectConfigurationFile.loadConfigurationFileForProject}, except * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. */ tryLoadConfigurationFileForProject(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): TConfigurationFile | undefined; /** * This function is identical to {@link ProjectConfigurationFile.loadConfigurationFileForProjectAsync}, except * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. */ tryLoadConfigurationFileForProjectAsync(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): Promise<TConfigurationFile | undefined>; private _getConfigurationFilePathForProject; private _getRigConfigFallback; } /** * @beta */ export declare type PropertyInheritanceCustomFunction<TObject> = (currentObject: TObject, parentObject: TObject) => TObject; /** * Returns an object with investigative annotations stripped, useful for snapshot testing. * * @beta */ declare function stripAnnotations<TObject>(obj: TObject): TObject; export declare namespace TestUtilities { export { stripAnnotations } } export { }