Skip to content

Commit

Permalink
feat(validations): add validateOptions module
Browse files Browse the repository at this point in the history
  • Loading branch information
joshwiens committed Jan 29, 2017
1 parent 8593f31 commit ae9b47b
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { validateOptions } from './lib/validate-options';

export default validateOptions;
17 changes: 17 additions & 0 deletions src/lib/validate-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Ajv from 'ajv';

const validateOptions = (schema, data) => {
// This mutates the original data with defaults!
const ajv = new Ajv({
useDefaults: true,
errorDataPath: 'property',
});
const isValid = ajv.validate(schema, data);

return {
isValid,
error: ajv.errors && ajv.errorsText(),
};
};

export default validateOptions;
129 changes: 129 additions & 0 deletions src/lib/validate-options.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import assert from 'assert';
import validateOptions from './validate-options';

const generateProperties = (entry) => {
const ret = {};

Object.keys(entry).forEach((e) => {
ret[e] = {
type: ['array', 'string'],
items: {
type: 'string',
},
};
});

return ret;
};

const parsePaths = (entry) => {
const ret = {
type: ['array', 'object'],
};

if (entry instanceof Object) {
ret.additionalProperties = false;
ret.properties = generateProperties(entry);
} else {
ret.items = {
type: 'string',
};
}

return ret;
};

const testSchema = ({ entry } = {}) => {
return {
$schema: 'http://json-schema.org/draft-04/schema#',
additionalProperties: false,
type: 'object',
properties: {
styleExtensions: {
type: 'array',
items: {
type: 'string',
},
default: ['.css'],
},
minimize: {
type: 'boolean',
},
moduleExtensions: {
type: 'array',
items: {
type: 'string',
},
},
paths: parsePaths(entry),
purifyOptions: {
type: 'object',
properties: {},
},
verbose: {
type: 'boolean',
},
},
required: [
'paths',
],
};
};

describe('Validate options', () => {
it('fails without a schema and data', () => {
assert.throws(
() => {
validateOptions();
},
Error,
);
});

it('fails with empty data', () => {
const result = validateOptions(testSchema());

assert.ok(!result.isValid);
assert.ok(result.error);
});

it('does not fail if paths are provided', () => {
const result = validateOptions(testSchema(), { paths: ['./foo'] });

assert.ok(result.isValid);
assert.ok(!result.error);
});

it('does not allow arbitrary properties', () => {
const result = validateOptions(testSchema(), { paths: ['./foo'], foobar: ['./foo'] });

assert.ok(!result.isValid);
assert.ok(result.error);
});

it('styleExtensions have defaults', () => {
const paths = ['./foo'];
const data = { paths };

const result = validateOptions(testSchema(), data);

assert.deepEqual(data, { paths, styleExtensions: ['.css'] });
assert.ok(!result.error);
});

it('fails without matching path keys', () => {
const data = {
paths: {
a: './foo',
},
};

const result = validateOptions(testSchema({
entry: {
b: './bar',
},
}), data);

assert.ok(result.error);
});
});

0 comments on commit ae9b47b

Please sign in to comment.