diff --git a/docs/api/js-yaml-schema.createinclude.md b/docs/api/js-yaml-schema.createinclude.md
new file mode 100644
index 0000000..6aaeb0e
--- /dev/null
+++ b/docs/api/js-yaml-schema.createinclude.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [createInclude](./js-yaml-schema.createinclude.md)
+
+## createInclude() function
+
+Instantiate an includer with closure over the provided options.
+
+Signature:
+
+```typescript
+export declare function createInclude(includeOptions: IncludeOptions): YamlType;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| includeOptions | [IncludeOptions](./js-yaml-schema.includeoptions.md) | |
+
+Returns:
+
+YamlType
+
diff --git a/docs/api/js-yaml-schema.createschema.md b/docs/api/js-yaml-schema.createschema.md
new file mode 100644
index 0000000..df6b5af
--- /dev/null
+++ b/docs/api/js-yaml-schema.createschema.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [createSchema](./js-yaml-schema.createschema.md)
+
+## createSchema() function
+
+Safe schema with additional library types added.
+
+Signature:
+
+```typescript
+export declare function createSchema(options: SchemaOptions): Schema;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| options | [SchemaOptions](./js-yaml-schema.schemaoptions.md) | |
+
+Returns:
+
+Schema
+
diff --git a/docs/api/js-yaml-schema.config_schema.md b/docs/api/js-yaml-schema.envtype.md
similarity index 50%
rename from docs/api/js-yaml-schema.config_schema.md
rename to docs/api/js-yaml-schema.envtype.md
index 9b60633..2b3d0ff 100644
--- a/docs/api/js-yaml-schema.config_schema.md
+++ b/docs/api/js-yaml-schema.envtype.md
@@ -1,13 +1,12 @@
-[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [CONFIG\_SCHEMA](./js-yaml-schema.config_schema.md)
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [envType](./js-yaml-schema.envtype.md)
-## CONFIG\_SCHEMA variable
+## envType variable
-Safe schema with additional library types added.
Signature:
```typescript
-CONFIG_SCHEMA: Schema
+envType: YamlType
```
diff --git a/docs/api/js-yaml-schema.includeoptions.exists.md b/docs/api/js-yaml-schema.includeoptions.exists.md
new file mode 100644
index 0000000..54c84a1
--- /dev/null
+++ b/docs/api/js-yaml-schema.includeoptions.exists.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [IncludeOptions](./js-yaml-schema.includeoptions.md) > [exists](./js-yaml-schema.includeoptions.exists.md)
+
+## IncludeOptions.exists property
+
+Signature:
+
+```typescript
+exists: (path: string) => boolean;
+```
diff --git a/docs/api/js-yaml-schema.includeoptions.join.md b/docs/api/js-yaml-schema.includeoptions.join.md
new file mode 100644
index 0000000..ad9cd73
--- /dev/null
+++ b/docs/api/js-yaml-schema.includeoptions.join.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [IncludeOptions](./js-yaml-schema.includeoptions.md) > [join](./js-yaml-schema.includeoptions.join.md)
+
+## IncludeOptions.join property
+
+Signature:
+
+```typescript
+join: (...path: Array) => string;
+```
diff --git a/docs/api/js-yaml-schema.includeoptions.md b/docs/api/js-yaml-schema.includeoptions.md
new file mode 100644
index 0000000..7ae75fb
--- /dev/null
+++ b/docs/api/js-yaml-schema.includeoptions.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [IncludeOptions](./js-yaml-schema.includeoptions.md)
+
+## IncludeOptions interface
+
+Signature:
+
+```typescript
+export interface IncludeOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [exists](./js-yaml-schema.includeoptions.exists.md) | (path: string) => boolean | |
+| [join](./js-yaml-schema.includeoptions.join.md) | (...path: Array<string>) => string | |
+| [read](./js-yaml-schema.includeoptions.read.md) | IncludeReader | |
+| [resolve](./js-yaml-schema.includeoptions.resolve.md) | (path: string) => string | |
+| [schema](./js-yaml-schema.includeoptions.schema.md) | Schema | |
+
diff --git a/docs/api/js-yaml-schema.includeoptions.read.md b/docs/api/js-yaml-schema.includeoptions.read.md
new file mode 100644
index 0000000..ff0d2c6
--- /dev/null
+++ b/docs/api/js-yaml-schema.includeoptions.read.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [IncludeOptions](./js-yaml-schema.includeoptions.md) > [read](./js-yaml-schema.includeoptions.read.md)
+
+## IncludeOptions.read property
+
+Signature:
+
+```typescript
+read: IncludeReader;
+```
diff --git a/docs/api/js-yaml-schema.includeoptions.resolve.md b/docs/api/js-yaml-schema.includeoptions.resolve.md
new file mode 100644
index 0000000..6115496
--- /dev/null
+++ b/docs/api/js-yaml-schema.includeoptions.resolve.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [IncludeOptions](./js-yaml-schema.includeoptions.md) > [resolve](./js-yaml-schema.includeoptions.resolve.md)
+
+## IncludeOptions.resolve property
+
+Signature:
+
+```typescript
+resolve: (path: string) => string;
+```
diff --git a/docs/api/js-yaml-schema.includeoptions.schema.md b/docs/api/js-yaml-schema.includeoptions.schema.md
new file mode 100644
index 0000000..f05f3d1
--- /dev/null
+++ b/docs/api/js-yaml-schema.includeoptions.schema.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [IncludeOptions](./js-yaml-schema.includeoptions.md) > [schema](./js-yaml-schema.includeoptions.schema.md)
+
+## IncludeOptions.schema property
+
+Signature:
+
+```typescript
+schema: Schema;
+```
diff --git a/docs/api/js-yaml-schema.includeschema.md b/docs/api/js-yaml-schema.includeschema.md
deleted file mode 100644
index eaf3dd7..0000000
--- a/docs/api/js-yaml-schema.includeschema.md
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [includeSchema](./js-yaml-schema.includeschema.md)
-
-## includeSchema variable
-
-The schema to be used for included files. This is necessary to work around circular dependency errors.
-
-Signature:
-
-```typescript
-includeOptions: IncludeOptions
-```
diff --git a/docs/api/js-yaml-schema.md b/docs/api/js-yaml-schema.md
index d045dd8..aeeb770 100644
--- a/docs/api/js-yaml-schema.md
+++ b/docs/api/js-yaml-schema.md
@@ -4,10 +4,25 @@
## js-yaml-schema package
+## Functions
+
+| Function | Description |
+| --- | --- |
+| [createInclude(includeOptions)](./js-yaml-schema.createinclude.md) | Instantiate an includer with closure over the provided options. |
+| [createSchema(options)](./js-yaml-schema.createschema.md) | Safe schema with additional library types added. |
+
+## Interfaces
+
+| Interface | Description |
+| --- | --- |
+| [IncludeOptions](./js-yaml-schema.includeoptions.md) | |
+| [SchemaOptions](./js-yaml-schema.schemaoptions.md) | |
+
## Variables
| Variable | Description |
| --- | --- |
-| [CONFIG\_SCHEMA](./js-yaml-schema.config_schema.md) | Safe schema with additional library types added. |
-| [includeSchema](./js-yaml-schema.includeschema.md) | The schema to be used for included files. This is necessary to work around circular dependency errors. |
+| [envType](./js-yaml-schema.envtype.md) | |
+| [regexpType](./js-yaml-schema.regexptype.md) | |
+| [streamType](./js-yaml-schema.streamtype.md) | |
diff --git a/docs/api/js-yaml-schema.regexptype.md b/docs/api/js-yaml-schema.regexptype.md
new file mode 100644
index 0000000..c690fc0
--- /dev/null
+++ b/docs/api/js-yaml-schema.regexptype.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [regexpType](./js-yaml-schema.regexptype.md)
+
+## regexpType variable
+
+
+Signature:
+
+```typescript
+regexpType: YamlType
+```
diff --git a/docs/api/js-yaml-schema.schemaoptions.include.md b/docs/api/js-yaml-schema.schemaoptions.include.md
new file mode 100644
index 0000000..ff5507d
--- /dev/null
+++ b/docs/api/js-yaml-schema.schemaoptions.include.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [SchemaOptions](./js-yaml-schema.schemaoptions.md) > [include](./js-yaml-schema.schemaoptions.include.md)
+
+## SchemaOptions.include property
+
+Signature:
+
+```typescript
+include: IncludeOptions;
+```
diff --git a/docs/api/js-yaml-schema.schemaoptions.md b/docs/api/js-yaml-schema.schemaoptions.md
new file mode 100644
index 0000000..8901772
--- /dev/null
+++ b/docs/api/js-yaml-schema.schemaoptions.md
@@ -0,0 +1,18 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [SchemaOptions](./js-yaml-schema.schemaoptions.md)
+
+## SchemaOptions interface
+
+Signature:
+
+```typescript
+export interface SchemaOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [include](./js-yaml-schema.schemaoptions.include.md) | [IncludeOptions](./js-yaml-schema.includeoptions.md) | |
+
diff --git a/docs/api/js-yaml-schema.streamtype.md b/docs/api/js-yaml-schema.streamtype.md
new file mode 100644
index 0000000..e24f4a9
--- /dev/null
+++ b/docs/api/js-yaml-schema.streamtype.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [streamType](./js-yaml-schema.streamtype.md)
+
+## streamType variable
+
+
+Signature:
+
+```typescript
+streamType: YamlType
+```
diff --git a/src/index.ts b/src/index.ts
index 217f26b..ed9f453 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
-export { CONFIG_SCHEMA } from './schema';
+export { createSchema, SchemaOptions } from './schema';
export { envType } from './type/Env';
-export { includeOptions, includeType, IncludeOptions } from './type/Include';
+export { createInclude, IncludeOptions } from './type/Include';
export { regexpType } from './type/Regexp';
export { streamType } from './type/Stream';
diff --git a/src/schema.ts b/src/schema.ts
index 91d0402..5f04e02 100644
--- a/src/schema.ts
+++ b/src/schema.ts
@@ -1,20 +1,29 @@
import { DEFAULT_SAFE_SCHEMA, Schema } from 'js-yaml';
import { envType } from './type/Env';
-import { includeOptions, includeType } from './type/Include';
+import { createInclude, IncludeOptions } from './type/Include';
import { regexpType } from './type/Regexp';
import { streamType } from './type/Stream';
+export interface SchemaOptions {
+ include: IncludeOptions;
+}
+
/**
* Safe schema with additional library types added.
*
* @public
*/
-export const CONFIG_SCHEMA = Schema.create([DEFAULT_SAFE_SCHEMA], [
- envType,
- includeType,
- regexpType,
- streamType,
-]);
+export function createSchema(options: SchemaOptions) {
+ const includeType = createInclude(options.include);
+ const schema = Schema.create([DEFAULT_SAFE_SCHEMA], [
+ envType,
+ includeType,
+ regexpType,
+ streamType,
+ ]);
-includeOptions.schema = CONFIG_SCHEMA;
+ options.include.schema = schema;
+
+ return schema;
+}
diff --git a/src/type/Env.ts b/src/type/Env.ts
index 06c66c8..0b64f50 100644
--- a/src/type/Env.ts
+++ b/src/type/Env.ts
@@ -2,7 +2,7 @@ import { NotFoundError } from '@apextoaster/js-utils';
import { Type as YamlType } from 'js-yaml';
/**
- * @internal
+ * @public
*/
export const envType = new YamlType('!env', {
kind: 'scalar',
diff --git a/src/type/Include.ts b/src/type/Include.ts
index 88354e3..811b06d 100644
--- a/src/type/Include.ts
+++ b/src/type/Include.ts
@@ -1,5 +1,5 @@
-import { InvalidArgumentError, NotFoundError, NotImplementedError } from '@apextoaster/js-utils';
-import { SAFE_SCHEMA, safeLoad, Schema, Type as YamlType } from 'js-yaml';
+import { InvalidArgumentError, NotFoundError } from '@apextoaster/js-utils';
+import { safeLoad, Schema, Type as YamlType } from 'js-yaml';
export interface ReaderOptions {
encoding: string;
@@ -16,62 +16,36 @@ export interface IncludeOptions {
}
/**
- * The schema to be used for included files. This is necessary to work around circular dependency errors.
- *
+ * Instantiate an includer with closure over the provided options.
* @public
*/
-export const includeOptions: IncludeOptions = {
- exists: (path: string) => false,
- join: (...path: Array) => {
- throw new NotImplementedError('join stub');
- },
- read: (path: string, encoding: ReaderOptions) => {
- throw new NotImplementedError('read stub');
- },
- resolve: (path: string) => {
- throw new NotImplementedError('resolve stub');
- },
- schema: SAFE_SCHEMA,
-};
-
-/**
- * @internal
- */
-export const includeType = new YamlType('!include', {
- kind: 'scalar',
- resolve(path: string) {
- try {
- const canonical = resolvePath(path);
- // throws in node 11+
- if (includeOptions.exists(canonical)) {
- return true;
- } else {
- throw new NotFoundError('included file does not exist');
+export function createInclude(includeOptions: IncludeOptions) {
+ return new YamlType('!include', {
+ kind: 'scalar',
+ resolve(path: string) {
+ try {
+ const canonical = includeOptions.resolve(path);
+ // throws in node 11+
+ if (includeOptions.exists(canonical)) {
+ return true;
+ } else {
+ throw new NotFoundError('included file does not exist');
+ }
+ } catch (err) {
+ throw new NotFoundError('included file does not exist', err);
}
- } catch (err) {
- throw new NotFoundError('included file does not exist', err);
- }
- },
- construct(path: string): unknown {
- try {
- return safeLoad(includeOptions.read(resolvePath(path), {
- encoding: 'utf-8',
- }), {
- schema: includeOptions.schema,
- });
- } catch (err) {
- throw new InvalidArgumentError('error including file', err);
- }
- },
-});
-
-/**
- * @todo take root parameter instead of __dirname
- */
-export function resolvePath(path: string): string {
- if (path[0] === '.') {
- return includeOptions.resolve(includeOptions.join(__dirname, path));
- } else {
- return includeOptions.resolve(path);
- }
+ },
+ construct(path: string): unknown {
+ try {
+ const abs = includeOptions.resolve(path);
+ return safeLoad(includeOptions.read(abs, {
+ encoding: 'utf-8',
+ }), {
+ schema: includeOptions.schema,
+ });
+ } catch (err) {
+ throw new InvalidArgumentError('error including file', err);
+ }
+ },
+ });
}
diff --git a/src/type/Regexp.ts b/src/type/Regexp.ts
index 7ce3843..5d578ed 100644
--- a/src/type/Regexp.ts
+++ b/src/type/Regexp.ts
@@ -4,7 +4,7 @@ import { Type as YamlType } from 'js-yaml';
export const REGEXP_REGEXP = /^\/(.+)\/([gimsuy]*)$/;
/**
- * @internal
+ * @public
*/
export const regexpType = new YamlType('!regexp', {
kind: 'scalar',
diff --git a/src/type/Stream.ts b/src/type/Stream.ts
index 96b15eb..599aba4 100644
--- a/src/type/Stream.ts
+++ b/src/type/Stream.ts
@@ -7,7 +7,7 @@ const ALLOWED_STREAMS = new Set([
]);
/**
- * @internal
+ * @public
*/
export const streamType = new YamlType('!stream', {
kind: 'scalar',
diff --git a/test/type/TestInclude.ts b/test/type/TestInclude.ts
index e2566e4..61c4d29 100644
--- a/test/type/TestInclude.ts
+++ b/test/type/TestInclude.ts
@@ -1,38 +1,33 @@
import { InvalidArgumentError, NotFoundError } from '@apextoaster/js-utils';
import { expect } from 'chai';
+import { DEFAULT_SAFE_SCHEMA } from 'js-yaml';
import { join } from 'path';
-import { IncludeOptions, includeOptions, includeType } from '../../src/type/Include';
+import { createInclude, IncludeOptions } from '../../src/type/Include';
const TEST_ROOT = '../test/type';
-const ORIGINAL_SCHEMA: IncludeOptions = {
- ...includeOptions,
+const TEST_OPTIONS: IncludeOptions = {
+ exists: () => true,
+ join: (...path) => path.join('/'),
+ read: () => 'test',
+ resolve: (path: string) => path,
+ schema: DEFAULT_SAFE_SCHEMA,
};
describe('include config type', async () => {
- beforeEach(() => {
- includeOptions.exists = () => true;
- includeOptions.join = (...path) => path.join('/');
- includeOptions.read = () => 'test';
- includeOptions.resolve = (path: string) => path;
- });
-
- afterEach(() => {
- 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 () => {
+ const includeType = createInclude(TEST_OPTIONS);
expect(includeType.resolve(join(TEST_ROOT, 'include.yml'))).to.equal(true);
});
it('should throw when resolving missing files', async () => {
- includeOptions.resolve = () => {
- throw new NotFoundError();
- };
+ const includeType = createInclude({
+ ...TEST_OPTIONS,
+ resolve: () => {
+ throw new NotFoundError();
+ },
+ });
expect(() => {
includeType.resolve(join(TEST_ROOT, 'missing.yml'));
@@ -40,13 +35,17 @@ describe('include config type', async () => {
});
it('should construct data from file', async () => {
+ const includeType = createInclude(TEST_OPTIONS);
expect(includeType.construct(join(TEST_ROOT, 'include.yml'))).to.equal('test');
});
it('should throw when constructing missing files', async () => {
- includeOptions.read = () => {
- throw new InvalidArgumentError();
- };
+ const includeType = createInclude({
+ ...TEST_OPTIONS,
+ read: () => {
+ throw new InvalidArgumentError();
+ },
+ });
expect(() => {
includeType.construct(join(TEST_ROOT, 'missing.yml'));