Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: no-obj-calls support Intl #16543

Merged
merged 4 commits into from Nov 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 14 additions & 4 deletions docs/src/rules/no-obj-calls.md
Expand Up @@ -17,13 +17,17 @@ The [ECMAScript 2015 specification](https://www.ecma-international.org/ecma-262/

> The Reflect object also does not have a `[[Call]]` internal method; it is not possible to invoke the Reflect object as a function.

And the [ECMAScript 2017 specification](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-atomics-object) makes it clear that `Atomics` cannot be invoked:
The [ECMAScript 2017 specification](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-atomics-object) makes it clear that `Atomics` cannot be invoked:

> The Atomics object does not have a `[[Call]]` internal method; it is not possible to invoke the Atomics object as a function.

And the [ECMAScript Internationalization API Specification](https://tc39.es/ecma402/#intl-object) makes it clear that `Intl` cannot be invoked:

> The Intl object does not have a `[[Call]]` internal method; it is not possible to invoke the Intl object as a function.

## Rule Details

This rule disallows calling the `Math`, `JSON`, `Reflect` and `Atomics` objects as functions.
This rule disallows calling the `Math`, `JSON`, `Reflect`, `Atomics` and `Intl` objects as functions.

This rule also disallows using these objects as constructors with the `new` operator.

Expand All @@ -33,7 +37,7 @@ Examples of **incorrect** code for this rule:

```js
/*eslint no-obj-calls: "error"*/
/*eslint-env es2017*/
/*eslint-env es2017, browser */

var math = Math();

Expand All @@ -50,6 +54,10 @@ var newReflect = new Reflect();
var atomics = Atomics();

var newAtomics = new Atomics();

var intl = Intl();

var newIntl = new Intl();
```

:::
Expand All @@ -60,7 +68,7 @@ Examples of **correct** code for this rule:

```js
/*eslint no-obj-calls: "error"*/
/*eslint-env es2017*/
/*eslint-env es2017, browser*/

function area(r) {
return Math.PI * r * r;
Expand All @@ -71,6 +79,8 @@ var object = JSON.parse("{}");
var value = Reflect.get({ x: 1, y: 2 }, "x");

var first = Atomics.load(foo, 0);

var segmenterFr = new Intl.Segmenter("fr", { granularity: "word" });
```

:::
2 changes: 1 addition & 1 deletion lib/rules/no-obj-calls.js
Expand Up @@ -16,7 +16,7 @@ const getPropertyName = require("./utils/ast-utils").getStaticPropertyName;
// Helpers
//------------------------------------------------------------------------------

const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect"];
const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect", "Intl"];

/**
* Returns the name of the node to report
Expand Down
69 changes: 69 additions & 0 deletions tests/lib/rules/no-obj-calls.js
Expand Up @@ -45,6 +45,14 @@ ruleTester.run("no-obj-calls", rule, {
code: "new Atomics.foo()",
env: { es2017: true }
},
{
code: "new Intl.Segmenter()",
env: { browser: true }
},
{
code: "Intl.foo()",
env: { browser: true }
},

{ code: "globalThis.Math();", env: { es6: true } },
{ code: "var x = globalThis.Math();", env: { es6: true } },
Expand All @@ -58,6 +66,8 @@ ruleTester.run("no-obj-calls", rule, {
{ code: "/*globals Reflect: true*/ globalThis.Reflect();", env: { es2017: true } },
{ code: "var x = globalThis.Atomics();", env: { es2017: true } },
{ code: "var x = globalThis.Atomics();", globals: { Atomics: false }, env: { es2017: true } },
{ code: "var x = globalThis.Intl();", env: { browser: true } },
{ code: "var x = globalThis.Intl();", globals: { Intl: false }, env: { browser: true } },

// non-existing variables
"/*globals Math: off*/ Math();",
Expand All @@ -78,6 +88,8 @@ ruleTester.run("no-obj-calls", rule, {
code: "Atomics();",
env: { es6: true }
},
"Intl()",
"new Intl()",

// shadowed variables
"var Math; Math();",
Expand Down Expand Up @@ -119,6 +131,20 @@ ruleTester.run("no-obj-calls", rule, {
{
code: "var construct = typeof Reflect !== \"undefined\" ? Reflect.construct : undefined; construct();",
globals: { Reflect: false }
},
{
code: "function foo(Intl) { Intl(); }",
env: { browser: true }
},
{
code: "if (foo) { const Intl = 1; Intl(); }",
parserOptions: { ecmaVersion: 2015 },
env: { browser: true }
},
{
code: "if (foo) { const Intl = 1; new Intl(); }",
parserOptions: { ecmaVersion: 2015 },
env: { browser: true }
}
],
invalid: [
Expand Down Expand Up @@ -225,6 +251,24 @@ ruleTester.run("no-obj-calls", rule, {
globals: { Atomics: "writable" },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "NewExpression" }]
},
{
code: "var x = Intl();",
env: { browser: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
},
{
code: "var x = new Intl();",
env: { browser: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "NewExpression" }]
},
{
code: "/*globals Intl: true*/ Intl();",
errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
},
{
code: "/*globals Intl: true*/ new Intl();",
errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "NewExpression" }]
},
{
code: "var x = globalThis.Math();",
env: { es2020: true },
Expand Down Expand Up @@ -288,6 +332,21 @@ ruleTester.run("no-obj-calls", rule, {
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }]
},
{
code: "var x = globalThis.Intl();",
env: { browser: true, es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
},
{
code: "var x = new globalThis.Intl;",
env: { browser: true, es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "NewExpression" }]
},
{
code: "/*globals Intl: true*/ Intl();",
env: { browser: true, es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
},
{
code: "var foo = bar ? baz: JSON; foo();",
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "JSON" }, type: "CallExpression" }]
Expand Down Expand Up @@ -316,6 +375,16 @@ ruleTester.run("no-obj-calls", rule, {
env: { es2020: true, browser: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Atomics" }, type: "NewExpression" }]
},
{
code: "var foo = window.Intl; foo();",
env: { es2020: true, browser: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Intl" }, type: "CallExpression" }]
},
{
code: "var foo = window.Intl; new foo;",
env: { es2020: true, browser: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Intl" }, type: "NewExpression" }]
},

// Optional chaining
{
Expand Down