@dabh/eslint-config-populist

中文文档
4.4.0发布于 2024/07/11MITCommonJS近 30 天下载 2547

A (one day) auto-updating style at the mercy of the people, and only the people.

原始使用文档
文档目录27 节
  1. Table of Contents
  2. Compliance Levels
  3. GOOD and BAD
  4. OK
  5. Ground Rules
  6. Semicolons
  7. Braces
  8. Naming Conventions
  9. Variable declarations
  10. Objects
  11. Arrays
  12. Strings
  13. Code Comments
  14. GOOD
  15. OK
  16. GOOD
  17. BAD
  18. Constructors
  19. Control-flow
  20. Functions
  21. Conditionals
  22. Type Casting & Coercion
  23. Ternary operators
  24. Errors
  25. Exports
  26. Async Programming
  27. Attribution (with modifications and additions)

Populist Style for JavaScript

A (one day) auto-updating style at the mercy of the people, and only the people.

Today it is still a bespoke set of rules. One has to have goals, no? The copy below is unfortunately a bit out of date compared to the latest eslint rules in index.js. They remain because reusing the English copy is very likely even with new and/or slightly different rules.

If you have comments on this or disagree about rules then please reach out to me directly. I want to hear it!

Table of Contents

Basics

Identifiers and Primitives

Statements and Techniques

Attribution

Compliance Levels

GOOD and BAD

  • always / must: This is mandatory. Seriously
  • never / must not: Don't ever do this. Seriously.

OK

  • should: Try to do this. It is encouraged but not strictly enforced.
  • should not: Try not to do this. It is discouraged but not prohibited.

Ground Rules

  • RULE: Always 2-space soft indents (no tabs)
  • RULE: Always semicolons (with one exception).
  • RULE: Never use comma first
  • RULE: Never use () around statements like typeof or delete.

Semicolons

  • RULE: Semicolons ; must be added at the end of every statement, except when the next character is a closing bracket }. In that case, they may be omitted.
//
// GOOD
//
var f = function add(a, b) {
  if (a == b) { return a * 2 }   // No `;` here.
  return a + b;
};
//
// BAD
//
var f = function add (a, b) {
  return a + b
}

[⬆]

Braces

  • RULE: Braces must be used in all circumstances. They may be used on a single line around simple statements.
//
// GOOD
//
if (x) { return true }
//
// BAD
//
if (x)
  while (1)
    i ++;
else
  //...
//
// BAD
//
if (x) return true;
//
// BAD
//
if (x)
  return true;

  • RULE: Opening Braces must never be on a line of their own.
  • Rule: Closing braces must never be followed by a conditional statement

Vertical screen space is precious, and ease of scanning code is more previous.

//
// GOOD
//
if (x) {
  return true;
}
else {
  return false;
}
//
// BAD
//
if (x)
{
  return true;
}
//
// BAD
//
if (x) {
  return true; }
//
// BAD
//
if (x) {
  return true;
} else {
  return false
}

  • RULE: Closing Braces must always be on a line of their own unless they also start on that line.

This makes it easy to see the end of a function or statement

//
// GOOD
//
return callback && callback({ foo: bar });
//
// GOOD
//
return callback && callback({
  foo: bar
});
//
// BAD
//
return callback && callback({
  foo: bar });
//
// BAD
//
return callback && callback({ foo: bar
  });

[⬆]

Naming Conventions

  • RULE: Avoid single letter names. Be descriptive with your naming.
//
// BAD
//
function q() {
  // ...stuff...
}

//
// GOOD
//
function query() {
  // ..stuff..
}

  • RULE: Use camelCase when naming objects, functions, and instances
//
// BAD
//
var OBJEcttsssss = {};
var this_is_my_object = {};
var this-is-my-object = {};
function c() {};
var u = new user({
  name: 'Bob Parr'
});

//
// GOOD
//
var thisIsMyObject = {};

function thisIsMyFunction() {};

var user = new User({
  name: 'Bob Parr'
});

  • RULE: Use PascalCase when naming constructors or classes
// BAD
function user(options) {
  this.name = options.name;
}

var bad = new user({
  name: 'nope'
});

// GOOD
function User(options) {
  this.name = options.name;
}

var good = new User({
  name: 'yup'
});

  • RULE: Use a leading underscore _ when naming private properties
// BAD
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';

// GOOD
this._firstName = 'Panda';

  • RULE: Saved references to this (which is a prototypal object) must use self.
function User (options) {
  this.setup();
}

//
// GOOD
//
User.prototype.setup = function () {
  var self = this;

  setTimeout(function () {
    self.ready = true
  }, 1000);
};

//
// BAD
//
User.prototype.setup = function () {
  var that = this;

  setTimeout(function () {
    that.ready = true
  }, 1000);
};

  • RULE: Saved references to this (which is an arbitrary scope) should use that.
//
// BAD
//
function () {
  var self = this;
  return function() {
    console.log(self);
  };
}

//
// BAD
//
function () {
  var _this = this;
  return function() {
    console.log(_this);
  };
}

//
// GOOD
//
function () {
  var that = this;
  return function() {
    console.log(that);
  };
}

  • RULE: Functions should be named. This is helpful for stack traces.
//
// OK
//
var log = function(msg) {
  console.log(msg);
};

//
// GOOD
//
var log = function log(msg) {
  console.log(msg);
};

[⬆]

Variable declarations

  • RULE: Variables must always be declared, prior to use.
  • RULE: Variable declarations must appear at the top of functions, and not inside other blocks. The exception is for loops.

Variable declarations are moved up to the top of the function scope anyway, so that's where they belong.

//
// GOOD
//
function (a, b) {
  var k;

  if (a == b) {
    k = true;
  }
  //...
}

for (var i = 0; i < l; i ++) {
  //...
}
//
// BAD
//
function (a, b) {
  if (a == b) {
    var k = true;
  }
  //...
}

  • RULE: Variables must always align when they are declared

This makes it easy to scan what is declared in a single block.

//
// GOOD
//
var bazz,
    foo,
    bar;
//
// BAD
//
var bazz,
  foo,
  bar;

  • RULE: Declare unassigned variables last.

This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.

//
// BAD
//
var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

//
// BAD
//
var i, items = getItems(),
    dragonball,
    goSportsTeam = true,
    len;

//
// GOOD
//
var items = getItems(),
    goSportsTeam = true,
    dragonball,
    length,
    i;

  • RULE: Variables should always be declared in decreasing length.

This also makes it easier to scan what is declared in a single block (trust me).

//
// GOOD
//
var reallyLongVar,
    shorterVar,
    fooBar,
    foo;
//
// BAD
//
var fooBar,
    shorterVar,
    foo,
    reallyLongVar;

  • RULE: Variable assignments must come before declarations.
  • RULE: Variable assignments should align when convenient depending on additional length.

This also makes it easier to scan what is declared in a single block (trust me).

//
// GOOD
//
var reallyLongVar = 10e3,
    shorterVar    = 5e2,
    fooBar        = 'foobar',
    foo;
//
// OK
//
var reallyLongVar = 10e3,
    shorterVar = 5e2,
    fooBar = 'foobar',
    foo;
//
// BAD
//
var foo,
    reallyLongVar = 10e3,
    shorterVar = 5e2,
    fooBar = 'foobar';

  • RULE: Multi-line object literals must be assigned outside of multi-line variable declaration blocks.

It's what god would have wanted.

//
// GOOD
//
var obj  = { list: [], expired: false },
    bazz = 100,
    foo,
    bar;
//
// GOOD
//
var bazz = 100,
    foo,
    bar,
    obj;

obj  = {
  list: [],
  expired: false
};
//
// BAD
//
var obj  = {
  list: [],
  expired: false
},
    bazz = 100,
    foo,
    bar;
//
// BAD
//
var bazz = 100,
    foo,
    bar,
    obj = {
      list: [],
      expired: false
    };

  • RULE: Assignment depending on multi-line functions or multiple functions must be assigned outside of multi-line variable declaration blocks.
//
// GOOD
//
var memo = list.filter(function (i) { return i < 10 }),
    bazz = 100,
    foo,
    bar;
//
// GOOD
//
var bazz = 100,
    memo,
    foo,
    bar;

memo = list.filter(function (i) {
  return i < 10;
}).filter(Boolean);
//
// BAD
//
var memo = list.filter(function (i) {
  return i < 10
}),
    bazz = 100,
    foo,
    bar;
//
// BAD
//
var bazz = 100,
    foo,
    bar,
    memo = list.filter(function (i) {
      return i < 10;
    }).filter(Boolean);
//
// BAD
//
var bazz = 100,
    foo,
    bar,
    memo = list.filter(function (i) { return i < 10 })
      .filter(Boolean);

[⬆]

Objects

  • RULE: Single line object must have a trailing space after { and a leading space before }.
//
// BAD
//
var foo = {bar: 1};
//
// BAD
//
return {bar: 1};
//
// GOOD
//
var foo = { bar: 1 };
//
// GOOD
//
return { bar: 1 };

  • RULE: Properties in objects must be followed by a :
//
// BAD
//
var foo = { bar:1 };
//
// BAD
//
var foo = {
  bar  : 1,
  bazz : 1
};
//
// GOOD
//
var foo = { bar: 1 };
//
// GOOD
//
var foo = {
  bar: 1,
  bazz: 1
};
//
// GOOD
//
var foo = {
  bar:  1,
  bazz: 1
};

  • RULE: Multi-line assignment statements inside an object literal are encouraged.

Reduces the number of variables managed and object creation is cheap.

//
// GOOD
//
return {
  foos: list.filter(function (i) {
    return i.type === 'foo';
  }),
  bars: list.filter(function (i) {
    return i.type === 'bar';
  })
}

  • RULE: Use the literal syntax for object creation.
//
// BAD
//
var item = new Object();

//
// GOOD
//
var item = {};
//
// OK
//
var superman = {
 class: 'superhero',
 default: { clark: 'kent' },
 private: true
};

[⬆]

Arrays

  • RULE: Use the literal syntax for array creation
//
// BAD
//
var items = new Array();

// GOOD
var items = [];

  • RULE: If you don't know array length use Array#push.
var someStack = [];

//
// BAD
//
someStack[someStack.length] = 'abracadabra';

//
// GOOD
//
someStack.push('abracadabra');

  • RULE: When you need to copy an array use Array#slice. jsPerf
var len = items.length,
    itemsCopy = [],
    i;

//
// BAD
//
for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

//
// GOOD
//
itemsCopy = items.slice();

[⬆]

Strings

  • RULE: Use single quotes '' for strings
//
// BAD
//
var name = "Bob Parr";

//
// GOOD
//
var name = 'Bob Parr';

//
// BAD
//
var fullName = "Bob " + this.lastName;

//
// GOOD
//
var fullName = 'Bob ' + this.lastName;

  • RULE: Strings longer than 80 characters should be written across multiple lines using string concatenation.

If overused, long strings with concatenation could impact performance. jsPerf & Discussion

//
// BAD
//
var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

//
// BAD
//
var errorMessage = 'This is a super long error that \
was thrown because of Batman. \
When you stop to think about \
how Batman had anything to do \
with this, you would get nowhere \
fast.';

//
// GOOD
//
var errorMessage = 'This is a super long error that ' +
  'was thrown because of Batman.' +
  'When you stop to think about ' +
  'how Batman had anything to do ' +
  'with this, you would get nowhere ' +
  'fast.';

//
// GOOD
//
var errorMessage = [
  'This is a super long error that ',
  'was thrown because of Batman.',
  'When you stop to think about',
  'how Batman had anything to do',
  'with this, you would get nowhere'
  'fast.'
].join(' ');

  • RULE: When programatically building up a string, use Array#join instead of string concatenation. Mostly for IE: jsPerf.
var items,
    messages,
    length,
    i;

messages = [{
  state: 'success',
  message: 'This one worked.'
}, {
  state: 'success',
  message: 'This one worked as well.'
}, {
  state: 'error',
  message: 'This one did not work.'
}];

length = messages.length;

//
// BAD
//
function inbox(messages) {
  items = '<ul>';

  for (i = 0; i < length; i++) {
    items += '<li>' + messages[i].message + '</li>';
  }

  return items + '</ul>';
}

//
// GOOD
//
function inbox(messages) {
  items = [];

  for (i = 0; i < length; i++) {
    items[i] = messages[i].message;
  }

  return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
}

[⬆]

Code Comments

  • RULE: You should not use JSDoc.
  • RULE: Block comments should only be used in file headers.
  • RULE: You should not use single-line block comments
  • RULE: Put an emptyline before a comment.

Having appropriate space in your code comments makes writing complex code easier to read. It's the "almost literate coding" approach.

  • REMARK: JSDoc should be considered deprecated. When time is available to improve the docco-style comments we have historically used we will replace it all together.

GOOD

/*
 * a-js-file.js: This is some file
 *
 * (C) 2013 Whomever
 * MIT LICENSE
 *
 */
//
// ### function myFunction (a, b, c)
// #### @a {string} A variable
// #### @b {boolean} Another variable
// #### @c {object|Array} An object or an array
//
// This is the description to my function.
//
//
// Adding additional padding in your code comments
//
var a = 0;

//
// Along with additional whitespace
//
if (!a) {
  console.log('Makes your code easier to read.');
  console.log('What are you running out of bytes?');
}

OK

// One line comments
var a = 0;
// and no whitespace
if (!a) {
  console.log('make your code harder to read');
  console.log('seriously.');
}
/*
 * I'm using block comments anywhere but the file header.
 */

  • RULE: Use // FIXME: to annotate problems.
  • RULE: Use // TODO: to annotate solutions to problems.
  • RULE: Use // REMARK: to annotate possible annotations or open implementation questions (which are not obvious problems).
  • RULE: Sign these comments with your Github username.

GOOD

function Calculator() {

  // FIXME (index zero): shouldn't use a global here
  total = 0;

  return this;
}
function Calculator() {

  // TODO (indexzero): total should be configurable by an options param
  this.total = 0;

  return this;
}

BAD

function Calculator() {

  // shouldn't use a global here
  total = 0;

  return this;
}
function Calculator() {

  // TODO: total should be configurable by an options param
  this.total = 0;

  return this;
}

[⬆]

Constructors

  • RULE: Assign methods to the prototype object. You must never overwrite the prototype with a new object completely.

Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base!

function Jedi() {
  console.log('new jedi');
}

//
// BAD
//
Jedi.prototype = {
  fight: function fight() {
    console.log('fighting');
  },

  block: function block() {
    console.log('blocking');
  }
};

//
// GOOD
//
Jedi.prototype.fight = function fight() {
  console.log('fighting');
};

Jedi.prototype.block = function block() {
  console.log('blocking');
};

  • RULE: Methods can return this to help with method chaining.
//
// OK
//
Jedi.prototype.jump = function() {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
};

var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20) // => undefined

//
// GOOD
//
Jedi.prototype.jump = function() {
  this.jumping = true;
  return this;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
  return this;
};

var luke = new Jedi();

luke.jump()
  .setHeight(20);

  • RULE: It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects.
function Jedi(options) {
  options || (options = {});
  this.name = options.name || 'no name';
}

Jedi.prototype.getName = function getName() {
  return this.name;
};

Jedi.prototype.toString = function toString() {
  return 'Jedi - ' + this.getName();
};

[⬆]

Control-flow

  • RULE: Control-flow statements, such as if, while and for must have a space between the keyword and the left parenthesis.

They aren't functions, and thus better distinguished like this.

//
// GOOD
//
if (a) {
  return true;
}
//
// BAD
//
if(a) {
  return true;
}

  • RULE: Eager returns must be preferred over if else blocks.

Eager returns simplifies most control-flow, especially more complex and high-level control-flow.

//
// BAD
//
if (foo) {
  callback(null, 'foo');
}
else {
  callback(null, 'bar');
}
//
// GOOD
//
if (foo) {
  return callback(null, 'foo');
}

callback(null, 'bar');

[⬆]

Functions

  • RULE: Anonymous functions must have a space between the function keyword and the left parenthesis.

To emphasise the lack of identifier and differentiate them with named functions.

//
// GOOD
//
function (a, b) {}
//
// BAD
//
function(a, b) {}

  • RULE: Named functions must not have a space between the function name and the left parenthesis.
  • RULE: Function calls must not have a space between the function name and the left parenthesis.
//
// GOOD
//
function add(a, b) {}
//
// BAD
//
function add (a, b) {}

[⬆]

Conditionals

  • RULE: Multi-line conditional statements must be properly indented.
  • RULE: Newlines in multi-line conditional statements must be be followed by a boolean operator or (.
  • RULE: Conditional should not contain complex logic.
//
// GOOD
//
if (something === 'foo' && (somethingElse === 'bar'
    && ohYeahThisToo === 'bazz')) {
  return false;
}
//
// BAD
//
if (something === 'foo' && (somethingElse === 'bar' &&
ohYeahThisToo === 'bazz')) {
  return false;
}
//
// BAD
//
if (something === 'foo' && (somethingElse === 'bar' &&
    ohYeahThisToo === 'bazz') {
  return false;
}
//
// OK
//
if (list.filter(function (i) { return i.ok }).length > 5) {
  return false;
}

[⬆]

Type Casting & Coercion

  • RULE: Perform type coercion at the beginning of the statement.
//  => this.reviewScore = 9;

//
// BAD
//
var totalScore = this.reviewScore + '';

//
// GOOD
//
var totalScore = '' + this.reviewScore;

//
// BAD
//
var totalScore = '' + this.reviewScore + ' total score';

//
// GOOD
//
var totalScore = this.reviewScore + ' total score';

  • RULE: Use parseInt for Numbers and always with a radix for type casting.

If for whatever reason you are doing something wild and parseInt is your bottleneck and need to use Bitshift for performance reasons, leave a comment explaining why and what you're doing.

Numbers

var inputValue = '4';

//
// OK
//
var val = +inputValue;

//
// BAD
//
var val = new Number(inputValue);

//
// BAD
//
var val = inputValue >> 0;

//
// BAD
//
var val = parseInt(inputValue);

//
// GOOD
//
var val = Number(inputValue);

//
// GOOD
//
var val = parseInt(inputValue, 10);

//
// GOOD
//

//
// parseInt was the reason my code was slow.
// Bitshifting the String to coerce it to a
// Number made it a lot faster.
//
var val = inputValue >> 0;

Booleans

var age = 0;

//
// BAD
//
var hasAge = new Boolean(age);

//
// GOOD
//
var hasAge = Boolean(age);

//
// GOOD
//
var hasAge = !!age;

[⬆]

Ternary operators

  • RULE: Ternary operators are OK, but must never be combined.

More than one and it's spaghetti.

//
// GOOD
//
var i = 2,
    x = i > 5 ? i : 0;
//
// BAD
//
var i = 2,
    j = 3,
    x = i > 5 ? j > 4 ? j : i : 0;

  • RULE: Multi-line Ternary operators are OK, but must be single line statements..
  //
  // GOOD
  //
  return foo
    ? foo + 1
    : bar;
  //
  // GOOD
  //
  return foo ? foo + 1 : bar;
  //
  // GOOD
  //
  return foo
    ? function () { return foo + 1 }
    : bar;
  //
  // GOOD
  //
  return err
    ? callback(err)
    : callback();
  //
  // BAD
  //
  return foo ?
    foo + 1 :
    bar;
  //
  // BAD
  //
  return foo
    ? foo + 1 :
    bar;
  //
  // BAD
  //
  return foo
    ? function (wtf) {
      return foo + 1; // No multi-line return values!
    }
    : bar;

  • RULE: Ternary operators combined with return should be preferred over if (err) { return } blocks.
  //
  // OK
  //
  if (err) {
    return callback(err);
  }

  callback();
  //
  // GOOD
  //
  return err
    ? callback(err)
    : callback();

[⬆]

Errors

If you want more descriptive Errors, use errs.

//
// GOOD
//
throw new Error('I have a call-stack and other good things.');
//
// GOOD
//
callback(new Error('I have a call-stack and other good things.'));
//
// BAD
//
throw 'I have no call-stack no interesting properties.';
//
// BAD
//
callback('I have no call-stack no interesting properties.');
//
// BAD
//
throw { message: 'I have no call-stack no interesting properties.' };
//
// BAD
//
callback({
  message: 'I have no call-stack no interesting properties.'
});

[⬆]

Exports

  • RULE: If you are exporting something, it should be exported on the same line as the declaration.

Makes it easier to understand what the exports are immediately in the same context.

//
// GOOD
//
var Foo = exports.Foo = function () {
  //...
};
//
// BAD
//
var Foo = function () {
  //...
};

//
// Lots of other code changing my mental context
// by the time I see Foo again I forgot what it was.
//

exports.Foo = Foo;

[⬆]

Async Programming

  • RULE: You must not use promises.
  • RULE: You must use async.

Just use async. If you love promises then sorry; this decision is final and not up for debate … ever.

//
// GOOD
//
var async = require('async');
//
// BAD
//
var Q = require('q');

  • RULE: A given function must not have more than three callback functions.

Rule of three. What? It works in fairy tales.

INSERT CODE EXAMPLES HERE

  • RULE: Named functions should be preferred over anonymous inline functions.

[⬆]

Attribution (with modifications and additions)

The following files include software modified from
eslint-config-godaddy with attribution under MIT
© GoDaddy Operating Company 2016

index.js
bin/eslint-autofix.js

Modifications © Charlie Robbins 2017

版本与发布记录

@dabh/eslint-config-populist 共发布 3 个版本,首次发布于 2022/02/06;过去 12 个月发布了 0 个版本。

版本发布日期距今
4.4.0latest2024/07/112 年前
5.0.02022/02/064 年前
4.3.02022/02/064 年前

关于 @dabh/eslint-config-populist 的常见问题

@dabh/eslint-config-populist 是什么?

A (one day) auto-updating style at the mercy of the people, and only the people.

如何安装 @dabh/eslint-config-populist?

在项目目录运行 npm install @dabh/eslint-config-populist,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:eslint(>=8.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@dabh/eslint-config-populist 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/dabh__eslint-config-populist 是否存在。

@dabh/eslint-config-populist 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@dabh/eslint-config-populist 可以商用吗?

@dabh/eslint-config-populist 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dabh/eslint-config-populist 的下载量有多少?

根据 npm 官方下载统计,@dabh/eslint-config-populist 在 2026/10/11 – 2026/11/09 这 30 天内被下载 2,547 次,日均约 85 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dabh/eslint-config-populist 还在维护吗?

最新版本 4.4.0 发布于 2024/07/11(2 年前);至今共发布 3 个版本,其中过去 12 个月发布了 0 个;首次发布于 2022/02/06。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。