1
0
Fork 0

feat: add join callback to include options

BREAKING CHANGE: usage of the include type now requires a join option
This commit is contained in:
ssube 2020-08-04 00:14:13 -05:00
parent dba9267828
commit 1d07d7c3ed
Signed by: ssube
GPG Key ID: 3EED7B957D362AF1
5 changed files with 37 additions and 29 deletions

View File

@ -9,5 +9,5 @@ The schema to be used for included files. This is necessary to work around circu
<b>Signature:</b>
```typescript
includeSchema: IncludeSchema
includeOptions: IncludeOptions
```

View File

@ -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';

View File

@ -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;

View File

@ -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>) => 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<string>) => {
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);
}
}

View File

@ -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();
};