Skip to content
This repository was archived by the owner on Mar 25, 2021. It is now read-only.

Conversation

@ghost
Copy link

@ghost ghost commented Apr 6, 2017

PR checklist

  • Addresses an existing issue: #0000
  • New feature, bugfix, or enhancement
    • Includes tests
  • Documentation update

Overview of change:

The var keyword is useful in one case: When you want to declare a global variable.
The problem with declaring a global const is that this is considered a block-scoped declaration, and will warn for duplicates.

declare global {
    var x: number;
    var x: number; // OK
    const y: number;
    const y: number; // Error
}

This PR changes the rule to allow var in a position where it declares a global variable.
It still warns for:

  • export var x: number; (not global)
  • var x; (not a declaration if not in declare global)

Note: Also disabled fixer in declaration files, because those should almost always be const instead of let, and we can't detect prefer-const in declarations (#2390).

CHANGELOG.md entry:

[enhancement] no-var-keyword: Allow global var declarations

Sorry, something went wrong.


return isNodeFlagSet(parentNode!, ts.NodeFlags.Let)
|| isNodeFlagSet(parentNode!, ts.NodeFlags.Const);
export function isBlockScopedVariableDeclarationList(node: ts.VariableDeclarationList): boolean {// tslint:disable-next-line no-bitwise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is already available from tsutils, so there is no need to duplicate it here

function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void {
switch (node.kind) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could simplify the condition and replace the whole switch statement with this:

if (isVariableDeclarationList(node) && !isBlockScopedVariableDeclarationList(node) &&
    (node.parent!.kind !== ts.SyntaxKind.VariableStatement || !isGlobalVarDeclaration(node.parent!)))
  fail(node);

you could even consider inlining fail

function fail(node: ts.Node): void {
// Don't apply fix in a declaration file, because may have meant 'const'.
const fix = sourceFile.isDeclarationFile ? undefined : new Lint.Replacement(node.getStart(), "var".length, "let");
ctx.addFailureAtNode(Lint.childOfKind(node, ts.SyntaxKind.VarKeyword)!, Rule.FAILURE_STRING, fix);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no need for addFailureAtNode with childOfKind, you already computed the position of the var keyword for the fix one line above.

this.createReplacement(nodeStart, "var".length, "let"));
}
function isDeclareGlobal(node: ts.Node): boolean {
return isModuleDeclaration(node) && node.name.kind === ts.SyntaxKind.Identifier && node.name.text === "global";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ModuleBlock.parent is always a ModuleDeclaration. typescript@next contains the correct types.
for now it is save to just assert the type

super.visitForOfStatement(node);
function fail(node: ts.Node): void {
// Don't apply fix in a declaration file, because may have meant 'const'.
const fix = sourceFile.isDeclarationFile ? undefined : new Lint.Replacement(node.getStart(), "var".length, "let");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider passing sourceFile as argument to node.getStart()

this.createReplacement(nodeStart, "var".length, "let"));
}
function isDeclareGlobal(node: ts.Node): boolean {
return isModuleDeclaration(node) && node.name.kind === ts.SyntaxKind.Identifier && node.name.text === "global";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could even simplify this further:

return (node.flags & ts.NodeFlags.GlobalAugmentation) !== 0;

In addition you avoid false positived for namespace foo.global {} and namespace foo { export namespace global {} } (those are also good candidates for a test)

You can even consider inlining this condition.

@adidahiya adidahiya added this to the TSLint v5.2 milestone Apr 12, 2017
@adidahiya adidahiya merged commit 7816eeb into palantir:master Apr 12, 2017
@ghost ghost deleted the var branch April 12, 2017 14:17
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

None yet

2 participants