Skip to content

Commit

Permalink
feat: no-obj-calls support Intl (#16543)
Browse files Browse the repository at this point in the history
* feat: support `Intl`

* test: add tests for `Intl`

* docs: update docs for `Intl`

* docs: update docs/src/rules/no-obj-calls.md

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
  • Loading branch information
sosukesuzuki and mdjermanovic committed Nov 13, 2022
1 parent a01315a commit a4e89db
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 5 deletions.
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

0 comments on commit a4e89db

Please sign in to comment.