diff --git a/docs/api/js-yaml-schema.includeschema.md b/docs/api/js-yaml-schema.includeschema.md index ed2ea91..eaf3dd7 100644 --- a/docs/api/js-yaml-schema.includeschema.md +++ b/docs/api/js-yaml-schema.includeschema.md @@ -9,5 +9,5 @@ The schema to be used for included files. This is necessary to work around circu Signature: ```typescript -includeSchema: IncludeSchema +includeOptions: IncludeOptions ``` diff --git a/src/index.ts b/src/index.ts index 921eefe..90f0c1f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export { CONFIG_SCHEMA } from './schema'; export { envType } from './type/Env'; -export { includeSchema, includeType } from './type/Include'; +export { includeOptions as includeSchema, includeType } from './type/Include'; export { regexpType } from './type/Regexp'; export { streamType } from './type/Stream'; diff --git a/src/schema.ts b/src/schema.ts index 6e11f03..91d0402 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -1,7 +1,7 @@ import { DEFAULT_SAFE_SCHEMA, Schema } from 'js-yaml'; import { envType } from './type/Env'; -import { includeSchema, includeType } from './type/Include'; +import { includeOptions, includeType } from './type/Include'; import { regexpType } from './type/Regexp'; import { streamType } from './type/Stream'; @@ -17,4 +17,4 @@ export const CONFIG_SCHEMA = Schema.create([DEFAULT_SAFE_SCHEMA], [ streamType, ]); -includeSchema.schema = CONFIG_SCHEMA; +includeOptions.schema = CONFIG_SCHEMA; diff --git a/src/type/Include.ts b/src/type/Include.ts index fd1a8d5..88354e3 100644 --- a/src/type/Include.ts +++ b/src/type/Include.ts @@ -1,15 +1,15 @@ -import { InvalidArgumentError, NotFoundError } from '@apextoaster/js-utils'; +import { InvalidArgumentError, NotFoundError, NotImplementedError } from '@apextoaster/js-utils'; import { SAFE_SCHEMA, safeLoad, Schema, Type as YamlType } from 'js-yaml'; -import { join } from 'path'; -export interface IncludeOptions { +export interface ReaderOptions { encoding: string; } -export type IncludeReader = (path: string, options: IncludeOptions) => string; +export type IncludeReader = (path: string, options: ReaderOptions) => string; -export interface IncludeSchema { +export interface IncludeOptions { exists: (path: string) => boolean; + join: (...path: Array) => string; read: IncludeReader; resolve: (path: string) => string; schema: Schema; @@ -20,13 +20,16 @@ export interface IncludeSchema { * * @public */ -export const includeSchema: IncludeSchema = { +export const includeOptions: IncludeOptions = { exists: (path: string) => false, - read: (path: string, encoding: IncludeOptions) => { - throw new Error('read stub'); + join: (...path: Array) => { + throw new NotImplementedError('join stub'); + }, + read: (path: string, encoding: ReaderOptions) => { + throw new NotImplementedError('read stub'); }, resolve: (path: string) => { - throw new Error('resolve stub'); + throw new NotImplementedError('resolve stub'); }, schema: SAFE_SCHEMA, }; @@ -40,7 +43,7 @@ export const includeType = new YamlType('!include', { try { const canonical = resolvePath(path); // throws in node 11+ - if (includeSchema.exists(canonical)) { + if (includeOptions.exists(canonical)) { return true; } else { throw new NotFoundError('included file does not exist'); @@ -51,10 +54,10 @@ export const includeType = new YamlType('!include', { }, construct(path: string): unknown { try { - return safeLoad(includeSchema.read(resolvePath(path), { + return safeLoad(includeOptions.read(resolvePath(path), { encoding: 'utf-8', }), { - schema: includeSchema.schema, + schema: includeOptions.schema, }); } catch (err) { throw new InvalidArgumentError('error including file', err); @@ -62,10 +65,13 @@ export const includeType = new YamlType('!include', { }, }); +/** + * @todo take root parameter instead of __dirname + */ export function resolvePath(path: string): string { if (path[0] === '.') { - return includeSchema.resolve(join(__dirname, path)); + return includeOptions.resolve(includeOptions.join(__dirname, path)); } else { - return includeSchema.resolve(path); + return includeOptions.resolve(path); } } diff --git a/test/type/TestInclude.ts b/test/type/TestInclude.ts index 6f917f9..e2566e4 100644 --- a/test/type/TestInclude.ts +++ b/test/type/TestInclude.ts @@ -2,25 +2,27 @@ import { InvalidArgumentError, NotFoundError } from '@apextoaster/js-utils'; import { expect } from 'chai'; import { join } from 'path'; -import { IncludeSchema, includeSchema, includeType } from '../../src/type/Include'; +import { IncludeOptions, includeOptions, includeType } from '../../src/type/Include'; const TEST_ROOT = '../test/type'; -const ORIGINAL_SCHEMA: IncludeSchema = { - ...includeSchema, +const ORIGINAL_SCHEMA: IncludeOptions = { + ...includeOptions, }; describe('include config type', async () => { beforeEach(() => { - includeSchema.exists = () => true; - includeSchema.read = () => 'test'; - includeSchema.resolve = (path: string) => path; + includeOptions.exists = () => true; + includeOptions.join = (...path) => path.join('/'); + includeOptions.read = () => 'test'; + includeOptions.resolve = (path: string) => path; }); afterEach(() => { - includeSchema.exists = ORIGINAL_SCHEMA.exists; - includeSchema.read = ORIGINAL_SCHEMA.read; - includeSchema.resolve = ORIGINAL_SCHEMA.resolve; + includeOptions.exists = ORIGINAL_SCHEMA.exists; + includeOptions.join = ORIGINAL_SCHEMA.join; + includeOptions.read = ORIGINAL_SCHEMA.read; + includeOptions.resolve = ORIGINAL_SCHEMA.resolve; }); it('should resolve existing files', async () => { @@ -28,7 +30,7 @@ describe('include config type', async () => { }); it('should throw when resolving missing files', async () => { - includeSchema.resolve = () => { + includeOptions.resolve = () => { throw new NotFoundError(); }; @@ -42,7 +44,7 @@ describe('include config type', async () => { }); it('should throw when constructing missing files', async () => { - includeSchema.read = () => { + includeOptions.read = () => { throw new InvalidArgumentError(); };