Skip to content

Commit 68c0bf8

Browse files
authored
Merge pull request #100 from DetachHead/transformNonNullExpressions
add transformNonNullExpressions
2 parents 1810277 + f16731d commit 68c0bf8

File tree

12 files changed

+102
-18
lines changed

12 files changed

+102
-18
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ There are some options to configure the transformer.
137137
| `ignoreFunctions` *(deprecated, use `functionBehavior` instead)* | Boolean (default: `false`). If `true`, when the transformer encounters a function, it will ignore it and simply return `true`. If `false`, an error is generated at compile time. |
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. |
140+
| `transformNonNullExpressions` | Boolean (default: `false`). If `true`, non-null expressions (eg. `foo!.bar`) are checked to not be `null` or `undefined` |
140141

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

@@ -150,7 +151,8 @@ If you are using `ttypescript`, you can include the options in your `tsconfig.js
150151
"ignoreClasses": true,
151152
"ignoreMethods": true,
152153
"functionBehavior": "ignore",
153-
"disallowSuperfluousObjectProperties": true
154+
"disallowSuperfluousObjectProperties": true,
155+
"transformNonNullExpressions": true
154156
}
155157
]
156158
}

src/transform-inline/transform-node.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,55 @@ export function transformNode(node: ts.Node, visitorContext: PartialVisitorConte
132132
]
133133
);
134134
}
135+
} else if (visitorContext.options.transformNonNullExpressions && ts.isNonNullExpression(node)) {
136+
const expression = node.expression
137+
return ts.factory.updateNonNullExpression(node, ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression(
138+
ts.factory.createParenthesizedExpression(ts.factory.createBinaryExpression(
139+
ts.factory.createBinaryExpression(
140+
ts.factory.createTypeOfExpression(expression),
141+
ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
142+
ts.factory.createStringLiteral('undefined')
143+
),
144+
ts.factory.createToken(ts.SyntaxKind.BarBarToken),
145+
ts.factory.createBinaryExpression(
146+
expression,
147+
ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
148+
ts.factory.createNull()
149+
)
150+
)),
151+
ts.factory.createToken(ts.SyntaxKind.QuestionToken),
152+
ts.factory.createCallExpression(
153+
ts.factory.createParenthesizedExpression(ts.factory.createArrowFunction(
154+
undefined,
155+
undefined,
156+
[],
157+
undefined,
158+
ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
159+
ts.factory.createBlock(
160+
[ts.factory.createThrowStatement(ts.factory.createNewExpression(
161+
ts.factory.createIdentifier('Error'),
162+
undefined,
163+
[ts.factory.createTemplateExpression(
164+
ts.factory.createTemplateHead(`${expression.getText()} was non-null asserted but is `),
165+
[ts.factory.createTemplateSpan(
166+
expression,
167+
ts.factory.createTemplateTail(
168+
''
169+
)
170+
)]
171+
)]
172+
))
173+
],
174+
false
175+
)
176+
)),
177+
undefined,
178+
[]
179+
),
180+
ts.factory.createToken(ts.SyntaxKind.ColonToken),
181+
expression
182+
)))
135183
}
136184
return node;
137185
}
186+

src/transform-inline/transformer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export default function transformer(program: ts.Program, options?: { [Key: strin
3232
ignoreClasses: !!(options && options.ignoreClasses),
3333
ignoreMethods: !!(options && options.ignoreMethods),
3434
functionBehavior: getFunctionBehavior(options),
35-
disallowSuperfluousObjectProperties: !!(options && options.disallowSuperfluousObjectProperties)
35+
disallowSuperfluousObjectProperties: !!(options && options.disallowSuperfluousObjectProperties),
36+
transformNonNullExpressions: !!(options && options.transformNonNullExpressions)
3637
},
3738
typeMapperStack: [],
3839
previousTypeReference: null

src/transform-inline/visitor-context.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ interface Options {
66
ignoreMethods: boolean;
77
functionBehavior: 'error' | 'ignore' | 'basic';
88
disallowSuperfluousObjectProperties: boolean;
9+
transformNonNullExpressions: boolean;
910
}
1011

1112
export interface VisitorContext extends PartialVisitorContext {

test/issue-16.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ describe('visitor', () => {
3636
ignoreMethods: false,
3737
functionBehavior: 'error',
3838
shortCircuit: false,
39-
disallowSuperfluousObjectProperties: false
39+
disallowSuperfluousObjectProperties: false,
40+
transformNonNullExpressions: false
4041
},
4142
typeMapperStack: [],
4243
previousTypeReference: null
@@ -61,7 +62,8 @@ describe('visitor', () => {
6162
ignoreMethods: false,
6263
functionBehavior: 'error',
6364
shortCircuit: false,
64-
disallowSuperfluousObjectProperties: false
65+
disallowSuperfluousObjectProperties: false,
66+
transformNonNullExpressions: false
6567
},
6668
typeMapperStack: [],
6769
previousTypeReference: null
@@ -90,7 +92,8 @@ describe('visitor', () => {
9092
ignoreMethods: true,
9193
functionBehavior: 'error',
9294
shortCircuit: false,
93-
disallowSuperfluousObjectProperties: false
95+
disallowSuperfluousObjectProperties: false,
96+
transformNonNullExpressions: false
9497
},
9598
typeMapperStack: [],
9699
previousTypeReference: null
@@ -118,7 +121,8 @@ describe('visitor', () => {
118121
ignoreMethods: false,
119122
functionBehavior: 'error',
120123
shortCircuit: false,
121-
disallowSuperfluousObjectProperties: false
124+
disallowSuperfluousObjectProperties: false,
125+
transformNonNullExpressions: false
122126
},
123127
typeMapperStack: [],
124128
previousTypeReference: null
@@ -146,7 +150,8 @@ describe('visitor', () => {
146150
ignoreMethods: true,
147151
functionBehavior: 'error',
148152
shortCircuit: false,
149-
disallowSuperfluousObjectProperties: false
153+
disallowSuperfluousObjectProperties: false,
154+
transformNonNullExpressions: false
150155
},
151156
typeMapperStack: [],
152157
previousTypeReference: null

test/issue-27.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ describe('visitor', () => {
3434
ignoreMethods: true,
3535
functionBehavior: 'error',
3636
shortCircuit: false,
37-
disallowSuperfluousObjectProperties: false
37+
disallowSuperfluousObjectProperties: false,
38+
transformNonNullExpressions: false
3839
},
3940
typeMapperStack: [],
4041
previousTypeReference: null

test/issue-3.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ describe('visitor', () => {
3535
ignoreMethods: false,
3636
functionBehavior: 'error',
3737
shortCircuit: false,
38-
disallowSuperfluousObjectProperties: false
38+
disallowSuperfluousObjectProperties: false,
39+
transformNonNullExpressions: false
3940
},
4041
typeMapperStack: [],
4142
previousTypeReference: null

test/issue-31.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ describe('visitor', () => {
4545
ignoreMethods: true, // Make sure it does not fail on the methods.
4646
functionBehavior: 'error',
4747
shortCircuit: false,
48-
disallowSuperfluousObjectProperties: false
48+
disallowSuperfluousObjectProperties: false,
49+
transformNonNullExpressions: false
4950
};
5051
const visitorContext = createVisitorContext(program, options);
5152
const visitorContextWithDate = createVisitorContext(programWithDate, options);
@@ -77,7 +78,8 @@ describe('visitor', () => {
7778
ignoreMethods: false, // It should never get to the methods of the class.
7879
functionBehavior: 'error',
7980
shortCircuit: false,
80-
disallowSuperfluousObjectProperties: false
81+
disallowSuperfluousObjectProperties: false,
82+
transformNonNullExpressions: false
8183
};
8284
const visitorContext = createVisitorContext(program, options);
8385
const visitorContextWithDate = createVisitorContext(programWithDate, options);

test/issue-50.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ describe('visitor', () => {
3535
ignoreMethods: true, // Make sure that the function is not seen as a method.
3636
functionBehavior: 'error',
3737
shortCircuit: false,
38-
disallowSuperfluousObjectProperties: false
38+
disallowSuperfluousObjectProperties: false,
39+
transformNonNullExpressions: false
3940
},
4041
typeMapperStack: [],
4142
previousTypeReference: null
@@ -63,7 +64,8 @@ describe('visitor', () => {
6364
ignoreMethods: false,
6465
functionBehavior: 'ignore',
6566
shortCircuit: false,
66-
disallowSuperfluousObjectProperties: false
67+
disallowSuperfluousObjectProperties: false,
68+
transformNonNullExpressions: false
6769
},
6870
typeMapperStack: [],
6971
previousTypeReference: null

test/issue-52.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ describe('visitor', () => {
3535
ignoreMethods: true, // Make sure that the function is not seen as a method.
3636
functionBehavior: 'error',
3737
shortCircuit: false,
38-
disallowSuperfluousObjectProperties: false
38+
disallowSuperfluousObjectProperties: false,
39+
transformNonNullExpressions: false
3940
},
4041
typeMapperStack: [],
4142
previousTypeReference: null
@@ -63,7 +64,8 @@ describe('visitor', () => {
6364
ignoreMethods: false,
6465
functionBehavior: 'ignore',
6566
shortCircuit: false,
66-
disallowSuperfluousObjectProperties: false
67+
disallowSuperfluousObjectProperties: false,
68+
transformNonNullExpressions: false
6769
},
6870
typeMapperStack: [],
6971
previousTypeReference: null
@@ -91,7 +93,8 @@ describe('visitor', () => {
9193
ignoreMethods: false,
9294
functionBehavior: 'basic',
9395
shortCircuit: false,
94-
disallowSuperfluousObjectProperties: false
96+
disallowSuperfluousObjectProperties: false,
97+
transformNonNullExpressions: false
9598
},
9699
typeMapperStack: [],
97100
previousTypeReference: null

0 commit comments

Comments
 (0)