mirror of https://github.com/lukechilds/ow.git
committed by
Sindre Sorhus
13 changed files with 147 additions and 77 deletions
@ -1,2 +1,5 @@ |
|||
node_modules |
|||
yarn.lock |
|||
.nyc_output |
|||
coverage |
|||
dist |
|||
|
@ -1,66 +0,0 @@ |
|||
'use strict'; |
|||
const is = require('@sindresorhus/is'); |
|||
|
|||
class ArgumentError extends Error { |
|||
constructor(message, context) { |
|||
super(message); |
|||
// TODO: Node does not preserve the error name in output when using the below, why?
|
|||
//Error.captureStackTrace(this, context);
|
|||
this.name = 'ArgumentError'; |
|||
} |
|||
} |
|||
|
|||
const ow = (value, predicate) => { |
|||
for (const validator of predicate.context.validators) { |
|||
const result = validator(value); |
|||
if (result) { |
|||
// TODO: Modify the stack output to show the original `ow()` call instead of this `throw` statement
|
|||
throw new ArgumentError(result, ow); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const newInstance = (fn, context) => { |
|||
const instance = fn(context); |
|||
instance.context = context; |
|||
return instance; |
|||
}; |
|||
|
|||
const stringPredicates = context => ({ |
|||
minLength: number => { |
|||
context.validators.push(value => { |
|||
if (value.length < number) { |
|||
return `Expected string length to be minimum ${number}`; |
|||
} |
|||
}); |
|||
return newInstance(stringPredicates, context); |
|||
}, |
|||
get alphanumeric() { |
|||
context.validators.push(value => { |
|||
if (/[a-z\d]/gi.test(value)) { |
|||
return `Expected string to contain only alphanumeric characters but received \`${value}\``; |
|||
} |
|||
}); |
|||
return newInstance(stringPredicates, context); |
|||
} |
|||
}); |
|||
|
|||
Object.defineProperty(ow, 'string', { |
|||
enumerable: true, |
|||
get() { |
|||
const instance = newInstance(stringPredicates, { |
|||
validators: [] |
|||
}); |
|||
|
|||
instance.context.validators.push(value => { |
|||
// TODO: Create a generic function for all types that can be used here
|
|||
if (!is.string(value)) { |
|||
return `Expected argument to be of type \`string\` but received type \`${is(value)}\``; |
|||
} |
|||
}); |
|||
|
|||
return instance; |
|||
} |
|||
}); |
|||
|
|||
module.exports = ow; |
@ -0,0 +1,3 @@ |
|||
import { ow } from './ow'; |
|||
|
|||
export = ow; |
@ -0,0 +1,8 @@ |
|||
export class ArgumentError extends Error { |
|||
constructor(message, context) { |
|||
super(message); |
|||
// TODO: Node does not preserve the error name in output when using the below, why?
|
|||
//Error.captureStackTrace(this, context);
|
|||
this.name = 'ArgumentError'; |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
import * as is from '@sindresorhus/is'; |
|||
|
|||
export type Validator = (value: any) => string | undefined; |
|||
|
|||
export interface Context { |
|||
validators: Validator[]; |
|||
} |
|||
|
|||
export class Predicate { |
|||
constructor( |
|||
type: string, |
|||
public context: Context = { validators: [] } |
|||
) { |
|||
this.context.validators.push(value => { |
|||
if (!is[type](value)) { |
|||
return `Expected argument to be of type \`${type}\` but received type \`${is(value)}\``; |
|||
} |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
import { Predicate, Context } from './predicate'; |
|||
|
|||
export class StringPredicate extends Predicate { |
|||
|
|||
constructor(context?: Context) { |
|||
super('string', context); |
|||
} |
|||
|
|||
/** |
|||
* Test a string to have a minimum length. |
|||
* |
|||
* @param number The minimum length of the string. |
|||
*/ |
|||
minLength(number: number) { |
|||
this.context.validators.push(value => { |
|||
if (value.length < number) { |
|||
return `Expected string length to be minimum ${number}`; |
|||
} |
|||
}); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Test a string to be alphanumeric. |
|||
*/ |
|||
get alphanumeric() { |
|||
this.context.validators.push(value => { |
|||
if (!/^[a-z\d]+$/i.test(value)) { |
|||
return `Expected string to contain only alphanumeric characters but received \`${value}\``; |
|||
} |
|||
}); |
|||
|
|||
return this; |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
import * as is from '@sindresorhus/is'; |
|||
import { ArgumentError } from './lib/argument-error'; |
|||
import { Predicate } from './lib/predicates/predicate'; |
|||
import { StringPredicate } from './lib/predicates/string'; |
|||
|
|||
export interface Ow { |
|||
(value: any, predicate: Predicate): void; |
|||
/** |
|||
* Test the value to be a string. |
|||
*/ |
|||
string?: StringPredicate; |
|||
} |
|||
|
|||
export const ow: Ow = (value: any, predicate: Predicate) => { |
|||
for (const validator of predicate.context.validators) { |
|||
const result = validator(value); |
|||
if (result) { |
|||
// TODO: Modify the stack output to show the original `ow()` call instead of this `throw` statement
|
|||
throw new ArgumentError(result, ow); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
ow.string = new StringPredicate(); |
@ -0,0 +1,18 @@ |
|||
import test from 'ava'; |
|||
import * as m from '..'; |
|||
|
|||
test('string', t => { |
|||
t.notThrows(() => m('foo', m.string)); |
|||
t.throws(() => m(12, m.string), 'Expected argument to be of type `string` but received type `number`'); |
|||
}); |
|||
|
|||
test('string.minLength', t => { |
|||
t.notThrows(() => m('foo', m.string.minLength(2))); |
|||
t.notThrows(() => m('foo', m.string.minLength(3))); |
|||
t.throws(() => m('foo', m.string.minLength(4)), 'Expected string length to be minimum 4'); |
|||
}); |
|||
|
|||
test('string.alphanumeric', t => { |
|||
t.notThrows(() => m('Foo123', m.string.alphanumeric)); |
|||
t.throws(() => m('Foo123!', m.string.alphanumeric), 'Expected string to contain only alphanumeric characters but received `Foo123!`'); |
|||
}); |
@ -1,6 +0,0 @@ |
|||
import test from 'ava'; |
|||
import m from '.'; |
|||
|
|||
test('', t => { |
|||
|
|||
}); |
@ -0,0 +1,20 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"target": "es2016", |
|||
"module": "commonjs", |
|||
"declaration": false, |
|||
"removeComments": false, |
|||
"pretty": true, |
|||
"allowUnreachableCode": false, |
|||
"allowUnusedLabels": false, |
|||
"noImplicitAny": false, |
|||
"noImplicitUseStrict": false, |
|||
"noFallthroughCasesInSwitch": true, |
|||
"allowSyntheticDefaultImports": true, |
|||
"outDir": "dist" |
|||
}, |
|||
"exclude": [ |
|||
"node_modules", |
|||
"dist" |
|||
] |
|||
} |
Loading…
Reference in new issue