Skip to content

Commit 8cb5333

Browse files
committed
Verify JS function is constructor
1 parent 08e7164 commit 8cb5333

File tree

5 files changed

+45
-4
lines changed

5 files changed

+45
-4
lines changed

Jakefile.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,8 @@ function runConsoleTests(defaultReporter, runInParallel) {
802802

803803
var debug = process.env.debug || process.env.d;
804804
var inspect = process.env.inspect;
805-
tests = process.env.test || process.env.tests || process.env.t;
805+
var testTimeout = process.env.timeout || defaultTestTimeout;
806+
var tests = process.env.test || process.env.tests || process.env.t;
806807
var light = process.env.light || false;
807808
var stackTraceLimit = process.env.stackTraceLimit;
808809
var testConfigFile = 'test.config';
@@ -820,7 +821,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
820821
} while (fs.existsSync(taskConfigsFolder));
821822
fs.mkdirSync(taskConfigsFolder);
822823

823-
workerCount = process.env.workerCount || os.cpus().length;
824+
workerCount = process.env.workerCount || process.env.p || os.cpus().length;
824825
}
825826

826827
if (tests || light || taskConfigsFolder) {
@@ -925,7 +926,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
925926
}
926927
}
927928

928-
var testTimeout = 20000;
929+
var defaultTestTimeout = 20000;
929930
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
930931
task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function () {
931932
runConsoleTests('min', /*runInParallel*/ true);

src/compiler/checker.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15892,7 +15892,7 @@ namespace ts {
1589215892
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
1589315893
if (callSignatures.length) {
1589415894
const signature = resolveCall(node, callSignatures, candidatesOutArray);
15895-
if (!isInJavaScriptFile(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
15895+
if (!isJavaScriptConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
1589615896
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
1589715897
}
1589815898
if (getThisTypeOfSignature(signature) === voidType) {
@@ -16119,6 +16119,26 @@ namespace ts {
1611916119
return getNodeLinks(node).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(node);
1612016120
}
1612116121

16122+
/**
16123+
* Indicates whether a declaration can be treated as a constructor in a JavaScript
16124+
* file.
16125+
*/
16126+
function isJavaScriptConstructor(node: Declaration): boolean {
16127+
if (isInJavaScriptFile(node)) {
16128+
// If the node has a @class tag, treat it like a constructor.
16129+
if (getJSDocClassTag(node)) return true;
16130+
16131+
// If the symbol of the node has members, treat it like a constructor.
16132+
const symbol = isFunctionDeclaration(node) || isFunctionExpression(node) ? getSymbolOfNode(node) :
16133+
isVariableDeclaration(node) && isFunctionExpression(node.initializer) ? getSymbolOfNode(node.initializer) :
16134+
undefined;
16135+
16136+
return symbol && symbol.members !== undefined;
16137+
}
16138+
16139+
return false;
16140+
}
16141+
1612216142
function getInferredClassType(symbol: Symbol) {
1612316143
const links = getSymbolLinks(symbol);
1612416144
if (!links.inferredClassType) {

src/compiler/parser.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6533,6 +6533,10 @@ namespace ts {
65336533
case "augments":
65346534
tag = parseAugmentsTag(atToken, tagName);
65356535
break;
6536+
case "class":
6537+
case "constructor":
6538+
tag = parseClassTag(atToken, tagName);
6539+
break;
65366540
case "arg":
65376541
case "argument":
65386542
case "param":
@@ -6752,6 +6756,13 @@ namespace ts {
67526756
return finishNode(result);
67536757
}
67546758

6759+
function parseClassTag(atToken: AtToken, tagName: Identifier): JSDocClassTag {
6760+
const tag = <JSDocClassTag>createNode(SyntaxKind.JSDocClassTag, atToken.pos);
6761+
tag.atToken = atToken;
6762+
tag.tagName = tagName;
6763+
return finishNode(tag);
6764+
}
6765+
67556766
function parseTypedefTag(atToken: AtToken, tagName: Identifier): JSDocTypedefTag {
67566767
const typeExpression = tryParseTypeExpression();
67576768
skipWhitespace();

src/compiler/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ namespace ts {
374374
JSDocComment,
375375
JSDocTag,
376376
JSDocAugmentsTag,
377+
JSDocClassTag,
377378
JSDocParameterTag,
378379
JSDocReturnTag,
379380
JSDocTypeTag,
@@ -2132,6 +2133,10 @@ namespace ts {
21322133
typeExpression: JSDocTypeExpression;
21332134
}
21342135

2136+
export interface JSDocClassTag extends JSDocTag {
2137+
kind: SyntaxKind.JSDocClassTag;
2138+
}
2139+
21352140
export interface JSDocTemplateTag extends JSDocTag {
21362141
kind: SyntaxKind.JSDocTemplateTag;
21372142
typeParameters: NodeArray<TypeParameterDeclaration>;

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,10 @@ namespace ts {
15621562
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsTag) as JSDocAugmentsTag;
15631563
}
15641564

1565+
export function getJSDocClassTag(node: Node): JSDocClassTag {
1566+
return getFirstJSDocTag(node, SyntaxKind.JSDocClassTag) as JSDocClassTag;
1567+
}
1568+
15651569
export function getJSDocReturnTag(node: Node): JSDocReturnTag {
15661570
return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag;
15671571
}

0 commit comments

Comments
 (0)