diff --git a/.changeset/no-json-israwjson.md b/.changeset/no-json-israwjson.md new file mode 100644 index 00000000..95ea5221 --- /dev/null +++ b/.changeset/no-json-israwjson.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-es-x": minor +--- + +Add `es-x/no-json-israwjson` rule diff --git a/.changeset/no-json-parse-reviver-context-parameter.md b/.changeset/no-json-parse-reviver-context-parameter.md new file mode 100644 index 00000000..f3df9848 --- /dev/null +++ b/.changeset/no-json-parse-reviver-context-parameter.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-es-x": minor +--- + +Add `es-x/no-json-parse-reviver-context-parameter` rule diff --git a/.changeset/no-json-parse-with-source.md b/.changeset/no-json-parse-with-source.md new file mode 100644 index 00000000..1b81547c --- /dev/null +++ b/.changeset/no-json-parse-with-source.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-es-x": minor +--- + +Add `no-json-parse-with-source` config \ No newline at end of file diff --git a/.changeset/no-json-rawjson.md b/.changeset/no-json-rawjson.md new file mode 100644 index 00000000..bb83ba27 --- /dev/null +++ b/.changeset/no-json-rawjson.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-es-x": minor +--- + +Add `es-x/no-json-rawjson` rule diff --git a/docs/configs/index.md b/docs/configs/index.md index 6518794b..2def6cb0 100644 --- a/docs/configs/index.md +++ b/docs/configs/index.md @@ -1041,6 +1041,32 @@ export default [ +## no-json-parse-with-source + +disallow proposal ES2026 [JSON.parse source text access](https://github.com/tc39/proposal-json-parse-with-source)\ +⚠️ This config will be changed in the minor versions of this plugin. + +This configs includes rules for [es-x/no-json-israwjson](../rules/no-json-israwjson.md), [es-x/no-json-parse-reviver-context-parameter](../rules/no-json-parse-reviver-context-parameter.md), and [es-x/no-json-rawjson](../rules/no-json-rawjson.md). + +```js +import pluginESx from "eslint-plugin-es-x" +export default [ + pluginESx.configs['flat/no-json-parse-with-source'] +] +``` + +
Legacy Config + +.eslintrc.*: + +```json +{ + "extends": ["plugin:es-x/no-json-parse-with-source"], +} +``` + +
+ ## no-float16array disallow proposal ES2025 [Float16Array](https://github.com/tc39/proposal-float16array) diff --git a/docs/rules/index.md b/docs/rules/index.md index cf6db172..5a09756c 100644 --- a/docs/rules/index.md +++ b/docs/rules/index.md @@ -14,6 +14,9 @@ There is a config that enables the rules in this category: [`no-new-in-esnext`] | [es-x/no-asyncdisposablestack](./no-asyncdisposablestack.md) | disallow the `AsyncDisposableStack` class. | | | [es-x/no-disposablestack](./no-disposablestack.md) | disallow the `DisposableStack` class. | | | [es-x/no-error-iserror](./no-error-iserror.md) | disallow the `Error.isError` method. | | +| [es-x/no-json-israwjson](./no-json-israwjson.md) | disallow the `JSON.isRawJSON` method. | | +| [es-x/no-json-parse-reviver-context-parameter](./no-json-parse-reviver-context-parameter.md) | disallow the `context` parameter in `JSON.parse` reviver function. | | +| [es-x/no-json-rawjson](./no-json-rawjson.md) | disallow the `JSON.rawJSON` method. | | | [es-x/no-suppressederror](./no-suppressederror.md) | disallow the `SuppressedError` class. | | | [es-x/no-symbol-asyncdispose](./no-symbol-asyncdispose.md) | disallow the `Symbol.asyncDispose` property. | | | [es-x/no-symbol-dispose](./no-symbol-dispose.md) | disallow the `Symbol.dispose` property. | | diff --git a/docs/rules/no-json-israwjson.md b/docs/rules/no-json-israwjson.md new file mode 100644 index 00000000..50050ea6 --- /dev/null +++ b/docs/rules/no-json-israwjson.md @@ -0,0 +1,55 @@ +--- +title: "es-x/no-json-israwjson" +description: "disallow the `JSON.isRawJSON` method" +--- + +# es-x/no-json-israwjson +> disallow the `JSON.isRawJSON` method + +- ❗ ***This rule has not been released yet.*** +- ✅ The following configurations enable this rule: [no-json-parse-with-source] and [no-new-in-esnext] + +This rule reports ES2026 [`JSON.isRawJSON` method](https://github.com/tc39/proposal-json-parse-with-source) as errors. + +## 💡 Examples + +⛔ Examples of **incorrect** code for this rule: + + + +```js +/*eslint es-x/no-json-israwjson: error */ +JSON.isRawJSON(object); +``` + + + +## 🔧 Options + +This rule has an option. + +```jsonc +{ + "rules": { + "es-x/no-json-israwjson": [ + "error", + { + "allowTestedProperty": false + } + ] + } +} +``` + +### allowTestedProperty: boolean + +Configure the allowTestedProperty mode for only this rule. +This is prior to the `settings['es-x'].allowTestedProperty` setting. + +## 📚 References + +- [Rule source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/lib/rules/no-json-israwjson.js) +- [Test source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/tests/lib/rules/no-json-israwjson.js) + +[no-json-parse-with-source]: ../configs/index.md#no-json-parse-with-source +[no-new-in-esnext]: ../configs/index.md#no-new-in-esnext diff --git a/docs/rules/no-json-parse-reviver-context-parameter.md b/docs/rules/no-json-parse-reviver-context-parameter.md new file mode 100644 index 00000000..a264d1f4 --- /dev/null +++ b/docs/rules/no-json-parse-reviver-context-parameter.md @@ -0,0 +1,41 @@ +--- +title: "es-x/no-json-parse-reviver-context-parameter" +description: "disallow the `context` parameter in `JSON.parse` reviver function" +--- + +# es-x/no-json-parse-reviver-context-parameter +> disallow the `context` parameter in `JSON.parse` reviver function + +- ❗ ***This rule has not been released yet.*** +- ✅ The following configurations enable this rule: [no-json-parse-with-source] and [no-new-in-esnext] + +This rule reports ES2026 [`JSON.parse` resolver `context` parameter](https://github.com/tc39/proposal-json-parse-with-source) as errors. + +## 💡 Examples + +⛔ Examples of **incorrect** code for this rule: + + + +```js +/*eslint es-x/no-json-parse-reviver-context-parameter: error */ +JSON.parse( + '{"key": "value"}', + ( + key, + value, + context // This is the context parameter + ) => { + return value; +}); +``` + + + +## 📚 References + +- [Rule source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/lib/rules/no-json-parse-reviver-context-parameter.js) +- [Test source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/tests/lib/rules/no-json-parse-reviver-context-parameter.js) + +[no-json-parse-with-source]: ../configs/index.md#no-json-parse-with-source +[no-new-in-esnext]: ../configs/index.md#no-new-in-esnext diff --git a/docs/rules/no-json-rawjson.md b/docs/rules/no-json-rawjson.md new file mode 100644 index 00000000..a8414e5a --- /dev/null +++ b/docs/rules/no-json-rawjson.md @@ -0,0 +1,55 @@ +--- +title: "es-x/no-json-rawjson" +description: "disallow the `JSON.rawJSON` method" +--- + +# es-x/no-json-rawjson +> disallow the `JSON.rawJSON` method + +- ❗ ***This rule has not been released yet.*** +- ✅ The following configurations enable this rule: [no-json-parse-with-source] and [no-new-in-esnext] + +This rule reports ES2026 [`JSON.rawJSON` method](https://github.com/tc39/proposal-json-parse-with-source) as errors. + +## 💡 Examples + +⛔ Examples of **incorrect** code for this rule: + + + +```js +/*eslint es-x/no-json-rawjson: error */ +JSON.rawJSON('123'); +``` + + + +## 🔧 Options + +This rule has an option. + +```jsonc +{ + "rules": { + "es-x/no-json-rawjson": [ + "error", + { + "allowTestedProperty": false + } + ] + } +} +``` + +### allowTestedProperty: boolean + +Configure the allowTestedProperty mode for only this rule. +This is prior to the `settings['es-x'].allowTestedProperty` setting. + +## 📚 References + +- [Rule source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/lib/rules/no-json-rawjson.js) +- [Test source](https://github.com/eslint-community/eslint-plugin-es-x/blob/master/tests/lib/rules/no-json-rawjson.js) + +[no-json-parse-with-source]: ../configs/index.md#no-json-parse-with-source +[no-new-in-esnext]: ../configs/index.md#no-new-in-esnext diff --git a/lib/configs/flat/no-json-parse-with-source.js b/lib/configs/flat/no-json-parse-with-source.js new file mode 100644 index 00000000..ebe9aa5d --- /dev/null +++ b/lib/configs/flat/no-json-parse-with-source.js @@ -0,0 +1,18 @@ +/** + * DON'T EDIT THIS FILE. + * This file was generated by "scripts/update-lib-flat-configs.js" script. + */ +"use strict" + +module.exports = { + plugins: { + get "es-x"() { + return require("../../index.js") + }, + }, + rules: { + "es-x/no-json-israwjson": "error", + "es-x/no-json-parse-reviver-context-parameter": "error", + "es-x/no-json-rawjson": "error", + }, +} diff --git a/lib/configs/flat/no-new-in-esnext.js b/lib/configs/flat/no-new-in-esnext.js index 8e89607b..c44aecde 100644 --- a/lib/configs/flat/no-new-in-esnext.js +++ b/lib/configs/flat/no-new-in-esnext.js @@ -15,6 +15,9 @@ module.exports = { "es-x/no-asyncdisposablestack": "error", "es-x/no-disposablestack": "error", "es-x/no-error-iserror": "error", + "es-x/no-json-israwjson": "error", + "es-x/no-json-parse-reviver-context-parameter": "error", + "es-x/no-json-rawjson": "error", "es-x/no-suppressederror": "error", "es-x/no-symbol-asyncdispose": "error", "es-x/no-symbol-dispose": "error", diff --git a/lib/configs/no-json-parse-with-source.js b/lib/configs/no-json-parse-with-source.js new file mode 100644 index 00000000..4292fd06 --- /dev/null +++ b/lib/configs/no-json-parse-with-source.js @@ -0,0 +1,14 @@ +/** + * DON'T EDIT THIS FILE. + * This file was generated by "scripts/update-lib-configs.js" script. + */ +"use strict" + +module.exports = { + plugins: ["es-x"], + rules: { + "es-x/no-json-israwjson": "error", + "es-x/no-json-parse-reviver-context-parameter": "error", + "es-x/no-json-rawjson": "error", + }, +} diff --git a/lib/configs/no-new-in-esnext.js b/lib/configs/no-new-in-esnext.js index b5eed918..3344448e 100644 --- a/lib/configs/no-new-in-esnext.js +++ b/lib/configs/no-new-in-esnext.js @@ -11,6 +11,9 @@ module.exports = { "es-x/no-asyncdisposablestack": "error", "es-x/no-disposablestack": "error", "es-x/no-error-iserror": "error", + "es-x/no-json-israwjson": "error", + "es-x/no-json-parse-reviver-context-parameter": "error", + "es-x/no-json-rawjson": "error", "es-x/no-suppressederror": "error", "es-x/no-symbol-asyncdispose": "error", "es-x/no-symbol-dispose": "error", diff --git a/lib/index.js b/lib/index.js index b523641b..b9178c17 100644 --- a/lib/index.js +++ b/lib/index.js @@ -19,6 +19,7 @@ module.exports = { "flat/no-intl-numberformat-v3": require("./configs/flat/no-intl-numberformat-v3"), "flat/no-is-usv-string": require("./configs/flat/no-is-usv-string"), "flat/no-iterator-helpers": require("./configs/flat/no-iterator-helpers"), + "flat/no-json-parse-with-source": require("./configs/flat/no-json-parse-with-source"), "flat/no-new-in-es5": require("./configs/flat/no-new-in-es5"), "flat/no-new-in-es2015": require("./configs/flat/no-new-in-es2015"), "flat/no-new-in-es2015-intl-api": require("./configs/flat/no-new-in-es2015-intl-api"), @@ -79,6 +80,7 @@ module.exports = { "no-intl-numberformat-v3": require("./configs/no-intl-numberformat-v3"), "no-is-usv-string": require("./configs/no-is-usv-string"), "no-iterator-helpers": require("./configs/no-iterator-helpers"), + "no-json-parse-with-source": require("./configs/no-json-parse-with-source"), "no-new-in-es5": require("./configs/no-new-in-es5"), "no-new-in-es2015": require("./configs/no-new-in-es2015"), "no-new-in-es2015-intl-api": require("./configs/no-new-in-es2015-intl-api"), @@ -258,7 +260,10 @@ module.exports = { "no-iterator-prototype-take": require("./rules/no-iterator-prototype-take"), "no-iterator-prototype-toarray": require("./rules/no-iterator-prototype-toarray"), "no-json": require("./rules/no-json"), + "no-json-israwjson": require("./rules/no-json-israwjson"), "no-json-modules": require("./rules/no-json-modules"), + "no-json-parse-reviver-context-parameter": require("./rules/no-json-parse-reviver-context-parameter"), + "no-json-rawjson": require("./rules/no-json-rawjson"), "no-json-superset": require("./rules/no-json-superset"), "no-keyword-properties": require("./rules/no-keyword-properties"), "no-labelled-function-declarations": require("./rules/no-labelled-function-declarations"), diff --git a/lib/rules/no-json-israwjson.js b/lib/rules/no-json-israwjson.js new file mode 100644 index 00000000..fd246416 --- /dev/null +++ b/lib/rules/no-json-israwjson.js @@ -0,0 +1,36 @@ +"use strict" + +const { + defineStaticPropertiesHandler, +} = require("../util/define-static-properties-handler") + +module.exports = { + meta: { + docs: { + description: "disallow the `JSON.isRawJSON` method", + category: "ES2026", + proposal: "json-parse-with-source", + recommended: false, + url: "http://eslint-community.github.io/eslint-plugin-es-x/rules/no-json-israwjson.html", + }, + fixable: null, + messages: { + forbidden: "ES2026 '{{name}}' method is forbidden.", + }, + schema: [ + { + type: "object", + properties: { + allowTestedProperty: { type: "boolean" }, + }, + additionalProperties: false, + }, + ], + type: "problem", + }, + create(context) { + return defineStaticPropertiesHandler(context, { + JSON: { isRawJSON: "function" }, + }) + }, +} diff --git a/lib/rules/no-json-parse-reviver-context-parameter.js b/lib/rules/no-json-parse-reviver-context-parameter.js new file mode 100644 index 00000000..f894ad6c --- /dev/null +++ b/lib/rules/no-json-parse-reviver-context-parameter.js @@ -0,0 +1,54 @@ +"use strict" + +const { ReferenceTracker, CALL } = require("@eslint-community/eslint-utils") + +module.exports = { + meta: { + docs: { + description: + "disallow the `context` parameter in `JSON.parse` reviver function", + category: "ES2026", + proposal: "json-parse-with-source", + recommended: false, + url: "http://eslint-community.github.io/eslint-plugin-es-x/rules/no-json-parse-reviver-context-parameter.html", + }, + fixable: null, + messages: { + forbidden: + "Unexpected context parameter in JSON.parse reviver function.", + }, + schema: [], + type: "problem", + }, + create(context) { + const sourceCode = context.sourceCode + return { + "Program:exit"(program) { + const tracker = new ReferenceTracker( + sourceCode.getScope(program), + ) + for (const { node } of tracker.iterateGlobalReferences({ + JSON: { parse: { [CALL]: true } }, + })) { + if (node.type !== "CallExpression") { + continue + } + const reviver = node.arguments[1] + if ( + !reviver || + (reviver.type !== "FunctionExpression" && + reviver.type !== "ArrowFunctionExpression") + ) { + continue + } + if (reviver.params.length >= 3) { + context.report({ + node: reviver.params[2], + messageId: "forbidden", + }) + } + } + }, + } + }, +} diff --git a/lib/rules/no-json-rawjson.js b/lib/rules/no-json-rawjson.js new file mode 100644 index 00000000..b8487c8b --- /dev/null +++ b/lib/rules/no-json-rawjson.js @@ -0,0 +1,36 @@ +"use strict" + +const { + defineStaticPropertiesHandler, +} = require("../util/define-static-properties-handler") + +module.exports = { + meta: { + docs: { + description: "disallow the `JSON.rawJSON` method", + category: "ES2026", + proposal: "json-parse-with-source", + recommended: false, + url: "http://eslint-community.github.io/eslint-plugin-es-x/rules/no-json-rawjson.html", + }, + fixable: null, + messages: { + forbidden: "ES2026 '{{name}}' method is forbidden.", + }, + schema: [ + { + type: "object", + properties: { + allowTestedProperty: { type: "boolean" }, + }, + additionalProperties: false, + }, + ], + type: "problem", + }, + create(context) { + return defineStaticPropertiesHandler(context, { + JSON: { rawJSON: "function" }, + }) + }, +} diff --git a/lib/util/well-known-properties.js b/lib/util/well-known-properties.js index e57adfa4..c418cd27 100644 --- a/lib/util/well-known-properties.js +++ b/lib/util/well-known-properties.js @@ -807,7 +807,9 @@ const jsonProperties = new Set([ ...objectPrototypeProperties, // https://tc39.es/ecma262/multipage/structured-data.html#sec-json-object + "isRawJSON", "parse", + "rawJSON", "stringify", // [ %Symbol.toStringTag% ] ]) diff --git a/scripts/proposals.js b/scripts/proposals.js index bde6cdfb..35097e63 100644 --- a/scripts/proposals.js +++ b/scripts/proposals.js @@ -37,6 +37,10 @@ module.exports = { title: "Iterator Helpers", link: "https://github.com/tc39/proposal-iterator-helpers", }, + "json-parse-with-source": { + title: "JSON.parse source text access", + link: "https://github.com/tc39/proposal-json-parse-with-source", + }, "relative-indexing-method": { title: "An .at() method on all the built-in indexables", link: "https://github.com/tc39/proposal-relative-indexing-method", diff --git a/tests/lib/rules/no-json-israwjson.js b/tests/lib/rules/no-json-israwjson.js new file mode 100644 index 00000000..fcf054ca --- /dev/null +++ b/tests/lib/rules/no-json-israwjson.js @@ -0,0 +1,14 @@ +"use strict" + +const RuleTester = require("../../tester") +const rule = require("../../../lib/rules/no-json-israwjson.js") + +new RuleTester().run("no-json-israwjson", rule, { + valid: ["JSON", "JSON.parse", "let JSON = 0; JSON.isRawJSON"], + invalid: [ + { + code: "JSON.isRawJSON", + errors: ["ES2026 'JSON.isRawJSON' method is forbidden."], + }, + ], +}) diff --git a/tests/lib/rules/no-json-parse-reviver-context-parameter.js b/tests/lib/rules/no-json-parse-reviver-context-parameter.js new file mode 100644 index 00000000..64d332c4 --- /dev/null +++ b/tests/lib/rules/no-json-parse-reviver-context-parameter.js @@ -0,0 +1,21 @@ +"use strict" + +const RuleTester = require("../../tester") +const rule = require("../../../lib/rules/no-json-parse-reviver-context-parameter.js") + +new RuleTester().run("no-json-parse-reviver-context-parameter", rule, { + valid: ['JSON.parse("{}")', 'JSON.parse("{}", (key, value) => value)'], + invalid: [ + { + code: 'JSON.parse("{}", (key, value, context) => { return value; })', + errors: [ + { + message: + "Unexpected context parameter in JSON.parse reviver function.", + line: 1, + column: 31, + }, + ], + }, + ], +}) diff --git a/tests/lib/rules/no-json-rawjson.js b/tests/lib/rules/no-json-rawjson.js new file mode 100644 index 00000000..a874c91e --- /dev/null +++ b/tests/lib/rules/no-json-rawjson.js @@ -0,0 +1,14 @@ +"use strict" + +const RuleTester = require("../../tester") +const rule = require("../../../lib/rules/no-json-rawjson.js") + +new RuleTester().run("no-json-rawjson", rule, { + valid: ["JSON", "JSON.parse", "let JSON = 0; JSON.rawJSON"], + invalid: [ + { + code: "JSON.rawJSON", + errors: ["ES2026 'JSON.rawJSON' method is forbidden."], + }, + ], +}) diff --git a/tests/lib/util/well-known-properties.js b/tests/lib/util/well-known-properties.js index 7a2272bf..5228e60c 100644 --- a/tests/lib/util/well-known-properties.js +++ b/tests/lib/util/well-known-properties.js @@ -685,8 +685,6 @@ function* getAllProperties(object) { (key === "pause" && object === Atomics) || // https://github.com/tc39/proposal-error-capturestacktrace (key === "captureStackTrace" && object === Error) || - // https://github.com/tc39/proposal-json-parse-with-source - ((key === "rawJSON" || key === "isRawJSON") && object === JSON) || // https://github.com/tc39/proposal-intl-locale-info ((key === "firstDayOfWeek" || key === "getCalendars" ||