Giter Club home page Giter Club logo

eslint-plugin-proper-arrows's Introduction

ESLint Plugin: proper-arrows

Build Status npm Module Dependencies devDependencies Coverage Status

Overview

The proper-arrows ESLint plugin provides rules that control the definitions of => arrow functions, restricting them to a narrower and more proper/readable form.

The rules defined in this plugin:

  • "params": controls definitions of => arrow function parameters, such as forbidding unused parameters, forbidding short/unsemantic parameter names, etc.

  • "name": requires => arrow functions to only be used in positions where they receive an inferred name (i.e., assigned to a variable or property, etc), to avoid the poor readbility/debuggability of anonymous function expressions.

    Note: This rule is like the "as-needed" mode of the built-in ESLint "func-names" rule, but applied to => arrow functions; the built-in rule ignores them.

  • "where": restricts where in program structure => arrow functions can be used: forbidding them in the global/top-level-module scope, object properties, export statements, etc.

  • "return": restricts the concise return value kind for => arrow functions, such as forbidding object literal concise returns (x => ({ x })), forbidding concise returns of conditional/ternary expressions (x => x ? y : z), etc.

  • "this": requires/disallows => arrow functions using a this reference, in the => arrow function itself or in a nested => arrow function; optionally, this rule can forbid this-containing => arrow functions only from the global scope.

Trivial => Arrow Functions

It's common for => arrow functions to be used as a shorthand for simple/trivial function roles, such as:

// no-op function
() => {};

// constant function
() => 42;

// closure function
() => v;

// identity function
v => v;

Note: To be specific on the definition of "trivial" being used here: trivial functions have no more than 1 parameter (simple identifier only), and either have no return ({}) or a concise return of: a single variable, primitive (non-object) literal, or a void __ expression.

These types of functions are so simple that they don't suffer much from readability issues despite their concise syntax. As such, it's likely preferred to allow them even if one of the rules here would normally report them.

By default, all rules ignore these trivial functions. To force a rule to check trivial functions, include this configuration option for the rule:

{ "trivial": true }

Note: The "trivial" option will not necessarily report trivial functions, but it will force trivial functions to be checked by the rule/mode in question.

Enabling The Plugin

To use proper-arrows, load it as a plugin into ESLint and configure the rules as desired.

extends

If you'd like to use the proper-arrows plugin in a recommended configuration preset, you can add the plugin in the extends clause of your ESLint configuration, and pick a preset by name:

"extends": [
    // ..
    "plugin:@getify/proper-arrows/CONFIG-PRESET-NAME",
    // ..
]

Note: All included configuration presets not only define specific rule configurations but also automatically load the plugin itself, so you don't need to list proper-arrows in the plugins clause.

The available configuration presets to choose from:

It's important to note that you can still override any of the preset rule definitions in your configuration. Think of these presets as convenience "defaults" that can still be customized.

.eslintrc.json

To load the plugin and enable its rules via a local or global .eslintrc.json configuration file:

"plugins": [
    "@getify/proper-arrows"
],
"rules": {
    "@getify/proper-arrows/params": ["error",{"unused":"trailing"}],
    "@getify/proper-arrows/name": ["error",{"trivial":false}],
    "@getify/proper-arrows/where": ["error",{"global":true}],
    "@getify/proper-arrows/return": ["error",{"object":true}],
    "@getify/proper-arrows/this": ["error","always",{"no-global":true}]
}

package.json

To load the plugin and enable its rules via a project's package.json:

"eslintConfig": {
    "plugins": [
        "@getify/proper-arrows"
    ],
    "rules": {
        "@getify/proper-arrows/params": ["error",{"unused":"trailing"}],
        "@getify/proper-arrows/name": ["error",{"trivial":false}],
        "@getify/proper-arrows/name": ["error",{"global":true}],
        "@getify/proper-arrows/return": ["error",{"object":true}],
        "@getify/proper-arrows/this": ["error","always",{"no-global":true}]
    }
}

ESLint CLI parameters

To load the plugin and enable its rules via ESLint CLI parameters, use --plugin and --rule flags:

eslint .. --plugin='@getify/proper-arrows' --rule='@getify/proper-arrows/params: [error,{"unused":"trailing"}]' ..
eslint .. --plugin='@getify/proper-arrows' --rule='@getify/proper-arrows/name: [error,{"trivial":false}]' ..
eslint .. --plugin='@getify/proper-arrows' --rule='@getify/proper-arrows/where: [error,{"global":true}]' ..
eslint .. --plugin='@getify/proper-arrows' --rule='@getify/proper-arrows/return: [error,{"object":true}' ..
eslint .. --plugin='@getify/proper-arrows' --rule='@getify/proper-arrows/this: [error,always,{"no-global":true}]' ..

ESLint Node API

To use this plugin in Node.js with the ESLint API, require the npm module, and then (for example) pass the rule's definition to Linter#defineRule(..), similar to:

var properArrows = require("@getify/eslint-plugin-proper-arrows");

// ..

var eslinter = new (require("eslint").Linter)();

eslinter.defineRule("@getify/proper-arrows/params",properArrows.rules.params);

eslinter.defineRule("@getify/proper-arrows/name",properArrows.rules.name);

eslinter.defineRule("@getify/proper-arrows/where",properArrows.rules.where);

eslinter.defineRule("@getify/proper-arrows/return",properArrows.rules.return);

eslinter.defineRule("@getify/proper-arrows/this",properArrows.rules.this);

Then lint some code like this:

eslinter.verify(".. some code ..",{
    rules: {
        "@getify/proper-arrows/params": ["error",{unused:"trailing"}],
        "@getify/proper-arrows/name": ["error",{trivial:false}],
        "@getify/proper-arrows/where": ["error",{trivial:true}],
        "@getify/proper-arrows/return": ["error",{object:true}],
        "@getify/proper-arrows/this": ["error","always",{"no-global":true}]
    }
});

Inline Comments

Once the plugin is loaded, the rule can be configured using inline code comments if desired, such as:

/* eslint "@getify/proper-arrows/params": ["error",{"unused":"trailing"}] */
/* eslint "@getify/proper-arrows/name": "error" */
/* eslint "@getify/proper-arrows/return": ["error",{"object":true}] */
/* eslint "@getify/proper-arrows/this": ["error","always",{"no-global":true}] */

Rule: "params"

The proper-arrows/params rule controls definitions of parameters for => arrow functions.

This rule can be configured to forbid unused parameter names ("unused"), limit the number of parameters ("count"), and require parameter names to be at least a certain length ("length"). Also, this rule can specify a list of exceptions to always allow certain parameter names ("allow").

To turn this rule on:

"@getify/proper-arrows/params": "error"
"@getify/proper-arrows/params": [ "error", { "unused": true, "count": 3, "length": 4, "allow": [ "e", "err" ], "trivial": false } ]

The main purpose of this rule is to avoid readability harm for => arrow functions by ensuring the parameters are clean and "proper".

By forbidding unused parameters, the reader is not confused searching for their usage. By requiring parameters that are long enough to have meaningful names, the reader can understand the function better. By limiting the number of parameters, the reader can more easily visually distinguish the whole function definition.

For example:

var fn = (data,user) => ajax(user.id,data);

In this snippet, the => arrow function has two parameters, and both are 4 characters long and used in the function body. Therefore, the proper-arrows/params rule would not report any errors.

By contrast, this rule would report errors for:

var fn = (d,u,m,b) => ajax(u.id,d);

Here, the => arrow function has 4 parameters (too many!), each one is a single character (too short!), and two of them are unused.

Rule Configuration

The proper-arrows/params rule can be configured with any combination of three modes: "unused", "count", and "length". Also, parameter names can be explicitly allowed by name (thus not reporting any error for these modes) in the "allowed" setting.

Note: The default behavior is that all three modes are turned on. You must specifically configure each mode to (effectively) disable it.

  • "unused" (default: "all") forbids named parameters that are not used inside the function. Can also be set to "trailing" to only report unused errors for trailing parameters -- that is, only those which come after the last parameter that is used -- or set to "none" to disable this mode.

  • "count" (default: 3) is the maximum count for parameters on an => arrow function. All parameters are counted to check against the limit, including any "allowed" parameters and the "...rest" parameter. Set to a larger number to effectively disable this mode.

  • "length" (default: 2) is the minimum length of allowed parameter names. Set to 0 to effectively disable this mode.

  • "allowed" (default: []) is a list of parameter names to ignore and not report any errors for.

Rule "params" Configuration: "unused"

Note: This rule mode resembles the built-in "no-unused-vars" rule, but instead focuses only on the parameters of => arrow functions.

To configure this rule mode (default: "all"):

"@getify/proper-arrows/params": "error"
"@getify/proper-arrows/params": [ "error", { "unused": "all", "trivial": false } ]

The "unused": "all" (default) mode checks each parameter to see if it's used anywhere within the function. If not, the parameter is reported as an error.

For example:

var fn1 = (one,two) => one + two;

var fn2 = (one,two = one) => two * 2;

var fn3 = one => two => three => one * two * three;

These statements all report no errors, because all parameters are used somewhere in each function.

By contrast, this rule would report errors for:

var fn1 = (one,two) => one * 2;

var fn2 = (one,...rest) => one * 2;

var fn3 = one => two => three => one * three;

In each statement, a parameter is defined in an => arrow function that is not used within.

"unused": "trailing"

It is sometimes desired to name some positional parameters that are effectively ignored by the function body, while using other named parameters that come after. As such, it can be helpful to suppress reports except on unused parameters that come after the last used parameter in the function signature.

In the "unused": "trailing" mode, only unused parameters that come positionally after the last used parameter are reported:

var fn1 = (one,two,three) => two * 2;

In this snippet, since two is the last used parameter, only three would be reported as an unused parameter (ignores one).

"unused": "none"

Disables this "unused" mode; no checks are made for any unused parameters.

Rule "params" Configuration: "count"

To configure this rule mode (default: 3):

"@getify/proper-arrows/params": "error"
"@getify/proper-arrows/params": [ "error", { "count": 3, "trivial": false } ]

This rule mode counts all parameters to make sure the maximum count limit is not violated.

For example:

var fn0 = () => "";

var fn1 = one => one;

var fn2 = (one,two) => one + two;

var fn3 = (one,two,three) => one * two * three;

var fn3b = (one,two,...three) => one * two * three[0];

These statements all report no errors, because all parameter counts are below the limit (default: 3).

By contrast, this rule would report errors for:

var fn4 = (one,two,three,four) => one + two * three / four;

var fn4b = (one,two,three,...four) => one + two * three / four[0];

In each statement, the parameter count is above the limit.

Rule "params" Configuration: "length"

Note: This rule mode resembles the built-in ESLint "id-length" rule, but instead focuses only on the parameters of => arrow functions.

To configure this rule mode (default: 2):

"@getify/proper-arrows/params": "error"
"@getify/proper-arrows/params": [ "error", { "length": 2, "trivial": false } ]

This rule mode checks all parameters to make sure their basic character length is at least the minimum "length" threshold.

For example:

var fn0 = () => 42;

var fn1 = (data) => data.id;

var fn2 = (user,cb) => ajax(user,cb);

These statements all report no errors, because all parameters are at least the length threshold specified (default: 2), and the absence of a parameter is ignored.

By contrast, this rule would report errors for:

users.map(v => v * 2);

In this statement, the parameter length of v is below the minimum threshold.

Rule "params" Configuration: "allowed"

To configure named exceptions to the main three rule modes (default: []):

"@getify/proper-arrows/params": [ "error", { "allowed": [ "e", "err" ], "trivial": false } ]

This exception list prevents any listed parameter from being reported as an error by any of this proper-arrows/params rule's modes.

For example:

var fn = (one,two,three,e) => 0;

By default, e would report all 3 errors: it's unused, it's beyond the default count limit, and it's below the minimum length threshold. However, no errors will be reported if "e" is included in the "allowed" exception list.

Rule: "name"

The proper-arrows/name rule requires => arrow functions to be in a position where they will receive an inferred name, such as from being assigned to a variable or property.

To turn this rule on:

"@getify/proper-arrows/name": "error"
"@getify/proper-arrows/name": ["error",{ "trivial": false }]

The main purpose of this rule is to reduce the impact of the anonymous nature of => arrow function expressions, making them more readable, improving stack trace output, and giving them a named self-reference (recursion, event unbinding, etc). Primarily, this rule disallows => arrow functions passed directly as inline function expression arguments, as well as returned directly from other functions.

Note: This rule is like the "as-needed" mode of the built-in ESLint "func-names" rule, but applied to => arrow functions; the built-in rule ignores them.

Before being used (passed, called, returned, etc), => arrow functions should be assigned somewhere, to receive a name inference:

function multiplier(x) {
    var multipliedBy = v => v * x;
    return multipliedBy;
}

var tripled = v => v * 3;
var fns = {
    doubled: multiplier(2),
    tripled,
    quadrupled: v => v * 4
};

[1,2,3].map(fns.doubled);     // [2,4,6]
[1,2,3].map(fns.tripled);     // [3,6,9]
[1,2,3].map(fns.quadrupled);  // [4,8,12]

fns.doubled.name;             // "multipledBy"
fns.tripled.name;             // "tripled"
fns.quadrupled.name;          // "quadrupled"

In this snippet, each => arrow function is first assigned to a variable or property, giving it an inferred name ("multipledBy", "tripled", or "quadrupled"). As such, they would all pass this rule.

By contrast, this rule would report errors for each of the => arrow functions here:

function getName(fn) {
    return fn.name;
}

function multiplier(x) {
    return v => v * x;
}

fns = [ multiplier(2), v => v * 3 ];
getName( fns[0] );         // ""
getName( fns[1] );         // ""
getName( v => v * 4 );     // ""

In this snippet, all three => arrow functions remain anonymous because no name inferences are possible.

Rule: "where"

The proper-arrows/where rule restricts where in program structure => arrow functions can be used.

This rule can be configured to forbid => arrow functions in the global/top-level-module scope ("global") (or "global-declaration" just for global arrow declarations), forbid => arrow functions as object properties ("property"), and forbid => arrow functions in export statements ("export").

To turn this rule on:

"@getify/proper-arrows/where": "error"
"@getify/proper-arrows/where": [ "error", { "global": true, "property": true, "export": true, "trivial": false } ]

The main purpose of this rule is to avoid readability harm when using => arrow functions in certain program structure locations.

Placing => arrow functions in the global/top-level-module scope has no benefit other than preferred style; they're more proper as regular function declarations. Placing => arrow functions on object properties has no benefit other than preferred style; they're more proper as concise object methods. Placing arrow functions in export statements offers no benefit other than being more concise; they're more proper as exported named function declarations.

For example:

var PEOPLE_URL = "http://some.tld/api";

var People = {
    getData(id,cb) {
        ajax(PEOPLE_URL,{ id },cb);
    }
};

function onData(data) {
    console.log(data);
}

export default function lookup(id) {
    return People.getData(id,onData);
}

export var lookup = function(id) {
    return People.getData(id,onData);
};

In this snippet, the getData(..) function is a clear and proper concise method on People object, onData(..) is a regular function declaration, and lookup(..) is either a default or named-declaration export declaration. Therefore, the proper-arrows/where rule would not report any errors.

By contrast, this rule would default to reporting errors for each of these => arrow functions:

var PEOPLE_URL = "http://some.tld/api";

var People = {
    getData: (id,cb) => ajax(PEOPLE_URL,{ id },cb)
};

const onData = data => {
    console.log(data);
};

export default id => People.getData(id,onData)

export var lookup = id => People.getData(id,onData)

These usages of => arrow functions are not helping the readability or behavior of this snippet.

Rule Configuration

The proper-arrows/where rule can be configured with four (non-exclusive) modes: "global", "global-declaration", "property", and "export".

Note: The default behavior is that all three modes are turned on for this rule. You must specifically configure each mode to disable it.

  • "global" (default: true) forbids => arrow functions in general expressions located in the global/top-level-module scope.

  • "global-declaration" (default: same as global) forbids => "arrow function declarations" (e.g. const foo = x => x * 2) in the global/top-level-module scope.

  • "property" (default: true) forbids assigning => arrow functions to object properties.

  • "export" (default: true) forbids => arrow functions in export statements.

Rule "where" Configuration: "global"

To configure this rule mode (on by default, set as false to turn off):

"@getify/proper-arrows/where": [ "error", { "global": true, "trivial": false } ]

For inline function expressions in the global/top-level-module scope, use the regular function declaration form to avoid errors:

getResults({ query: "foo" },function onResults(results){
    console.log(results);
});

By contrast, this rule mode would report errors for:

getResults({ query: "foo" },results => {
    console.log(results);
});

In this snippet, the => arrow function is less obviously a function than the function expression form.

Global Arrow Declarations

A "global arrow declaration" is specifically and only an arrow function expression initially assigned to a variable at the moment the variable is declared (in the global/top-level-module scope):

const onData = data => {
    console.log(data);
};

The global rule mode includes forbidding this form of "declaration". Instead, the standard function declaration form should be used to avoid such errors:

function onData(data) {
    console.log(data);
}

However, the "global-declaration" mode only applies to these types of "declarations", not all arrow expressions, and it overrides this rule mode's treatment of such declarations.

Rule "where" Configuration: "global-declaration"

This rule mode by default mirrors the "global" rule mode, whatever value it's set or defaulted to. However, you can explicitly configure this rule mode to a different value as such:

"@getify/proper-arrows/where": [ "error", { "global-declaration": true, "trivial": false } ]

This rule mode only controls reporting an error for a "global arrow declaration", such as:

const onData = data => {
    console.log(data);
};

To avoid such errors, use the regular function declaration form:

function onData(data) {
    console.log(data);
}

Other global arrow expressions are unaffected by this particular rule mode; however, the separate "global" rule mode, which is on by default, controls all arrow function forms in the global/top-level-module scope.

If "global" mode is explicitly turned off (via false), but this "global-declaration" is explicitly turned on (via true), ONLY "global arrow declarations" will report errors.

If "global" mode is on (by default, or set to true explicitly), but this "global-declaration" mode is explicitly turned off (via false), all other global/top-level-module scope arrow function expressions EXCEPT "global arrow declarations" will report errors.

However, if this "global-declaration" mode is not set explicitly, it will always mirror the value of the "global" rule mode, whether it is set explicitly or left to default.

Rule "where" Configuration: "property"

To configure this rule mode (on by default, set as false to turn off):

"@getify/proper-arrows/where": [ "error", { "property": true, "trivial": false } ]

When defining a function in an object literal definition, use the concise method form:

var People = {
    getData(id,cb) {
        ajax(PEOPLE_URL,{ id },cb);
    }
};

By contrast, this rule mode would report errors for:

var People = {
    getData: (id,cb) => ajax(PEOPLE_URL,{ id },cb)
};

In this snippet, the => arrow function is less obviously a method than the concise method form.

Rule "where" Configuration: "export"

To configure this rule mode (on by default, set as false to turn off):

"@getify/proper-arrows/where": [ "error", { "export": true, "trivial": false } ]

When exporting function declarations/expressions, use non-arrow functions:

export default function lookup(id) {
    return People.getData(id,onData);
}

export var lookup = function(id) {
    return People.getData(id,onData);
}

By contrast, this rule mode would report errors for:

export default id => People.getData(id,onData)

export var lookup = id => People.getData(id,onData)

In this snippet, the => arrow functions are less obviously a function than named function form.

Rule: "return"

The proper-arrows/return rule restricts the concise return values for => arrow functions.

This rule can be configured to forbid concise return of object literals ("object"), forbid concise return of => arrow functions (aka, "chained arrow returns") without visual delimiters like ( .. ) ("chained"), forbid concise return of ternary/conditional expressions ("ternary"), and forbid concise returns of comma sequences ("sequence").

To turn this rule on:

"@getify/proper-arrows/return": "error"
"@getify/proper-arrows/return": [ "error", { "object": true, "chained": true, "sequence": true, "trivial": false } ]

The main purpose of this rule is to avoid readability harm for => arrow functions by ensuring concise return values are clean and "proper".

By forbidding concise return of object literals, the reader is not confused at first glance by the { .. } looking like a non-concise function body. By forbidding chained => arrow function concise returns without enclosing visual delimiters (like ( .. )), the reader doesn't have to visually parse functions in a reverse/right-to-left fashion to determine the function boundaries. By forbidding concise return of comma sequences (ie, (x = 3,y = foo(x + 1),[x,y])), the reader doesn't have as much trouble figuring out which value will be returned from the function. By forbidding concise return of ternary/conditional expressions, especially nested ternaries, the function's boundary is not as visually ambiguous.

For example:

var fn1 = prop => ( val => { return { [prop]: val }; } );
var fn2 = (x,y) => { x = 3; y = foo(x + 1); return [x,y]; };
var fn3 = (x,y) => {
    return (
        x > 3 ? x :
        y > 3 ? y :
        3;
    );
};

In this snippet, the chained => arrow function fn1(..) is surrounded by ( .. ) to visually delimit it, and the object literal being returned is done with a full function body and return keyword. For fn2(..), the function body's return value ([x,y]) is clear. For fn3(..), the presence of a return keyword inside the { } function body more clearly delimits the nested ternary/conditional expression as determining the return value. Therefore, the proper-arrows/return rule would not report any errors.

By contrast, this rule would report errors for each of these statements:

var fn1 = prop => val => ({ [prop]: val });
var fn2 = (x,y) => (x = 3, y = foo(x + 1), [x,y]);
var fn3 = (x,y) => x > 3 ? x : y > 3 ? y : 3;

In this snippet, the chained => arrow function return is not as clear, the concise return of the object literal can be confused as a function block at first glance, the concise return of the comma sequence makes it hard to determine which value will actually be returned, and the nested ternary/conditional expression obscures the determination of the return value.

Some claim that extra whitespace solves these readability issues. However, if you go to the trouble to space/indent to this extent, skipping the return keyword doesn't really contribute to the readability, and in fact still makes the return values a little less visually distinct than the above forms.

var fn1 = prop
    => val
        => (
            { [prop]: val }
        );
var fn2 = (x,y) => (
    x = 3,
    y = foo(x + 1),
    [x,y]
);
var fn3 = (x,y) =>
    x > 3 ? x :
    y > 3 ? y :
    3;

Also, many proponents of this whitespace "solution" advocate it in theory only; in practice, these sorts of functions are often just found in their less readable single-line form.

Rule Configuration

The proper-arrows/return rule can be configured with four (non-exclusive) modes: "object", "ternary", "chained", and "sequence".

Note: The default behavior is that all four modes are turned on for this rule. You must specifically configure each mode to disable it.

  • "object" (default: true) forbids returning object literals as concise return expressions.

  • "ternary" (default: 0) controls whether (and to what extent of nesting) conditional/ternary expressions (x ? y : z) are allowed as the concise return expression of an => arrow function.

  • "chained" (default: true) forbids returning => arrow functions (aka, "chained arrow returns") as concise return expressions, without visual delimiters ( .. ).

  • "sequence" (default: true) forbids returning comma sequences (ie, (x = 3, y + x)) as concise return expressions.

Rule "return" Configuration: "object"

Note: This rule is similar to the built-in ESLint "arrow-body-style" rule, specifically the requireReturnForObjectLiteral: true mode. However, that built-in rule mode is only defined for as-needed, which requires always using the concise return expression form for all other => arrow functions where it's possible to do so.

The proper-arrows/return rule's "object" mode is different (more narrowly focused): it only disallows the concise return of an object literal; otherwise, it doesn't place any requirements or restrictions on usage of => arrow functions.

To configure this rule mode (on by default, set as false to turn off):

"@getify/proper-arrows/return": [ "error", { "object": true, "trivial": false } ]

If returning an object literal from an => arrow function, use the full-body return form:

var fn = prop => val => { return { [prop]: val }; };

In this snippet, the => arrow function uses the full-body return form for the object literal. As such, it would pass this rule.

By contrast, this rule mode would report errors for:

var fn = prop => val => ({ [prop]: val });

In this snippet, the => arrow function has an object literal as the concise return expression.

Rule "return" Configuration: "ternary"

Note: This rule is similar to the built-in ESLint "no-ternary" rule and "no-nested-ternary" rule. However, those built-in rules focus on all conditional/ternary (? :) expressions, and aren't configurable to an allowed level of nesting.

The proper-arrows/return rule's "ternary" mode is different (more narrowly focused): it only controls the ternary/conditional expressions as the concise return of an => arrow function; otherwise, it doesn't place any requirements or restrictions on ternary/conditional expressions.

To configure this rule mode (defaults to 0, set to a higher number to effectively disable):

"@getify/proper-arrows/return": [ "error", { "ternary": 1, "trivial": false } ]

The number specified for the "ternary" option controls what level of (nested) ternary/conditional expressions are allowed as the concise return of an => arrow function. 0 means none allowed, 1 means a single ternary/conditional allowed, 2 means one level nested (x ? y ? z : w : u) allowed, etc.

If this rule mode is set to 1, it would pass this snippet:

var fn = data => data.id ? lookup(data.id) : lookup(-1);

But this rule mode set to 1 would report errors for:

var fn = data => data.id ? data.extra ? lookup(data.id,data.extra) : lookup(data.id) : lookup(-1);

Rule "return" Configuration: "chained"

To configure this rule mode (on by default, set as false to turn off):

"@getify/proper-arrows/return": [ "error", { "chained": true, "trivial": false } ]

This rule mode requires ( .. ) surrounding any concise return that is itself an => arrow function, because the parentheses help visually disambiguate where the function boundaries are, especially when there are several => arrow functions chained together.

If concise returning a chained => arrow function, wrap ( .. ) around it:

var fn = prop => ( val => { return { [prop]: val }; } );

In this snippet, the chained => arrow function return is visually disambiguated with ( .. ). As such, it would pass this rule.

Though this rule does require it, visual ambiguity can even further be reduced by using whitespace to position the delimiters similarly to regular function bodies delimited by { .. }:

var fn = prop => (
    val => { return { [prop]: val }; }
);

Note: The extra whitespace is merely a readability suggestion if you plan to use this rule, not a requirement of it.

By contrast, this rule mode would report errors for:

var fn = prop => val => { return { [prop]: val }; };

In this snippet, the boundary of the chained => arrow function return is less clear.

Rule "return" Configuration: "sequence"

Note: This rule is similar to the built-in ESLint "no-sequences" rule.

The proper-arrows/return rule's "sequence" mode is different (more narrowly focused): it only disallows comma sequences as => arrow function concise return expressions.

To configure this rule mode (on by default, set as false to turn off):

"@getify/proper-arrows/return": [ "error", { "sequence": true, "trivial": false } ]

Comma sequences are not very common, but one place they're a bit more common is as the concise return expression from an => arrow function so that multiple expression-statements can be strung together without needing a full function body. This may be clever or concise, but it's almost always less readable than just using separate statements.

For example:

var fn2 = (x,y) => { x = 3; y = foo(x + 1); return [x,y]; };

In this snippet, the => arrow function uses the full-body return form with separate statements and an explicit return statement. As such, it would pass this rule.

By contrast, this rule mode would report errors for:

var fn2 = (x,y) => (x = 3, y = foo(x + 1), [x,y] );

In this snippet, the => arrow function has a comma sequence as the concise return expression.

Rule: "this"

The proper-arrows/this rule requires => arrow functions to reference the this keyword. It also supports a "never" configuration mode, which reverses the rule and means that => arrow functions must never use this, as well as a "never-global" configuration mode which only disallows this usage in arrow functions that are in the global scope.

To turn this rule on:

"@getify/proper-arrows/this": "error"
"@getify/proper-arrows/this": [ "error", "always", { "no-global": true, "trivial": false } ]

The main purpose of this rule is to avoid usage of => arrow functions as just function shorthand (i.e., arr.map(x => x * 2)), which can be argued as a misusage. Concise => arrow function syntax (with all its myriad variations) can harm readability, so instead => arrow functions should only be used when the "lexical this" behavior is needed.

Since => arrow functions don't have their own this, they treat any this reference as a normal variable (not a special keyword). That means this is lexically looked up through any parent scopes until a valid definition of this is found -- from a normal non-arrow function, or finally in the global scope itself.

Such this behavior is referred to as "lexical this", and it is one of the main design characteristics for => arrow functions.

For example:

var o = {
    id: 42,
    getData() {
        ajax("https://some.tld/api",() => console.log(this.id));
    }
};

o.getData();   // 42

In this snippet, the => arrow function is inside a normal function and therefore looks up and adopts its this (aka, "lexical this") -- which is set to the o object by the o.getData() call. Therefore, the proper-arrows/this rule would not report an error.

By contrast, this rule would report an error for:

var o = {
    id: 42,
    getData() {
        ajax("https://some.tld/api",() => console.log(o.id));
    }
};

o.getData();   // 42

Here, the => arrow function is lexically closed over the o rather than using "lexical this", so it can be considered a misusage of the => arrow function merely for shorthand; rather, the callback should have used this.id instead of o.id, or just been a regular named function expression (ie, function onResp(){ console.log(o.id); }).

To pass the proper-arrows/this rule without a reported error, all => arrow functions must reference a this somewhere in their arguments or body -- or, when using the "nested" configuration, any nested => arrow functions.

Rule Configuration

The proper-arrows/this rule can be configured in one of four modes: "nested" (default), "always", "never" and "never-global".

  • "nested" (default) permits a this to appear lower in a nested => arrow function (i.e., x = y => z => this.foo(z)), as long as there is no non-arrow function boundary crossed.

    Additionally, include the "no-global" option (default: false) to forbid this-containing => arrow functions from the global scope (where they might inherit the global object as this) or from the top-level of a module (where this would be undefined).

  • "always" is more strict, requiring every single => arrow function to have its own this reference.

    Additionally, include the "no-global" option (default: false) to forbid this-containing => arrow functions from the global scope (where they might inherit the global object as this) or from the top-level of a module (where this would be undefined).

  • "never" is the reverse of the rule: all => arrow functions are forbidden from using this.

  • "never-global" disallows this usage in arrow functions that are in the global scope.

Rule "this" Configuration: "nested"

To configure this rule mode (default):

"@getify/proper-arrows/this": "error"
"@getify/proper-arrows/this": [ "error", "nested" ]
"@getify/proper-arrows/this": [ "error", "nested", { "no-global": true, "trivial": false } ]

This rule mode allows a this to appear either in the => arrow function, or nested deeper in a chain of => arrow functions, as long as there is no non-arrow function boundary crossed in the nesting.

If the "no-global" option has not been set for this mode, these statements will all pass the rule:

var a = b => this.foo(b);

var c = d => e => this.foo(e);

var f = (g = h => this.foo(h)) => g;

But these statements will each fail this rule:

var a = b => foo(b);

var c = d => this.foo(e => e);

var f = (g = h => h) => this.foo(g);

var h = i => function(j){ this.foo(j); };

var k = l => function(){ return m => this.foo(m); };
"no-global" Option

If the "no-global" option has been set for this mode, these statements will all pass the rule:

function foo() { return a => this.bar(a); }

function foo() { return a => b => this.bar(a,b); }

function foo(cb = a => this.bar(a)) { .. }

function foo(cb = a => b => this.bar(a,b)) { .. }

And these statments will each fail this "no-global" option rule:

var foo = a => this.bar(a);

var foo = a => b => this.bar(a,b);

var o = {
    foo: a => this.bar(a)
};

var o = {
    foo: a => b => this.bar(a,b)
};

Rule "this" Configuration: "always"

To configure this rule mode:

"@getify/proper-arrows/this": [ "error", "always" ]
"@getify/proper-arrows/this": [ "error", "always", { "no-global": true, "trivial": false } ]

This rule mode requires a this reference to appear in every single => arrow function (e.g., nested this is not sufficient).

If the "no-global" option has not been set for this mode, these statements will all pass the rule:

var a = b => this.foo(b);

var c = d => this.foo(e => this.bar(e));

var f = (g = h => this.foo(h)) => this.bar(g);

But these statements will each fail this rule:

var a = b => foo(b);

var c = d => e => this.foo(e);

var f = g => this.foo(h => h);

var i = (j = k => k) => this.foo(j);

Note: In each of the above examples, at least one of the => arrow functions does not have its own this, hence the mode's rule failure (doesn't consider nested this).

"no-global" Option

If the "no-global" option has been set for this mode, these statements will all pass the rule:

function foo() { return a => this.bar(a); }

function foo(cb = a => this.bar(a)) { .. }

And these statements will each fail this "no-global" option rule:

var foo = a => this.bar(a);

var o = {
    foo: a => this.bar(a)
};

Rule "this" Configuration: "never"

To configure this rule mode:

"@getify/proper-arrows/this": [ "error", "never" ]

This rule mode forbids a this reference from appearing in any => arrow function.

These statements will all pass the rule in this mode:

var a = b => foo(b);

var c = d => foo(e => bar(e));

var f = (g = h => foo(h)) => bar(g);

But these statements will each fail the rule in this mode:

var a = b => this.foo(b);

var c = d => e => this.foo(e);

var f = g => foo(h => this.bar(h));

Note: The "no-global" option and "trivial" option are not applicable and have no effect for this rule mode.

Rule "this" Configuration: "never-global"

To configure this rule mode:

"@getify/proper-arrows/this": [ "error", "never-global" ]

This rule mode forbids this usage in arrow functions that are in the global scope (including nested arrow functions).

These statements will all pass the rule in this mode:

var a = b => foo(b);

var c = d => foo({ set baz(v){ return z => this.bar(z); } })

var e = f => foo({ method(){ return z => this.bar(z); } })

But these statements will each fail the rule in this mode:

var a = b => this.foo(b);

var c = d => e => this.foo(e);

var f = g => foo(h => this.bar(h));

npm Package

To use this plugin with a global install of ESLint (recommended):

npm install -g @getify/eslint-plugin-proper-arrows

To use this plugin with a local install of ESLint:

npm install @getify/eslint-plugin-proper-arrows

Builds

Build Status npm Module

If you need to bundle/distribute this eslint plugin, use dist/eslint-plugin-proper-arrows.js, which comes pre-built with the npm package distribution; you shouldn't need to rebuild it under normal circumstances.

However, if you download this repository via Git:

  1. The included build utility (scripts/build-core.js) builds (and minifies) dist/eslint-plugin-proper-arrows.js from source.

  2. To install the build and test dependencies, run npm install from the project root directory.

  3. To manually run the build utility with npm:

    npm run build
  4. To run the build utility directly without npm:

    node scripts/build-core.js

Tests

A comprehensive test suite is included in this repository, as well as the npm package distribution. The default test behavior runs the test suite against lib/index.js.

  1. The included Node.js test utility (scripts/node-tests.js) runs the test suite.

  2. Ensure the test dependencies are installed by running npm install from the project root directory.

    • Note: Starting with npm v5, the test utility is not run automatically during this npm install. With npm v4 and before, the test utility automatically runs at this point.
  3. To run the test utility with npm:

    npm test

    Other npm test scripts:

    • npm run test:dist will run the test suite against dist/eslint-plugins-proper-arrows.js instead of the default of lib/index.js.

    • npm run test:package will run the test suite as if the package had just been installed via npm. This ensures package.json:main properly references dist/eslint-plugins-proper-arrows.js for inclusion.

    • npm run test:all will run all three modes of the test suite.

  4. To run the test utility directly without npm:

    node scripts/node-tests.js

Test Coverage

Coverage Status

If you have Istanbul already installed on your system (requires v1.0+), you can use it to check the test coverage:

npm run coverage

Then open up coverage/lcov-report/index.html in a browser to view the report.

To run Istanbul directly without npm:

istanbul cover scripts/node-tests.js

Note: The npm script coverage:report is only intended for use by project maintainers; it sends coverage reports to Coveralls.

License

All code and documentation are (c) 2019-2021 Kyle Simpson and released under the MIT License. A copy of the MIT License is also included.

eslint-plugin-proper-arrows's People

Contributors

gaggle avatar gamtiq avatar gertig avatar getify avatar palnes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eslint-plugin-proper-arrows's Issues

Errors when disabling the rules in Create React App

I am getting the following error when I add the rules to a CRA app and try and disable existing errors:

Line 1:1:  Definition for rule '@getify/proper-arrows/return' was not found  @getify/proper-arrows/return

Search for the keywords to learn more about each error.

The eslint-disable directive is as follows:

/* eslint-disable @getify/proper-arrows/return */

Add rule to forbid inline function expressions nested in default parameter value

When an inline function expression appears in a default parameter value, it can create a closure over the normally-indistinguishable "parameter scope", which is super confusing, and should almost always be avoided.

For example:

var f = (x,cb = () => x) => { var x = 2; return [x,cb()]; };
f(5);   // [2,5]

The x parameter is in a separate scope from the var x in the function body, and in this case they are shown to have different values, via the closure.

For more info: https://gist.github.com/getify/0978136c0c66c0357f611e2c7233f105


This is confusing enough for regular functions, but it's significantly more confusing for arrow functions.

This rule would forbid inline function expressions in an arrow function's parameter default value position. It will have 3 modes:

  • "all" - forbid all inline function expressions (arrow or normal)
  • "closure" - only forbid inline function expressions that actually close over a parameter in the parameter scope
  • "none" - disable the rule

There would also be two additional flags (both default to true), in effect only for "all" and "closure" modes:

  • "arrow": forbids inline arrow function expressions
  • "function": forbids inline regular function expressions

Bug (?): Not identifying module-level arrow functions

This is either a bug or I'm unwittingly making a feature-request.

I've added eslint-plugin-proper-arrows to our preset and added the following code to its test-suite which I was expecting to fail:

# properArrowsWhere.invalid.js
const arrowFunc = (foo, bar, baz) => { console.log(foo, bar, baz) }

export default arrowExport => console.log(arrowExport)

I expect it to generate two errors on rule @getify/proper-arrows/where, but actually only get one error for the arrow-export. My eslint configuration:

    "@getify/proper-arrows/where": ["error", { global: true, property: false, export: true, trivial: false }],

From your readme I expected the arrow function to fail because it says:

"where": restricts where in program structure => arrow functions can be used: forbidding them in the top-level/global scope, object properties, export statements, etc.

Here top-level/global scope to me reads as the top-level in a module. But maybe that's not the intention of the library?

From debugging I think the change I expect could be satisfied by changing the line in https://github.com/getify/eslint-plugin-proper-arrows/blob/master/lib/index.js#L735 from:

scope.upper.type == "global"

to:

scope.upper.type == "global" || scope.upper.type == "module"

But I don't quite understand your test-suite setup (or indeed eslint in general :) so I'm not sure that's right.. and I'm doubly not sure if you intend for "global" to also mean top-level in a module at all. Maybe I'm actually making a feature-request to add a "module" toggle flag?

Either way I'm happy to try and help, but first need to reach out to you to understand the context of your library. Is this a bug at all?

(and thanks for making the library available)

Prevent arrow functions that implicitly return arrow functions

I'm not sure if this rule exists already or not.

I find it hard to read arrow functions that return arrow functions like this:

var x = (a,b) => () => a + b;

I think having a more explicit return is easier to read.

var x = (a,b) => {
  return () => a + b
};

Add setting to disallow "arrow function declarations" at the global/top level

I would like to forbid top level function declarations that use arrow syntax. This works using global.

const bad = () => {
  console.log('bad');
};

But I would like to allow top level arrow functions present within a function call. I cannot get this to work because these are considered global. I recognize they are indeed global. I would like to carve out an exception here. This issue here blocks me from being able to benefit from this plugin and I am going to have to disable it.

const things = [].map(x => console.log('eh, this is ok, it is in a function call');

some "where" rules do not notify warning/error on text editors

Issue

Running the command eslint . all the rules are notified properly. But when using ESLint on text editors such as VSCode and Atom for instance, some warnings/erros are not notified:

"where" rule:

// not notified cases
export const a = () => {};

// or

const b = () => {};
b();

// notified
export default () => {};

I changed some tests, adding this cases:

QUnit.test( "WHERE (global, default): violating const", function test(assert){
	var code = `
		const f = x => y;
	`;

	var results = eslinter.verify( code, linterOptions.whereGlobalDefault );
	var [{ ruleId, messageId, } = {},] = results || [];

	assert.expect( 3 );
	assert.strictEqual( results.length, 1, "only 1 error" );
	assert.strictEqual( ruleId, "@getify/proper-arrows/where", "ruleId" );
	assert.strictEqual( messageId, "noGlobal", "messageId" );
} );

✅ The test above passes but this warning/error is not notified on the editor.

QUnit.test( "WHERE (export): violating const", function test(assert){
	var code = `
		export const a = () => {};
	`;

	var results = eslinter.verify( code, linterOptions.whereExport );
	// HERE THE RESULTS VARIABLE IS AN EMPTY ARRAY []
	var [{ ruleId, messageId, } = {},] = results || [];

	assert.expect( 3 );
	assert.strictEqual( results.length, 1, "only 1 error" );
	assert.strictEqual( ruleId, "@getify/proper-arrows/where", "ruleId" );
	assert.strictEqual( messageId, "noExport", "messageId" );
} );

❌ The test above breaks because results variable is an empty array. But this case is notified while running on CLI.


Could someone help me understand what is the problem in these cases?

I was trying to add an export-only-named-function (do-not-export-arrow-functions) rule to my project and found this awesome ESLint plugin that would fit perfectly for my scenario. The problem is that I cannot add it if other developers cannot see it at development time. It would only notify on CI by the time they open a Pull Request, and it would be a bad experience to find the log and come back to the code to fix a linter issue 😞

More info:

Tested editors: VSCode and Atom

OS: Mac OS X Catalina (10.15.2)

Node: v12.13.0
npm: 6.12.0

My project is using ESLint v5.16.0

ESLint config:

// .eslintrc.js
module.exports = {
  root: true,
  env: {
    browser: true,
    es6: true,
    jest: true,
  },
  parserOptions: {
    parser: 'babel-eslint',
  },
  plugins: [
    '@getify/proper-arrows',
  ],
  rules: {
    '@getify/proper-arrows/where': 'error',
  },
};

Ignoring React components defined as an arrow function

Would it be possible to ignore React components in the rule where? While I agree that function declaration is preferable when exporting a function (i.e. export function somefn() { /* ... */}), I would like to make exception for React components, because arrow functions are typed more easily.

When using function declaration, you have to type props and also return (from my experience, people usually forget to add null):

interface BoldProps {
    caption: string;
}

export function Bold({ caption }: BoldProps): JSX.Element | null {
    return <b>{caption}</b>;
}

Using arrow function is little bit more concise, less error prone, but still readable thanks to the React.FC type right after the variable name:

interface BoldProps {
    caption: string;
}

export const Bold: React.FC<BoldProps> = ({ caption }) => {
    return <b>{caption}</b>;
}

Thanks for the info.

Create a wizard for picking rules config

If you want to "train" a rules config on your existing code, a web based wizard tool could be helpful for that. You paste in code, it tells you what the maximum rules config is that would work (not throw errors) on your code.

Would just brute-force try all combinations of rules, in "decreasing" order, and print the first one that doesn't give any errors.

Add rule to forbid "chained arrows"

Because some of us feel that chained arrow returns (such as are common in curried function definitions) is much harder to read, given that you basically have to read them right-to-left to figure out where the function boundaries are, add rule that forbids chained arrow returns:

var f => x + 1;   // not chained, OK

var g => x => y => x + y;   // Error

Also, we need a flag to optionally allow/ignore these:

var g = x => (y => x + y);
var g = x => { return y => x + y; }

@getify/proper-arrows/names should follow func-names schema

and support as-needed and never

afaik async functions would behave the same as sync functions when it comes to inferred names

PS: I don't see why eslint's func-names shouldn't support asyncs, so if a PR gets accepted upstream, it's probably better than having a separate rule doing what func-names does but for async functions

Extend definition of trivial to include comparisons

It would be nice to allow x => x < 0 and x => x > 0 as trivial functions, with other comparison operators too. These cannot ever throw and don't really need fancy names or parameters.

The boolean operators && and || should be allowed too IMHO.

Note that this does not include all arithmetic expressions, as for example x / y could still throw.

Add rule to forbid unused parameters

Some people like to define arrows like this:

x => 1;
x => {};
x => void 0;

Those forms are all generally to avoid the () => ... But since this can be confusing to a reader to see a parameter listed that isn't used, this rule would forbid that.

It would also catch straight-up mistakes like:

(x,y,z) => x + y;   // z is unused here

This is similar to the built-in "no-unused-vars" rule, but is much narrower in focus: only for arrow functions.

False positive on object destructuring in arrow function parameters

The following will report a params count error:

({foo, bar, baz, bat, bongo }) => {/* a function that handles all those 'named' parameters */}

While the following won't

function namedParams({foo, bar, baz, bat, bongo }) {/* a function that handles all those 'named' parameters */}

This might be intentional, as it seems weird to use the pattern in an anonymous function, but the lint error should be more exact.

Add option to enable only in blocks where brackets are present

[EDITORS NOTE: This issue was transferred from another repository, so it may no longer be valid, still TBD]

I personally can see merit to using anonymous functions using the shorthand syntax when doing simple calculations for filters and mapping arrays, for instance.

I would like the ability to only apply the rule when the arrow function contains curly brackets, so this should be fine

[1, 2, 3].map(x => x * 2).filter(x => x < 4);

But this wouldn’t be, without a reference to this

new Array(6).fill(undefined).map((_, key) => {
   let thing = DoSomething(key);
   return thing();
}

I’m in two minds as to what to do about returning objects:

x => ({})

I’ve never used this syntax because it’s too messy in my opinion, but I think it should be part of the rule options too, which may complicate things because of the brackets.

Add `id` to the default allowed list of short params

Reasoning:

  • Usually clear from context which ID is being referenced.
    • Rule could be be interpreted to say that a name like userId is preferred, but inside a function handling user logic that might be redundant.
  • people use the term ID rather than Identifier when talking
  • Even if the type of ID is unclear, it is still clear what an ID is. That sort of code review seems beyond the scope of a linter.

Global scope detection (for "no-global") is incorrect

The current detection makes an assumption about global scopes which doesn't hold for when the script in question is being linted as if in a node/commonjs env, as they create an "extra" scope below the real global for your script's top-level scope.

Detecting this environment difference is quite tricky/nuanced, since env setup is not reported to plugins. But it turns out it can be detected by looking at context.parserOptions.ecmaFeatures.globalReturn, which if set to true, means the extra scope has been created.

Elision of destructured function parameters causes crash

While linting the following code, the plugin crashed:

export const clampData = data => flow(
    // Trim left side of the array
    dropWhile(([, y]) => y === null),
    // Trim right side of the array
    dropRightWhile(([, y]) => y === null),
)(data);

The error message:

TypeError: Cannot read property 'type' of null
    at getAllIdentifiers (./node_modules/@getify/eslint-plugin-proper-arrows/lib/index.js:628:12)
    at getAllIdentifiers (./node_modules/@getify/eslint-plugin-proper-arrows/lib/index.js:635:23)
    at exit (./node_modules/@getify/eslint-plugin-proper-arrows/lib/index.js:66:25)
    at listeners.(anonymous function).forEach.listener (./node_modules/eslint/lib/util/safe-emitter.js:45:58)
    at Array.forEach (<anonymous>)
    at Object.emit (./node_modules/eslint/lib/util/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (./node_modules/eslint/lib/util/node-event-generator.js:251:26)
    at NodeEventGenerator.applySelectors (./node_modules/eslint/lib/util/node-event-generator.js:280:22)
    at NodeEventGenerator.leaveNode (./node_modules/eslint/lib/util/node-event-generator.js:303:14)
    at CodePathAnalyzer.leaveNode (./node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js:654:23)

Expected:
Skipping entries in an array is allowed (but perhaps not friendly) when destructuring. However, this entry will be returned as a null when iterating. A fix would probably entail checking for a null entry before checking the properties.

Include delegations under trivial functions

It'd be nice if we could include the functions x => f(x) under the definition of trivial. For example, if we want to call Array.map(x => f(x)) sometimes there are optional extra parameters of f that don't necessarily coincide with the parameters Array.map passes, and you need to delegate like this.

Another good example is for delegations that use methods, e.g. x => x.f().

Also constructors: x => new T(x)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.