douglascrockford/JSLint — pull request #165 by jacksonrayhamilton (2014-11-15 10:16:17+00:00)
Title: Add exceptions for __dirname and __filename in dangling underbar check.

Node developers frequently interface with the `__dirname` and `__filename` variables. While their globality may be tolerable via the `node` option, their usage is still considered an error due to the dangling underbar check. You must also enable `nomen` to skip the check, which is undesirable.

Either one lazily enables `nomen` for the entire file (permitting developers to define `_private` methods), or he "temporarily" enables the option...

```javascript
/*jslint node: true */

/*jslint nomen: true */
var a = __dirname;
/*jslint nomen: false */
```

...which gets messy.

The workarounds are not good. Furthermore, node developers are stuck with this API. It's not within our power to make better nomenclature decisions.

On the Google Plus community, you have stated that the `nomen` option will be removed soon. If that were to happen today, it would be impossible for node developers to pass JSLint. That stinks. We just used an API that was given to us; we didn't do anything wrong.

With these points in mind, you should consider adding a special case for tolerating the dangling underbars in the `__dirname` and `__filename` variables if the `node` option is enabled. The variables should be tolerated in their entirety; not just to the extent that they are recognized as poorly-named globals. This will be more in-line with users' expectations, work into the future when `nomen` goes away, and best of all free developers of silly workarounds to comply with a rule that cannot be complied with.

## Tests

`master` currently returns the following:

```javascript
> JSLINT('var a = __dirname;', {node: true})
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: 'var a = __dirname;',
line: 1,
character: 9,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' } ]
> JSLINT('var a = __dirname;')
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: 'var a = __dirname;',
line: 1,
character: 9,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' },
{ id: '(error)',
raw: '\'{a}\' was used before it was defined.',
code: 'used_before_a',
evidence: 'var a = __dirname;',
line: 1,
character: 9,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: '\'__dirname\' was used before it was defined.' } ]
> JSLINT('__dirname = 0;', {node: true})
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: '__dirname = 0;',
line: 1,
character: 1,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' },
{ id: '(error)',
raw: 'Read only.',
code: 'read_only',
evidence: '__dirname = 0;',
line: 1,
character: 1,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Read only.' } ]
> JSLINT('__dirname = 0;')
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: '__dirname = 0;',
line: 1,
character: 1,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' },
{ id: '(error)',
raw: '\'{a}\' was used before it was defined.',
code: 'used_before_a',
evidence: '__dirname = 0;',
line: 1,
character: 1,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: '\'__dirname\' was used before it was defined.' } ]
> JSLINT('var __dirname = 0;', {node: true})
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: 'var __dirname = 0;',
line: 1,
character: 5,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' },
{ id: '(error)',
raw: 'Read only.',
code: 'read_only',
evidence: 'var __dirname = 0;',
line: 1,
character: 5,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Read only.' } ]
> JSLINT('var __dirname = 0;')
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: 'var __dirname = 0;',
line: 1,
character: 5,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' } ]
```

My branch returns the following:

```javascript
> JSLINT('var a = __dirname;', {node: true})
true
> JSLINT('var a = __dirname;')
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: 'var a = __dirname;',
line: 1,
character: 9,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' },
{ id: '(error)',
raw: '\'{a}\' was used before it was defined.',
code: 'used_before_a',
evidence: 'var a = __dirname;',
line: 1,
character: 9,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: '\'__dirname\' was used before it was defined.' } ]
> JSLINT('__dirname = 0;', {node: true})
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Read only.',
code: 'read_only',
evidence: '__dirname = 0;',
line: 1,
character: 1,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Read only.' } ]
> JSLINT('__dirname = 0;')
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: '__dirname = 0;',
line: 1,
character: 1,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' },
{ id: '(error)',
raw: '\'{a}\' was used before it was defined.',
code: 'used_before_a',
evidence: '__dirname = 0;',
line: 1,
character: 1,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: '\'__dirname\' was used before it was defined.' } ]
> JSLINT('var __dirname = 0;', {node: true})
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Read only.',
code: 'read_only',
evidence: 'var __dirname = 0;',
line: 1,
character: 5,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Read only.' } ]
> JSLINT('var __dirname = 0;')
false
> JSLINT.data().errors
[ { id: '(error)',
raw: 'Unexpected dangling \'_\' in \'{a}\'.',
code: 'dangling_a',
evidence: 'var __dirname = 0;',
line: 1,
character: 5,
a: '__dirname',
b: undefined,
c: undefined,
d: undefined,
reason: 'Unexpected dangling \'_\' in \'__dirname\'.' } ]
```

If you diff them, you will find that JSLINT only stops reporting errors in the case of interfacing with `__dirname`. Everything else remains the same. Adding this exception doesn't open up a "loophole" whereby node developers can violate good nomenclature rules by declaring a local variable called `__dirname`; we still get `"Read only."`.