diff --git a/.sonar-project.properties b/.sonar-project.properties index 86bff892..d2d7b516 100644 --- a/.sonar-project.properties +++ b/.sonar-project.properties @@ -1,6 +1,6 @@ sonar.projectKey=jitar sonar.projectName=jitar -sonar.langugage=typescript +sonar.language=typescript # Path to sources sonar.sources=packages/**/src diff --git a/packages/configuration/src/ConfigurationManager.ts b/packages/configuration/src/ConfigurationManager.ts index ce3bbb5f..bb7f41bf 100644 --- a/packages/configuration/src/ConfigurationManager.ts +++ b/packages/configuration/src/ConfigurationManager.ts @@ -1,5 +1,6 @@ import { Validator } from '@jitar/validation'; +import { LocalFileManager } from '@jitar/sourcing'; import { EnvironmentConfigurator } from './environment'; import { RuntimeConfiguration, RuntimeConfigurationBuilder } from './runtime'; @@ -17,7 +18,8 @@ export default class ConfigurationManager constructor(rootPath: string = DEFAULT_ROOT_PATH) { - const reader = new ConfigurationReader(rootPath); + const fileManager = new LocalFileManager(rootPath); + const reader = new ConfigurationReader(fileManager); const validator = new Validator(); this.#environmentConfigurator = new EnvironmentConfigurator(); diff --git a/packages/configuration/src/runtime/index.ts b/packages/configuration/src/runtime/index.ts index 19271b5c..4b9bb1be 100644 --- a/packages/configuration/src/runtime/index.ts +++ b/packages/configuration/src/runtime/index.ts @@ -1,3 +1,4 @@ +export { default as RuntimeConfigurationInvalid } from './errors/RuntimeConfigurationInvalid'; export { default as RuntimeConfiguration } from './definitions/RuntimeConfiguration'; export { default as RuntimeConfigurationBuilder } from './ConfigurationBuilder'; diff --git a/packages/configuration/src/server/definitions/GatewayConfiguration.ts b/packages/configuration/src/server/definitions/GatewayConfiguration.ts index 67747eff..f98db72b 100644 --- a/packages/configuration/src/server/definitions/GatewayConfiguration.ts +++ b/packages/configuration/src/server/definitions/GatewayConfiguration.ts @@ -3,7 +3,7 @@ import type { ValidationScheme } from '@jitar/validation'; type GatewayConfiguration = { - monitor: number; + monitor?: number; trustKey?: string; }; diff --git a/packages/configuration/src/server/index.ts b/packages/configuration/src/server/index.ts index e93287f3..51eb1168 100644 --- a/packages/configuration/src/server/index.ts +++ b/packages/configuration/src/server/index.ts @@ -1,4 +1,6 @@ +export { default as ServerConfigurationInvalid } from './errors/ServerConfigurationInvalid'; + export { default as ServerConfiguration } from './definitions/ServerConfiguration'; export { default as StandaloneConfiguration } from './definitions/StandaloneConfiguration'; export { default as ProxyConfiguration } from './definitions/ProxyConfiguration'; diff --git a/packages/configuration/src/utils/ConfigurationReader.ts b/packages/configuration/src/utils/ConfigurationReader.ts index 5f0fdd07..1524decd 100644 --- a/packages/configuration/src/utils/ConfigurationReader.ts +++ b/packages/configuration/src/utils/ConfigurationReader.ts @@ -1,16 +1,17 @@ -import { LocalFileManager } from '@jitar/sourcing'; import type { FileManager } from '@jitar/sourcing'; +import InvalidFileType from './errors/InvalidConfigurationFile'; + const ENVIRONMENT_VARIABLE_REGEX = /\${([^}]*)}/g; export default class ConfigurationReader { readonly #fileManager: FileManager; - constructor(rootPath: string) + constructor(fileManager: FileManager) { - this.#fileManager = new LocalFileManager(rootPath); + this.#fileManager = fileManager; } async read(filename: string): Promise> @@ -23,12 +24,16 @@ export default class ConfigurationReader } const file = await this.#fileManager.read(filename); + + if (file.type.includes('json') === false) + { + throw new InvalidFileType(filename); + } + const content = file.content.toString(); const configuration = this.#replaceEnvironmentVariables(content); - - return file.type.includes('json') - ? this.#parseJson(configuration) - : this.#parseText(configuration); + + return this.#parseJson(configuration); } #replaceEnvironmentVariables(content: string): string @@ -43,10 +48,4 @@ export default class ConfigurationReader { return JSON.parse(configuration); } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - #parseText(configuration: string): Record - { - return {}; - } } diff --git a/packages/configuration/src/utils/errors/InvalidConfigurationFile.ts b/packages/configuration/src/utils/errors/InvalidConfigurationFile.ts new file mode 100644 index 00000000..21cf73a1 --- /dev/null +++ b/packages/configuration/src/utils/errors/InvalidConfigurationFile.ts @@ -0,0 +1,8 @@ + +export default class InvalidConfigurationFile extends Error +{ + constructor(filename: string) + { + super(`${filename} is not a valid configuration file.`); + } +} diff --git a/packages/configuration/src/utils/index.ts b/packages/configuration/src/utils/index.ts index 7df7adc6..27c4d5ff 100644 --- a/packages/configuration/src/utils/index.ts +++ b/packages/configuration/src/utils/index.ts @@ -1,2 +1,3 @@ +export { default as InvalidConfigurationFile } from './errors/InvalidConfigurationFile'; export { default as ConfigurationReader } from './ConfigurationReader'; diff --git a/packages/configuration/test/dummy.spec.ts b/packages/configuration/test/dummy.spec.ts deleted file mode 100644 index 2489f1ee..00000000 --- a/packages/configuration/test/dummy.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ - -import { describe, expect, it } from 'vitest'; - -describe('dummy', () => -{ - // TODO: Add real tests - - it('should not complain about missing tests', async () => - { - expect(true).toBeTruthy(); - }); -}); diff --git a/packages/configuration/test/environment/Configurator.spec.ts b/packages/configuration/test/environment/Configurator.spec.ts new file mode 100644 index 00000000..130a6b80 --- /dev/null +++ b/packages/configuration/test/environment/Configurator.spec.ts @@ -0,0 +1,10 @@ + +import { describe, expect, it } from 'vitest'; + +describe('Configurator', () => +{ + it('should not test standard library functions', async () => + { + expect(true).toBeTruthy(); + }); +}); diff --git a/packages/configuration/test/fixtures/fileManager.fixture.ts b/packages/configuration/test/fixtures/fileManager.fixture.ts new file mode 100644 index 00000000..6a9d274d --- /dev/null +++ b/packages/configuration/test/fixtures/fileManager.fixture.ts @@ -0,0 +1,86 @@ + +import { File, FileManager } from '@jitar/sourcing'; + +export default class TestFileManager implements FileManager +{ + readonly #files: Record; + + constructor(files: Record) + { + this.#files = files; + } + + getRootLocation(): string + { + throw new Error('Method not implemented.'); + } + + getAbsoluteLocation(filename: string): string + { + throw new Error('Method not implemented.'); + } + + getRelativeLocation(filename: string): string + { + throw new Error('Method not implemented.'); + } + + getType(filename: string): Promise + { + throw new Error('Method not implemented.'); + } + + getContent(filename: string): Promise + { + throw new Error('Method not implemented.'); + } + + exists(filename: string): Promise + { + for (const key in this.#files) + { + const value = this.#files[key]; + + if (value.location === filename) + { + return Promise.resolve(true); + } + } + + return Promise.resolve(false); + } + + read(filename: string): Promise + { + let file: File | undefined; + + for (const key in this.#files) + { + const value = this.#files[key]; + + if (value.location === filename) + { + file = value; + + break; + } + } + + return Promise.resolve(file as File); + } + + write(filename: string, content: string): Promise + { + throw new Error('Method not implemented.'); + } + + delete(filename: string): Promise + { + throw new Error('Method not implemented.'); + } + + filter(pattern: string): Promise + { + throw new Error('Method not implemented.'); + } +} diff --git a/packages/configuration/test/fixtures/index.ts b/packages/configuration/test/fixtures/index.ts new file mode 100644 index 00000000..067c75fb --- /dev/null +++ b/packages/configuration/test/fixtures/index.ts @@ -0,0 +1,2 @@ + +export { default as FileManager } from './fileManager.fixture'; diff --git a/packages/configuration/test/runtime/ConfigurationBuilder.spec.ts b/packages/configuration/test/runtime/ConfigurationBuilder.spec.ts new file mode 100644 index 00000000..07ce6f9b --- /dev/null +++ b/packages/configuration/test/runtime/ConfigurationBuilder.spec.ts @@ -0,0 +1,35 @@ + +import { describe, expect, it } from 'vitest'; + +import { configurationBuilder, FILENAMES, CONFIGURATIONS, RuntimeConfigurationInvalid, VALIDATION_RESULT } from './fixtures'; + +describe('runtime/ConfigurationBuilder', () => +{ + it('should build a default runtime configuration without configuration file', async () => + { + const promise = configurationBuilder.build(); + + await expect(promise).resolves.toEqual(CONFIGURATIONS.DEFAULT); + }); + + it('should build a valid runtime configuration from a valid file', async () => + { + const promise = configurationBuilder.build(FILENAMES.VALID); + + await expect(promise).resolves.toEqual(CONFIGURATIONS.RUNTIME); + }); + + it('should build a default runtime when the configuration file does not exist', async () => + { + const promise = configurationBuilder.build(FILENAMES.MISSING); + + await expect(promise).resolves.toEqual(CONFIGURATIONS.DEFAULT); + }); + + it('should reject an invalid runtime configuration', async () => + { + const promise = configurationBuilder.build(FILENAMES.INVALID); + + await expect(promise).rejects.toEqual(new RuntimeConfigurationInvalid(VALIDATION_RESULT)); + }); +}); diff --git a/packages/configuration/test/runtime/fixtures/configuration.fixture.ts b/packages/configuration/test/runtime/fixtures/configuration.fixture.ts new file mode 100644 index 00000000..63eaae65 --- /dev/null +++ b/packages/configuration/test/runtime/fixtures/configuration.fixture.ts @@ -0,0 +1,26 @@ + +import { RuntimeConfiguration } from '../../../src/runtime'; + +const defaultConfiguration: RuntimeConfiguration = +{ + source: './src', + target: './dist', +} as const; + +const runtimeConfiguration: RuntimeConfiguration = +{ + source: './source', + target: './target', +} as const; + +const invalidConfiguration: any = +{ + invalid: true +} as const; + +export const CONFIGURATIONS: Record = +{ + DEFAULT: defaultConfiguration, + RUNTIME: runtimeConfiguration, + INVALID: invalidConfiguration, +} as const; diff --git a/packages/configuration/test/runtime/fixtures/filenames.fixture.ts b/packages/configuration/test/runtime/fixtures/filenames.fixture.ts new file mode 100644 index 00000000..1f1bd925 --- /dev/null +++ b/packages/configuration/test/runtime/fixtures/filenames.fixture.ts @@ -0,0 +1,7 @@ + +export const FILENAMES = { + DEFAULT: './jitar.json', + VALID: 'valid-runtime-configuration.json', + INVALID: 'invalid-runtime-configuration.json', + MISSING: 'missing-runtime-configuration.json', +} as const; diff --git a/packages/configuration/test/runtime/fixtures/files.fixture.ts b/packages/configuration/test/runtime/fixtures/files.fixture.ts new file mode 100644 index 00000000..e1de9d57 --- /dev/null +++ b/packages/configuration/test/runtime/fixtures/files.fixture.ts @@ -0,0 +1,12 @@ + +import { File } from '@jitar/sourcing'; + +import { CONFIGURATIONS } from './configuration.fixture'; +import { FILENAMES } from './filenames.fixture'; + +export const FILES: Record = +{ + DEFAULT: new File(FILENAMES.DEFAULT, 'text/json', JSON.stringify(CONFIGURATIONS.DEFAULT)), + VALID: new File(FILENAMES.VALID, 'text/json', JSON.stringify(CONFIGURATIONS.RUNTIME)), + INVALID: new File(FILENAMES.INVALID, 'text/json', JSON.stringify(CONFIGURATIONS.INVALID)) +} as const; diff --git a/packages/configuration/test/runtime/fixtures/index.ts b/packages/configuration/test/runtime/fixtures/index.ts new file mode 100644 index 00000000..acb6f9a8 --- /dev/null +++ b/packages/configuration/test/runtime/fixtures/index.ts @@ -0,0 +1,21 @@ + +import { Validator } from '@jitar/validation'; + +import { RuntimeConfigurationBuilder } from '../../../src/runtime'; +import RuntimeConfigurationInvalid from '../../../src/runtime/errors/RuntimeConfigurationInvalid'; +import { ConfigurationReader } from '../../../src/utils'; + +import { FileManager } from '../../fixtures'; + +import { FILES } from './files.fixture'; +import { FILENAMES } from './filenames.fixture'; +import { CONFIGURATIONS } from './configuration.fixture'; +import { VALIDATION_RESULT } from './validation.fixture'; + +const fileManager = new FileManager(FILES); +const configurationReader = new ConfigurationReader(fileManager); +const validator = new Validator(); + +const configurationBuilder = new RuntimeConfigurationBuilder(configurationReader, validator); + +export { configurationBuilder, FILENAMES, CONFIGURATIONS, RuntimeConfigurationInvalid, VALIDATION_RESULT }; diff --git a/packages/configuration/test/runtime/fixtures/validation.fixture.ts b/packages/configuration/test/runtime/fixtures/validation.fixture.ts new file mode 100644 index 00000000..6b53931c --- /dev/null +++ b/packages/configuration/test/runtime/fixtures/validation.fixture.ts @@ -0,0 +1,12 @@ + +import { ValidationResult } from "@jitar/validation"; + +const VALIDATION_RESULT: ValidationResult = +{ + valid: false, + errors: [ + "Unknown field 'invalid'", + ] +} as const; + +export { VALIDATION_RESULT }; diff --git a/packages/configuration/test/server/ConfigurationBuilder.spec.ts b/packages/configuration/test/server/ConfigurationBuilder.spec.ts new file mode 100644 index 00000000..396d87b9 --- /dev/null +++ b/packages/configuration/test/server/ConfigurationBuilder.spec.ts @@ -0,0 +1,21 @@ + +import { describe, expect, it } from 'vitest'; + +import { configurationBuilder, FILENAMES, SERVER_CONFIGURATION, ServerConfigurationInvalid, VALIDATION_RESULT } from './fixtures'; + +describe('server/ConfigurationBuilder', () => +{ + it('should build a valid server configuration', async () => + { + const promise = configurationBuilder.build(FILENAMES.VALID_CONFIGURATION); + + await expect(promise).resolves.toEqual(SERVER_CONFIGURATION); + }); + + it('should reject an invalid server configuration', async () => + { + const promise = configurationBuilder.build(FILENAMES.INVALID_CONFIGURATION); + + await expect(promise).rejects.toEqual(new ServerConfigurationInvalid(VALIDATION_RESULT)); + }); +}); diff --git a/packages/configuration/test/server/fixtures/configuration.fixture.ts b/packages/configuration/test/server/fixtures/configuration.fixture.ts new file mode 100644 index 00000000..704103a4 --- /dev/null +++ b/packages/configuration/test/server/fixtures/configuration.fixture.ts @@ -0,0 +1,31 @@ + +import type { GatewayConfiguration, ProxyConfiguration, RepositoryConfiguration, ServerConfiguration, StandaloneConfiguration, WorkerConfiguration } from '../../../src/server'; + +const serveIndexOnNotFound = true; +const assets = ['index.html', 'favicon.ico']; +const segments = ['segment']; +const indexFilename = 'index.html'; +const trustKey = 'trust-key'; +const gateway = 'https://gateway'; +const repository = 'https://repository'; + +const gatewayConfiguration: GatewayConfiguration = { monitor: 5000, trustKey } as const; +const proxyConfiguration: ProxyConfiguration = { gateway, repository } as const; +const repositoryConfiguration: RepositoryConfiguration = { indexFilename, serveIndexOnNotFound, assets } as const; +const standaloneConfiguration: StandaloneConfiguration = { segments, indexFilename, serveIndexOnNotFound, assets } as const; +const workerConfiguration: WorkerConfiguration = { gateway, segments, trustKey } as const; + +export const SERVER_CONFIGURATION: ServerConfiguration = +{ + url: 'https://server', + setUp: ['setup'], + tearDown: ['tearDown'], + middleware: ['middleware'], + healthChecks: ['healthChecks'], + + gateway: gatewayConfiguration, + proxy: proxyConfiguration, + repository: repositoryConfiguration, + standalone: standaloneConfiguration, + worker: workerConfiguration +} as const; diff --git a/packages/configuration/test/server/fixtures/filenames.fixture.ts b/packages/configuration/test/server/fixtures/filenames.fixture.ts new file mode 100644 index 00000000..8f089f1f --- /dev/null +++ b/packages/configuration/test/server/fixtures/filenames.fixture.ts @@ -0,0 +1,6 @@ + +export const FILENAMES = +{ + VALID_CONFIGURATION: 'valid-configuration.json', + INVALID_CONFIGURATION: 'invalid-configuration.json', +} as const; diff --git a/packages/configuration/test/server/fixtures/files.fixture.ts b/packages/configuration/test/server/fixtures/files.fixture.ts new file mode 100644 index 00000000..68f5297a --- /dev/null +++ b/packages/configuration/test/server/fixtures/files.fixture.ts @@ -0,0 +1,11 @@ + +import { File } from '@jitar/sourcing'; + +import { SERVER_CONFIGURATION } from './configuration.fixture'; +import { FILENAMES } from './filenames.fixture'; + +export const FILES: Record = +{ + VALID_CONFIGURATION: new File(FILENAMES.VALID_CONFIGURATION, 'text/json', JSON.stringify(SERVER_CONFIGURATION)), + INVALID_CONFIGURATION: new File(FILENAMES.INVALID_CONFIGURATION, 'text/json', JSON.stringify({})), +} as const; diff --git a/packages/configuration/test/server/fixtures/index.ts b/packages/configuration/test/server/fixtures/index.ts new file mode 100644 index 00000000..def4196c --- /dev/null +++ b/packages/configuration/test/server/fixtures/index.ts @@ -0,0 +1,20 @@ + +import { Validator } from '@jitar/validation'; + +import { ServerConfigurationBuilder, ServerConfigurationInvalid } from '../../../src/server'; +import { ConfigurationReader } from '../../../src/utils'; + +import { FileManager } from '../../fixtures'; + +import { FILES } from './files.fixture'; +import { FILENAMES } from './filenames.fixture'; +import { SERVER_CONFIGURATION } from './configuration.fixture'; +import { VALIDATION_RESULT } from './validation.fixture'; + +const fileManager = new FileManager(FILES); +const configurationReader = new ConfigurationReader(fileManager); +const validator = new Validator(); + +const configurationBuilder = new ServerConfigurationBuilder(configurationReader, validator); + +export { configurationBuilder, SERVER_CONFIGURATION, ServerConfigurationInvalid, VALIDATION_RESULT, FILENAMES }; diff --git a/packages/configuration/test/server/fixtures/validation.fixture.ts b/packages/configuration/test/server/fixtures/validation.fixture.ts new file mode 100644 index 00000000..58a6c5b7 --- /dev/null +++ b/packages/configuration/test/server/fixtures/validation.fixture.ts @@ -0,0 +1,12 @@ + +import { ValidationResult } from "@jitar/validation"; + +const VALIDATION_RESULT: ValidationResult = +{ + valid: false, + errors: [ + "Field 'url' is required", + ] +} as const; + +export { VALIDATION_RESULT }; diff --git a/packages/configuration/test/utils/ConfigurationReader.spec.ts b/packages/configuration/test/utils/ConfigurationReader.spec.ts new file mode 100644 index 00000000..62e21310 --- /dev/null +++ b/packages/configuration/test/utils/ConfigurationReader.spec.ts @@ -0,0 +1,39 @@ + +import { describe, expect, it, vi } from 'vitest'; + +import { reader, FILENAMES, CONFIGURATIONS, InvalidConfigurationFile } from "./fixtures"; + +describe('ConfigurationReader', () => +{ + it('should return an empty configuration for non-existing config file', async () => + { + const configuration = await reader.read(FILENAMES.NON_EXISTING); + + expect(configuration).toEqual(CONFIGURATIONS.EMPTY); + }); + + it('should read json configuration', async () => + { + const configuration = await reader.read(FILENAMES.CORRECT_TYPE); + + expect(configuration).toEqual(CONFIGURATIONS.RESULT); + }); + + it('should read json configuration with environment variables', async () => + { + vi.stubEnv(CONFIGURATIONS.ENV_VARIABLES.TARGET_PATH_ENV_UTIL_KEY, CONFIGURATIONS.ENV_VARIABLES.TARGET_PATH_ENV_UTIL_VALUE); + + const configuration = await reader.read(FILENAMES.ENV_VARIABLES); + + expect(configuration).toEqual(CONFIGURATIONS.ENV_RESULT); + + vi.unstubAllEnvs(); + }); + + it('should not except non-json files', async () => + { + const promise = reader.read(FILENAMES.INCORRECT_TYPE); + + await expect(promise).rejects.toEqual(new InvalidConfigurationFile(FILENAMES.INCORRECT_TYPE)); + }); +}); diff --git a/packages/configuration/test/utils/fixtures/configuration.fixture.ts b/packages/configuration/test/utils/fixtures/configuration.fixture.ts new file mode 100644 index 00000000..6be017f6 --- /dev/null +++ b/packages/configuration/test/utils/fixtures/configuration.fixture.ts @@ -0,0 +1,35 @@ + +const resultConfiguration: Record = +{ + source: null, + target: './jitar' +} as const; + +const envConfiguration: Record = +{ + source: '${SOURCE_PATH_ENV_UTIL}', + target: '${TARGET_PATH_ENV_UTIL}' +} as const; + +const envResultConfiguration: Record = +{ + source: 'null', + target: './jitar' +} as const; + +const emptyConfiguration: Record = {} as const; + +const envVariables: Record = +{ + TARGET_PATH_ENV_UTIL_KEY: 'TARGET_PATH_ENV_UTIL', + TARGET_PATH_ENV_UTIL_VALUE: './jitar' +} as const; + +export const CONFIGURATIONS: Record = +{ + EMPTY: emptyConfiguration, + RESULT: resultConfiguration, + ENV: envConfiguration, + ENV_RESULT: envResultConfiguration, + ENV_VARIABLES: envVariables +} as const; diff --git a/packages/configuration/test/utils/fixtures/filenames.fixture.ts b/packages/configuration/test/utils/fixtures/filenames.fixture.ts new file mode 100644 index 00000000..be589730 --- /dev/null +++ b/packages/configuration/test/utils/fixtures/filenames.fixture.ts @@ -0,0 +1,8 @@ + +export const FILENAMES = +{ + CORRECT_TYPE: 'jitar.json', + INCORRECT_TYPE: 'jitar.txt', + ENV_VARIABLES: 'jitar-env.json', + NON_EXISTING: 'non-existent-file.json' +} as const; diff --git a/packages/configuration/test/utils/fixtures/files.fixture.ts b/packages/configuration/test/utils/fixtures/files.fixture.ts new file mode 100644 index 00000000..348e6cd6 --- /dev/null +++ b/packages/configuration/test/utils/fixtures/files.fixture.ts @@ -0,0 +1,12 @@ + +import { File } from '@jitar/sourcing'; + +import { FILENAMES } from './filenames.fixture'; +import { CONFIGURATIONS } from './configuration.fixture'; + +export const FILES: Record = +{ + CORRECT_TYPE: new File(FILENAMES.CORRECT_TYPE, 'text/json', JSON.stringify(CONFIGURATIONS.RESULT)), + INCORRECT_TYPE: new File(FILENAMES.INCORRECT_TYPE, 'text/plain', 'source: null\ntarget: .jitar'), + ENV_VARIABLES: new File(FILENAMES.ENV_VARIABLES, 'text/json', JSON.stringify(CONFIGURATIONS.ENV)) +} as const; diff --git a/packages/configuration/test/utils/fixtures/index.ts b/packages/configuration/test/utils/fixtures/index.ts new file mode 100644 index 00000000..44f34af4 --- /dev/null +++ b/packages/configuration/test/utils/fixtures/index.ts @@ -0,0 +1,13 @@ + +import { ConfigurationReader, InvalidConfigurationFile } from '../../../src/utils'; + +import { FileManager } from '../../fixtures'; + +import { CONFIGURATIONS } from './configuration.fixture'; +import { FILES } from './files.fixture'; +import { FILENAMES } from './filenames.fixture'; + +const fileManager = new FileManager(FILES); +const reader = new ConfigurationReader(fileManager); + +export { reader, FILENAMES, CONFIGURATIONS, InvalidConfigurationFile };