typescript-is
Advanced tools
Comparing version 0.18.3 to 0.19.0
@@ -128,3 +128,3 @@ /** | ||
*/ | ||
export function AssertType(): (target: object, propertyKey: string | symbol, parameterIndex: number) => void; | ||
export function AssertType(options?: { async: boolean }): (target: object, propertyKey: string | symbol, parameterIndex: number) => void; | ||
@@ -131,0 +131,0 @@ /** |
15
index.js
@@ -22,2 +22,4 @@ let defaultGetErrorObject = undefined; | ||
function appendInputToErrorMessage(message, path, inputObject) { | ||
if (message === undefined) | ||
return 'validation error'; | ||
const foundInputObject = inputObjectAtPath(path, inputObject); | ||
@@ -49,3 +51,7 @@ try { | ||
const assertions = Reflect.getOwnMetadata(assertionsMetadataKey, target, propertyKey) || []; | ||
assertions[parameterIndex] = { assertion, options }; | ||
if(Reflect.getOwnMetadata('design:returntype', target, propertyKey) === Promise) { | ||
assertions[parameterIndex] = { assertion, options: Object.assign({ async: true }, options) }; | ||
} else { | ||
assertions[parameterIndex] = { assertion, options }; | ||
} | ||
Reflect.defineMetadata(assertionsMetadataKey, assertions, target, propertyKey); | ||
@@ -69,3 +75,8 @@ }; | ||
if (errorObject !== null) { | ||
throw new errorConstructor(errorObject, args[i]); | ||
const errorInstance = new errorConstructor(errorObject, args[i]); | ||
if(assertions[i].options.async) { | ||
return Promise.reject(errorInstance); | ||
} else { | ||
throw errorInstance; | ||
} | ||
} | ||
@@ -72,0 +83,0 @@ } |
@@ -12,3 +12,5 @@ "use strict"; | ||
const functionNames = new Set(); | ||
const visitorContext = Object.assign(Object.assign({}, partialVisitorContext), { functionNames, functionMap }); | ||
const typeIdMap = new Map(); | ||
const visitorContext = Object.assign(Object.assign({}, partialVisitorContext), { functionNames, functionMap, typeIdMap }); | ||
const emitDetailedErrors = !!visitorContext.options.emitDetailedErrors; | ||
const functionName = partialVisitorContext.options.shortCircuit | ||
@@ -19,11 +21,13 @@ ? visitor_type_check_1.visitShortCircuit(visitorContext) | ||
: visitor_type_check_1.visitType(type, visitorContext)); | ||
const errorIdentifier = ts.createIdentifier('error'); | ||
const declarations = utils_1.sliceMapValues(functionMap); | ||
const variableDeclarations = []; | ||
if (emitDetailedErrors) { | ||
variableDeclarations.push(ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ts.createVariableDeclaration(VisitorUtils.pathIdentifier, undefined, ts.createArrayLiteral([ts.createStringLiteral(rootName)]))])); | ||
} | ||
const functionDeclarations = utils_1.sliceMapValues(functionMap); | ||
return ts.createArrowFunction(undefined, undefined, [ | ||
ts.createParameter(undefined, undefined, undefined, VisitorUtils.objectIdentifier, undefined, ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)) | ||
], undefined, undefined, ts.createBlock([ | ||
ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ts.createVariableDeclaration(VisitorUtils.pathIdentifier, undefined, ts.createArrayLiteral([ts.createStringLiteral(rootName)]))]), | ||
...declarations, | ||
ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ts.createVariableDeclaration(errorIdentifier, undefined, ts.createCall(ts.createIdentifier(functionName), undefined, [VisitorUtils.objectIdentifier]))]), | ||
ts.createReturn(errorIdentifier) | ||
...variableDeclarations, | ||
...functionDeclarations, | ||
ts.createReturn(ts.createCall(ts.createIdentifier(functionName), undefined, [VisitorUtils.objectIdentifier])) | ||
])); | ||
@@ -65,5 +69,7 @@ } | ||
const isEquals = name === 'equals' || name === 'createEquals' || name === 'assertEquals' || name === 'createAssertEquals'; | ||
const isAssert = name === 'assertEquals' || name === 'assertType' || name === 'createAssertEquals' || name === 'createAssertType'; | ||
const emitDetailedErrors = visitorContext.options.emitDetailedErrors === 'auto' ? isAssert : visitorContext.options.emitDetailedErrors; | ||
const typeArgument = node.typeArguments[0]; | ||
const type = visitorContext.checker.getTypeFromTypeNode(typeArgument); | ||
const arrowFunction = createArrowFunction(type, extractVariableName(node.arguments[0]), false, Object.assign(Object.assign({}, visitorContext), { options: Object.assign(Object.assign({}, visitorContext.options), { disallowSuperfluousObjectProperties: isEquals || visitorContext.options.disallowSuperfluousObjectProperties }) })); | ||
const arrowFunction = createArrowFunction(type, extractVariableName(node.arguments[0]), false, Object.assign(Object.assign({}, visitorContext), { options: Object.assign(Object.assign({}, visitorContext.options), { disallowSuperfluousObjectProperties: isEquals || visitorContext.options.disallowSuperfluousObjectProperties, emitDetailedErrors }) })); | ||
return ts.updateCall(node, node.expression, node.typeArguments, [ | ||
@@ -75,2 +81,7 @@ ...node.arguments, | ||
} | ||
else if (visitorContext.options.transformNonNullExpressions && ts.isNonNullExpression(node)) { | ||
const expression = node.expression; | ||
return ts.factory.updateNonNullExpression(node, ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression(ts.factory.createParenthesizedExpression(ts.factory.createBinaryExpression(ts.factory.createBinaryExpression(ts.factory.createTypeOfExpression(expression), ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), ts.factory.createStringLiteral('undefined')), ts.factory.createToken(ts.SyntaxKind.BarBarToken), ts.factory.createBinaryExpression(expression, ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), ts.factory.createNull()))), ts.factory.createToken(ts.SyntaxKind.QuestionToken), ts.factory.createCallExpression(ts.factory.createParenthesizedExpression(ts.factory.createArrowFunction(undefined, undefined, [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock([ts.factory.createThrowStatement(ts.factory.createNewExpression(ts.factory.createIdentifier('Error'), undefined, [ts.factory.createTemplateExpression(ts.factory.createTemplateHead(`${expression.getText()} was non-null asserted but is `), [ts.factory.createTemplateSpan(expression, ts.factory.createTemplateTail(''))])])) | ||
], false))), undefined, []), ts.factory.createToken(ts.SyntaxKind.ColonToken), expression))); | ||
} | ||
return node; | ||
@@ -77,0 +88,0 @@ } |
@@ -21,2 +21,10 @@ "use strict"; | ||
} | ||
function getEmitDetailedErrors(options) { | ||
if (options) { | ||
if (options.emitDetailedErrors === 'auto' || typeof options.emitDetailedErrors === 'boolean') { | ||
return options.emitDetailedErrors; | ||
} | ||
} | ||
return 'auto'; | ||
} | ||
function transformer(program, options) { | ||
@@ -35,3 +43,5 @@ if (options && options.verbose) { | ||
functionBehavior: getFunctionBehavior(options), | ||
disallowSuperfluousObjectProperties: !!(options && options.disallowSuperfluousObjectProperties) | ||
disallowSuperfluousObjectProperties: !!(options && options.disallowSuperfluousObjectProperties), | ||
transformNonNullExpressions: !!(options && options.transformNonNullExpressions), | ||
emitDetailedErrors: getEmitDetailedErrors(options) | ||
}, | ||
@@ -38,0 +48,0 @@ typeMapperStack: [], |
@@ -9,2 +9,4 @@ import * as ts from 'typescript'; | ||
disallowSuperfluousObjectProperties: boolean; | ||
transformNonNullExpressions: boolean; | ||
emitDetailedErrors: boolean | 'auto'; | ||
} | ||
@@ -15,2 +17,4 @@ | ||
functionMap: Map<string, ts.FunctionDeclaration>; | ||
typeIdMap: Map<string, string>; | ||
overrideDisallowSuperfluousObjectProperies?: boolean; | ||
} | ||
@@ -17,0 +21,0 @@ |
@@ -56,3 +56,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, { type: 'object-keyof', properties: names }, name); | ||
return VisitorUtils.createAssertionFunction(condition, { type: 'object-keyof', properties: names }, name, visitorContext); | ||
}); | ||
@@ -59,0 +59,0 @@ } |
@@ -18,6 +18,26 @@ "use strict"; | ||
ts.createIf(ts.createBinary(ts.createTypeOf(ts.createIdentifier('global')), ts.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), ts.createStringLiteral('undefined')), ts.createExpressionStatement(ts.createBinary(ts.createIdentifier('nativeDateObject'), ts.createToken(ts.SyntaxKind.EqualsToken), ts.createPropertyAccess(ts.createIdentifier('window'), ts.createIdentifier('Date')))), ts.createExpressionStatement(ts.createBinary(ts.createIdentifier('nativeDateObject'), ts.createToken(ts.SyntaxKind.EqualsToken), ts.createPropertyAccess(ts.createIdentifier('global'), ts.createIdentifier('Date'))))), | ||
ts.createIf(ts.createLogicalNot(ts.createBinary(ts.createIdentifier('object'), ts.createToken(ts.SyntaxKind.InstanceOfKeyword), ts.createIdentifier('nativeDateObject'))), ts.createReturn(VisitorUtils.createErrorObject({ type: 'date' })), ts.createReturn(ts.createNull())) | ||
ts.createIf(ts.createLogicalNot(ts.createBinary(ts.createIdentifier('object'), ts.createToken(ts.SyntaxKind.InstanceOfKeyword), ts.createIdentifier('nativeDateObject'))), ts.createReturn(VisitorUtils.createErrorObject({ type: 'date' }, visitorContext)), ts.createReturn(ts.createNull())) | ||
], true)); | ||
}); | ||
} | ||
function createRecursiveCall(functionName, functionArgument, pathExpression, visitorContext) { | ||
const errorIdentifier = ts.createIdentifier('error'); | ||
const emitDetailedErrors = !!visitorContext.options.emitDetailedErrors; | ||
const statements = []; | ||
if (emitDetailedErrors) { | ||
statements.push(ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'push'), undefined, [ | ||
VisitorUtils.createBinaries([ | ||
pathExpression | ||
], ts.SyntaxKind.PlusToken) | ||
]))); | ||
} | ||
statements.push(ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ | ||
ts.createVariableDeclaration(errorIdentifier, undefined, ts.createCall(ts.createIdentifier(functionName), undefined, [functionArgument])) | ||
])); | ||
if (emitDetailedErrors) { | ||
statements.push(ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'pop'), undefined, undefined))); | ||
} | ||
statements.push(ts.createIf(errorIdentifier, ts.createReturn(errorIdentifier))); | ||
return statements; | ||
} | ||
function visitTupleObjectType(type, visitorContext) { | ||
@@ -29,3 +49,2 @@ const name = VisitorTypeName.visitType(type, visitorContext, { type: 'type-check' }); | ||
: []; | ||
const errorIdentifier = ts.createIdentifier('error'); | ||
const maxLength = functionNames.length; | ||
@@ -48,11 +67,4 @@ let minLength = functionNames.length; | ||
ts.createBinary(ts.createNumericLiteral(maxLength.toString()), ts.SyntaxKind.LessThanToken, ts.createPropertyAccess(VisitorUtils.objectIdentifier, 'length')) | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createErrorObject({ type: 'tuple', minLength, maxLength }))), | ||
...functionNames.map((functionName, index) => ts.createBlock([ | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'push'), undefined, [ts.createStringLiteral(`[${index}]`)])), | ||
ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ | ||
ts.createVariableDeclaration(errorIdentifier, undefined, ts.createCall(ts.createIdentifier(functionName), undefined, [ts.createElementAccess(VisitorUtils.objectIdentifier, index)])) | ||
]), | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'pop'), undefined, undefined)), | ||
ts.createIf(errorIdentifier, ts.createReturn(errorIdentifier)) | ||
])), | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createErrorObject({ type: 'tuple', minLength, maxLength }, visitorContext))), | ||
...functionNames.map((functionName, index) => ts.createBlock(createRecursiveCall(functionName, ts.createElementAccess(VisitorUtils.objectIdentifier, index), ts.createStringLiteral(`[${index}]`), visitorContext))), | ||
ts.createReturn(ts.createNull()) | ||
@@ -71,3 +83,2 @@ ])); | ||
const indexIdentifier = ts.createIdentifier('i'); | ||
const errorIdentifier = ts.createIdentifier('error'); | ||
return ts.createFunctionDeclaration(undefined, undefined, undefined, name, undefined, [ | ||
@@ -77,17 +88,8 @@ ts.createParameter(undefined, undefined, undefined, VisitorUtils.objectIdentifier, undefined, undefined, undefined) | ||
VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext), | ||
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([ | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'push'), undefined, [ | ||
VisitorUtils.createBinaries([ | ||
ts.createStringLiteral('['), | ||
indexIdentifier, | ||
ts.createStringLiteral(']') | ||
], ts.SyntaxKind.PlusToken) | ||
])), | ||
ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ | ||
ts.createVariableDeclaration(errorIdentifier, undefined, ts.createCall(ts.createIdentifier(functionName), undefined, [ts.createElementAccess(VisitorUtils.objectIdentifier, indexIdentifier)])) | ||
]), | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'pop'), undefined, undefined)), | ||
ts.createIf(errorIdentifier, ts.createReturn(errorIdentifier)) | ||
])), | ||
ts.createIf(ts.createLogicalNot(ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Array'), 'isArray'), undefined, [VisitorUtils.objectIdentifier])), ts.createReturn(VisitorUtils.createErrorObject({ type: 'array' }, visitorContext))), | ||
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(createRecursiveCall(functionName, ts.createElementAccess(VisitorUtils.objectIdentifier, indexIdentifier), VisitorUtils.createBinaries([ | ||
ts.createStringLiteral('['), | ||
indexIdentifier, | ||
ts.createStringLiteral(']') | ||
], ts.SyntaxKind.PlusToken), visitorContext))), | ||
ts.createReturn(ts.createNull()) | ||
@@ -104,3 +106,2 @@ ])); | ||
const keyIdentifier = ts.createIdentifier('key'); | ||
const errorIdentifier = ts.createIdentifier('error'); | ||
return ts.createFunctionDeclaration(undefined, undefined, undefined, name, undefined, [ | ||
@@ -114,3 +115,3 @@ ts.createParameter(undefined, undefined, undefined, VisitorUtils.objectIdentifier, undefined, undefined, undefined) | ||
ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Array'), 'isArray'), undefined, [VisitorUtils.objectIdentifier]) | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createErrorObject({ type: 'object' }))), | ||
], ts.SyntaxKind.BarBarToken), ts.createReturn(VisitorUtils.createErrorObject({ type: 'object' }, visitorContext))), | ||
...propertyInfos.map((propertyInfo) => { | ||
@@ -128,27 +129,13 @@ if (propertyInfo.isSymbol) { | ||
return ts.createBlock([ | ||
ts.createIf(ts.createBinary(ts.createStringLiteral(propertyInfo.name), ts.SyntaxKind.InKeyword, VisitorUtils.objectIdentifier), ts.createBlock([ | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'push'), undefined, [ts.createStringLiteral(propertyInfo.name)])), | ||
ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ | ||
ts.createVariableDeclaration(errorIdentifier, undefined, ts.createCall(ts.createIdentifier(functionName), undefined, [ts.createElementAccess(VisitorUtils.objectIdentifier, ts.createStringLiteral(propertyInfo.name))])) | ||
]), | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'pop'), undefined, undefined)), | ||
ts.createIf(errorIdentifier, ts.createReturn(errorIdentifier)) | ||
]), propertyInfo.optional | ||
ts.createIf(ts.createBinary(ts.createStringLiteral(propertyInfo.name), ts.SyntaxKind.InKeyword, VisitorUtils.objectIdentifier), ts.createBlock(createRecursiveCall(functionName, ts.createElementAccess(VisitorUtils.objectIdentifier, ts.createStringLiteral(propertyInfo.name)), ts.createStringLiteral(propertyInfo.name), visitorContext)), propertyInfo.optional | ||
? undefined | ||
: ts.createReturn(VisitorUtils.createErrorObject({ type: 'missing-property', property: propertyInfo.name }))) | ||
: ts.createReturn(VisitorUtils.createErrorObject({ type: 'missing-property', property: propertyInfo.name }, visitorContext))) | ||
]); | ||
}), | ||
...(visitorContext.options.disallowSuperfluousObjectProperties && stringIndexFunctionName === undefined | ||
? [VisitorUtils.createSuperfluousPropertiesLoop(propertyInfos.map((propertyInfo) => propertyInfo.name))] | ||
? [VisitorUtils.createSuperfluousPropertiesLoop(propertyInfos.map((propertyInfo) => propertyInfo.name), visitorContext)] | ||
: []), | ||
...(stringIndexFunctionName | ||
? [ | ||
ts.createForOf(undefined, ts.createVariableDeclarationList([ts.createVariableDeclaration(keyIdentifier, undefined, undefined)], ts.NodeFlags.Const), ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Object'), 'keys'), undefined, [VisitorUtils.objectIdentifier]), ts.createBlock([ | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'push'), undefined, [keyIdentifier])), | ||
ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ConstKeyword)], [ | ||
ts.createVariableDeclaration(errorIdentifier, undefined, ts.createCall(ts.createIdentifier(stringIndexFunctionName), undefined, [ts.createElementAccess(VisitorUtils.objectIdentifier, keyIdentifier)])) | ||
]), | ||
ts.createExpressionStatement(ts.createCall(ts.createPropertyAccess(VisitorUtils.pathIdentifier, 'pop'), undefined, undefined)), | ||
ts.createIf(errorIdentifier, ts.createReturn(errorIdentifier)) | ||
])) | ||
ts.createForOf(undefined, ts.createVariableDeclarationList([ts.createVariableDeclaration(keyIdentifier, undefined, undefined)], ts.NodeFlags.Const), ts.createCall(ts.createPropertyAccess(ts.createIdentifier('Object'), 'keys'), undefined, [VisitorUtils.objectIdentifier]), ts.createBlock(createRecursiveCall(stringIndexFunctionName, ts.createElementAccess(VisitorUtils.objectIdentifier, keyIdentifier), keyIdentifier, visitorContext))) | ||
] | ||
@@ -245,3 +232,3 @@ : []), | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createStringLiteral(value)), { type: 'string-literal', value }, name, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createStringLiteral(value)), { type: 'string-literal', value }, name, visitorContext, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -253,3 +240,3 @@ } | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createNumericLiteral(value.toString())), { type: 'number-literal', value }, name, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createNumericLiteral(value.toString())), { type: 'number-literal', value }, name, visitorContext, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -262,2 +249,7 @@ } | ||
function visitUnionOrIntersectionType(type, visitorContext) { | ||
let disallowSuperfluousPropertyCheck = visitorContext.options.disallowSuperfluousObjectProperties; | ||
if (visitorContext.overrideDisallowSuperfluousObjectProperies) { | ||
visitorContext.overrideDisallowSuperfluousObjectProperies = false; | ||
disallowSuperfluousPropertyCheck = false; | ||
} | ||
const typeUnion = type; | ||
@@ -275,8 +267,8 @@ if (tsutils.isUnionType(typeUnion)) { | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
const functionNames = intersectionType.types.map((type) => visitType(type, Object.assign(Object.assign({}, visitorContext), { options: Object.assign(Object.assign({}, visitorContext.options), { disallowSuperfluousObjectProperties: false }) }))); | ||
if (visitorContext.options.disallowSuperfluousObjectProperties) { | ||
const functionNames = intersectionType.types.map((type) => visitType(type, Object.assign(Object.assign({}, visitorContext), { overrideDisallowSuperfluousObjectProperies: true }))); | ||
if (disallowSuperfluousPropertyCheck) { | ||
// Check object keys at intersection type level. https://github.com/woutervh-/typescript-is/issues/21 | ||
const keys = VisitorIsStringKeyof.visitType(type, visitorContext); | ||
if (keys instanceof Set) { | ||
const loop = VisitorUtils.createSuperfluousPropertiesLoop(utils_1.sliceSet(keys)); | ||
const loop = VisitorUtils.createSuperfluousPropertiesLoop(utils_1.sliceSet(keys), visitorContext); | ||
return VisitorUtils.createConjunctionFunction(functionNames, name, [loop]); | ||
@@ -295,3 +287,3 @@ } | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createTrue()), { type: 'boolean-literal', value: true }, name, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createTrue()), { type: 'boolean-literal', value: true }, name, visitorContext, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -302,3 +294,3 @@ } | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => { | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createFalse()), { type: 'boolean-literal', value: false }, name, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
return VisitorUtils.createAssertionFunction(ts.createStrictInequality(VisitorUtils.objectIdentifier, ts.createFalse()), { type: 'boolean-literal', value: false }, name, visitorContext, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -323,3 +315,3 @@ } | ||
const condition = VisitorUtils.createBinaries(conditions, ts.SyntaxKind.AmpersandAmpersandToken); | ||
return VisitorUtils.createAssertionFunction(ts.createLogicalNot(condition), { type: 'non-primitive' }, name, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
return VisitorUtils.createAssertionFunction(ts.createLogicalNot(condition), { type: 'non-primitive' }, name, visitorContext, VisitorUtils.createStrictNullCheckStatement(VisitorUtils.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -376,3 +368,3 @@ } | ||
value: typePairs | ||
}); | ||
}, visitorContext); | ||
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => ts.factory.createFunctionDeclaration(undefined, undefined, undefined, name, undefined, [ | ||
@@ -379,0 +371,0 @@ ts.factory.createParameterDeclaration(undefined, undefined, undefined, VisitorUtils.objectIdentifier, undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined) |
@@ -25,6 +25,15 @@ "use strict"; | ||
} | ||
function visitRegularObjectType(type) { | ||
const id = type.id; | ||
return `_${id}`; | ||
function getTypeIndexById(type, { typeIdMap }) { | ||
const id = type.id.toString(); | ||
let index = typeIdMap.get(id); | ||
if (index === undefined) { | ||
index = typeIdMap.size.toString(); | ||
typeIdMap.set(id, index); | ||
} | ||
return index; | ||
} | ||
function visitRegularObjectType(type, visitorContext) { | ||
const index = getTypeIndexById(type, visitorContext); | ||
return `_${index}`; | ||
} | ||
function visitTypeReference(type, visitorContext, mode) { | ||
@@ -58,3 +67,3 @@ const mapping = VisitorUtils.getTypeReferenceMapping(type, visitorContext); | ||
else { | ||
return visitRegularObjectType(type); | ||
return visitRegularObjectType(type, visitorContext); | ||
} | ||
@@ -83,3 +92,3 @@ } | ||
let name; | ||
const id = type.id; | ||
const index = getTypeIndexById(type, visitorContext); | ||
if ((ts.TypeFlags.Any & type.flags) !== 0) { | ||
@@ -113,3 +122,3 @@ name = VisitorUtils.getAnyFunction(visitorContext); | ||
else if ((ts.TypeFlags.BooleanLiteral & type.flags) !== 0) { | ||
name = `_${id}`; | ||
name = `_${index}`; | ||
} | ||
@@ -126,3 +135,3 @@ else if (tsutils.isTypeReference(type) && visitorContext.previousTypeReference !== type) { | ||
else if (tsutils.isLiteralType(type)) { | ||
name = `_${id}`; | ||
name = `_${index}`; | ||
} | ||
@@ -133,3 +142,3 @@ else if (tsutils.isUnionOrIntersectionType(type)) { | ||
else if ((ts.TypeFlags.NonPrimitive & type.flags) !== 0) { | ||
name = `_${id}`; | ||
name = `_${index}`; | ||
} | ||
@@ -143,3 +152,3 @@ else if ((ts.TypeFlags.Index & type.flags) !== 0) { | ||
else if ((ts.TypeFlags.TemplateLiteral & type.flags) !== 0) { | ||
name = `_${id}`; | ||
name = `_${index}`; | ||
} | ||
@@ -162,3 +171,4 @@ else { | ||
const resolvedType = VisitorUtils.getResolvedTypeParameter(typeArgument, visitorContext) || typeArgument; | ||
name += `_${resolvedType.id}`; | ||
const resolvedTypeIndex = getTypeIndexById(resolvedType, visitorContext); | ||
name += `_${resolvedTypeIndex}`; | ||
} | ||
@@ -165,0 +175,0 @@ } |
@@ -42,7 +42,7 @@ import * as ts from 'typescript'; | ||
export declare function createStrictNullCheckStatement(identifier: ts.Identifier, visitorContext: VisitorContext): ts.EmptyStatement | ts.IfStatement; | ||
export declare function createAssertionFunction(failureCondition: ts.Expression, expected: Reason, functionName: string, ...otherStatements: ts.Statement[]): ts.FunctionDeclaration; | ||
export declare function createSuperfluousPropertiesLoop(propertyNames: string[]): ts.ForOfStatement; | ||
export declare function createAssertionFunction(failureCondition: ts.Expression, expected: Reason, functionName: string, visitorContext: VisitorContext, ...otherStatements: ts.Statement[]): ts.FunctionDeclaration; | ||
export declare function createSuperfluousPropertiesLoop(propertyNames: string[], visitorContext: VisitorContext): ts.ForOfStatement; | ||
export declare function isBigIntType(type: ts.Type): number | false; | ||
export declare function createErrorObject(reason: Reason): ts.Expression; | ||
export declare function createErrorObject(reason: Reason, visitorContext: VisitorContext): ts.Expression; | ||
export declare function getIntrinsicName(type: ts.Type): string | undefined; | ||
export {}; |
@@ -174,3 +174,3 @@ "use strict"; | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('function')), { type: 'function' }, name, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('function')), { type: 'function' }, name, visitorContext, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -182,3 +182,3 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('string')), { type: 'string' }, name, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('string')), { type: 'string' }, name, visitorContext, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -190,3 +190,3 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('boolean')), { type: 'boolean' }, name, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('boolean')), { type: 'boolean' }, name, visitorContext, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -198,3 +198,3 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('bigint')), { type: 'big-int' }, name, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('bigint')), { type: 'big-int' }, name, visitorContext, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -206,3 +206,3 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('number')), { type: 'number' }, name, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
return createAssertionFunction(ts.createStrictInequality(ts.createTypeOf(exports.objectIdentifier), ts.createStringLiteral('number')), { type: 'number' }, name, visitorContext, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -214,3 +214,3 @@ } | ||
return setFunctionIfNotExists(name, visitorContext, () => { | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createIdentifier('undefined')), { type: 'undefined' }, name, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createIdentifier('undefined')), { type: 'undefined' }, name, visitorContext, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -228,3 +228,3 @@ } | ||
} | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createNull()), { type: 'null' }, name, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
return createAssertionFunction(ts.createStrictInequality(exports.objectIdentifier, ts.createNull()), { type: 'null' }, name, visitorContext, createStrictNullCheckStatement(exports.objectIdentifier, visitorContext)); | ||
}); | ||
@@ -239,3 +239,3 @@ } | ||
], undefined, ts.createBlock([ | ||
ts.createReturn(createErrorObject({ type: 'never' })) | ||
ts.createReturn(createErrorObject({ type: 'never' }, visitorContext)) | ||
])); | ||
@@ -323,3 +323,3 @@ }); | ||
])), | ||
ts.createReturn(createErrorObject({ type: 'union' })) | ||
ts.createReturn(createErrorObject({ type: 'union' }, visitorContext)) | ||
])); | ||
@@ -344,3 +344,3 @@ } | ||
exports.createStrictNullCheckStatement = createStrictNullCheckStatement; | ||
function createAssertionFunction(failureCondition, expected, functionName, ...otherStatements) { | ||
function createAssertionFunction(failureCondition, expected, functionName, visitorContext, ...otherStatements) { | ||
return ts.createFunctionDeclaration(undefined, undefined, undefined, functionName, undefined, [ | ||
@@ -350,9 +350,9 @@ ts.createParameter(undefined, undefined, undefined, exports.objectIdentifier, undefined, undefined, undefined) | ||
...otherStatements, | ||
ts.createIf(failureCondition, ts.createReturn(createErrorObject(expected)), ts.createReturn(ts.createNull())) | ||
ts.createIf(failureCondition, ts.createReturn(createErrorObject(expected, visitorContext)), ts.createReturn(ts.createNull())) | ||
])); | ||
} | ||
exports.createAssertionFunction = createAssertionFunction; | ||
function createSuperfluousPropertiesLoop(propertyNames) { | ||
function createSuperfluousPropertiesLoop(propertyNames, visitorContext) { | ||
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(createErrorObject({ type: 'superfluous-property' }))) | ||
ts.createIf(createBinaries(propertyNames.map((propertyName) => ts.createStrictInequality(keyIdentifier, ts.createStringLiteral(propertyName))), ts.SyntaxKind.AmpersandAmpersandToken, ts.createTrue()), ts.createReturn(createErrorObject({ type: 'superfluous-property' }, visitorContext))) | ||
])); | ||
@@ -387,3 +387,6 @@ } | ||
} | ||
function createErrorObject(reason) { | ||
function createErrorObject(reason, visitorContext) { | ||
if (visitorContext.options.emitDetailedErrors === false) { | ||
return ts.createObjectLiteral([]); | ||
} | ||
return ts.createObjectLiteral([ | ||
@@ -390,0 +393,0 @@ ts.createPropertyAssignment('message', createErrorMessage(reason)), |
{ | ||
"name": "typescript-is", | ||
"version": "0.18.3", | ||
"version": "0.19.0", | ||
"engines": { | ||
@@ -37,3 +37,2 @@ "node": ">=6.14.4" | ||
"nested-error-stacks": "^2", | ||
"reflect-metadata": ">=0.1.12", | ||
"tsutils": "^3.17.1" | ||
@@ -40,0 +39,0 @@ }, |
@@ -140,2 +140,4 @@ # typescript-is | ||
| `disallowSuperfluousObjectProperties` | Boolean (default: `false`). If `true`, objects are checked for having superfluous properties and will cause the validation to fail if they do. If `false`, no check for superfluous properties is made. | | ||
| `transformNonNullExpressions` | Boolean (default: `false`). If `true`, non-null expressions (eg. `foo!.bar`) are checked to not be `null` or `undefined` | | ||
| `emitDetailedErrors` | Boolean or `auto` (default: `auto`). The generated validation functions can return detailed error messages, pointing out where and why validation failed. These messages are used by `assertType<T>()`, but are ignored by `is<T>()`. If `false`, validation functions return empty error messages, decreasing code size. `auto` will generate detailed error messages for assertions, but not for type checks. `true` will always generate detailed error messages, matching the behaviour of version 0.18.3 and older. | | ||
@@ -154,3 +156,5 @@ If you are using `ttypescript`, you can include the options in your `tsconfig.json`: | ||
"functionBehavior": "ignore", | ||
"disallowSuperfluousObjectProperties": true | ||
"disallowSuperfluousObjectProperties": true, | ||
"transformNonNullExpressions": true, | ||
"emitDetailedErrors": "auto" | ||
} | ||
@@ -262,2 +266,70 @@ ] | ||
### async and `Promise` returning methods | ||
`AssertType` can also work correctly with `async` methods, returning promise rejected with `TypeGuardError` | ||
To enable this functionality, you need to emit decorators metadata for your TypeScript project. | ||
```json | ||
{ | ||
"compilerOptions": { | ||
"emitDecoratorMetadata": true | ||
} | ||
} | ||
``` | ||
Then `AssertType` will work with async methods and `Promise` returning methods automatically. | ||
```typescript | ||
import { ValidateClass, AssertType } from 'typescript-is'; | ||
@ValidateClass() | ||
class A { | ||
async method(@AssertType({ async: true }) value: number) { | ||
// You can safely use value as a number | ||
return value; | ||
} | ||
methodPromise(@AssertType({ async: true }) value: number): Promise<number> { | ||
// You can safely use value as a number | ||
return Promise.resolve(value); | ||
} | ||
} | ||
new A().method(42).then(value => value === 42 /* true */); | ||
new A().method('42' as any).catch(error => { | ||
// error will be of TypeGuardError type | ||
}) | ||
new A().methodPromise('42' as any).catch(error => { | ||
// error will be of TypeGuardError type | ||
}) | ||
``` | ||
If you want to throw synchronously for some reason, you can override the behaviour using with `@AssertType({ async: false })`: | ||
```typescript | ||
import { ValidateClass, AssertType } from 'typescript-is'; | ||
@ValidateClass() | ||
class A { | ||
async method(@AssertType({ async: false }) value: number) { | ||
// You can safely use value as a number | ||
return value; | ||
} | ||
} | ||
new A().method(42).then(value => value === 42 /* true */); | ||
new A().method('42' as any); // will throw error | ||
``` | ||
If you cannot or don't want to enable decorators metadata, you still make AssertType reject with promise using `@AssertType({ async: true })` | ||
```typescript | ||
import { ValidateClass, AssertType } from 'typescript-is'; | ||
@ValidateClass() | ||
class A { | ||
async method(@AssertType({ async: true }) value: number) { | ||
// You can safely use value as a number | ||
return value; | ||
} | ||
} | ||
``` | ||
## Strict equality (`equals`, `createEquals`, `assertEquals`, `createAssertEquals`) | ||
@@ -264,0 +336,0 @@ |
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
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
270609
4
3008
407
- Removedreflect-metadata@>=0.1.12