diff --git a/src/generator.ts b/src/generator.ts index e05149c..d388eb7 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -1,5 +1,6 @@ import { compile, compileFromFile, Options } from 'json-schema-to-typescript' import { flow } from 'lodash' +import { JsonObject } from 'type-fest' /** * Options of json-schema-to-typescript. @@ -48,9 +49,9 @@ function postProcess(source: string) { * Generate types from a JSON schema object. */ export async function generateTypes( - schema: any, + schema: JsonObject, options: Partial = {} -) { +): Promise { const mergedOptions = { ...defaultOptions, ...options } return await compile(schema, '', mergedOptions).then(postProcess) } @@ -61,7 +62,7 @@ export async function generateTypes( export async function generateTypesFromFile( schemaPath: string, options: Partial = {} -) { +): Promise { const mergedOptions = { ...defaultOptions, ...options } return await compileFromFile(schemaPath, mergedOptions).then(postProcess) } diff --git a/src/loaders/loadArgs.test.ts b/src/loaders/loadArgs.test.ts index 648c928..93090c1 100644 --- a/src/loaders/loadArgs.test.ts +++ b/src/loaders/loadArgs.test.ts @@ -1,6 +1,7 @@ +import { JsonObject } from 'type-fest' import { loadFromArgs } from './loadArgs' -const TEST_CASES: [string, string[], {}][] = [ +const TEST_CASES: [string, string[], JsonObject][] = [ ['camelCase a flag', ['--foo-bar'], { fooBar: true }], ['accept a value as option', ['--foo=bar'], { foo: 'bar' }], ['accept a value as flags', ['--foo', 'bar'], { foo: 'bar' }], diff --git a/src/loaders/loadArgs.ts b/src/loaders/loadArgs.ts index b13a269..36c8bf7 100644 --- a/src/loaders/loadArgs.ts +++ b/src/loaders/loadArgs.ts @@ -1,6 +1,7 @@ -import { camelCase, chain } from 'lodash' import getopts from 'getopts' +import { camelCase, chain } from 'lodash' import { parseArray } from './utils' +import { JsonObject } from 'type-fest' /** * Loads configuration from command line arguments. @@ -8,14 +9,15 @@ import { parseArray } from './utils' * Arguments name describe a path to the desired options using `-` as * separator. * - * @see https://github.com/jorgebucaran/getopts * @example - * - * --server-port=1337 - * --directives="['@graph0/directives', './directives']" - * --directives=@graph0/directives --directives=./directives + * ``` + * $ --cooking-time=200 + * $ --types="['Fettuccine', 'Tagliatelle']" + * $ --directives=Fettuccine --directives=Tagliatelle + * ``` + * @see https://github.com/jorgebucaran/getopts */ -export function loadFromArgs(args: string[]): {} { +export function loadFromArgs(args: string[]): JsonObject { return chain(getopts(args)) .omit('_') .mapKeys((_v, k) => camelCase(k)) diff --git a/src/loaders/loadEnv.test.ts b/src/loaders/loadEnv.test.ts index eb6f927..980506c 100644 --- a/src/loaders/loadEnv.test.ts +++ b/src/loaders/loadEnv.test.ts @@ -1,20 +1,21 @@ +import { JsonObject } from 'type-fest' import { loadFromEnv } from './loadEnv' -const TEST_CASES: [string, NodeJS.ProcessEnv, {}][] = [ +const TEST_CASES: [string, NodeJS.ProcessEnv, JsonObject][] = [ [ 'map name to camelcase without namespace', - { FAUDA_FOO: 'bar' }, + { PASTA_FOO: 'bar' }, { foo: 'bar' } ], [ 'parse an array value', - { FAUDA_FOO: '["bar", 1337]' }, + { PASTA_FOO: '["bar", 1337]' }, { foo: ['bar', 1337] } ], - ['trim the value', { FAUDA_FOO: ' 1337 ' }, { foo: '1337' }], + ['trim the value', { PASTA_FOO: ' 1337 ' }, { foo: '1337' }], ['remove variables without namespace', { FOO: '1337' }, {}] ] test.each(TEST_CASES)('%s', (_title, env, expected) => { - expect(loadFromEnv(env, 'fauda')).toEqual(expected) + expect(loadFromEnv('pasta', env)).toEqual(expected) }) diff --git a/src/loaders/loadEnv.ts b/src/loaders/loadEnv.ts index eca0667..f73c5bd 100644 --- a/src/loaders/loadEnv.ts +++ b/src/loaders/loadEnv.ts @@ -10,8 +10,8 @@ import { parseArray } from './utils' * * @example * - * GRAPH0_SERVER_PORT=1337 - * GRAPH0_DIRECTIVES="['@graph0/directives', './directives']" + * PASTA_COOKING_TIME=200 + * PASTA_TYPES="['Fettuccine', 'Tagliatelle']" */ export function loadFromEnv( namespace: string, diff --git a/src/loaders/loadFile.ts b/src/loaders/loadFile.ts index d61ec83..41bf816 100644 --- a/src/loaders/loadFile.ts +++ b/src/loaders/loadFile.ts @@ -1,10 +1,11 @@ -import { cosmiconfig, Options as CosmiconfigOptions } from 'cosmiconfig' import loadTs from '@endemolshinegroup/cosmiconfig-typescript-loader' +import { cosmiconfig, Options as CosmiconfigOptions } from 'cosmiconfig' +import { JsonObject } from 'type-fest' /** * @internal */ -export function getDefaultSearchPlaces(namespace: string) { +export function getDefaultSearchPlaces(namespace: string): string[] { return [ 'package.json', `.${namespace}rc`, diff --git a/src/normalizer/expandVars.test.ts b/src/normalizer/expandVars.test.ts index 805f754..fcba19f 100644 --- a/src/normalizer/expandVars.test.ts +++ b/src/normalizer/expandVars.test.ts @@ -1,6 +1,7 @@ +import { JsonObject } from 'type-fest' import { expandVars } from './expandVars' -const TEST_CASES: [string, NodeJS.ProcessEnv, {}, {}][] = [ +const TEST_CASES: [string, NodeJS.ProcessEnv, JsonObject, JsonObject][] = [ [ 'expand an existing env var to its value', { BAR: 'bar' }, diff --git a/src/normalizer/validate.test.ts b/src/normalizer/validate.test.ts index 7c260d3..0ae4eb4 100644 --- a/src/normalizer/validate.test.ts +++ b/src/normalizer/validate.test.ts @@ -46,7 +46,8 @@ test('throw an error for invalid values', async () => { await expect(async () => validate({ cookingTime: 'nope', seasoning: {} }, await getSchema()) ).rejects.toThrowErrorMatchingInlineSnapshot(` - ".cookingTime should be number - .seasoning should be array" - `) + "validate: Validation failed + .cookingTime should be number + .seasoning should be array" + `) }) diff --git a/src/normalizer/validate.ts b/src/normalizer/validate.ts index 47370e7..2b026d6 100644 --- a/src/normalizer/validate.ts +++ b/src/normalizer/validate.ts @@ -1,20 +1,21 @@ import Ajv from 'ajv' import { chain } from 'lodash' +import { JsonObject } from 'type-fest' function createError(errors: Ajv.ErrorObject[]): Error { const message = chain(errors) .map(err => `${err.dataPath} ${err.message}`) .join('\n') .value() - return new Error(message) + return new Error(`validate: Validation failed\n${message}`) } /** * @see https://github.com/ajv-validator/ajv */ export function validate( - input: any, - schema: any + input: JsonObject, + schema: JsonObject ): Configuration { const ajv = new Ajv({ allErrors: true, @@ -28,8 +29,10 @@ export function validate( const isValid = ajv.validate(schema, output) if (!isValid) { - throw createError(ajv.errors!) + throw ajv.errors + ? createError(ajv.errors) + : new Error('validate: Unknown error') } - return output + return (output as unknown) as Configuration } diff --git a/test/utils/testProject.ts b/test/utils/testProject.ts index 0ff5a49..c788d49 100644 --- a/test/utils/testProject.ts +++ b/test/utils/testProject.ts @@ -11,7 +11,7 @@ export class TestProject { this.rootDir = path.join(FIXTURES_ROOT, snakeCase(variant)) } - async setup() { + async setup(): Promise { const { rootDir, variant } = this const variantDir = path.dirname(variant) const ext = path.extname(variant) || '.json' @@ -29,7 +29,7 @@ export class TestProject { } catch (e) {} } - async teardown() { + async teardown(): Promise { const { rootDir } = this await fs.rmdir(path.join(rootDir), { recursive: true }) }