import Ajv from 'ajv' ; import clone from '@tinkoff/utils/clone' ; import type { Config , SyncJsonFile } from '../typings/projectType' ; import type { ConfigEntry } from '../typings/configEntry/common' ; import { getTramvaiConfig } from '../utils/getTramvaiConfig' ; import { merge } from '../utils/merge' ; import { schema } from '../schema/tramvai' ; export class ConfigManager { private readonly defaultConfigFileName = 'platform.json' ; config : Config ; syncConfigFile : SyncJsonFile ; constructor ( { config , syncConfigFile } ) { this . config = config ; this . syncConfigFile = syncConfigFile ; this . validateConfig ( ) ; } get ( ) { return this . config ; } set ( config ) { this . config = merge ( this . config , config ) ; } getProject ( projectName ) { const entry = this . config . projects [ projectName ] ; if ( ! entry ) { console . error ( 'This repo support projects: ' , Object . keys ( this . config . projects ) ) ; throw new Error ( `${ projectName } not found in platform.json` ) ; } return entry ; } addProject ( configEntry , name = configEntry . name ) { if ( this . config . projects [ name ] ) { return Promise . reject ( new Error ( `Project ${ name } also exist` ) ) ; } const newConfig = merge ( this . config , { projects : { [ name ] : configEntry , } , } ) ; return this . updateConfig ( newConfig ) ; } private updateConfig ( config ) { const { path , configName : configFileName = this . defaultConfigFileName } = getTramvaiConfig ( ) ; return this . syncConfigFile ( { path , newContent : config } ) . then ( ( ) => { this . set ( config ) ; this . validateConfig ( ) ; } ) ; } private validateConfig ( ) { if ( ! this . config ) { return ; } const { projectsConfig = { } } = this . get ( ) ; const configParameters = clone ( this . get ( ) ) ; delete configParameters . projectsConfig ; Object . keys ( configParameters . projects ) . forEach ( ( projectName ) => { const entry = configParameters . projects [ projectName ] ; configParameters . projects [ projectName ] = merge ( projectsConfig , projectsConfig [ entry . type ] , entry ) ; } ) ; const ajv = new Ajv ( { useDefaults : true } ) ; const validate = ajv . compile ( schema ) ; const valid = validate ( configParameters ) ; this . config = configParameters ; if ( ! valid ) { const errorsMessage = validate . errors . map ( ( error ) => { let message = ajv . errorsText ( [ error ] ) ; if ( error . message === 'should NOT have additional properties' ) { message += ` - remove or rename "${ ( error . params as any ) . additionalProperty }" property` ; } return message ; } ) . join ( '\n' ) ; throw new Error ( `[validateConfig] ${ errorsMessage }` ) ; } } }