diff --git a/package.json b/package.json index c13d83c..9f7f5cd 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,8 @@ "author": "ssube", "license": "MIT", "devDependencies": { - "@apextoaster/js-config": "0.2.0-3", "@apextoaster/js-utils": "0.3.0", - "@apextoaster/js-yaml-schema": "0.4.0-4", + "@apextoaster/js-yaml-schema": "0.4.0", "@gitbeaker/browser": "23.7.0", "@gitbeaker/core": "23.7.0", "@gitbeaker/node": "23.7.0", @@ -60,6 +59,7 @@ "jsdom": "16.6.0", "jsdom-global": "3.0.2", "lodash": "4.17.21", + "memfs": "^3.2.2", "mobx": "6.3.2", "mobx-react": "7.2.0", "mocha": "8.4.0", diff --git a/src/config/index.ts b/src/config/index.ts index 45f6177..95ff71b 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,15 +1,32 @@ -import { createConfig } from '@apextoaster/js-config'; -import { IncludeOptions } from '@apextoaster/js-yaml-schema'; +import { createSchema } from '@apextoaster/js-yaml-schema'; import Ajv from 'ajv'; -import { existsSync, readFileSync, realpathSync } from 'fs'; -import { DEFAULT_SCHEMA } from 'js-yaml'; +import { promises } from 'fs'; +import { load } from 'js-yaml'; import { LogLevel } from 'noicejs'; -import { join } from 'path'; import { FlagLabel, StateLabel } from '../labels'; import { RemoteOptions } from '../remote'; import * as SCHEMA_DATA from './schema.yml'; +let { readFile } = promises; + +export const FILE_ENCODING = 'utf-8'; + +export type Filesystem = Pick; + +/** + * Hook for tests to override the fs fns. + */ +export function setFs(fs: Filesystem) { + const originalRead = readFile; + + readFile = fs.readFile; + + return () => { + readFile = originalRead; + }; +} + export interface LoggerConfig { level: LogLevel; name: string; @@ -64,27 +81,24 @@ export const CONFIG_SCHEMA_KEY = 'cautious-journey#/definitions/config'; /** * Load the config from files. */ -export async function initConfig(path: string, include = SCHEMA_OPTIONS): Promise { +export async function initConfig(path: string): Promise { + const schema = createSchema({}); const validator = new Ajv(AJV_OPTIONS); validator.addSchema(SCHEMA_DATA, 'cautious-journey'); - const config = createConfig({ - config: { - key: CONFIG_SCHEMA_KEY, - sources: [{ - name: '.', - paths: [path], - type: 'file', - }], - }, - process, - schema: { - include, - }, - validator, + const data = await readFile(path, { + encoding: 'utf8', }); - return config.getData(); + const config = load(data, { + schema, + }); + + if (validator.validate(CONFIG_SCHEMA_KEY, config) === true) { + return config as ConfigData; + } else { + throw new Error('invalid config data'); + } } export const AJV_OPTIONS: Ajv.Options = { @@ -96,11 +110,3 @@ export const AJV_OPTIONS: Ajv.Options = { useDefaults: true, verbose: true, }; - -export const SCHEMA_OPTIONS: IncludeOptions = { - exists: existsSync, - join, - read: readFileSync, - resolve: realpathSync, - schema: DEFAULT_SCHEMA, -}; diff --git a/test/config/TestConfig.ts b/test/config/TestConfig.ts index e75f5a5..c98c162 100644 --- a/test/config/TestConfig.ts +++ b/test/config/TestConfig.ts @@ -1,60 +1,34 @@ -import { IncludeOptions } from '@apextoaster/js-yaml-schema'; import { expect } from 'chai'; -import { DEFAULT_SCHEMA } from 'js-yaml'; -import { match, stub } from 'sinon'; +import { vol } from 'memfs'; -import { initConfig } from '../../src/config'; +import { Filesystem, initConfig, setFs } from '../../src/config'; describe('config', () => { describe('init config', () => { it('should load a valid config', async () => { const path = 'valid.yml'; - const include: IncludeOptions = { - exists: stub(), - join: stub().returns(path), - read: stub().returns(` + vol.fromJSON({ + [path]: ` logger: level: info name: test -projects: [] - `), - resolve: stub(), - schema: DEFAULT_SCHEMA, - }; +projects: []`, + }); + + const restore = setFs(vol.promises as Filesystem); + const config = await initConfig(path); + + restore(); - const config = await initConfig(path, include); - expect(include.read).to.have.been.calledWith(path, match.object); expect(config.logger.name).to.equal('test'); }); it('should throw on invalid config', async () => { - const include: IncludeOptions = { - exists: stub(), - join: stub().returnsArg(0), - read: stub().returns(` -logger: [] -projects: {} - `), - resolve: stub(), - schema: DEFAULT_SCHEMA, - }; - - await expect(initConfig('./invalid.yml', include)).to.eventually.be.rejectedWith(Error); + await expect(initConfig('./invalid.yml')).to.eventually.be.rejectedWith(Error); }); it('should throw on missing paths', async () => { - const err = new Error(); - Reflect.set(err, 'code', 'ENOENT'); - - const include: IncludeOptions = { - exists: stub().returns(false), - join: stub().returnsArg(0), - read: stub().throws(err), - resolve: stub(), - schema: DEFAULT_SCHEMA, - }; - - await expect(initConfig('.fake', include)).to.eventually.be.rejectedWith(Error); + await expect(initConfig('.fake')).to.eventually.be.rejectedWith(Error); }); }); }); diff --git a/yarn.lock b/yarn.lock index fb43fb1..d188e5b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,20 +2,15 @@ # yarn lockfile v1 -"@apextoaster/js-config@0.2.0-3": - version "0.2.0-3" - resolved "https://artifacts.apextoaster.com/repository/group-npm/@apextoaster/js-config/-/js-config-0.2.0-3.tgz#077b9916fcf6541af038ddb9bd585026c4c4c08a" - integrity sha512-mcsbrWmKJ0tTcsX0v0BU4+VMlvQKsZ+A6zCUcD7rxyTu43w5+gbx8M94mMpA1hhCkC9Q12aKUl+8vgqXhUCOmw== - "@apextoaster/js-utils@0.3.0": version "0.3.0" resolved "https://artifacts.apextoaster.com/repository/group-npm/@apextoaster/js-utils/-/js-utils-0.3.0.tgz#c592732d22c95c9df6b97447da641047b4f69e01" integrity sha512-CUJk4N/69XtiLMz4KFR9kXIvX2tqCqeqGd6Pa+LQ1u0iGD7IOZVJej0Dkr2qFeWwsPamS+XwwSvs8JV02m8/FA== -"@apextoaster/js-yaml-schema@0.4.0-4": - version "0.4.0-4" - resolved "https://artifacts.apextoaster.com/repository/group-npm/@apextoaster/js-yaml-schema/-/js-yaml-schema-0.4.0-4.tgz#fe9aa034f94a395b8c7eb62b638883a8bc6cbe7d" - integrity sha512-StRuVWApi4O5esIoEeMfYIImK821OcMTiJ2siihQKJgXAc/HDWuAEeq0K0DgZBZP0lHjEuFOheeDNHeCLNH/fA== +"@apextoaster/js-yaml-schema@0.4.0": + version "0.4.0" + resolved "https://artifacts.apextoaster.com/repository/group-npm/@apextoaster/js-yaml-schema/-/js-yaml-schema-0.4.0.tgz#6008bb90bbe958a5a645e2224317d14e8dcfa3b9" + integrity sha512-On4e0AytT6lpXIw9nHMYbHNyzRLNORzZwcETm4CssfGWRzF3FEzyLhSLfvX7ZNK+Z7l/pntVxiYWZu0S3Vv6Yw== "@babel/code-frame@7.12.11": version "7.12.11" @@ -2709,6 +2704,11 @@ fs-extra@~7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-monkey@1.0.3: + version "1.0.3" + resolved "https://artifacts.apextoaster.com/repository/group-npm/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://artifacts.apextoaster.com/repository/group-npm/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3927,6 +3927,13 @@ matched@^5.0.0: glob "^7.1.6" picomatch "^2.2.1" +memfs@^3.2.2: + version "3.2.2" + resolved "https://artifacts.apextoaster.com/repository/group-npm/memfs/-/memfs-3.2.2.tgz#5de461389d596e3f23d48bb7c2afb6161f4df40e" + integrity sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q== + dependencies: + fs-monkey "1.0.3" + meow@^3.3.0: version "3.7.0" resolved "https://artifacts.apextoaster.com/repository/group-npm/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"