X Tutup
Skip to content

Commit cc6d403

Browse files
tomblindPerryvw
authored andcommitted
New functions - tests (#303)
* passing nil instead of _G as context for global functions when in ES strict mode * fixed logic for determining strict mode * replaced hack-around when passing nil as a function context with a null keyword * testing viability of wrapping context/no-context calls on assignment * working on more function assignment situations * fixed getting constructor signature and refactored things a bit * checking resolved signature when comparing function types passed as arguments * working on assignment checks for methods vs functions * handling context in calls and decls * refactoring and handling tuple destructuring * generalized tuple assignment checking * overloads with function and method signatures default to functions now * preventing non-methods from being passed to bind/call/apply * removed uneccessary helpers * using proper exceptions for function conversion errors * removed context arg from custom constructors and added check for assigning to untyped vars * updated tests * removing leftover NoContext decorators * recursing into interfaces during assignment validation * fixes for issues with overloads using different context types * less-lazy variable naming and improved error message * suite of tests for new functions and fixes for edge-cases found
1 parent 281ab54 commit cc6d403

File tree

4 files changed

+486
-12
lines changed

4 files changed

+486
-12
lines changed

src/Errors.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,25 @@ export class TSTLErrors {
7171

7272
public static UnsupportedFunctionConversion = (node: ts.Node, name?: string) => {
7373
if (name) {
74-
return new TranspileError(`Unsupported conversion from method to function "${name}".`, node);
74+
return new TranspileError(`Unsupported conversion from method to function "${name}". `
75+
+ `To fix, wrap the method in an arrow function.`,
76+
node);
7577
} else {
76-
return new TranspileError(`Unsupported conversion from method to function.`, node);
78+
return new TranspileError(`Unsupported conversion from method to function. `
79+
+ `To fix, wrap the method in an arrow function.`,
80+
node);
7781
}
7882
}
7983

8084
public static UnsupportedMethodConversion = (node: ts.Node, name?: string) => {
8185
if (name) {
82-
return new TranspileError(`Unsupported conversion from function to method "${name}".`, node);
86+
return new TranspileError(`Unsupported conversion from function to method "${name}". `
87+
+ `To fix, wrap the function in an arrow function.`,
88+
node);
8389
} else {
84-
return new TranspileError(`Unsupported conversion from function to method.`, node);
90+
return new TranspileError(`Unsupported conversion from function to method. `
91+
+ `To fix, wrap the function in an arrow function.`,
92+
node);
8593
}
8694
}
8795

src/TSHelper.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,37 @@ export class TSHelper {
256256
return [false, null, null];
257257
}
258258

259+
public static getExplicitThisParameter(signatureDeclaration: ts.SignatureDeclaration): ts.ParameterDeclaration {
260+
return signatureDeclaration.parameters.find(
261+
param => ts.isIdentifier(param.name) && param.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword);
262+
}
263+
264+
public static getSignatureDeclarations(signatures: ts.Signature[], checker: ts.TypeChecker)
265+
: ts.SignatureDeclaration[] {
266+
const signatureDeclarations: ts.SignatureDeclaration[] = [];
267+
for (const signature of signatures) {
268+
const signatureDeclaration = signature.getDeclaration();
269+
if ((ts.isFunctionExpression(signatureDeclaration) || ts.isArrowFunction(signatureDeclaration))
270+
&& !this.getExplicitThisParameter(signatureDeclaration)) {
271+
// Function expressions: get signatures of type being assigned to, unless 'this' was explicit
272+
const declType = checker.getTypeAtLocation(signatureDeclaration.parent);
273+
const declSignatures = declType.getCallSignatures();
274+
if (declSignatures.length > 0) {
275+
declSignatures.map(s => s.getDeclaration()).forEach(decl => signatureDeclarations.push(decl));
276+
continue;
277+
}
278+
}
279+
signatureDeclarations.push(signatureDeclaration);
280+
}
281+
return signatureDeclarations;
282+
}
283+
259284
public static getDeclarationContextType(signatureDeclaration: ts.SignatureDeclaration,
260285
checker: ts.TypeChecker): ContextType {
261-
const thisArg = signatureDeclaration.parameters.find(
262-
param => ts.isIdentifier(param.name) && param.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword);
263-
if (thisArg) {
286+
const thisParameter = this.getExplicitThisParameter(signatureDeclaration);
287+
if (thisParameter) {
264288
// Explicit 'this'
265-
return thisArg.type && thisArg.type.kind === ts.SyntaxKind.VoidKeyword
289+
return thisParameter.type && thisParameter.type.kind === ts.SyntaxKind.VoidKeyword
266290
? ContextType.Void : ContextType.NonVoid;
267291
}
268292
if ((ts.isMethodDeclaration(signatureDeclaration) || ts.isMethodSignature(signatureDeclaration))
@@ -288,10 +312,10 @@ export class TSHelper {
288312
if (signatures.length === 0) {
289313
return ContextType.None;
290314
}
291-
const signatureDeclataions = signatures.map(sig => sig.getDeclaration());
292-
const context = this.getDeclarationContextType(signatureDeclataions[0], checker);
293-
for (let i = 1; i < signatureDeclataions.length; ++i) {
294-
if (this.getDeclarationContextType(signatureDeclataions[i], checker) !== context) {
315+
const signatureDeclarations = this.getSignatureDeclarations(signatures, checker);
316+
const context = this.getDeclarationContextType(signatureDeclarations[0], checker);
317+
for (let i = 1; i < signatureDeclarations.length; ++i) {
318+
if (this.getDeclarationContextType(signatureDeclarations[i], checker) !== context) {
295319
return ContextType.Mixed;
296320
}
297321
}

0 commit comments

Comments
 (0)
X Tutup