Skip to content

Commit 8fc8a15

Browse files
committed
Add es-x/no-math-sumprecise rule
1 parent f7a9733 commit 8fc8a15

File tree

6 files changed

+248
-13
lines changed

6 files changed

+248
-13
lines changed

.changeset/no-math-sumprecise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-es-x": minor
3+
---
4+
5+
Add `es-x/no-math-sumprecise` rule

docs/rules/no-math-sumprecise.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# es-x/no-math-sumprecise
2+
>
3+
4+
This rule reports ES2026 [`Math.sumPrecise` property](https://github.com/tc39/proposal-math-sum) as errors.
5+
6+
## 💡 Examples
7+
8+
⛔ Examples of **incorrect** code for this rule:
9+
10+
<eslint-playground type="bad">
11+
12+
```js
13+
/*eslint es-x/no-math-sumprecise: error */
14+
Math.sumPrecise([1e20, 0.1, -1e20]);
15+
```
16+
17+
</eslint-playground>
18+
19+
## 🔧 Options
20+
21+
This rule has an option.
22+
23+
```jsonc
24+
{
25+
"rules": {
26+
"es-x/no-math-sumprecise": [
27+
"error",
28+
{
29+
"allowTestedProperty": false
30+
}
31+
]
32+
}
33+
}
34+
```
35+
36+
### allowTestedProperty: boolean
37+
38+
Configure the allowTestedProperty mode for only this rule.
39+
This is prior to the `settings['es-x'].allowTestedProperty` setting.

lib/rules/no-math-sumprecise.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"use strict"
2+
3+
const {
4+
defineStaticPropertiesHandler,
5+
} = require("../util/define-static-properties-handler")
6+
7+
module.exports = {
8+
meta: {
9+
docs: {
10+
description: "disallow the `Math.sumPrecise` method",
11+
category: "ES2026",
12+
recommended: false,
13+
url: "http://eslint-community.github.io/eslint-plugin-es-x/rules/no-math-sumprecise.html",
14+
},
15+
fixable: null,
16+
messages: {
17+
forbidden: "ES2026 '{{name}}' method is forbidden.",
18+
},
19+
schema: [
20+
{
21+
type: "object",
22+
properties: {
23+
allowTestedProperty: { type: "boolean" },
24+
},
25+
additionalProperties: false,
26+
},
27+
],
28+
type: "problem",
29+
},
30+
create(context) {
31+
return defineStaticPropertiesHandler(context, {
32+
Math: { sumPrecise: "function" },
33+
})
34+
},
35+
}

lib/util/well-known-properties.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ const mathProperties = new Set([
248248
"sin",
249249
"sinh",
250250
"sqrt",
251+
"sumPrecise",
251252
"tan",
252253
"tanh",
253254
"trunc",

scripts/new-rule.js

Lines changed: 154 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ async function main(ruleId) {
3636
const ruleFile = path.resolve(__dirname, `../lib/rules/${ruleId}.js`)
3737
const testFile = path.resolve(__dirname, `../tests/lib/rules/${ruleId}.js`)
3838
const docFile = path.resolve(__dirname, `../docs/rules/${ruleId}.md`)
39+
const changesetFile = path.resolve(__dirname, `../.changeset/${ruleId}.md`)
3940

4041
prompts.intro("Create the new rule!")
4142

@@ -47,10 +48,10 @@ async function main(ruleId) {
4748
value: "global-object",
4849
label: "The rule forbids the use of global objects.",
4950
},
50-
// {
51-
// value: "static-properties",
52-
// label: "The rule forbids the use of static properties.",
53-
// },
51+
{
52+
value: "static-properties",
53+
label: "The rule forbids the use of static properties.",
54+
},
5455
// {
5556
// value: "prototype-properties",
5657
// label: "The rule forbids the use of prototype properties.",
@@ -131,20 +132,32 @@ async function main(ruleId) {
131132
.filter((s) => s)
132133
}
133134

135+
const BUILDERS = {
136+
"global-object": buildGlobalObjectRuleResources,
137+
"static-properties": buildStaticPropertiesRuleResources,
138+
"nonstandard-static-properties":
139+
buildNonStandardStaticPropertiesRuleResources,
140+
"nonstandard-prototype-properties":
141+
buildNonStandardPrototypePropertiesRuleResources,
142+
default: buildDefaultResources,
143+
}
144+
134145
const resources =
135-
kind === "global-object"
136-
? buildGlobalObjectRuleResources(resourceOptions)
137-
: kind === "nonstandard-static-properties"
138-
? buildNonStandardStaticPropertiesRuleResources(resourceOptions)
139-
: kind === "nonstandard-prototype-properties"
140-
? buildNonStandardPrototypePropertiesRuleResources(
141-
resourceOptions,
142-
)
143-
: buildDefaultResources(resourceOptions)
146+
BUILDERS[kind]?.(resourceOptions) ??
147+
buildDefaultResources(resourceOptions)
144148

145149
fs.writeFileSync(ruleFile, resources.rule)
146150
fs.writeFileSync(testFile, resources.test)
147151
fs.writeFileSync(docFile, resources.doc)
152+
fs.writeFileSync(
153+
changesetFile,
154+
`---
155+
"eslint-plugin-es-x": minor
156+
---
157+
158+
Add \`es-x/${ruleId}\` rule
159+
`,
160+
)
148161

149162
cp.execSync(`code "${ruleFile}"`)
150163
cp.execSync(`code "${testFile}"`)
@@ -243,6 +256,134 @@ let ${object.toLowerCase()} = new ${object}()
243256
}
244257
}
245258

259+
function buildStaticPropertiesRuleResources({ ruleId, object, properties }) {
260+
const promptObject = globalThis[object]
261+
const exampleProperty = promptObject
262+
? Object.getOwnPropertyNames(promptObject)[0]
263+
: "example"
264+
const propertyType =
265+
promptObject && promptObject[properties[0]]
266+
? typeof promptObject[properties[0]]
267+
: "function"
268+
const kind =
269+
propertyType === "function"
270+
? ["method", "methods"]
271+
: ["property", "properties"]
272+
const propertiesString =
273+
properties.length > 1 ? `{${properties.join(",")}}` : properties[0]
274+
let propertiesName = `\`${object}.${properties[properties.length - 1]}\` ${kind[0]}`
275+
if (properties.length > 1) {
276+
propertiesName = `${properties
277+
.slice(0, -1)
278+
.map((p) => `\`${object}.${p}\``)
279+
.join(
280+
", ",
281+
)}, and \`${object}.${properties[properties.length - 1]}\` ${kind[1]}`
282+
}
283+
284+
return {
285+
rule: `"use strict"
286+
287+
const {
288+
defineStaticPropertiesHandler,
289+
} = require("../util/define-static-properties-handler")
290+
291+
module.exports = {
292+
meta: {
293+
docs: {
294+
description: "disallow the \`${object}.${propertiesString}\` ${kind[0]}",
295+
category: "ES${maxESVersion}",
296+
recommended: false,
297+
url: "",
298+
},
299+
fixable: null,
300+
messages: {
301+
forbidden: "ES${maxESVersion} '{{name}}' ${kind[0]} is forbidden.",
302+
},
303+
schema: [
304+
{
305+
type: "object",
306+
properties: {
307+
allowTestedProperty: { type: "boolean" },
308+
},
309+
additionalProperties: false,
310+
},
311+
],
312+
type: "problem",
313+
},
314+
create(context) {
315+
return defineStaticPropertiesHandler(context, {
316+
"${object}": { ${properties.map((p) => `"${p}": "${propertyType}"`).join(",\n")} },
317+
})
318+
},
319+
}
320+
`,
321+
test: `"use strict"
322+
323+
const RuleTester = require("../../tester")
324+
const rule = require("../../../lib/rules/${ruleId}.js")
325+
326+
new RuleTester().run("${ruleId}", rule, {
327+
valid: [
328+
"${object}",
329+
"${object}.${exampleProperty}",
330+
${properties.map((p) => `"let ${object} = 0; ${object}.${p}"`).join(",\n")}
331+
],
332+
invalid: [
333+
${properties
334+
.map(
335+
(p) => `{
336+
code: "${object}.${p}",
337+
errors: ["ES${maxESVersion} '${object}.${p}' ${kind[0]} is forbidden."],
338+
}`,
339+
)
340+
.join(",\n")}
341+
],
342+
})
343+
`,
344+
doc: `# es-x/${ruleId}
345+
>
346+
347+
This rule reports ES${maxESVersion} [${propertiesName}]($$LINK$$) as errors.
348+
349+
## 💡 Examples
350+
351+
⛔ Examples of **incorrect** code for this rule:
352+
353+
<eslint-playground type="bad">
354+
355+
\`\`\`js
356+
/*eslint es-x/${ruleId}: error */
357+
${properties.map((p) => `${object}.${p}();`).join("\n")}
358+
\`\`\`
359+
360+
</eslint-playground>
361+
362+
## 🔧 Options
363+
364+
This rule has an option.
365+
366+
\`\`\`jsonc
367+
{
368+
"rules": {
369+
"es-x/${ruleId}": [
370+
"error",
371+
{
372+
"allowTestedProperty": false
373+
}
374+
]
375+
}
376+
}
377+
\`\`\`
378+
379+
### allowTestedProperty: boolean
380+
381+
Configure the allowTestedProperty mode for only this rule.
382+
This is prior to the \`settings['es-x'].allowTestedProperty\` setting.
383+
`,
384+
}
385+
}
386+
246387
function buildNonStandardStaticPropertiesRuleResources({ ruleId, object }) {
247388
const camelObject = camelCase(object)
248389
return {

tests/lib/rules/no-math-sumprecise.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"use strict"
2+
3+
const RuleTester = require("../../tester")
4+
const rule = require("../../../lib/rules/no-math-sumprecise.js")
5+
6+
new RuleTester().run("no-math-sumprecise", rule, {
7+
valid: ["Math", "Math.abs", "let Math = 0; Math.sumPrecise"],
8+
invalid: [
9+
{
10+
code: "Math.sumPrecise",
11+
errors: ["ES2026 'Math.sumPrecise' method is forbidden."],
12+
},
13+
],
14+
})

0 commit comments

Comments
 (0)