question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`object-shorthand` with `ignoreConstructors` option wrongly identifies '_foo' as a constructor name

See original GitHub issue

Tell us about your environment

  • ESLint Version: v5.16.0
  • Node Version: v10.15.3
  • npm Version: v6.4.1

What parser (default, Babel-ESLint, etc.) are you using?

default

Please show your full configuration:

Configuration
{
	env: {
		node: true
	},
	parserOptions: {
		sourceType: 'script'
	},
	extends: [
		'airbnb-base',
		'plugin:eslint-comments/recommended'
	],
	rules: {
		// Alterations of airbnb rules
		'max-len': ['error', {
			code: 105,
			tabWidth: 4,
			ignoreStrings: true,
			ignoreTemplateLiterals: true,
			ignoreRegExpLiterals: true,
			ignoreUrls: true
		}],
		indent: ['error', 'tab'],
		'no-tabs': ['error', {allowIndentationTabs: true}],
		'comma-dangle': ['error', 'never'],
		'object-curly-spacing': ['error', 'never'],
		'one-var': ['off'],
		'no-plusplus': ['off'],
		'no-restricted-syntax': ['off'],
		'no-param-reassign': ['off'],
		'no-use-before-define': ['error', {functions: false}],
		'object-curly-newline': ['error', {multiline: true, consistent: true}],
		'one-var-declaration-per-line': ['error', 'initializations'],
		'prefer-destructuring': ['error',
			{
				VariableDeclarator: {array: false, object: true},
				AssignmentExpression: {array: false, object: false}
			},
			{enforceForRenamedProperties: false}
		],
		'no-invalid-this': ['error'],
		'no-underscore-dangle': ['off'],
		'space-before-function-paren': ['error', {
			anonymous: 'never',
			named: 'never',
			asyncArrow: 'always'
		}],
		'func-names': ['off'],
		'object-shorthand': ['error', 'always', {
			avoidQuotes: true,
			ignoreConstructors: true,
			avoidExplicitReturnArrows: true
		}],

		// eslint-comments rules
		'eslint-comments/no-unused-disable': ['error'],
		'eslint-comments/disable-enable-pair': ['error', {allowWholeFile: true}]
	}
}

What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.

const o = {
  _foo: function() {
    // Foo foo!
  }
};
eslint lib/** --ext .js

What did you expect to happen?

Expected object-shorthand rule to flag a violation of the rule. I am using ignoreConstructors: true option but _foo is not a constructor.

What actually happened? Please include the actual, raw output from ESLint.

No output. The rule is not triggered.

Are you willing to submit a pull request to fix this bug?

Yes.

However, I’m not completely sure what correct behavior is. What characters can a constructor name begin with?

The current check for if an identifier is a “constructor” here is:

function isConstructor(name) {
  const firstChar = name.charAt(0);
  return firstChar === firstChar.toUpperCase();
}

So '_foo' is identified as a constructor. So is '$foo'.

From ECMAScript spec here, it looks like '_' and '$' are the only non-letter characters which are legal as the start of identifiers, so the only chars which will cause this issue.

In which case, an additional line would solve it:

if (firstChar === '_' || firstChar === '$') return false;

But would _Foo be considered a constructor name or not? $Foo?

And are there any other unicode chars which should be similarly be considered not valid as first char of constructor names?

Certainly method names starting with _ are quite common cases, so it’d be good to solve that case at least.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
overlookmotelcommented, Apr 11, 2019

Thanks for swift reply. So are you saying that you think all the following should be treated as constructors names:

Foo
_Foo
$Foo
__Foo
___Foo
$__Foo
_8Foo
$8Foo
__123Foo

and these not:

foo
_foo
$foo
__foo
_8foo
$8foo
_123foo
_
__
$
$$

If so, something like this would do it:

const CTOR_PREFIX_REGEX = /[^_$0-9]/;

function isConstructor(name) {
  const match = CTOR_PREFIX_REGEX.exec(name);
  if (!match) return false; // In case name is e.g. `_`, `$$`, `_8`
  const firstChar = name.charAt(match.index);
  return firstChar === firstChar.toUpperCase();
}
1reaction
btmillscommented, Apr 11, 2019

Good question, I can clarify that a bit if I expand on your example (demo):

/* eslint object-shorthand: ["error", "always", { "ignoreConstructors": true }] */

const obj = {
    // Should have an object-shorthand error
    _privateMethod: function() {
        // Do stuff
    },
    // Should not have an object-shorthand error
    _PrivateConstructor: function() {
        // Return a new instance
    }
};

This is a bit contrived, but the issue I see is that if we change the constructor-detection logic to be firstChar !== "_" && firstChar !== "$" && firstChar === firstChar.toUpperCase(), then _PrivateConstructor wouldn’t be detected, and the error from object-shorthand would be a false positive.

Now that I typed out an example, what if instead of looking at name.charAt(0), should we instead do the first non-/[_$]/ character? People could theoretically then run into the same issue you encountered with a name like _8Name, but that seems way less common than an identifier with just a _ or $ prefix.

Read more comments on GitHub >

github_iconTop Results From Across the Web

object-shorthand - ESLint - Pluggable JavaScript Linter
A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease.
Read more >
demo-outil-edition - node_modules - eslint - CHANGELOG.md
c5c7086 Fix: ignore aligning single line in key-spacing (fixes #11414) (#12652) (YeonJuan) · 9986d9e Chore: add object option test cases in yield ...
Read more >
parsing error: 'const declarations' require an initialization ...
When parsing an assignment within an object pattern, acorn reuses the identifier object for both the Property.key , and the AssignmentPattern.left .
Read more >
IntelliJ IDEA 2018.2 EAP 182.2371.2 Release Notes - YouTrack
Feature IDEA‑152725 Extend templating language to expose outer class Feature IDEA‑143537 Allow line breaks in scope patterns Feature IDEA‑190682 Support multi ip hosts in client‑api...
Read more >
eslint object-shorthand error with variable passed in
Require Object Literal Shorthand Syntax (object-shorthand) - Rule ... defined where the key name matches name of the assigned variable.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found