@rushstack/heft-config-file
Version:
Configuration file loader for @rushstack/heft
382 lines • 15 kB
TypeScript
import type { ITerminal } from '@rushstack/terminal';
/**
* @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.
*/
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
*/
type InheritanceType = (typeof InheritanceType)[keyof typeof InheritanceType];
/**
* @beta
*/
declare namespace InheritanceType {
/**
* Append additional elements after elements from the parent file's property. Only applicable
* for arrays.
*/
type append = typeof InheritanceType.append;
/**
* Perform a shallow merge of additional elements after elements from the parent file's property.
* Only applicable for objects.
*/
type merge = typeof InheritanceType.merge;
/**
* Discard elements from the parent file's property
*/
type replace = typeof InheritanceType.replace;
/**
* Custom inheritance functionality
*/
type custom = typeof InheritanceType.custom;
}
export { InheritanceType };
/**
* @beta
*
* The set of possible resolution methods for fields that refer to paths.
*/
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
*/
type PathResolutionMethod = (typeof PathResolutionMethod)[keyof typeof PathResolutionMethod];
/**
* @beta
*/
declare namespace PathResolutionMethod {
/**
* Resolve a path relative to the configuration file
*/
type resolvePathRelativeToConfigurationFile = typeof PathResolutionMethod.resolvePathRelativeToConfigurationFile;
/**
* Resolve a path relative to the root of the project containing the configuration file
*/
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
*/
type NodeResolve = typeof PathResolutionMethod.NodeResolve;
/**
* Treat the property as a NodeJS-style require/import reference and resolve using standard
* NodeJS filesystem resolution
*/
type nodeResolve = typeof PathResolutionMethod.nodeResolve;
/**
* Resolve the property using a custom resolver.
*/
type custom = typeof PathResolutionMethod.custom;
}
export { PathResolutionMethod };
export declare const CONFIGURATION_FILE_FIELD_ANNOTATION: unique symbol;
export interface IAnnotatedField<TField, TConfigurationFileFieldAnnotation extends IConfigurationFileFieldAnnotation<TField> = IConfigurationFileFieldAnnotation<TField>> {
[CONFIGURATION_FILE_FIELD_ANNOTATION]: TConfigurationFileFieldAnnotation;
}
interface IConfigurationFileFieldAnnotation<TField> {
configurationFilePath: string | undefined;
originalValues: {
[propertyName in keyof TField]: unknown;
};
}
/**
* Options provided to the custom resolver specified in {@link ICustomJsonPathMetadata}.
*
* @beta
*/
export 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;
}
/**
* Used to specify how node(s) in a JSON object should be processed after being loaded.
*
* @beta
*/
export 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;
}
/**
* Used to specify how node(s) in a JSON object should be processed after being loaded.
*
* @beta
*/
export 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;
}
/**
* @beta
*/
export type PropertyInheritanceCustomFunction<TObject> = (currentObject: TObject, parentObject: TObject) => TObject;
/**
* @beta
*/
export interface IPropertyInheritance<TInheritanceType extends InheritanceType> {
inheritanceType: TInheritanceType;
}
/**
* @beta
*/
export 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 type IPropertiesInheritance<TConfigurationFile> = {
[propertyName in keyof TConfigurationFile]?: IPropertyInheritance<InheritanceType.append | InheritanceType.merge | InheritanceType.replace> | ICustomPropertyInheritance<TConfigurationFile[propertyName]>;
};
/**
* @beta
*/
export interface IPropertyInheritanceDefaults {
array?: IPropertyInheritance<InheritanceType.append | InheritanceType.replace>;
object?: IPropertyInheritance<InheritanceType.merge | InheritanceType.replace>;
}
/**
* @beta
*/
export type IJsonPathMetadata<T> = ICustomJsonPathMetadata<T> | INonCustomJsonPathMetadata;
/**
* 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 interface IJsonPathsMetadata<TConfigurationFile> {
[jsonPath: string]: IJsonPathMetadata<TConfigurationFile>;
}
/**
* 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 type CustomValidationFunction<TConfigurationFile> = (configurationFile: TConfigurationFile, resolvedConfigurationFilePathForLogging: string, terminal: ITerminal) => boolean;
/**
* @beta
*/
export 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 type IConfigurationFileOptionsWithJsonSchemaFilePath<TConfigurationFile, TExtraOptions extends {}> = IConfigurationFileOptionsBase<TConfigurationFile> & TExtraOptions & {
/**
* The path to the schema for the configuration file.
*/
jsonSchemaPath: string;
jsonSchemaObject?: never;
};
/**
* @beta
*/
export type IConfigurationFileOptionsWithJsonSchemaObject<TConfigurationFile, TExtraOptions extends {}> = IConfigurationFileOptionsBase<TConfigurationFile> & TExtraOptions & {
/**
* The schema for the configuration file.
*/
jsonSchemaObject: object;
jsonSchemaPath?: never;
};
/**
* @beta
*/
export type IConfigurationFileOptions<TConfigurationFile, TExtraOptions extends object> = IConfigurationFileOptionsWithJsonSchemaFilePath<TConfigurationFile, TExtraOptions> | IConfigurationFileOptionsWithJsonSchemaObject<TConfigurationFile, TExtraOptions>;
/**
* @beta
*/
export interface IOriginalValueOptions<TParentProperty> {
parentObject: Partial<TParentProperty>;
propertyName: keyof TParentProperty;
}
/**
* Callback that returns a fallback configuration file path if the original configuration file was not found.
* @beta
*/
export type IOnConfigurationFileNotFoundCallback = (resolvedConfigurationFilePathForLogging: string) => string | undefined;
/**
* @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;
}
//# sourceMappingURL=ConfigurationFileBase.d.ts.map