Skip to content

Commit

Permalink
Feature: Allow schema to be free-form sindresorhus#80
Browse files Browse the repository at this point in the history
  • Loading branch information
dawidgarus committed Mar 20, 2022
1 parent 07f5344 commit 06a550f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 10 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"debounce-fn": "^4.0.0",
"dot-prop": "^6.0.1",
"env-paths": "^2.2.1",
"json-schema-typed": "^7.0.3",
"json-schema-typed": "^8.0.0",
"onetime": "^5.1.2",
"pkg-up": "^3.1.0",
"semver": "^7.3.5"
Expand Down
22 changes: 18 additions & 4 deletions source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@ import debounceFn = require('debounce-fn');
import semver = require('semver');
import onetime = require('onetime');
import {JSONSchema} from 'json-schema-typed';
import {Deserialize, Migrations, OnDidChangeCallback, Options, Serialize, Unsubscribe, Schema, OnDidAnyChangeCallback} from './types';
import {
Deserialize,
Migrations,
OnDidChangeCallback,
Options,
Serialize,
Unsubscribe,
Schema,
OnDidAnyChangeCallback,
ObjectSchema
} from './types';

const encryptionAlgorithm = 'aes-256-cbc';

Expand Down Expand Up @@ -49,6 +59,10 @@ const checkValueType = (key: string, value: unknown): void => {
}
};

const isObjectJSONSchema = <T>(schema: Schema<T>): schema is ObjectSchema => {
return typeof schema === 'object' && 'type' in schema && schema.type === 'object';
};

const INTERNAL_KEY = '__internal__';
const MIGRATION_KEY = `${INTERNAL_KEY}.migrations.version`;

Expand Down Expand Up @@ -105,15 +119,15 @@ class Conf<T extends Record<string, any> = Record<string, unknown>> implements I
});
ajvFormats(ajv);

const schema: JSONSchema = {
const schema: JSONSchema = isObjectJSONSchema(options.schema) ? options.schema : {
type: 'object',
properties: options.schema
};

this.#validator = ajv.compile(schema);

for (const [key, value] of Object.entries<JSONSchema>(options.schema)) {
if (value?.default) {
for (const [key, value] of Object.entries<JSONSchema>(schema.properties!)) {
if (value && typeof value === 'object' && value.default) {
this.#defaultValues[key as keyof T] = value.default;
}
}
Expand Down
5 changes: 3 additions & 2 deletions source/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,9 @@ export interface Options<T> {

export type Migrations<T> = Record<string, (store: Conf<T>) => void>;

export type Schema<T> = {[Property in keyof T]: ValueSchema};
export type ValueSchema = TypedJSONSchema;
export type Schema<T> = ObjectSchema | {[Property in keyof T]: ValueSchema<T[Property]>};
export type ObjectSchema = TypedJSONSchema<Record<string | number, unknown>>;
export type ValueSchema<T> = TypedJSONSchema<T>;

export type Serialize<T> = (value: T) => string;
export type Deserialize<T> = (text: string) => T;
Expand Down
30 changes: 27 additions & 3 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,30 @@ test('schema - valid set', t => {
});
});

test('schema - valid set with full schema', t => {
const schema: Schema<{foo: {bar: number; foobar: number}}> = {
type: 'object',
properties: {
foo: {
type: 'object',
properties: {
bar: {
type: 'number'
},
foobar: {
type: 'number',
maximum: 100
}
}
}
}
};
const config = new Conf({cwd: tempy.directory(), schema});
t.notThrows(() => {
config.set('foo', {bar: 1, foobar: 2});
});
});

test('schema - one violation', t => {
const config = new Conf({
cwd: tempy.directory(),
Expand Down Expand Up @@ -835,11 +859,11 @@ test('schema - validate Conf default', t => {
new Conf({
cwd: tempy.directory(),
defaults: {
// For our tests to fail and typescript to compile, we'll ignore this ts error.
// This error is not bad and means the package is well typed.
// @ts-expect-error
foo: 1
},
// For our tests to fail and typescript to compile, we'll ignore this ts error.
// This error is not bad and means the package is well typed.
// @ts-expect-error
schema
});
}, {message: 'Config schema violation: `foo` must be string'});
Expand Down

0 comments on commit 06a550f

Please sign in to comment.