Skip to content

Commit 0dbefd0

Browse files
authored
Merge pull request #108 from cauthmann/master
Add an option to generate code without detailed error messages
2 parents 6938d9d + bb84bc4 commit 0dbefd0

14 files changed

+181
-190
lines changed

Diff for: README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ There are some options to configure the transformer.
138138
| `functionBehavior` | One of `error`, `ignore`, or `basic` (default: `error`). Determines the behavior of transformer when encountering a function. `error` will cause a compile-time error, `ignore` will cause the validation function to always return `true`, and `basic` will do a simple function-type-check. Overrides `ignoreFunctions`. |
139139
| `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. |
140140
| `transformNonNullExpressions` | Boolean (default: `false`). If `true`, non-null expressions (eg. `foo!.bar`) are checked to not be `null` or `undefined` |
141+
| `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. |
141142

142143
If you are using `ttypescript`, you can include the options in your `tsconfig.json`:
143144

@@ -152,7 +153,8 @@ If you are using `ttypescript`, you can include the options in your `tsconfig.js
152153
"ignoreMethods": true,
153154
"functionBehavior": "ignore",
154155
"disallowSuperfluousObjectProperties": true,
155-
"transformNonNullExpressions": true
156+
"transformNonNullExpressions": true,
157+
"emitDetailedErrors": "auto"
156158
}
157159
]
158160
}

Diff for: index.js

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ function inputObjectAtPath(path, inputObject) {
1919
}
2020

2121
function appendInputToErrorMessage(message, path, inputObject) {
22+
if (message === undefined)
23+
return 'validation error';
2224
const foundInputObject = inputObjectAtPath(path, inputObject);
2325
try {
2426
return message + ', found: ' + require('util').inspect(foundInputObject);

Diff for: src/transform-inline/transform-node.ts

+19-14
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,25 @@ function createArrowFunction(type: ts.Type, rootName: string, optional: boolean,
99
const functionMap: VisitorContext['functionMap'] = new Map();
1010
const functionNames: VisitorContext['functionNames'] = new Set();
1111
const typeIdMap: VisitorContext['typeIdMap'] = new Map();
12-
const visitorContext = { ...partialVisitorContext, functionNames, functionMap, typeIdMap };
12+
const visitorContext: VisitorContext = { ...partialVisitorContext, functionNames, functionMap, typeIdMap };
13+
const emitDetailedErrors = !!visitorContext.options.emitDetailedErrors;
1314
const functionName = partialVisitorContext.options.shortCircuit
1415
? visitShortCircuit(visitorContext)
1516
: (optional
1617
? visitUndefinedOrType(type, visitorContext)
1718
: visitType(type, visitorContext)
1819
);
1920

20-
const errorIdentifier = ts.createIdentifier('error');
21-
const declarations = sliceMapValues(functionMap);
21+
const variableDeclarations: ts.VariableStatement[] = [];
22+
if (emitDetailedErrors) {
23+
variableDeclarations.push(
24+
ts.createVariableStatement(
25+
[ts.createModifier(ts.SyntaxKind.ConstKeyword)],
26+
[ts.createVariableDeclaration(VisitorUtils.pathIdentifier, undefined, ts.createArrayLiteral([ts.createStringLiteral(rootName)]))]
27+
)
28+
);
29+
}
30+
const functionDeclarations = sliceMapValues(functionMap);
2231

2332
return ts.createArrowFunction(
2433
undefined,
@@ -36,16 +45,9 @@ function createArrowFunction(type: ts.Type, rootName: string, optional: boolean,
3645
undefined,
3746
undefined,
3847
ts.createBlock([
39-
ts.createVariableStatement(
40-
[ts.createModifier(ts.SyntaxKind.ConstKeyword)],
41-
[ts.createVariableDeclaration(VisitorUtils.pathIdentifier, undefined, ts.createArrayLiteral([ts.createStringLiteral(rootName)]))]
42-
),
43-
...declarations,
44-
ts.createVariableStatement(
45-
[ts.createModifier(ts.SyntaxKind.ConstKeyword)],
46-
[ts.createVariableDeclaration(errorIdentifier, undefined, ts.createCall(ts.createIdentifier(functionName), undefined, [VisitorUtils.objectIdentifier]))]
47-
),
48-
ts.createReturn(errorIdentifier)
48+
...variableDeclarations,
49+
...functionDeclarations,
50+
ts.createReturn(ts.createCall(ts.createIdentifier(functionName), undefined, [VisitorUtils.objectIdentifier]))
4951
])
5052
);
5153
}
@@ -106,6 +108,8 @@ export function transformNode(node: ts.Node, visitorContext: PartialVisitorConte
106108
) {
107109
const name = visitorContext.checker.getTypeAtLocation(signature.declaration).symbol.name;
108110
const isEquals = name === 'equals' || name === 'createEquals' || name === 'assertEquals' || name === 'createAssertEquals';
111+
const isAssert = name === 'assertEquals' || name === 'assertType' || name === 'createAssertEquals' || name === 'createAssertType';
112+
const emitDetailedErrors = visitorContext.options.emitDetailedErrors === 'auto' ? isAssert : visitorContext.options.emitDetailedErrors;
109113

110114
const typeArgument = node.typeArguments[0];
111115
const type = visitorContext.checker.getTypeFromTypeNode(typeArgument);
@@ -117,7 +121,8 @@ export function transformNode(node: ts.Node, visitorContext: PartialVisitorConte
117121
...visitorContext,
118122
options: {
119123
...visitorContext.options,
120-
disallowSuperfluousObjectProperties: isEquals || visitorContext.options.disallowSuperfluousObjectProperties
124+
disallowSuperfluousObjectProperties: isEquals || visitorContext.options.disallowSuperfluousObjectProperties,
125+
emitDetailedErrors
121126
}
122127
}
123128
);

Diff for: src/transform-inline/transformer.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ function getFunctionBehavior(options?: { [Key: string]: unknown }): PartialVisit
1818
return 'error';
1919
}
2020

21+
function getEmitDetailedErrors(options?: { [Key: string]: unknown }): PartialVisitorContext['options']['emitDetailedErrors'] {
22+
if (options) {
23+
if (options.emitDetailedErrors === 'auto' || typeof options.emitDetailedErrors === 'boolean') {
24+
return options.emitDetailedErrors;
25+
}
26+
}
27+
return 'auto';
28+
}
29+
2130
export default function transformer(program: ts.Program, options?: { [Key: string]: unknown }): ts.TransformerFactory<ts.SourceFile> {
2231
if (options && options.verbose) {
2332
console.log(`typescript-is: transforming program with ${program.getSourceFiles().length} source files; using TypeScript ${ts.version}.`);
@@ -33,7 +42,8 @@ export default function transformer(program: ts.Program, options?: { [Key: strin
3342
ignoreMethods: !!(options && options.ignoreMethods),
3443
functionBehavior: getFunctionBehavior(options),
3544
disallowSuperfluousObjectProperties: !!(options && options.disallowSuperfluousObjectProperties),
36-
transformNonNullExpressions: !!(options && options.transformNonNullExpressions)
45+
transformNonNullExpressions: !!(options && options.transformNonNullExpressions),
46+
emitDetailedErrors: getEmitDetailedErrors(options)
3747
},
3848
typeMapperStack: [],
3949
previousTypeReference: null

Diff for: src/transform-inline/visitor-context.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface Options {
77
functionBehavior: 'error' | 'ignore' | 'basic';
88
disallowSuperfluousObjectProperties: boolean;
99
transformNonNullExpressions: boolean;
10+
emitDetailedErrors: boolean | 'auto';
1011
}
1112

1213
export interface VisitorContext extends PartialVisitorContext {

Diff for: src/transform-inline/visitor-keyof.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ function visitRegularObjectType(type: ts.ObjectType, visitorContext: VisitorCont
6060
return VisitorUtils.createAssertionFunction(
6161
condition,
6262
{ type: 'object-keyof', properties: names },
63-
name
63+
name,
64+
visitorContext
6465
);
6566
});
6667
}

0 commit comments

Comments
 (0)