typescript-is
Advanced tools
Comparing version 0.13.1 to 0.14.0
124
index.d.ts
@@ -117,18 +117,5 @@ /** | ||
/** | ||
* Options for the `AssertType` decorator. | ||
*/ | ||
export interface AssertTypeOptions { | ||
/** | ||
* Message that will be passed to the error constructor, in case type assertion fails. | ||
*/ | ||
message?: string; | ||
} | ||
/** | ||
* Creates a type assertion and saves it in the reflection metadata of the method's class. | ||
* Then, when the class is decorated with `ValidateClass`, the method's arguments will be validated. | ||
* | ||
* @param options options for the decorator. | ||
* Check `AssertTypeOptions` documentation for more information. | ||
* | ||
* @example | ||
@@ -142,3 +129,3 @@ * ``` | ||
*/ | ||
export function AssertType(options?: AssertTypeOptions): (target: object, propertyKey: string | symbol, parameterIndex: number) => void; | ||
export function AssertType(): (target: object, propertyKey: string | symbol, parameterIndex: number) => void; | ||
@@ -182,9 +169,110 @@ /** | ||
*/ | ||
export class TypeGuardError extends Error { } | ||
export class TypeGuardError extends Error { | ||
public readonly path: string; | ||
public readonly reason: Reason; | ||
} | ||
interface ExpectedString { | ||
type: 'string'; | ||
} | ||
interface ExpectedNumber { | ||
type: 'number'; | ||
} | ||
interface ExpectedBigInt { | ||
type: 'big-int'; | ||
} | ||
interface ExpectedBoolean { | ||
type: 'boolean'; | ||
} | ||
interface ExpectedStringLiteral { | ||
type: 'string-literal'; | ||
value: string; | ||
} | ||
interface ExpectedNumberLiteral { | ||
type: 'number-literal'; | ||
value: number; | ||
} | ||
interface ExpectedBooleanLiteral { | ||
type: 'boolean-literal'; | ||
value: boolean; | ||
} | ||
interface ExpectedObject { | ||
type: 'object'; | ||
} | ||
interface ExpectedNonPrimitive { | ||
type: 'non-primitive'; | ||
} | ||
interface MissingObjectProperty { | ||
type: 'missing-property'; | ||
property: string; | ||
} | ||
interface SuperfluousObjectProperty { | ||
type: 'superfluous-property'; | ||
} | ||
interface ExpectedObjectKeyof { | ||
type: 'object-keyof'; | ||
properties: string[]; | ||
} | ||
interface ExpectedArray { | ||
type: 'array'; | ||
} | ||
interface NeverType { | ||
type: 'never'; | ||
} | ||
interface ExpectedTuple { | ||
type: 'tuple'; | ||
minLength: number; | ||
maxLength: number; | ||
} | ||
interface NoValidUnionAlternatives { | ||
type: 'union'; | ||
} | ||
interface ExpectedUndefined { | ||
type: 'undefined'; | ||
} | ||
interface ExpectedNull { | ||
type: 'null'; | ||
} | ||
type Reason = ExpectedString | ||
| ExpectedNumber | ||
| ExpectedBigInt | ||
| ExpectedBoolean | ||
| ExpectedObject | ||
| ExpectedNonPrimitive | ||
| MissingObjectProperty | ||
| SuperfluousObjectProperty | ||
| ExpectedObjectKeyof | ||
| ExpectedArray | ||
| ExpectedTuple | ||
| NeverType | ||
| NoValidUnionAlternatives | ||
| ExpectedUndefined | ||
| ExpectedNull | ||
| ExpectedStringLiteral | ||
| ExpectedNumberLiteral | ||
| ExpectedBooleanLiteral; | ||
/** | ||
* Set default getErrorMessage function used for transpiled source. | ||
* Set default getErrorObject function used for transpiled source. | ||
* | ||
* @param getErrorMessage | ||
* @param getErrorObject | ||
*/ | ||
export function setDefaultGetErrorMessage(getErrorMessage?: () => string | null): void; | ||
export function setDefaultGetErrorObject(getErrorObject?: () => string | null): void; |
54
index.js
@@ -1,5 +0,5 @@ | ||
let defaultGetErrorMessage = undefined; | ||
let defaultGetErrorObject = undefined; | ||
function checkGetErrorMessage(getErrorMessage) { | ||
if (typeof getErrorMessage !== 'function') { | ||
function checkGetErrorObject(getErrorObject) { | ||
if (typeof getErrorObject !== 'function') { | ||
throw new Error('This module should not be used in runtime. Instead, use a transformer during compilation.'); | ||
@@ -12,5 +12,7 @@ } | ||
class TypeGuardError extends Error { | ||
constructor(...args) { | ||
super(...args); | ||
constructor(errorObject) { | ||
super(errorObject.message); | ||
this.name = 'TypeGuardError'; | ||
this.path = errorObject.path; | ||
this.reason = errorObject.reason; | ||
} | ||
@@ -37,5 +39,5 @@ } | ||
for (let i = 0; i < assertions.length; i++) { | ||
const errorMessage = assertions[i].assertion(args[i]); | ||
if (errorMessage !== null) { | ||
throw new errorConstructor(assertions[i].options.message || errorMessage); | ||
const errorObject = assertions[i].assertion(args[i]); | ||
if (errorObject !== null) { | ||
throw new errorConstructor(errorObject); | ||
} | ||
@@ -50,30 +52,30 @@ } | ||
function is(obj, getErrorMessage = defaultGetErrorMessage) { | ||
checkGetErrorMessage(getErrorMessage); | ||
const errorMessage = getErrorMessage(obj); | ||
return errorMessage === null; | ||
function is(obj, getErrorObject = defaultGetErrorObject) { | ||
checkGetErrorObject(getErrorObject); | ||
const errorObject = getErrorObject(obj); | ||
return errorObject === null; | ||
} | ||
function assertType(obj, getErrorMessage = defaultGetErrorMessage) { | ||
checkGetErrorMessage(getErrorMessage); | ||
const errorMessage = getErrorMessage(obj); | ||
if (errorMessage === null) { | ||
function assertType(obj, getErrorObject = defaultGetErrorObject) { | ||
checkGetErrorObject(getErrorObject); | ||
const errorObject = getErrorObject(obj); | ||
if (errorObject === null) { | ||
return obj; | ||
} else { | ||
throw new TypeGuardError(errorMessage); | ||
throw new TypeGuardError(errorObject); | ||
} | ||
} | ||
function createIs(getErrorMessage = defaultGetErrorMessage) { | ||
checkGetErrorMessage(getErrorMessage); | ||
return (obj) => is(obj, getErrorMessage); | ||
function createIs(getErrorObject = defaultGetErrorObject) { | ||
checkGetErrorObject(getErrorObject); | ||
return (obj) => is(obj, getErrorObject); | ||
} | ||
function createAssertType(getErrorMessage = defaultGetErrorMessage) { | ||
checkGetErrorMessage(getErrorMessage); | ||
return (obj) => assertType(obj, getErrorMessage); | ||
function createAssertType(getErrorObject = defaultGetErrorObject) { | ||
checkGetErrorObject(getErrorObject); | ||
return (obj) => assertType(obj, getErrorObject); | ||
} | ||
function setDefaultGetErrorMessage(getErrorMessage) { | ||
defaultGetErrorMessage = getErrorMessage; | ||
function setDefaultGetErrorObject(getErrorObject) { | ||
defaultGetErrorObject = getErrorObject; | ||
} | ||
@@ -93,3 +95,3 @@ | ||
TypeGuardError, | ||
setDefaultGetErrorMessage | ||
setDefaultGetErrorObject | ||
}; |
@@ -55,3 +55,3 @@ "use strict"; | ||
const condition = VisitorUtils.createBinaries(names.map((name) => ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createStringLiteral(name))), ts.SyntaxKind.AmpersandAmpersandToken, ts.createTrue()); | ||
return VisitorUtils.createAssertionFunction(condition, `expected ${names.map((name) => `'${name}'`).join('|')}`, name); | ||
return VisitorUtils.createAssertionFunction(condition, { type: 'object-keyof', properties: names }, name); | ||
}); | ||
@@ -58,0 +58,0 @@ } |
@@ -34,7 +34,3 @@ "use strict"; | ||
ts.createBinary(ts.createNumericLiteral(maxLength.toString()), ts.SyntaxKind.LessThanToken, ts.createPropertyAccess(VisitorUtils.objectIdentifier, 'length')) | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: expected an array with length ${minLength}-${maxLength}`) | ||
], ts.SyntaxKind.PlusToken))), | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createErrorObject({ type: 'tuple', minLength, maxLength }))), | ||
...functionNames.map((functionName, index) => ts.createBlock([ | ||
@@ -65,7 +61,3 @@ ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'push'), undefined, [ts.createStringLiteral(`[${index}]`)])), | ||
], undefined, ts.createBlock([ | ||
ts.createIf(ts.createLogicalNot(ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Array'), 'isArray'), undefined, [VisitorUtils.objectIdentifier])), ts.createReturn(VisitorUtils.createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(': expected an array') | ||
], ts.SyntaxKind.PlusToken))), | ||
ts.createIf(ts.createLogicalNot(ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Array'), 'isArray'), undefined, [VisitorUtils.objectIdentifier])), ts.createReturn(VisitorUtils.createErrorObject({ type: 'array' }))), | ||
ts.createFor(ts.createVariableDeclarationList([ts.createVariableDeclaration(indexIdentifier, undefined, ts.createNumericLiteral('0'))], ts.NodeFlags.Let), ts.createBinary(indexIdentifier, ts.SyntaxKind.LessThanToken, ts.createPropertyAccess(VisitorUtils.objectIdentifier, 'length')), ts.createPostfixIncrement(indexIdentifier), ts.createBlock([ | ||
@@ -104,7 +96,3 @@ ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'push'), undefined, [ | ||
ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Array'), 'isArray'), undefined, [VisitorUtils.objectIdentifier]) | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(': expected an object') | ||
], ts.SyntaxKind.PlusToken))), | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createErrorObject({ type: 'object' }))), | ||
...propertyInfos.map((propertyInfo) => { | ||
@@ -127,7 +115,3 @@ if (propertyInfo.isSymbol) { | ||
? undefined | ||
: ts.createReturn(VisitorUtils.createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: expected '${propertyInfo.name}' in object`) | ||
], ts.SyntaxKind.PlusToken))) | ||
: ts.createReturn(VisitorUtils.createErrorObject({ type: 'missing-property', property: propertyInfo.name }))) | ||
]); | ||
@@ -193,3 +177,3 @@ }), | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createStringLiteral(value)), `expected string '${type.value}'`, name); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createStringLiteral(value)), { type: 'string-literal', value }, name); | ||
}); | ||
@@ -199,4 +183,5 @@ } | ||
const name = VisitorTypeName.visitType(type, visitorContext, { type: 'type-check' }); | ||
const value = type.value; | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createNumericLiteral(type.value.toString())), `expected number '${type.value}'`, name); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createNumericLiteral(value.toString())), { type: 'number-literal', value }, name); | ||
}); | ||
@@ -241,3 +226,3 @@ } | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createTrue()), `expected true`, name); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createTrue()), { type: 'boolean-literal', value: true }, name); | ||
}); | ||
@@ -248,3 +233,3 @@ } | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createFalse()), `expected false`, name); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createFalse()), { type: 'boolean-literal', value: false }, name); | ||
}); | ||
@@ -270,3 +255,3 @@ } | ||
const condition = VisitorUtils.createBinaries(conditions, ts.SyntaxKind.AmpersandAmpersandToken); | ||
return VisitorUtils.createAssertionFunction(ts.createLogicalNot(condition), `expected a non-primitive`, name); | ||
return VisitorUtils.createAssertionFunction(ts.createLogicalNot(condition), { type: 'non-primitive' }, name); | ||
}); | ||
@@ -297,3 +282,3 @@ } | ||
function visitBigInt(visitorContext) { | ||
return VisitorUtils.getBigintFunction(visitorContext); | ||
return VisitorUtils.getBigIntFunction(visitorContext); | ||
} | ||
@@ -300,0 +285,0 @@ function visitBoolean(visitorContext) { |
@@ -96,3 +96,3 @@ "use strict"; | ||
else if (VisitorUtils.isBigIntType(type)) { | ||
name = VisitorUtils.getBigintFunction(visitorContext); | ||
name = VisitorUtils.getBigIntFunction(visitorContext); | ||
} | ||
@@ -99,0 +99,0 @@ else if ((ts.TypeFlags.Boolean & type.flags) !== 0) { |
import * as ts from 'typescript'; | ||
import { VisitorContext } from './visitor-context'; | ||
import { Reason } from '../../index'; | ||
export declare const objectIdentifier: ts.Identifier; | ||
@@ -18,3 +19,3 @@ export declare const pathIdentifier: ts.Identifier; | ||
export declare function getBooleanFunction(visitorContext: VisitorContext): string; | ||
export declare function getBigintFunction(visitorContext: VisitorContext): string; | ||
export declare function getBigIntFunction(visitorContext: VisitorContext): string; | ||
export declare function getNumberFunction(visitorContext: VisitorContext): string; | ||
@@ -29,7 +30,7 @@ export declare function getUndefinedFunction(visitorContext: VisitorContext): string; | ||
export declare function createAcceptingFunction(functionName: string): ts.FunctionDeclaration; | ||
export declare function createRejectingFunction(reason: string, functionName: string): ts.FunctionDeclaration; | ||
export declare function createConjunctionFunction(functionNames: string[], functionName: string, extraStatements?: ts.Statement[]): ts.FunctionDeclaration; | ||
export declare function createDisjunctionFunction(functionNames: string[], functionName: string): ts.FunctionDeclaration; | ||
export declare function createAssertionFunction(failureCondition: ts.Expression, reason: string, functionName: string): ts.FunctionDeclaration; | ||
export declare function createAssertionFunction(failureCondition: ts.Expression, expected: Reason, functionName: string): ts.FunctionDeclaration; | ||
export declare function createSuperfluousPropertiesLoop(propertyNames: string[]): ts.ForOfStatement; | ||
export declare function isBigIntType(type: ts.Type): number | false; | ||
export declare function createErrorObject(reason: Reason): ts.Expression; |
@@ -7,2 +7,3 @@ "use strict"; | ||
exports.pathIdentifier = ts.createIdentifier('path'); | ||
const keyIdentifier = ts.createIdentifier('key'); | ||
function checkIsClass(type, visitorContext) { | ||
@@ -138,3 +139,3 @@ // Hacky: using internal TypeScript API. | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('string')), `expected a string`, name); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('string')), { type: 'string' }, name); | ||
}); | ||
@@ -146,17 +147,17 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('boolean')), 'expected a boolean', name); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('boolean')), { type: 'boolean' }, name); | ||
}); | ||
} | ||
exports.getBooleanFunction = getBooleanFunction; | ||
function getBigintFunction(visitorContext) { | ||
function getBigIntFunction(visitorContext) { | ||
const name = '_bigint'; | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('bigint')), 'expected a bigint', name); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('bigint')), { type: 'big-int' }, name); | ||
}); | ||
} | ||
exports.getBigintFunction = getBigintFunction; | ||
exports.getBigIntFunction = getBigIntFunction; | ||
function getNumberFunction(visitorContext) { | ||
const name = '_number'; | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('number')), 'expected a number', name); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('number')), { type: 'number' }, name); | ||
}); | ||
@@ -168,3 +169,3 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createIdentifier('undefined')), 'expected undefined', name); | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createIdentifier('undefined')), { type: 'undefined' }, name); | ||
}); | ||
@@ -176,3 +177,3 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createNull()), 'expected null', name); | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createNull()), { type: 'null' }, name); | ||
}); | ||
@@ -184,3 +185,7 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createRejectingFunction('type is never', name); | ||
return ts.createFunctionDeclaration(undefined, undefined, undefined, name, undefined, [ | ||
ts.createParameter(undefined, undefined, undefined, exports.objectIdentifier, undefined, undefined, undefined) | ||
], undefined, ts.createBlock([ | ||
ts.createReturn(createErrorObject({ type: 'never' })) | ||
])); | ||
}); | ||
@@ -223,14 +228,2 @@ } | ||
exports.createAcceptingFunction = createAcceptingFunction; | ||
function createRejectingFunction(reason, functionName) { | ||
return ts.createFunctionDeclaration(undefined, undefined, undefined, functionName, undefined, [ | ||
ts.createParameter(undefined, undefined, undefined, exports.objectIdentifier, undefined, undefined, undefined) | ||
], undefined, ts.createBlock([ | ||
ts.createReturn(createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(exports.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: ${reason}`) | ||
], ts.SyntaxKind.PlusToken)) | ||
])); | ||
} | ||
exports.createRejectingFunction = createRejectingFunction; | ||
function createConjunctionFunction(functionNames, functionName, extraStatements) { | ||
@@ -273,19 +266,11 @@ const conditionsIdentifier = ts.createIdentifier('conditions'); | ||
])), | ||
ts.createReturn(createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(exports.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: there are no valid alternatives`) | ||
], ts.SyntaxKind.PlusToken)) | ||
ts.createReturn(createErrorObject({ type: 'union' })) | ||
])); | ||
} | ||
exports.createDisjunctionFunction = createDisjunctionFunction; | ||
function createAssertionFunction(failureCondition, reason, functionName) { | ||
function createAssertionFunction(failureCondition, expected, functionName) { | ||
return ts.createFunctionDeclaration(undefined, undefined, undefined, functionName, undefined, [ | ||
ts.createParameter(undefined, undefined, undefined, exports.objectIdentifier, undefined, undefined, undefined) | ||
], undefined, ts.createBlock([ | ||
ts.createIf(failureCondition, ts.createReturn(createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(exports.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: ${reason}`) | ||
], ts.SyntaxKind.PlusToken)), ts.createReturn(ts.createNull())) | ||
ts.createIf(failureCondition, ts.createReturn(createErrorObject(expected)), ts.createReturn(ts.createNull())) | ||
])); | ||
@@ -295,11 +280,4 @@ } | ||
function createSuperfluousPropertiesLoop(propertyNames) { | ||
const keyIdentifier = ts.createIdentifier('key'); | ||
return ts.createForOf(undefined, ts.createVariableDeclarationList([ts.createVariableDeclaration(keyIdentifier, undefined, undefined)], ts.NodeFlags.Const), ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Object'), 'keys'), undefined, [exports.objectIdentifier]), ts.createBlock([ | ||
ts.createIf(createBinaries(propertyNames.map((propertyName) => ts.createStrictInequality(keyIdentifier, ts.createStringLiteral(propertyName))), ts.SyntaxKind.AmpersandAmpersandToken, ts.createTrue()), ts.createReturn(createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(exports.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: superfluous property '`), | ||
keyIdentifier, | ||
ts.createStringLiteral(`' in object`) | ||
], ts.SyntaxKind.PlusToken))) | ||
ts.createIf(createBinaries(propertyNames.map((propertyName) => ts.createStrictInequality(keyIdentifier, ts.createStringLiteral(propertyName))), ts.SyntaxKind.AmpersandAmpersandToken, ts.createTrue()), ts.createReturn(createErrorObject({ type: 'superfluous-property' }))) | ||
])); | ||
@@ -317,2 +295,103 @@ } | ||
exports.isBigIntType = isBigIntType; | ||
function createAssertionString(reason) { | ||
if (typeof reason === 'string') { | ||
return createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(exports.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: ${reason}`) | ||
], ts.SyntaxKind.PlusToken); | ||
} | ||
else { | ||
return createBinaries([ | ||
ts.createStringLiteral('validation failed at '), | ||
ts.createCall(ts.createPropertyAccess(exports.pathIdentifier, 'join'), undefined, [ts.createStringLiteral('.')]), | ||
ts.createStringLiteral(`: `), | ||
reason | ||
], ts.SyntaxKind.PlusToken); | ||
} | ||
} | ||
function createErrorObject(reason) { | ||
return ts.createObjectLiteral([ | ||
ts.createPropertyAssignment('message', createErrorMessage(reason)), | ||
ts.createPropertyAssignment('path', ts.createCall(ts.createPropertyAccess(exports.pathIdentifier, 'slice'), undefined, undefined)), | ||
ts.createPropertyAssignment('reason', serializeObjectToExpression(reason)) | ||
]); | ||
} | ||
exports.createErrorObject = createErrorObject; | ||
function serializeObjectToExpression(object) { | ||
if (typeof object === 'string') { | ||
return ts.createStringLiteral(object); | ||
} | ||
else if (typeof object === 'number') { | ||
return ts.createNumericLiteral(object.toString()); | ||
} | ||
else if (typeof object === 'boolean') { | ||
return object ? ts.createTrue() : ts.createFalse(); | ||
} | ||
else if (typeof object === 'bigint') { | ||
return ts.createBigIntLiteral(object.toString()); | ||
} | ||
else if (typeof object === 'undefined') { | ||
return ts.createIdentifier('undefined'); | ||
} | ||
else if (typeof object === 'object') { | ||
if (object === null) { | ||
return ts.createNull(); | ||
} | ||
else if (Array.isArray(object)) { | ||
return ts.createArrayLiteral(object.map((item) => serializeObjectToExpression(item))); | ||
} | ||
else { | ||
return ts.createObjectLiteral(Object.keys(object).map((key) => { | ||
const value = object[key]; | ||
return ts.createPropertyAssignment(key, serializeObjectToExpression(value)); | ||
})); | ||
} | ||
} | ||
throw new Error('Cannot serialize object to expression.'); | ||
} | ||
function createErrorMessage(reason) { | ||
switch (reason.type) { | ||
case 'tuple': | ||
return createAssertionString(`expected an array with length ${reason.minLength}-${reason.maxLength}`); | ||
case 'array': | ||
return createAssertionString('expected an array'); | ||
case 'object': | ||
return createAssertionString('expected an object'); | ||
case 'missing-property': | ||
return createAssertionString(`expected '${reason.property}' in object`); | ||
case 'superfluous-property': | ||
return createAssertionString(createBinaries([ | ||
ts.createStringLiteral(`superfluous property '`), | ||
keyIdentifier, | ||
ts.createStringLiteral(`' in object`) | ||
], ts.SyntaxKind.PlusToken)); | ||
case 'never': | ||
return createAssertionString('type is never'); | ||
case 'union': | ||
return createAssertionString('there are no valid alternatives'); | ||
case 'string': | ||
return createAssertionString('expected a string'); | ||
case 'boolean': | ||
return createAssertionString('expected a boolean'); | ||
case 'big-int': | ||
return createAssertionString('expected a bigint'); | ||
case 'number': | ||
return createAssertionString('expected a number'); | ||
case 'undefined': | ||
return createAssertionString('expected undefined'); | ||
case 'null': | ||
return createAssertionString('expected null'); | ||
case 'object-keyof': | ||
return createAssertionString(`expected ${reason.properties.map((property) => `'${property}'`).join('|')}`); | ||
case 'string-literal': | ||
return createAssertionString(`expected string '${reason.value}'`); | ||
case 'number-literal': | ||
return createAssertionString(`expected number '${reason.value}'`); | ||
case 'boolean-literal': | ||
return createAssertionString(`expected ${reason.value ? 'true' : 'false'}`); | ||
case 'non-primitive': | ||
return createAssertionString('expected a non-primitive'); | ||
} | ||
} | ||
//# sourceMappingURL=visitor-utils.js.map |
{ | ||
"name": "typescript-is", | ||
"version": "0.13.1", | ||
"version": "0.14.0", | ||
"engines": { | ||
@@ -52,3 +52,3 @@ "node": ">=6.14.4" | ||
"reflect-metadata": "^0.1.12", | ||
"rimraf": "^2.6.2", | ||
"rimraf": "^3.0.0", | ||
"ts-node": "^8.0.1", | ||
@@ -55,0 +55,0 @@ "tslint": "^5.11.0", |
@@ -277,8 +277,2 @@ # typescript-is | ||
* ~~More detailed error message when using `assertType` and `createAssertType`. | ||
Give the reason why the assertion failed to the user as part of the error.~~ | ||
[issue 2](https://github.com/woutervh-/typescript-is/issues/2) | ||
Done as of version `0.10.0`. | ||
* ~~Support detailed error message when using the decorators `@ValidateClass` and `@AssertType`.~~ | ||
* ~~Detect additional keys. [issue 11](https://github.com/woutervh-/typescript-is/issues/11)~~ Done as of version `0.11.0`. | ||
* Promise support. Something like `assertOrReject<Type>(object)` will either `resolve(object)` or `reject(error)`. | ||
@@ -285,0 +279,0 @@ * Optimize the generated conditions. Things like `false || "key" === "key"` can be simplified. Might be more interesting to publish a different library that can transform a TypeScript AST, and then use it here, or use an existing one. Might be out of scope, as there are plenty of minifiers/uglifiers/manglers out there already. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2623
208914
39
293