├── .github ├── FUNDING.yml └── workflows │ ├── format.yml │ ├── GHPages.yml │ ├── pkg.pr.new-comment.yml │ ├── stale.yml │ ├── pkg.pr.new.yml │ └── Release.yml ├── .npmrc ├── tests ├── fixtures │ ├── indent │ │ ├── array-01.json │ │ ├── object-01.json │ │ └── vue-sfc-01.vue │ ├── integrations │ │ └── eslint-plugin │ │ │ ├── test01 │ │ │ ├── src │ │ │ │ ├── test.json │ │ │ │ └── test.js │ │ │ └── .eslintrc.json │ │ │ ├── test-auto-rule01 │ │ │ ├── src │ │ │ │ ├── test.json │ │ │ │ └── test.js │ │ │ └── .eslintrc.json │ │ │ ├── test-auto-rule-with-flat-config01 │ │ │ ├── src │ │ │ │ ├── test.json │ │ │ │ └── test.js │ │ │ └── eslint.config.js │ │ │ └── test-as-parser01 │ │ │ ├── src │ │ │ └── test.json6 │ │ │ └── .eslintrc.json │ └── auto │ │ ├── test02 │ │ └── .eslintrc.json │ │ ├── test03 │ │ └── .eslintrc.json │ │ └── test01 │ │ └── .eslintrc.json └── lib │ ├── test-lib │ └── eslint-compat.ts │ ├── rules │ ├── no-nan.ts │ ├── no-plus-sign.ts │ ├── no-floating-decimal.ts │ ├── no-infinity.ts │ ├── no-octal-numeric-literals.ts │ ├── no-binary-numeric-literals.ts │ ├── no-octal.ts │ ├── no-dupe-keys.ts │ ├── no-hexadecimal-numeric-literals.ts │ ├── no-escape-sequence-in-identifier.ts │ ├── quote-props.ts │ ├── no-number-props.ts │ ├── object-curly-newline.ts │ ├── no-octal-escape.ts │ ├── no-regexp-literals.ts │ ├── no-bigint-literals.ts │ ├── key-spacing.ts │ ├── no-multi-str.ts │ ├── comma-dangle.ts │ ├── no-binary-expression.ts │ ├── no-comments.ts │ ├── quotes.ts │ ├── no-unicode-codepoint-escapes.ts │ ├── array-element-newline.ts │ ├── no-undefined-value.ts │ ├── object-property-newline.ts │ ├── no-numeric-separators.ts │ ├── no-sparse-arrays.ts │ ├── array-bracket-newline.ts │ ├── no-useless-escape.ts │ ├── no-template-literals.ts │ ├── space-unary-ops.ts │ └── no-parenthesized.ts │ ├── meta.ts │ ├── eslint-plugin.ts │ ├── configs │ ├── flat │ │ └── base.ts │ └── recommended-with-json.ts │ └── as-parser.ts ├── logo.png ├── tests-integrations ├── fixtures │ ├── vue-eslint-parser-option │ │ ├── test.json │ │ ├── .eslintrc.json │ │ └── package.json │ ├── eslint-plugin-markdown-nest-for-v6 │ │ ├── test.md │ │ ├── .eslintrc.json │ │ └── package.json │ ├── eslint-plugin-markdown │ │ ├── test.md │ │ ├── .eslintrc.json │ │ └── package.json │ └── eslint-plugin-markdown-nest │ │ ├── test.md │ │ ├── .eslintrc.json │ │ └── package.json └── lib │ ├── vue-eslint-parser-option.ts │ ├── eslint-plugin-markdown.ts │ └── eslint-plugin-markdown-nest-for-v6.ts ├── docs ├── .vitepress │ ├── theme │ │ ├── components │ │ │ ├── state │ │ │ │ ├── index.js │ │ │ │ ├── deserialize.js │ │ │ │ └── serialize.js │ │ │ ├── components │ │ │ │ └── PgEditor.vue │ │ │ └── eslint-code-block.vue │ │ ├── style.css │ │ └── index.ts │ ├── shim │ │ ├── module.mjs │ │ └── rules │ │ │ └── auto.mjs │ ├── build-system │ │ ├── src │ │ │ ├── events.mjs │ │ │ └── vue-eslint-parser.mjs │ │ └── build.ts │ └── stylelint.config.js ├── playground │ └── index.md └── rules │ ├── no-comments.md │ ├── no-undefined-value.md │ ├── no-regexp-literals.md │ ├── no-nan.md │ ├── no-bigint-literals.md │ ├── no-infinity.md │ ├── no-octal-escape.md │ ├── no-multi-str.md │ ├── no-binary-expression.md │ ├── no-parenthesized.md │ ├── vue-custom-block │ └── no-parsing-error.md │ ├── no-octal.md │ ├── no-plus-sign.md │ ├── no-template-literals.md │ ├── no-unicode-codepoint-escapes.md │ ├── no-number-props.md │ ├── no-escape-sequence-in-identifier.md │ ├── no-dupe-keys.md │ ├── auto.md │ ├── no-numeric-separators.md │ ├── no-octal-numeric-literals.md │ ├── no-binary-numeric-literals.md │ ├── no-hexadecimal-numeric-literals.md │ ├── no-useless-escape.md │ ├── no-sparse-arrays.md │ ├── space-unary-ops.md │ ├── array-bracket-spacing.md │ ├── object-curly-spacing.md │ ├── array-element-newline.md │ ├── comma-style.md │ ├── indent.md │ ├── no-floating-decimal.md │ ├── object-curly-newline.md │ ├── key-spacing.md │ ├── key-name-casing.md │ ├── array-bracket-newline.md │ ├── no-irregular-whitespace.md │ ├── object-property-newline.md │ ├── valid-json-number.md │ └── quotes.md ├── typings └── espree │ └── index.d.ts ├── tools ├── update.ts ├── lib │ ├── changesets-util.ts │ └── load-rules.ts ├── update-docs-rules-index.ts ├── update-meta.ts └── update-rules.ts ├── lib ├── meta.ts ├── configs │ ├── auto-config.ts │ ├── base.ts │ ├── flat │ │ ├── all.ts │ │ ├── base.ts │ │ ├── prettier.ts │ │ ├── recommended-with-json5.ts │ │ ├── recommended-with-jsonc.ts │ │ └── recommended-with-json.ts │ ├── all.ts │ ├── prettier.ts │ ├── recommended-with-json5.ts │ ├── recommended-with-jsonc.ts │ └── recommended-with-json.ts ├── utils │ ├── get-auto-jsonc-rules-config │ │ ├── worker.ts │ │ ├── calculate-config-for-file.ts │ │ └── should-use-flat-config.ts │ ├── eslint-string-utils.ts │ └── eslint-keywords.ts ├── rules │ ├── no-octal.ts │ ├── no-sparse-arrays.ts │ ├── no-octal-escape.ts │ ├── no-dupe-keys.ts │ ├── no-regexp-literals.ts │ ├── no-bigint-literals.ts │ ├── no-useless-escape.ts │ ├── no-comments.ts │ ├── no-floating-decimal.ts │ ├── no-multi-str.ts │ ├── no-undefined-value.ts │ ├── no-nan.ts │ ├── no-infinity.ts │ ├── no-template-literals.ts │ ├── no-irregular-whitespace.ts │ ├── no-binary-expression.ts │ ├── no-number-props.ts │ ├── no-octal-numeric-literals.ts │ ├── no-binary-numeric-literals.ts │ ├── no-hexadecimal-numeric-literals.ts │ ├── no-numeric-separators.ts │ ├── no-plus-sign.ts │ └── no-escape-sequence-in-identifier.ts └── index.ts ├── .env-cmdrc ├── conf ├── eslint-all.js ├── eslint-recommended.js └── rules.js ├── tsconfig.build.json ├── renovate.json ├── .eslintrc.for-vscode.mjs ├── .changeset ├── config.json └── README.md ├── tsconfig.json ├── .vscode └── settings.json ├── .devcontainer └── devcontainer.json └── LICENSE /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ota-meshi 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | force=true -------------------------------------------------------------------------------- /tests/fixtures/indent/array-01.json: -------------------------------------------------------------------------------- 1 | /*{}*/ 2 | [ 3 | "value" 4 | ] -------------------------------------------------------------------------------- /tests/fixtures/indent/object-01.json: -------------------------------------------------------------------------------- 1 | /*{}*/ 2 | { 3 | "key": "value" 4 | } -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test01/src/test.json: -------------------------------------------------------------------------------- 1 | {"foo": "bar"} -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ota-meshi/eslint-plugin-jsonc/HEAD/logo.png -------------------------------------------------------------------------------- /tests-integrations/fixtures/vue-eslint-parser-option/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": "b" 3 | } -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test01/src/test.js: -------------------------------------------------------------------------------- 1 | var a = {foo: 'bar'} -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-auto-rule01/src/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | } -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-auto-rule01/src/test.js: -------------------------------------------------------------------------------- 1 | var a = { 2 | foo: 'bar' 3 | } -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-auto-rule-with-flat-config01/src/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | } -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/state/index.js: -------------------------------------------------------------------------------- 1 | export * from "./deserialize.js"; 2 | export * from "./serialize.js"; 3 | -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-as-parser01/src/test.json6: -------------------------------------------------------------------------------- 1 | { 2 | // comment 3 | "foo": "bar" 4 | } -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-auto-rule-with-flat-config01/src/test.js: -------------------------------------------------------------------------------- 1 | var a = { 2 | foo: 'bar' 3 | } -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown-nest-for-v6/test.md: -------------------------------------------------------------------------------- 1 | ```json 2 | { 3 | "quotes": 'value' 4 | } 5 | ``` 6 | -------------------------------------------------------------------------------- /tests/fixtures/auto/test02/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "rules": { 4 | "indent": "error" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown/test.md: -------------------------------------------------------------------------------- 1 | 2 | ```json 3 | { 4 | "arr": ["a", "b" 5 | ] 6 | } 7 | ``` 8 | -------------------------------------------------------------------------------- /docs/.vitepress/shim/module.mjs: -------------------------------------------------------------------------------- 1 | export function createRequire() { 2 | // noop 3 | } 4 | export default { 5 | createRequire, 6 | }; 7 | -------------------------------------------------------------------------------- /typings/espree/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { Program } from "estree"; 2 | 3 | export function parse(text: string, options?: any): Program; 4 | -------------------------------------------------------------------------------- /docs/.vitepress/build-system/src/events.mjs: -------------------------------------------------------------------------------- 1 | import all from "events"; 2 | export default all; 3 | export const EventEmitter = all.EventEmitter; 4 | -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test01/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["plugin:jsonc/recommended-with-jsonc"] 4 | } 5 | -------------------------------------------------------------------------------- /tests/fixtures/auto/test03/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["eslint:all"], 4 | "rules": { 5 | "indent": ["off", 4] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/build-system/src/vue-eslint-parser.mjs: -------------------------------------------------------------------------------- 1 | import all from "vue-eslint-parser"; 2 | export default all; 3 | export const parseForESLint = all.parseForESLint; 4 | -------------------------------------------------------------------------------- /tools/update.ts: -------------------------------------------------------------------------------- 1 | import "./update-rules"; 2 | import "./update-rulesets"; 3 | import "./update-docs"; 4 | import "./update-readme"; 5 | import "./update-docs-rules-index"; 6 | import "./update-meta"; 7 | -------------------------------------------------------------------------------- /tests/lib/test-lib/eslint-compat.ts: -------------------------------------------------------------------------------- 1 | import { getLegacyESLint, getESLint } from "eslint-compat-utils/eslint"; 2 | 3 | export const LegacyESLint = getLegacyESLint(); 4 | export const ESLint = getESLint(); 5 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown-nest/test.md: -------------------------------------------------------------------------------- 1 | ```json 2 | { 3 | "quotes": 'value' 4 | } 5 | ``` 6 | 7 | ````md 8 | ```json 9 | { 10 | "quotes": 'value' 11 | } 12 | ``` 13 | ```` 14 | -------------------------------------------------------------------------------- /lib/meta.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | export const name = "eslint-plugin-jsonc" as const; 5 | export const version = "2.21.0" as const; 6 | -------------------------------------------------------------------------------- /docs/playground/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "playground" 3 | --- 4 | 5 | # Playground 6 | 7 | 8 | 9 | The playground is [here](https://ota-meshi.github.io/eslint-plugin-jsonc/playground/)!! 10 | 11 | 12 | -------------------------------------------------------------------------------- /.env-cmdrc: -------------------------------------------------------------------------------- 1 | { 2 | "test": { 3 | "SYNCKIT_TS_RUNNER": "swc" 4 | }, 5 | "version": { 6 | "IN_VERSION_SCRIPT": "true", 7 | "SYNCKIT_TS_RUNNER": "swc" 8 | }, 9 | "version-ci": { 10 | "IN_VERSION_CI_SCRIPT": "true", 11 | "SYNCKIT_TS_RUNNER": "swc" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-as-parser01/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["plugin:jsonc/recommended-with-json"], 4 | "overrides": [ 5 | { 6 | "files": ["*.json6"], 7 | "parser": "jsonc-eslint-parser" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /conf/eslint-all.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | "use strict"; 3 | 4 | const getCoreRules = require("./rules"); 5 | 6 | const allRules = {}; 7 | 8 | for (const [ruleId, rule] of getCoreRules()) { 9 | if (!rule.meta.deprecated) { 10 | allRules[ruleId] = "error"; 11 | } 12 | } 13 | module.exports = { rules: allRules }; 14 | -------------------------------------------------------------------------------- /docs/.vitepress/stylelint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["stylelint-config-standard-vue"], 3 | rules: { 4 | "no-descending-specificity": null, 5 | "selector-class-pattern": null, 6 | "value-keyword-case": null, 7 | 8 | // Conflict with Prettier 9 | indentation: null, 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": [ 4 | "tests/**/*", 5 | "tests-integrations/lib/**/*", 6 | "tools/**/*", 7 | "typings/**/*", 8 | "docs/**/*" 9 | ], 10 | "compilerOptions": { 11 | "removeComments": true /* Do not emit comments to output. */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /conf/eslint-recommended.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | "use strict"; 3 | 4 | const getCoreRules = require("./rules"); 5 | 6 | const rules = {}; 7 | 8 | for (const [ruleId, rule] of getCoreRules()) { 9 | if (rule.meta.docs.recommended && !rule.meta.deprecated) { 10 | rules[ruleId] = "error"; 11 | } 12 | } 13 | module.exports = { 14 | rules, 15 | }; 16 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/vue-eslint-parser-option/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "plugins": ["jsonc"], 4 | "parser": "vue-eslint-parser", 5 | "parserOptions": { 6 | "parser": "jsonc-eslint-parser", 7 | "sourceType": "module", 8 | "ecmaVersion": 2015 9 | }, 10 | "rules": { 11 | "jsonc/indent": "error" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/style.css: -------------------------------------------------------------------------------- 1 | a > img { 2 | display: inline-block; 3 | } 4 | 5 | /* Playground */ 6 | .playground .VPDoc.has-aside .content-container, 7 | .playground .VPDoc:not(.has-sidebar) .content, 8 | .playground .VPDoc:not(.has-sidebar) .container { 9 | max-width: none; 10 | } 11 | 12 | .playground .VPDoc.has-aside .aside { 13 | display: none; 14 | } 15 | -------------------------------------------------------------------------------- /lib/configs/auto-config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @deprecated Use the `jsonc/auto` rule instead. 3 | */ 4 | import path from "path"; 5 | const base = require.resolve("./base"); 6 | const baseExtend = 7 | path.extname(`${base}`) === ".ts" ? "plugin:jsonc/base" : base; 8 | export = { 9 | extends: [baseExtend], 10 | rules: { 11 | "jsonc/auto": "error", 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":preserveSemverRanges", 5 | ":disableDependencyDashboard" 6 | ], 7 | "packageRules": [ 8 | { 9 | "updateTypes": ["minor", "patch", "pin", "digest"], 10 | "automerge": true 11 | }, 12 | { 13 | "depTypeList": ["devDependencies"], 14 | "automerge": true 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.eslintrc.for-vscode.mjs: -------------------------------------------------------------------------------- 1 | import base from "./eslint.config.mjs"; 2 | import eslintRuleTester from "eslint-plugin-eslint-rule-tester"; 3 | 4 | export default [ 5 | ...base, 6 | { 7 | files: ["tests/lib/rules/**/*.ts"], 8 | plugins: { "eslint-rule-tester": eslintRuleTester }, 9 | rules: { 10 | "eslint-rule-tester/valid-testcase": "error", 11 | }, 12 | }, 13 | ]; 14 | -------------------------------------------------------------------------------- /lib/utils/get-auto-jsonc-rules-config/worker.ts: -------------------------------------------------------------------------------- 1 | import { runAsWorker } from "synckit"; 2 | import { getESLint } from "eslint-compat-utils/eslint"; 3 | const ESLint = getESLint(); 4 | 5 | runAsWorker(async (cwd: string, fileName: string) => { 6 | const eslint = new ESLint({ cwd }); 7 | const config = await eslint.calculateConfigForFile(fileName); 8 | return { rules: config.rules }; 9 | }); 10 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parserOptions": { 4 | "sourceType": "module", 5 | "ecmaVersion": 2015 6 | }, 7 | "extends": [ 8 | "plugin:markdown/recommended", 9 | "plugin:jsonc/recommended-with-json" 10 | ], 11 | "rules": { 12 | "array-bracket-newline": "error", 13 | "jsonc/auto": "error" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-auto-rule01/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["plugin:jsonc/base","eslint:recommended"], 4 | "rules": { 5 | "indent": "error", 6 | "no-unused-vars": "off", 7 | "no-multi-spaces": "error", 8 | "no-multiple-empty-lines": "error", 9 | "jsonc/auto": "error", 10 | "jsonc/no-comments": "error" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/configs/base.ts: -------------------------------------------------------------------------------- 1 | export = { 2 | plugins: ["jsonc"], 3 | overrides: [ 4 | { 5 | files: ["*.json", "*.json5", "*.jsonc"], 6 | parser: require.resolve("jsonc-eslint-parser"), 7 | rules: { 8 | // ESLint core rules known to cause problems with JSON. 9 | strict: "off", 10 | "no-unused-expressions": "off", 11 | "no-unused-vars": "off", 12 | }, 13 | }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /tools/lib/changesets-util.ts: -------------------------------------------------------------------------------- 1 | import getReleasePlan from "@changesets/get-release-plan"; 2 | import path from "path"; 3 | 4 | /** Get new version string from changesets */ 5 | export async function getNewVersion(): Promise { 6 | const releasePlan = await getReleasePlan(path.resolve(__dirname, "../..")); 7 | 8 | return releasePlan.releases.find( 9 | ({ name }) => name === "eslint-plugin-jsonc", 10 | )!.newVersion; 11 | } 12 | -------------------------------------------------------------------------------- /lib/utils/get-auto-jsonc-rules-config/calculate-config-for-file.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from "eslint"; 2 | import { createSyncFn } from "synckit"; 3 | 4 | const getSync = createSyncFn(require.resolve("./worker")); 5 | 6 | /** 7 | * Synchronously calculateConfigForFile 8 | */ 9 | export function calculateConfigForFile( 10 | cwd: string, 11 | fileName: string, 12 | ): Pick { 13 | return getSync(cwd, fileName); 14 | } 15 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { 6 | "repo": "ota-meshi/eslint-plugin-jsonc" 7 | } 8 | ], 9 | "commit": false, 10 | "linked": [], 11 | "access": "restricted", 12 | "baseBranch": "main", 13 | "updateInternalDependencies": "patch", 14 | "bumpVersionsWithWorkspaceProtocolOnly": true, 15 | "ignore": [] 16 | } 17 | -------------------------------------------------------------------------------- /conf/rules.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | "use strict"; 3 | 4 | let ruleMap; 5 | 6 | /** Get all rules */ 7 | module.exports = function getCoreRules() { 8 | const eslint = require("eslint"); 9 | try { 10 | return ruleMap || (ruleMap = new eslint.Linter().getRules()); 11 | } catch { 12 | // getRules() is no longer available in flat config. 13 | } 14 | 15 | const { builtinRules } = require("eslint/use-at-your-own-risk"); 16 | return builtinRules; 17 | }; 18 | -------------------------------------------------------------------------------- /lib/configs/flat/all.ts: -------------------------------------------------------------------------------- 1 | import { rules } from "../../utils/rules"; 2 | import base from "./base"; 3 | import type { Linter } from "eslint"; 4 | const all: Linter.RulesRecord = {}; 5 | for (const rule of rules) { 6 | if (rule.meta.docs.ruleId === "jsonc/sort-array-values") continue; 7 | all[rule.meta.docs.ruleId] = "error"; 8 | } 9 | 10 | export default [ 11 | ...base, 12 | { 13 | rules: { 14 | ...all, 15 | }, 16 | }, 17 | ] satisfies Linter.FlatConfig[]; 18 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown-nest/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parserOptions": { 4 | "sourceType": "module", 5 | "ecmaVersion": 2015 6 | }, 7 | "extends": ["plugin:markdown/recommended"], 8 | "rules": { 9 | "quotes": ["error", "single"] 10 | }, 11 | "overrides": [ 12 | { 13 | "files": ["*.json"], 14 | "extends": ["plugin:jsonc/recommended-with-json"], 15 | "rules": { "jsonc/auto": "error" } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown-nest-for-v6/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parserOptions": { 4 | "sourceType": "module", 5 | "ecmaVersion": 2015 6 | }, 7 | "extends": ["plugin:markdown/recommended"], 8 | "rules": { 9 | "quotes": ["error", "single"] 10 | }, 11 | "overrides": [ 12 | { 13 | "files": ["*.json"], 14 | "extends": ["plugin:jsonc/recommended-with-json"], 15 | "rules": { "jsonc/auto": "error" } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /lib/configs/all.ts: -------------------------------------------------------------------------------- 1 | import { rules } from "../utils/rules"; 2 | import path from "path"; 3 | const base = require.resolve("./base"); 4 | const baseExtend = 5 | path.extname(`${base}`) === ".ts" ? "plugin:jsonc/base" : base; 6 | 7 | const all: Record = {}; 8 | for (const rule of rules) { 9 | if (rule.meta.docs.ruleId === "jsonc/sort-array-values") continue; 10 | all[rule.meta.docs.ruleId] = "error"; 11 | } 12 | 13 | export = { 14 | extends: [baseExtend], 15 | rules: { 16 | ...all, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /tests/fixtures/indent/vue-sfc-01.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | { 4 | "key": "value" 5 | } 6 | 7 | 8 | { 9 | "key": "value" 10 | } 11 | 12 | 13 | { 14 | "key": "value" 15 | } 16 | 17 | 18 | { 19 | key: "value", 20 | } 21 | 22 | 23 | 24 | { 25 | "key": "value" 26 | } 27 | 28 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-for-eslint-plugin-jsonc-with-md", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "eslint": "^9.0.0", 14 | "eslint-plugin-jsonc": "file:../../../eslint-plugin-jsonc-2.16.0.tgz", 15 | "eslint-plugin-markdown": "^3.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/vue-eslint-parser-option/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-for-eslint-plugin-jsonc-with-vue", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "eslint": "^9.0.0", 14 | "eslint-plugin-jsonc": "file:../../../eslint-plugin-jsonc-2.16.0.tgz", 15 | "vue-eslint-parser": "^10.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown-nest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-for-eslint-plugin-jsonc-with-md-nest", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "eslint": "^9.0.0", 14 | "eslint-plugin-jsonc": "file:../../../eslint-plugin-jsonc-2.16.0.tgz", 15 | "eslint-plugin-markdown": "^3.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests-integrations/fixtures/eslint-plugin-markdown-nest-for-v6/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-for-eslint-plugin-jsonc-with-md-nest", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "eslint": "^9.0.0", 14 | "eslint-plugin-jsonc": "file:../../../eslint-plugin-jsonc-2.16.0.tgz", 15 | "eslint-plugin-markdown": "^3.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/lib/rules/no-nan.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-nan"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | }); 11 | 12 | tester.run("no-nan", rule, { 13 | valid: ["Infinity", "1234", '"foo"', "{NaN:42}"], 14 | invalid: [ 15 | { 16 | code: `NaN`, 17 | errors: ["NaN should not be used."], 18 | }, 19 | { 20 | code: `+NaN`, 21 | errors: ["NaN should not be used."], 22 | }, 23 | { 24 | code: `-NaN`, 25 | errors: ["NaN should not be used."], 26 | }, 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /tests/lib/rules/no-plus-sign.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-plus-sign"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | }); 11 | 12 | tester.run("no-plus-sign", rule, { 13 | valid: ["42", "-42", "-42.0"], 14 | invalid: [ 15 | { 16 | code: `+42`, 17 | output: `42`, 18 | errors: ["Plus sign should not be used."], 19 | }, 20 | { 21 | code: `+ 42`, 22 | output: ` 42`, 23 | errors: ["Plus sign should not be used."], 24 | ignoreMomoa: true, 25 | }, 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /tests/lib/rules/no-floating-decimal.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-floating-decimal"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | }); 11 | 12 | tester.run("no-floating-decimal", rule, { 13 | valid: ["42", "42.0", "0.42"], 14 | invalid: [ 15 | { 16 | code: `.42`, 17 | output: `0.42`, 18 | errors: ["A leading decimal point can be confused with a dot."], 19 | }, 20 | { 21 | code: `42.`, 22 | output: `42.0`, 23 | errors: ["A trailing decimal point can be confused with a dot."], 24 | }, 25 | ], 26 | }); 27 | -------------------------------------------------------------------------------- /tests/lib/rules/no-infinity.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-infinity"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | }); 11 | 12 | tester.run("no-infinity", rule, { 13 | valid: ["NaN", "42", '"foo"', "{Infinity:42}"], 14 | invalid: [ 15 | { 16 | code: `Infinity`, 17 | errors: ["Infinity should not be used."], 18 | }, 19 | { 20 | code: `+Infinity`, 21 | errors: ["Infinity should not be used."], 22 | }, 23 | { 24 | code: `-Infinity`, 25 | errors: ["Infinity should not be used."], 26 | }, 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /tests/lib/rules/no-octal-numeric-literals.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-octal-numeric-literals"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-octal-numeric-literals", rule, { 14 | valid: ["0", "777"], 15 | invalid: [ 16 | { 17 | code: `0o777`, 18 | output: `511`, 19 | errors: ["Octal numeric literals should not be used."], 20 | }, 21 | { 22 | code: `0O777`, 23 | output: `511`, 24 | errors: ["Octal numeric literals should not be used."], 25 | }, 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /tests/lib/rules/no-binary-numeric-literals.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-binary-numeric-literals"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-binary-numeric-literals", rule, { 14 | valid: ["0", "1010"], 15 | invalid: [ 16 | { 17 | code: `0b1010`, 18 | output: `10`, 19 | errors: ["Binary numeric literals should not be used."], 20 | }, 21 | { 22 | code: `0B1010`, 23 | output: `10`, 24 | errors: ["Binary numeric literals should not be used."], 25 | }, 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /tests/fixtures/integrations/eslint-plugin/test-auto-rule-with-flat-config01/eslint.config.js: -------------------------------------------------------------------------------- 1 | let plugin; 2 | try { 3 | plugin = require("../../../../../lib/index"); 4 | } catch (e) { 5 | // @ts-ignore -- ignore 6 | plugin = require("../../../../../dist/index"); 7 | } 8 | const parser = require("jsonc-eslint-parser"); 9 | 10 | module.exports = [ 11 | { 12 | plugins: { 13 | jsonc: plugin, 14 | }, 15 | rules: { 16 | indent: "error", 17 | "no-unused-vars": "off", 18 | "no-multi-spaces": "error", 19 | "no-multiple-empty-lines": "error", 20 | "jsonc/auto": "error", 21 | "jsonc/no-comments": "error", 22 | }, 23 | }, 24 | { 25 | files: ["**/*.json"], 26 | languageOptions: { 27 | parser, 28 | }, 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /tests/fixtures/auto/test01/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["eslint:recommended"], 4 | "rules": { 5 | "array-bracket-newline": "error", 6 | "array-bracket-spacing": "error", 7 | "array-element-newline": "error", 8 | "comma-dangle": "error", 9 | "comma-style": "error", 10 | "indent": "error", 11 | "key-spacing": "error", 12 | "no-dupe-keys": "error", 13 | "no-multi-str": "error", 14 | "no-octal-escape": "error", 15 | "no-sparse-arrays": "error", 16 | "no-useless-escape": "error", 17 | "object-curly-newline": "error", 18 | "object-curly-spacing": "error", 19 | "object-property-newline": "error", 20 | "quote-props": "error", 21 | "quotes": "error", 22 | "sort-keys": "error", 23 | "space-unary-ops": "error" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/rules/no-octal.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-octal"); 3 | 4 | export default createRule("no-octal", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: "disallow legacy octal literals", 9 | recommended: ["json", "jsonc", "json5"], 10 | extensionRule: true, 11 | layout: false, 12 | }, 13 | fixable: coreRule.meta?.fixable, 14 | hasSuggestions: (coreRule.meta as any).hasSuggestions, 15 | schema: coreRule.meta!.schema!, 16 | messages: coreRule.meta!.messages!, 17 | type: coreRule.meta!.type!, 18 | deprecated: false, 19 | replacedBy: [], 20 | }, 21 | create(context) { 22 | return defineWrapperListener(coreRule, context, context.options); 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/components/PgEditor.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 36 | -------------------------------------------------------------------------------- /lib/rules/no-sparse-arrays.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-sparse-arrays"); 3 | 4 | export default createRule("no-sparse-arrays", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: "disallow sparse arrays", 9 | recommended: ["json", "jsonc", "json5"], 10 | extensionRule: true, 11 | layout: false, 12 | }, 13 | fixable: coreRule.meta?.fixable, 14 | hasSuggestions: (coreRule.meta as any).hasSuggestions, 15 | schema: coreRule.meta!.schema!, 16 | messages: coreRule.meta!.messages!, 17 | type: coreRule.meta!.type!, 18 | deprecated: false, 19 | replacedBy: [], 20 | }, 21 | create(context) { 22 | return defineWrapperListener(coreRule, context, context.options); 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /lib/rules/no-octal-escape.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-octal-escape"); 3 | 4 | export default createRule("no-octal-escape", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: "disallow octal escape sequences in string literals", 9 | recommended: null, 10 | extensionRule: true, 11 | layout: false, 12 | }, 13 | fixable: coreRule.meta?.fixable, 14 | hasSuggestions: (coreRule.meta as any).hasSuggestions, 15 | schema: coreRule.meta!.schema!, 16 | messages: coreRule.meta!.messages!, 17 | type: coreRule.meta!.type!, 18 | deprecated: false, 19 | replacedBy: [], 20 | }, 21 | create(context) { 22 | return defineWrapperListener(coreRule, context, context.options); 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "node16", 5 | "lib": ["es2022"], 6 | "allowJs": true, 7 | "checkJs": true, 8 | "outDir": "./dist", 9 | "strict": true, 10 | "noImplicitAny": true, 11 | 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "*": ["typings/*"] 19 | }, 20 | "esModuleInterop": true, 21 | "resolveJsonModule": true, 22 | 23 | "skipLibCheck": true 24 | }, 25 | "include": [ 26 | "lib/**/*", 27 | "tests/lib/**/*", 28 | "tests-integrations/lib/**/*", 29 | "tools/**/*", 30 | "typings/**/*", 31 | "docs/.vitepress/**/*" 32 | ], 33 | "exclude": ["dist/**/*"] 34 | } 35 | -------------------------------------------------------------------------------- /lib/configs/flat/base.ts: -------------------------------------------------------------------------------- 1 | import type { ESLint, Linter } from "eslint"; 2 | import * as parser from "jsonc-eslint-parser"; 3 | export default [ 4 | { 5 | plugins: { 6 | get jsonc(): ESLint.Plugin { 7 | // eslint-disable-next-line @typescript-eslint/no-require-imports -- ignore 8 | return require("../../index"); 9 | }, 10 | }, 11 | }, 12 | { 13 | files: [ 14 | "*.json", 15 | "**/*.json", 16 | "*.json5", 17 | "**/*.json5", 18 | "*.jsonc", 19 | "**/*.jsonc", 20 | ], 21 | languageOptions: { 22 | parser, 23 | }, 24 | rules: { 25 | // ESLint core rules known to cause problems with JSON. 26 | strict: "off", 27 | "no-unused-expressions": "off", 28 | "no-unused-vars": "off", 29 | }, 30 | }, 31 | ] satisfies Linter.FlatConfig[]; 32 | -------------------------------------------------------------------------------- /lib/rules/no-dupe-keys.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-dupe-keys"); 3 | 4 | export default createRule("no-dupe-keys", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: "disallow duplicate keys in object literals", 9 | recommended: ["json", "jsonc", "json5"], 10 | extensionRule: true, 11 | layout: false, 12 | }, 13 | fixable: coreRule.meta?.fixable, 14 | hasSuggestions: (coreRule.meta as any).hasSuggestions, 15 | schema: coreRule.meta!.schema!, 16 | messages: coreRule.meta!.messages!, 17 | type: coreRule.meta!.type!, 18 | deprecated: false, 19 | replacedBy: [], 20 | }, 21 | create(context) { 22 | return defineWrapperListener(coreRule, context, context.options); 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /lib/rules/no-regexp-literals.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | export default createRule("no-regexp-literals", { 4 | meta: { 5 | docs: { 6 | description: "disallow RegExp literals", 7 | recommended: ["json", "jsonc", "json5"], 8 | extensionRule: false, 9 | layout: false, 10 | }, 11 | schema: [], 12 | messages: { 13 | unexpected: "RegExp literals are not allowed.", 14 | }, 15 | type: "problem", 16 | }, 17 | create(context) { 18 | if (!context.sourceCode.parserServices.isJSON) { 19 | return {}; 20 | } 21 | return { 22 | JSONLiteral(node) { 23 | if (node.regex) { 24 | context.report({ 25 | loc: node.loc, 26 | messageId: "unexpected", 27 | }); 28 | } 29 | }, 30 | }; 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /lib/rules/no-bigint-literals.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | export default createRule("no-bigint-literals", { 4 | meta: { 5 | docs: { 6 | description: "disallow BigInt literals", 7 | recommended: ["json", "jsonc", "json5"], 8 | extensionRule: false, 9 | layout: false, 10 | }, 11 | schema: [], 12 | messages: { 13 | unexpected: "BigInt literals are not allowed.", 14 | }, 15 | type: "problem", 16 | }, 17 | create(context) { 18 | if (!context.sourceCode.parserServices.isJSON) { 19 | return {}; 20 | } 21 | return { 22 | JSONLiteral(node) { 23 | if (node.bigint != null) { 24 | context.report({ 25 | loc: node.loc, 26 | messageId: "unexpected", 27 | }); 28 | } 29 | }, 30 | }; 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /lib/rules/no-useless-escape.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-useless-escape"); 3 | 4 | export default createRule("no-useless-escape", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: "disallow unnecessary escape usage", 9 | recommended: ["json", "jsonc", "json5"], 10 | extensionRule: true, 11 | layout: false, 12 | }, 13 | fixable: coreRule.meta?.fixable, 14 | hasSuggestions: (coreRule.meta as any).hasSuggestions, 15 | schema: coreRule.meta!.schema!, 16 | messages: coreRule.meta!.messages!, 17 | type: coreRule.meta!.type!, 18 | deprecated: false, 19 | replacedBy: [], 20 | }, 21 | create(context) { 22 | return defineWrapperListener(coreRule, context, context.options); 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | if (typeof globalThis !== "undefined") { 2 | if (typeof require === "undefined") { 3 | (globalThis as any).require = () => { 4 | const e = new Error("require is not defined"); 5 | (e as any).code = "MODULE_NOT_FOUND"; 6 | throw e; 7 | }; 8 | } 9 | } 10 | import type { Theme } from "vitepress"; 11 | import DefaultTheme from "vitepress/theme"; 12 | import ESLintCodeBlock from "./components/eslint-code-block.vue"; 13 | import PlaygroundBlock from "./components/playground-block.vue"; 14 | import "./style.css"; 15 | 16 | const theme: Theme = { 17 | extends: DefaultTheme, 18 | enhanceApp(ctx) { 19 | DefaultTheme.enhanceApp(ctx); 20 | ctx.app.component("eslint-code-block", ESLintCodeBlock); 21 | ctx.app.component("playground-block", PlaygroundBlock); 22 | }, 23 | }; 24 | export default theme; 25 | -------------------------------------------------------------------------------- /lib/rules/no-comments.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | export default createRule("no-comments", { 4 | meta: { 5 | docs: { 6 | description: "disallow comments", 7 | recommended: ["json"], 8 | extensionRule: false, 9 | layout: false, 10 | }, 11 | schema: [], 12 | messages: { 13 | unexpected: "Unexpected comment.", 14 | }, 15 | type: "problem", 16 | }, 17 | create(context) { 18 | const sourceCode = context.sourceCode; 19 | if (!sourceCode.parserServices.isJSON) { 20 | return {}; 21 | } 22 | return { 23 | Program() { 24 | for (const comment of sourceCode.getAllComments()) { 25 | context.report({ 26 | loc: comment.loc!, 27 | messageId: "unexpected", 28 | }); 29 | } 30 | }, 31 | }; 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /tools/update-docs-rules-index.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | import renderRulesTableContent from "./render-rules"; 4 | 5 | // ----------------------------------------------------------------------------- 6 | const readmeFilePath = path.resolve(__dirname, "../docs/rules/index.md"); 7 | fs.writeFileSync( 8 | readmeFilePath, 9 | `--- 10 | sidebarDepth: 0 11 | --- 12 | 13 | # Available Rules 14 | 15 | The \`--fix\` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) automatically fixes problems reported by rules which have a wrench :wrench: below. 16 | The rules with the following star :star: are included in the \`plugin:jsonc/recommended\` config. 17 | 18 | 19 | ${renderRulesTableContent(1)}`, 20 | ); 21 | -------------------------------------------------------------------------------- /lib/rules/no-floating-decimal.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-floating-decimal"); 3 | 4 | export default createRule("no-floating-decimal", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: 9 | "disallow leading or trailing decimal points in numeric literals", 10 | recommended: ["json", "jsonc"], 11 | extensionRule: true, 12 | layout: true, 13 | }, 14 | fixable: coreRule.meta?.fixable, 15 | hasSuggestions: (coreRule.meta as any).hasSuggestions, 16 | schema: coreRule.meta!.schema!, 17 | messages: coreRule.meta!.messages!, 18 | type: coreRule.meta!.type!, 19 | deprecated: false, 20 | replacedBy: [], 21 | }, 22 | create(context) { 23 | return defineWrapperListener(coreRule, context, context.options); 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /tests/lib/rules/no-octal.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-octal"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-octal", rule, { 14 | valid: ["0", "1", "9"], 15 | invalid: [ 16 | { 17 | code: `01`, 18 | errors: ["Octal literals should not be used."], 19 | ...({ 20 | languageOptions: { 21 | sourceType: "script", 22 | }, 23 | } as any), 24 | }, 25 | { 26 | code: `09`, 27 | errors: ["Octal literals should not be used."], 28 | ...({ 29 | languageOptions: { 30 | sourceType: "script", 31 | }, 32 | } as any), 33 | }, 34 | ], 35 | }); 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": [ 3 | "javascript", 4 | "javascriptreact", 5 | "vue", 6 | "typescript", 7 | "jsonc", 8 | "json", 9 | "markdown", 10 | "yaml" 11 | ], 12 | "eslint.options": { 13 | "overrideConfigFile": "./.eslintrc.for-vscode.mjs" 14 | }, 15 | "typescript.validate.enable": true, 16 | "javascript.validate.enable": false, 17 | "vetur.validation.script": false, 18 | "vetur.validation.style": false, 19 | "css.validate": false, 20 | "typescript.tsdk": "node_modules/typescript/lib", 21 | "editor.codeActionsOnSave": { 22 | "source.fixAll.eslint": "explicit", 23 | "source.fixAll.stylelint": "explicit" 24 | }, 25 | "stylelint.validate": [ 26 | "css", 27 | "html", 28 | "less", 29 | "postcss", 30 | "sass", 31 | "scss", 32 | "vue", 33 | "vue-html", 34 | "vue-postcss", 35 | "stylus" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /lib/rules/no-multi-str.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-multi-str"); 3 | 4 | export default createRule("no-multi-str", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: "disallow multiline strings", 9 | recommended: ["json", "jsonc"], 10 | extensionRule: true, 11 | layout: false, 12 | }, 13 | fixable: coreRule.meta?.fixable, 14 | hasSuggestions: (coreRule.meta as any).hasSuggestions, 15 | schema: coreRule.meta!.schema!, 16 | messages: { 17 | ...coreRule.meta!.messages!, 18 | multilineString: "Multiline support is limited to JSON5 only.", 19 | }, 20 | type: coreRule.meta!.type!, 21 | deprecated: false, 22 | replacedBy: [], 23 | }, 24 | create(context) { 25 | return defineWrapperListener(coreRule, context, context.options); 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /tests/lib/rules/no-dupe-keys.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-dupe-keys"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("no-dupe-keys", rule, { 13 | valid: ['{"key": "value"}', '{"key": "value", "key2": "value"}'], 14 | invalid: [ 15 | { 16 | code: '{"key": "value", "key": "value"}', 17 | errors: ["Duplicate key 'key'."], 18 | }, 19 | { 20 | filename: "test.vue", 21 | code: `{"key": "value", "key": "value"}`, 22 | errors: ["Duplicate key 'key'."], 23 | ...({ 24 | languageOptions: { 25 | parser: vueParser, 26 | }, 27 | } as any), 28 | }, 29 | ], 30 | }); 31 | -------------------------------------------------------------------------------- /lib/rules/no-undefined-value.ts: -------------------------------------------------------------------------------- 1 | import { isUndefinedIdentifier } from "jsonc-eslint-parser"; 2 | import { createRule } from "../utils"; 3 | 4 | export default createRule("no-undefined-value", { 5 | meta: { 6 | docs: { 7 | description: "disallow `undefined`", 8 | recommended: ["json", "jsonc", "json5"], 9 | extensionRule: false, 10 | layout: false, 11 | }, 12 | schema: [], 13 | messages: { 14 | unexpected: "`undefined` is not allowed.", 15 | }, 16 | type: "problem", 17 | }, 18 | create(context) { 19 | if (!context.sourceCode.parserServices.isJSON) { 20 | return {}; 21 | } 22 | return { 23 | JSONIdentifier(node) { 24 | if (!isUndefinedIdentifier(node)) { 25 | return; 26 | } 27 | context.report({ 28 | loc: node.loc, 29 | messageId: "unexpected", 30 | }); 31 | }, 32 | }; 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /tests/lib/rules/no-hexadecimal-numeric-literals.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-hexadecimal-numeric-literals"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | }); 11 | 12 | tester.run("no-hexadecimal-numeric-literals", rule, { 13 | valid: ["0", "777", '"FFF"'], 14 | invalid: [ 15 | { 16 | code: `0x777`, 17 | output: `1911`, 18 | errors: ["Hexadecimal numeric literals should not be used."], 19 | }, 20 | { 21 | code: `0X777`, 22 | output: `1911`, 23 | errors: ["Hexadecimal numeric literals should not be used."], 24 | }, 25 | { 26 | code: `0xFFFF`, 27 | output: `65535`, 28 | errors: ["Hexadecimal numeric literals should not be used."], 29 | }, 30 | ], 31 | }); 32 | -------------------------------------------------------------------------------- /docs/.vitepress/shim/rules/auto.mjs: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line n/no-missing-import -- The file path used is the actual rule path 2 | import { createRule } from "../utils"; 3 | export default createRule("auto", { 4 | meta: { 5 | docs: { 6 | description: 7 | "apply jsonc rules similar to your configured ESLint core rules", 8 | recommended: null, 9 | extensionRule: false, 10 | layout: false, 11 | }, 12 | fixable: "code", 13 | schema: [], 14 | messages: {}, 15 | type: "suggestion", 16 | }, 17 | create(context) { 18 | const sourceCode = context.sourceCode; 19 | if (!sourceCode.parserServices.isJSON) { 20 | return {}; 21 | } 22 | context.report({ 23 | node: sourceCode.ast, 24 | loc: { 25 | line: 1, 26 | column: 0, 27 | }, 28 | message: "The `auto` rule does not work in browsers.", 29 | }); 30 | return {}; 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /lib/rules/no-nan.ts: -------------------------------------------------------------------------------- 1 | import { isNumberIdentifier } from "jsonc-eslint-parser"; 2 | import { createRule } from "../utils"; 3 | 4 | export default createRule("no-nan", { 5 | meta: { 6 | docs: { 7 | description: "disallow NaN", 8 | recommended: ["json", "jsonc"], 9 | extensionRule: false, 10 | layout: false, 11 | }, 12 | messages: { 13 | disallow: "NaN should not be used.", 14 | }, 15 | schema: [], 16 | type: "problem", 17 | }, 18 | create(context) { 19 | if (!context.sourceCode.parserServices.isJSON) { 20 | return {}; 21 | } 22 | return { 23 | JSONIdentifier(node) { 24 | if (!isNumberIdentifier(node)) { 25 | return; 26 | } 27 | if (node.name === "NaN") { 28 | context.report({ 29 | loc: node.loc, 30 | messageId: "disallow", 31 | }); 32 | } 33 | }, 34 | }; 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /tests/lib/meta.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import plugin from "../../lib"; 3 | import { version } from "../../package.json"; 4 | const expectedMeta = { 5 | name: "eslint-plugin-jsonc", 6 | version, 7 | }; 8 | 9 | describe("Test for meta object", () => { 10 | it("A plugin should have a meta object.", () => { 11 | assert.strictEqual(plugin.meta.name, expectedMeta.name); 12 | assert.strictEqual(typeof plugin.meta.version, "string"); 13 | }); 14 | 15 | for (const [name, processor] of Object.entries( 16 | // @ts-expect-error -- missing processors 17 | plugin.processors || {}, 18 | )) { 19 | it(`"${name}" processor should have a meta object.`, () => { 20 | // @ts-expect-error -- missing type 21 | assert.strictEqual(processor.meta.name, expectedMeta.name); 22 | // @ts-expect-error -- missing type 23 | assert.strictEqual(typeof processor.meta.version, "string"); 24 | }); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /lib/rules/no-infinity.ts: -------------------------------------------------------------------------------- 1 | import { isNumberIdentifier } from "jsonc-eslint-parser"; 2 | import { createRule } from "../utils"; 3 | 4 | export default createRule("no-infinity", { 5 | meta: { 6 | docs: { 7 | description: "disallow Infinity", 8 | recommended: ["json", "jsonc"], 9 | extensionRule: false, 10 | layout: false, 11 | }, 12 | messages: { 13 | disallow: "Infinity should not be used.", 14 | }, 15 | schema: [], 16 | type: "problem", 17 | }, 18 | create(context) { 19 | if (!context.sourceCode.parserServices.isJSON) { 20 | return {}; 21 | } 22 | return { 23 | JSONIdentifier(node) { 24 | if (!isNumberIdentifier(node)) { 25 | return; 26 | } 27 | if (node.name === "Infinity") { 28 | context.report({ 29 | loc: node.loc, 30 | messageId: "disallow", 31 | }); 32 | } 33 | }, 34 | }; 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /lib/configs/flat/prettier.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import type { Linter } from "eslint"; 5 | import base from "./base"; 6 | export default [ 7 | ...base, 8 | { 9 | rules: { 10 | // eslint-plugin-jsonc rules 11 | "jsonc/array-bracket-newline": "off", 12 | "jsonc/array-bracket-spacing": "off", 13 | "jsonc/array-element-newline": "off", 14 | "jsonc/comma-dangle": "off", 15 | "jsonc/comma-style": "off", 16 | "jsonc/indent": "off", 17 | "jsonc/key-spacing": "off", 18 | "jsonc/no-floating-decimal": "off", 19 | "jsonc/object-curly-newline": "off", 20 | "jsonc/object-curly-spacing": "off", 21 | "jsonc/object-property-newline": "off", 22 | "jsonc/quote-props": "off", 23 | "jsonc/quotes": "off", 24 | "jsonc/space-unary-ops": "off", 25 | }, 26 | }, 27 | ] satisfies Linter.FlatConfig[]; 28 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: 👔 Format 2 | 3 | on: 4 | workflow_dispatch: null 5 | 6 | jobs: 7 | format: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Checkout repo 12 | uses: actions/checkout@v4 13 | - name: Setup node 14 | uses: actions/setup-node@v5 15 | - name: Install deps 16 | run: npm install -f 17 | - name: Format 18 | run: npm run eslint-fix 19 | - name: Commit 20 | run: | 21 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 22 | git config --local user.name "github-actions[bot]" 23 | 24 | git add . 25 | if [ -z "$(git status --porcelain)" ]; then 26 | echo "no formatting changed" 27 | exit 0 28 | fi 29 | git commit -m "chore: format" 30 | git push 31 | echo "pushed formatting changes https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)" 32 | -------------------------------------------------------------------------------- /tests/lib/rules/no-escape-sequence-in-identifier.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-escape-sequence-in-identifier"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-escape-sequence-in-identifier", rule, { 14 | valid: ["{key: 42}"], 15 | invalid: [ 16 | { 17 | code: `{\\u0041_\\u{42}: "\\u0043\\u{44}"}`, 18 | output: `{A_B: "\\u0043\\u{44}"}`, 19 | errors: [ 20 | { 21 | message: "Escape sequence in identifiers should not be used.", 22 | line: 1, 23 | column: 2, 24 | }, 25 | { 26 | message: "Escape sequence in identifiers should not be used.", 27 | line: 1, 28 | column: 9, 29 | }, 30 | ], 31 | }, 32 | ], 33 | }); 34 | -------------------------------------------------------------------------------- /lib/configs/prettier.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import path from "path"; 5 | const base = require.resolve("./base"); 6 | const baseExtend = 7 | path.extname(`${base}`) === ".ts" ? "plugin:jsonc/base" : base; 8 | export = { 9 | extends: [baseExtend], 10 | rules: { 11 | // eslint-plugin-jsonc rules 12 | "jsonc/array-bracket-newline": "off", 13 | "jsonc/array-bracket-spacing": "off", 14 | "jsonc/array-element-newline": "off", 15 | "jsonc/comma-dangle": "off", 16 | "jsonc/comma-style": "off", 17 | "jsonc/indent": "off", 18 | "jsonc/key-spacing": "off", 19 | "jsonc/no-floating-decimal": "off", 20 | "jsonc/object-curly-newline": "off", 21 | "jsonc/object-curly-spacing": "off", 22 | "jsonc/object-property-newline": "off", 23 | "jsonc/quote-props": "off", 24 | "jsonc/quotes": "off", 25 | "jsonc/space-unary-ops": "off", 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/rules/no-template-literals.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | export default createRule("no-template-literals", { 4 | meta: { 5 | docs: { 6 | description: "disallow template literals", 7 | recommended: ["json", "jsonc", "json5"], 8 | extensionRule: false, 9 | layout: false, 10 | }, 11 | fixable: "code", 12 | schema: [], 13 | messages: { 14 | unexpected: "The template literals are not allowed.", 15 | }, 16 | type: "problem", 17 | }, 18 | create(context) { 19 | if (!context.sourceCode.parserServices.isJSON) { 20 | return {}; 21 | } 22 | return { 23 | JSONTemplateLiteral(node) { 24 | context.report({ 25 | loc: node.loc, 26 | messageId: "unexpected", 27 | fix(fixer) { 28 | const s = node.quasis[0].value.cooked; 29 | return fixer.replaceTextRange(node.range, JSON.stringify(s)); 30 | }, 31 | }); 32 | }, 33 | }; 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /tests/lib/rules/quote-props.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/quote-props"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("quote-props", rule, { 13 | valid: ['{"key": "value"}', '"string"', '["element"]'], 14 | invalid: [ 15 | { 16 | code: '{key: "value"}', 17 | output: '{"key": "value"}', 18 | errors: ["Unquoted property 'key' found."], 19 | }, 20 | { 21 | filename: "test.vue", 22 | code: `{key: "value"}`, 23 | output: `{"key": "value"}`, 24 | errors: ["Unquoted property 'key' found."], 25 | ...({ 26 | languageOptions: { 27 | parser: vueParser, 28 | }, 29 | } as any), 30 | }, 31 | ], 32 | }); 33 | -------------------------------------------------------------------------------- /lib/rules/no-irregular-whitespace.ts: -------------------------------------------------------------------------------- 1 | import { createRule, defineWrapperListener, getCoreRule } from "../utils"; 2 | const coreRule = getCoreRule("no-irregular-whitespace"); 3 | 4 | export default createRule("no-irregular-whitespace", { 5 | meta: { 6 | ...coreRule.meta, 7 | docs: { 8 | description: "disallow irregular whitespace", 9 | // TODO: We will switch this in the next major version. 10 | recommended: null, 11 | // recommended: ["json", "jsonc", "json5"], // TODO: We need to turn off core `no-irregular-whitespace` rule in shared config. 12 | extensionRule: true, 13 | layout: false, 14 | }, 15 | fixable: coreRule.meta?.fixable, 16 | hasSuggestions: (coreRule.meta as any)?.hasSuggestions, 17 | schema: coreRule.meta!.schema!, 18 | messages: coreRule.meta!.messages!, 19 | type: coreRule.meta!.type!, 20 | deprecated: false, 21 | replacedBy: [], 22 | }, 23 | create(context) { 24 | return defineWrapperListener(coreRule, context, context.options); 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /docs/rules/no-comments.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-comments" 5 | description: "disallow comments" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/no-comments 10 | 11 | > disallow comments 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule reports comments. 18 | 19 | Cannot use comments when in JSON. 20 | 21 | 22 | 23 | 24 | 25 | ```json5 26 | /* eslint jsonc/no-comments: 'error' */ 27 | { 28 | /* ✗ BAD */ 29 | // ✗ BAD 30 | } 31 | ``` 32 | 33 | 34 | 35 | ## :wrench: Options 36 | 37 | Nothing. 38 | 39 | ## :rocket: Version 40 | 41 | This rule was introduced in eslint-plugin-jsonc v0.1.0 42 | 43 | ## :mag: Implementation 44 | 45 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-comments.ts) 46 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-comments.ts) 47 | -------------------------------------------------------------------------------- /tests/lib/eslint-plugin.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import assert from "assert"; 3 | import plugin from "../../lib/index"; 4 | import { getLegacyESLint } from "eslint-compat-utils/eslint"; 5 | const ESLint = getLegacyESLint(); 6 | 7 | // ----------------------------------------------------------------------------- 8 | // Tests 9 | // ----------------------------------------------------------------------------- 10 | 11 | const TEST_CWD = path.join(__dirname, "../fixtures/integrations/eslint-plugin"); 12 | 13 | describe("Integration with eslint-plugin-jsonc", () => { 14 | it("should lint without errors", async () => { 15 | const engine = new ESLint({ 16 | cwd: TEST_CWD, 17 | extensions: [".js", ".json"], 18 | plugins: { 19 | "eslint-plugin-jsonc": plugin as never, 20 | }, 21 | }); 22 | const results = await engine.lintFiles(["test01/src"]); 23 | assert.strictEqual(results.length, 2); 24 | assert.strictEqual( 25 | results.reduce((s, m) => s + m.errorCount, 0), 26 | 0, 27 | ); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /tests/lib/rules/no-number-props.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-number-props"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-number-props", rule, { 14 | valid: ['{"key": 123}', "{key: 123}", "123", "[123]"], 15 | invalid: [ 16 | { 17 | code: "{123: 123}", 18 | output: '{"123": 123}', 19 | errors: ["The number property keys are not allowed."], 20 | }, 21 | { 22 | filename: "test.vue", 23 | code: `{123: 123}`, 24 | output: `{"123": 123}`, 25 | errors: ["The number property keys are not allowed."], 26 | ...({ 27 | languageOptions: { 28 | parser: vueParser, 29 | }, 30 | } as any), 31 | }, 32 | ], 33 | }); 34 | -------------------------------------------------------------------------------- /tests/lib/rules/object-curly-newline.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/object-curly-newline"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("object-curly-newline", rule, { 13 | valid: ['{"key": "value"}', '{\n"key": "value"\n}'], 14 | invalid: [ 15 | { 16 | code: '{\n"key": "value"}', 17 | output: '{"key": "value"}', 18 | errors: ["Unexpected line break after this opening brace."], 19 | }, 20 | { 21 | filename: "test.vue", 22 | code: `{\n"key": "value"}`, 23 | output: `{"key": "value"}`, 24 | errors: ["Unexpected line break after this opening brace."], 25 | ...({ 26 | languageOptions: { 27 | parser: vueParser, 28 | }, 29 | } as any), 30 | }, 31 | ], 32 | }); 33 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node 3 | { 4 | "name": "Node.js & TypeScript", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye", 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | // "features": {}, 10 | 11 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 12 | // "forwardPorts": [], 13 | 14 | // Use 'postCreateCommand' to run commands after the container is created. 15 | "postCreateCommand": "npm install", 16 | 17 | // Configure tool-specific properties. 18 | "customizations": { 19 | "vscode": { 20 | "extensions": ["dbaeumer.vscode-eslint"] 21 | } 22 | } 23 | 24 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 25 | // "remoteUser": "root" 26 | } 27 | -------------------------------------------------------------------------------- /lib/rules/no-binary-expression.ts: -------------------------------------------------------------------------------- 1 | import { getStaticJSONValue } from "jsonc-eslint-parser"; 2 | import { createRule } from "../utils"; 3 | 4 | export default createRule("no-binary-expression", { 5 | meta: { 6 | docs: { 7 | description: "disallow binary expression", 8 | recommended: ["json", "jsonc", "json5"], 9 | extensionRule: false, 10 | layout: false, 11 | }, 12 | fixable: "code", 13 | hasSuggestions: false, 14 | schema: [], 15 | messages: { 16 | disallow: "The binary expressions are not allowed.", 17 | }, 18 | type: "problem", 19 | }, 20 | create(context) { 21 | if (!context.sourceCode.parserServices.isJSON) { 22 | return {}; 23 | } 24 | 25 | return { 26 | JSONBinaryExpression(node) { 27 | context.report({ 28 | loc: node.loc, 29 | messageId: "disallow", 30 | fix(fixer) { 31 | const value = getStaticJSONValue(node); 32 | return fixer.replaceTextRange(node.range, JSON.stringify(value)); 33 | }, 34 | }); 35 | }, 36 | }; 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /tests/lib/rules/no-octal-escape.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-octal-escape"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("no-octal-escape", rule, { 13 | valid: ['{"GOOD": "Copyright \\u00A9"}'], 14 | invalid: [ 15 | { 16 | code: '{"BAD": "Copyright \\251"}', 17 | errors: ["Don't use octal: '\\251'. Use '\\u....' instead."], 18 | ...({ 19 | languageOptions: { 20 | sourceType: "script", 21 | }, 22 | } as any), 23 | }, 24 | { 25 | filename: "test.vue", 26 | code: `{"BAD": "Copyright \\251"}`, 27 | errors: ["Don't use octal: '\\251'. Use '\\u....' instead."], 28 | ...({ 29 | languageOptions: { 30 | sourceType: "script", 31 | parser: vueParser, 32 | }, 33 | } as any), 34 | }, 35 | ], 36 | }); 37 | -------------------------------------------------------------------------------- /tests/lib/rules/no-regexp-literals.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-regexp-literals"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-regexp-literals", rule, { 14 | valid: ['{"key": "value"}', '"string"', '["element"]'], 15 | invalid: [ 16 | { 17 | code: "/reg/", 18 | errors: ["RegExp literals are not allowed."], 19 | }, 20 | { 21 | code: "[/reg/, {'/val/': /reg/}]", 22 | errors: [ 23 | "RegExp literals are not allowed.", 24 | "RegExp literals are not allowed.", 25 | ], 26 | }, 27 | { 28 | filename: "test.vue", 29 | code: `/reg/`, 30 | errors: ["RegExp literals are not allowed."], 31 | ...({ 32 | languageOptions: { 33 | parser: vueParser, 34 | }, 35 | } as any), 36 | }, 37 | ], 38 | }); 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yosuke Ota 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/lib/rules/no-bigint-literals.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-bigint-literals"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | ecmaVersion: 2020, 10 | }, 11 | ignoreMomoa: true, 12 | }); 13 | 14 | tester.run("no-bigint-literals", rule, { 15 | valid: ['{"key": "value"}', '"string"', '["element"]'], 16 | invalid: [ 17 | { 18 | code: "42n", 19 | errors: ["BigInt literals are not allowed."], 20 | }, 21 | { 22 | code: "[1n, {'2n': 3n}]", 23 | errors: [ 24 | "BigInt literals are not allowed.", 25 | "BigInt literals are not allowed.", 26 | ], 27 | }, 28 | { 29 | filename: "test.vue", 30 | code: `42n`, 31 | errors: ["BigInt literals are not allowed."], 32 | ...({ 33 | languageOptions: { 34 | parser: vueParser, 35 | }, 36 | } as any), 37 | }, 38 | ], 39 | }); 40 | -------------------------------------------------------------------------------- /tests/lib/configs/flat/base.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import plugin from "../../../../lib/index"; 3 | import { ESLint } from "../../test-lib/eslint-compat"; 4 | 5 | const code = `{ foo: 42 }`; 6 | describe("`flat/base` config", () => { 7 | it("`flat/base` config should work. ", async () => { 8 | const linter = new ESLint({ 9 | overrideConfigFile: true as never, 10 | overrideConfig: plugin.configs["flat/base"] as never, 11 | }); 12 | const result = await linter.lintText(code, { filePath: "test.json" }); 13 | const messages = result[0].messages; 14 | 15 | assert.deepStrictEqual( 16 | messages.map((m) => ({ 17 | ruleId: m.ruleId, 18 | line: m.line, 19 | message: m.message, 20 | })), 21 | [], 22 | ); 23 | 24 | const resultWithJs = await linter.lintText(";", { filePath: "test.js" }); 25 | const messagesWithJs = resultWithJs[0].messages; 26 | 27 | assert.deepStrictEqual( 28 | messagesWithJs.map((m) => ({ 29 | ruleId: m.ruleId, 30 | line: m.line, 31 | message: m.message, 32 | })), 33 | [], 34 | ); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /lib/rules/no-number-props.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | export default createRule("no-number-props", { 4 | meta: { 5 | docs: { 6 | description: "disallow number property keys", 7 | recommended: ["json", "jsonc", "json5"], 8 | extensionRule: false, 9 | layout: false, 10 | }, 11 | fixable: "code", 12 | schema: [], 13 | messages: { 14 | unexpected: "The number property keys are not allowed.", 15 | }, 16 | type: "problem", 17 | }, 18 | create(context) { 19 | if (!context.sourceCode.parserServices.isJSON) { 20 | return {}; 21 | } 22 | return { 23 | JSONProperty(node) { 24 | if (node.key.type !== "JSONLiteral") { 25 | return; 26 | } 27 | if (typeof node.key.value === "number") { 28 | const raw = node.key.raw; 29 | context.report({ 30 | loc: node.key.loc, 31 | messageId: "unexpected", 32 | fix(fixer) { 33 | return fixer.replaceTextRange(node.key.range, `"${raw}"`); 34 | }, 35 | }); 36 | } 37 | }, 38 | }; 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /tests/lib/rules/key-spacing.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/key-spacing"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("key-spacing", rule, { 13 | valid: ['{"key": "value"}'], 14 | invalid: [ 15 | { 16 | code: '{"key" :"value"}', 17 | output: '{"key": "value"}', 18 | errors: [ 19 | "Extra space after key 'key'.", 20 | "Missing space before value for key 'key'.", 21 | ], 22 | }, 23 | { 24 | filename: "test.vue", 25 | code: `{"key" :"value"}`, 26 | output: `{"key": "value"}`, 27 | errors: [ 28 | "Extra space after key 'key'.", 29 | "Missing space before value for key 'key'.", 30 | ], 31 | ...({ 32 | languageOptions: { 33 | parser: vueParser, 34 | }, 35 | } as any), 36 | }, 37 | ], 38 | }); 39 | -------------------------------------------------------------------------------- /tests/lib/as-parser.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import assert from "assert"; 3 | import plugin from "../../lib/index"; 4 | import { getLegacyESLint } from "eslint-compat-utils/eslint"; 5 | const ESLint = getLegacyESLint(); 6 | 7 | // ----------------------------------------------------------------------------- 8 | // Tests 9 | // ----------------------------------------------------------------------------- 10 | 11 | const TEST_CWD = path.join(__dirname, "../fixtures/integrations/eslint-plugin"); 12 | 13 | describe("eslint-plugin-jsonc as parser", () => { 14 | it("should parse '.json6'", async () => { 15 | const engine = new ESLint({ 16 | cwd: TEST_CWD, 17 | extensions: [".js", ".json6"], 18 | plugins: { 19 | "eslint-plugin-jsonc": plugin as never, 20 | }, 21 | }); 22 | const results = await engine.lintFiles(["test-as-parser01/src"]); 23 | assert.strictEqual(results.length, 1); 24 | assert.strictEqual(path.basename(results[0].filePath), "test.json6"); 25 | assert.strictEqual(results[0].messages.length, 1); 26 | assert.strictEqual(results[0].messages[0].ruleId, "jsonc/no-comments"); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /lib/utils/eslint-string-utils.ts: -------------------------------------------------------------------------------- 1 | // Most source code was copied from ESLint v8. 2 | // MIT License. Copyright OpenJS Foundation and other contributors, 3 | /** 4 | * @fileoverview Utilities to operate on strings. 5 | * @author Stephen Wade 6 | */ 7 | 8 | import Graphemer from "graphemer"; 9 | // eslint-disable-next-line no-control-regex -- intentionally including control characters 10 | const ASCII_REGEX = /^[\u0000-\u007f]*$/u; 11 | let segmenter: Intl.Segmenter | undefined; 12 | let splitter: Graphemer | undefined; 13 | 14 | /** 15 | * Counts graphemes in a given string. 16 | * @param value A string to count graphemes. 17 | * @returns The number of graphemes in `value`. 18 | */ 19 | export function getGraphemeCount(value: string): number { 20 | if (ASCII_REGEX.test(value)) return value.length; 21 | 22 | try { 23 | if (!segmenter) segmenter = new Intl.Segmenter(); 24 | 25 | return [...segmenter.segment(value)].length; 26 | } catch { 27 | // ignore 28 | } 29 | if (!splitter) 30 | // @ts-expect-error CJS interop 31 | splitter = new (Graphemer.default || Graphemer)(); 32 | return splitter!.countGraphemes(value); 33 | } 34 | -------------------------------------------------------------------------------- /tools/update-meta.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { ESLint } from "eslint"; 4 | import { name, version } from "../package.json"; 5 | import { getNewVersion } from "./lib/changesets-util"; 6 | 7 | const META_PATH = path.join(__dirname, "../lib/meta.ts"); 8 | 9 | void main(); 10 | 11 | /** main */ 12 | async function main() { 13 | if (!fs.existsSync(META_PATH)) { 14 | fs.writeFileSync(META_PATH, "", "utf8"); 15 | } 16 | const eslint = new ESLint({ fix: true }); 17 | const [result] = await eslint.lintText( 18 | `/* 19 | * IMPORTANT! 20 | * This file has been automatically generated, 21 | * in order to update its content execute "npm run update" 22 | */ 23 | export const name = ${JSON.stringify(name)} as const; 24 | export const version = ${JSON.stringify(await getVersion())} as const; 25 | `, 26 | { filePath: META_PATH }, 27 | ); 28 | fs.writeFileSync(META_PATH, result.output!); 29 | } 30 | 31 | /** Get version */ 32 | function getVersion() { 33 | // eslint-disable-next-line no-process-env -- ignore 34 | if (process.env.IN_VERSION_CI_SCRIPT) { 35 | return getNewVersion(); 36 | } 37 | return version; 38 | } 39 | -------------------------------------------------------------------------------- /tests/lib/rules/no-multi-str.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-multi-str"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("no-multi-str", rule, { 13 | valid: ['{"GOOD": "Line 1 \\nLine 2"}', '"Line 1 \\nLine 2"'], 14 | invalid: [ 15 | { 16 | code: '{"GOOD": "Line 1 \\\nLine 2"}', 17 | errors: 1, // FIXME: drop supports eslint6 ["Multiline support is limited to JSON5 only."], 18 | }, 19 | { 20 | filename: "test.json", 21 | code: '"Line 1 \\\nLine 2"', 22 | errors: 1, // FIXME: drop supports eslint6 ["Multiline support is limited to JSON5 only."], 23 | }, 24 | { 25 | filename: "test.vue", 26 | code: `"Line 1 \\\nLine 2"`, 27 | errors: 1, 28 | languageOptions: { 29 | parser: vueParser, 30 | }, // FIXME: drop supports eslint6 ["Multiline support is limited to JSON5 only."], 31 | }, 32 | ], 33 | }); 34 | -------------------------------------------------------------------------------- /lib/rules/no-octal-numeric-literals.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | const octalNumericLiteralPattern = /^0o/iu; 4 | 5 | export default createRule("no-octal-numeric-literals", { 6 | meta: { 7 | docs: { 8 | description: "disallow octal numeric literals", 9 | recommended: ["json", "jsonc", "json5"], 10 | extensionRule: false, 11 | layout: false, 12 | }, 13 | fixable: "code", 14 | messages: { 15 | disallow: "Octal numeric literals should not be used.", 16 | }, 17 | schema: [], 18 | type: "problem", 19 | }, 20 | create(context) { 21 | if (!context.sourceCode.parserServices.isJSON) { 22 | return {}; 23 | } 24 | return { 25 | JSONLiteral(node) { 26 | if ( 27 | typeof node.value === "number" && 28 | octalNumericLiteralPattern.test(node.raw) 29 | ) { 30 | context.report({ 31 | loc: node.loc, 32 | messageId: "disallow", 33 | fix: (fixer) => { 34 | return fixer.replaceTextRange(node.range, `${node.value}`); 35 | }, 36 | }); 37 | } 38 | }, 39 | }; 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /.github/workflows/GHPages.yml: -------------------------------------------------------------------------------- 1 | name: GHPages 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | workflow_dispatch: null 7 | 8 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | # Allow one concurrent deployment 15 | concurrency: 16 | group: pages 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | deploy: 21 | environment: 22 | name: github-pages 23 | url: ${{ steps.deployment.outputs.page_url }} 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v4 28 | - uses: actions/setup-node@v5 29 | - name: Install Packages 30 | run: npm install -f 31 | - name: Build docs 32 | run: |+ 33 | npm run docs:build 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v5 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v3 38 | with: 39 | path: ./docs/.vitepress/dist/eslint-plugin-jsonc 40 | - name: Deploy to GitHub Pages 41 | id: deployment 42 | uses: actions/deploy-pages@v4 43 | -------------------------------------------------------------------------------- /lib/rules/no-binary-numeric-literals.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | const binaryNumericLiteralPattern = /^0b/iu; 4 | 5 | export default createRule("no-binary-numeric-literals", { 6 | meta: { 7 | docs: { 8 | description: "disallow binary numeric literals", 9 | recommended: ["json", "jsonc", "json5"], 10 | extensionRule: false, 11 | layout: false, 12 | }, 13 | fixable: "code", 14 | messages: { 15 | disallow: "Binary numeric literals should not be used.", 16 | }, 17 | schema: [], 18 | type: "problem", 19 | }, 20 | create(context) { 21 | if (!context.sourceCode.parserServices.isJSON) { 22 | return {}; 23 | } 24 | return { 25 | JSONLiteral(node) { 26 | if ( 27 | typeof node.value === "number" && 28 | binaryNumericLiteralPattern.test(node.raw) 29 | ) { 30 | context.report({ 31 | loc: node.loc, 32 | messageId: "disallow", 33 | fix: (fixer) => { 34 | return fixer.replaceTextRange(node.range, `${node.value}`); 35 | }, 36 | }); 37 | } 38 | }, 39 | }; 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /lib/rules/no-hexadecimal-numeric-literals.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | const hexadecimalNumericLiteralPattern = /^0x/iu; 4 | 5 | export default createRule("no-hexadecimal-numeric-literals", { 6 | meta: { 7 | docs: { 8 | description: "disallow hexadecimal numeric literals", 9 | recommended: ["json", "jsonc"], 10 | extensionRule: false, 11 | layout: false, 12 | }, 13 | fixable: "code", 14 | messages: { 15 | disallow: "Hexadecimal numeric literals should not be used.", 16 | }, 17 | schema: [], 18 | type: "problem", 19 | }, 20 | create(context) { 21 | if (!context.sourceCode.parserServices.isJSON) { 22 | return {}; 23 | } 24 | return { 25 | JSONLiteral(node) { 26 | if ( 27 | typeof node.value === "number" && 28 | hexadecimalNumericLiteralPattern.test(node.raw) 29 | ) { 30 | context.report({ 31 | loc: node.loc, 32 | messageId: "disallow", 33 | fix: (fixer) => { 34 | return fixer.replaceTextRange(node.range, `${node.value}`); 35 | }, 36 | }); 37 | } 38 | }, 39 | }; 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /lib/rules/no-numeric-separators.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | export default createRule("no-numeric-separators", { 4 | meta: { 5 | docs: { 6 | description: "disallow numeric separators", 7 | recommended: ["json", "jsonc", "json5"], 8 | extensionRule: false, 9 | layout: false, 10 | }, 11 | fixable: "code", 12 | schema: [], 13 | messages: { 14 | unexpected: "Numeric separators are not allowed.", 15 | }, 16 | type: "problem", 17 | }, 18 | create(context) { 19 | const sourceCode = context.sourceCode; 20 | if (!sourceCode.parserServices.isJSON) { 21 | return {}; 22 | } 23 | return { 24 | JSONLiteral(node) { 25 | if (typeof node.value !== "number") { 26 | return; 27 | } 28 | const text = sourceCode.text.slice(...node.range); 29 | if (text.includes("_")) { 30 | context.report({ 31 | loc: node.loc, 32 | messageId: "unexpected", 33 | fix(fixer) { 34 | return fixer.replaceTextRange(node.range, text.replace(/_/g, "")); 35 | }, 36 | }); 37 | } 38 | }, 39 | }; 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /.github/workflows/pkg.pr.new-comment.yml: -------------------------------------------------------------------------------- 1 | name: Update pkg.pr.new comment 2 | 3 | on: 4 | workflow_run: 5 | workflows: [Publish to pkg.pr.new] 6 | types: 7 | - completed 8 | 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | 13 | jobs: 14 | build: 15 | if: github.repository == 'ota-meshi/eslint-plugin-jsonc' 16 | name: Update comment 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v5 20 | - name: Download artifact 21 | uses: actions/download-artifact@v5 22 | with: 23 | name: output 24 | github-token: ${{ secrets.GITHUB_TOKEN }} 25 | run-id: ${{ github.event.workflow_run.id }} 26 | - run: ls -R . 27 | - name: Post or update comment 28 | uses: actions/github-script@v8 29 | with: 30 | github-token: ${{ secrets.GITHUB_TOKEN }} 31 | script: | 32 | const fs = require('fs'); 33 | const output = JSON.parse(fs.readFileSync('output.json', 'utf8')); 34 | const { default: process } = await import('${{ github.workspace }}/tools/pkg.pr.new-comment.mjs') 35 | 36 | await process({github, context, core, output}) 37 | -------------------------------------------------------------------------------- /docs/rules/no-undefined-value.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-undefined-value" 5 | description: "disallow `undefined`" 6 | since: "v0.2.0" 7 | --- 8 | 9 | # jsonc/no-undefined-value 10 | 11 | > disallow `undefined` 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule reports the use of `undefined`. 18 | 19 | JSON, JSONC and JSON5 do not allow `undefined`. 20 | 21 | 22 | 23 | 24 | 25 | ```json5 26 | /* eslint jsonc/no-undefined-value: 'error' */ 27 | { 28 | /* ✗ BAD */ 29 | "BAD": undefined 30 | } 31 | ``` 32 | 33 | 34 | 35 | ## :wrench: Options 36 | 37 | Nothing. 38 | 39 | ## :rocket: Version 40 | 41 | This rule was introduced in eslint-plugin-jsonc v0.2.0 42 | 43 | ## :mag: Implementation 44 | 45 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-undefined-value.ts) 46 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-undefined-value.ts) 47 | -------------------------------------------------------------------------------- /docs/rules/no-regexp-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-regexp-literals" 5 | description: "disallow RegExp literals" 6 | since: "v0.2.0" 7 | --- 8 | 9 | # jsonc/no-regexp-literals 10 | 11 | > disallow RegExp literals 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule reports the use of RegExp literals. 18 | 19 | JSON, JSONC and JSON5 do not allow RegExp literals. 20 | 21 | 22 | 23 | 24 | 25 | ```json5 26 | /* eslint jsonc/no-regexp-literals: 'error' */ 27 | { 28 | /* ✗ BAD */ 29 | "BAD": /foo/ 30 | } 31 | ``` 32 | 33 | 34 | 35 | ## :wrench: Options 36 | 37 | Nothing. 38 | 39 | ## :rocket: Version 40 | 41 | This rule was introduced in eslint-plugin-jsonc v0.2.0 42 | 43 | ## :mag: Implementation 44 | 45 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-regexp-literals.ts) 46 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-regexp-literals.ts) 47 | -------------------------------------------------------------------------------- /docs/rules/no-nan.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-nan" 5 | description: "disallow NaN" 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-nan 10 | 11 | > disallow NaN 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule reports the use of NaN. 18 | 19 | Cannot use NaN when in JSON and JSONC. 20 | 21 | 22 | 23 | 24 | 25 | ```json5 26 | /* eslint jsonc/no-nan: 'error' */ 27 | { 28 | /* ✓ GOOD */ 29 | "GOOD": 42, 30 | 31 | /* ✗ BAD */ 32 | "BAD": NaN 33 | } 34 | ``` 35 | 36 | 37 | 38 | ## :wrench: Options 39 | 40 | Nothing. 41 | 42 | ## :couple: Related rules 43 | 44 | - [jsonc/valid-json-number] 45 | 46 | [jsonc/valid-json-number]: ./valid-json-number.md 47 | 48 | ## :rocket: Version 49 | 50 | This rule was introduced in eslint-plugin-jsonc v1.1.0 51 | 52 | ## :mag: Implementation 53 | 54 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-nan.ts) 55 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-nan.ts) 56 | -------------------------------------------------------------------------------- /lib/rules/no-plus-sign.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils"; 2 | 3 | export default createRule("no-plus-sign", { 4 | meta: { 5 | docs: { 6 | description: "disallow plus sign", 7 | recommended: ["json", "jsonc"], 8 | extensionRule: false, 9 | layout: false, 10 | }, 11 | fixable: "code", 12 | messages: { 13 | disallow: "Plus sign should not be used.", 14 | }, 15 | schema: [], 16 | type: "problem", 17 | }, 18 | create(context) { 19 | const sourceCode = context.sourceCode; 20 | if (!sourceCode.parserServices.isJSON) { 21 | return {}; 22 | } 23 | return { 24 | JSONUnaryExpression(node) { 25 | if (node.operator === "+") { 26 | const operator = sourceCode.getFirstToken( 27 | node as any, 28 | (token) => 29 | token.type === "Punctuator" && token.value === node.operator, 30 | ); 31 | context.report({ 32 | loc: operator?.loc || node.loc, 33 | messageId: "disallow", 34 | fix(fixer) { 35 | return operator ? fixer.removeRange(operator.range) : null; 36 | }, 37 | }); 38 | } 39 | }, 40 | }; 41 | }, 42 | }); 43 | -------------------------------------------------------------------------------- /lib/utils/eslint-keywords.ts: -------------------------------------------------------------------------------- 1 | // Most source code was copied from ESLint v8. 2 | // MIT License. Copyright OpenJS Foundation and other contributors, 3 | /** 4 | * @fileoverview A shared list of ES3 keywords. 5 | * @author Josh Perez 6 | */ 7 | 8 | export const keywords = [ 9 | "abstract", 10 | "boolean", 11 | "break", 12 | "byte", 13 | "case", 14 | "catch", 15 | "char", 16 | "class", 17 | "const", 18 | "continue", 19 | "debugger", 20 | "default", 21 | "delete", 22 | "do", 23 | "double", 24 | "else", 25 | "enum", 26 | "export", 27 | "extends", 28 | "false", 29 | "final", 30 | "finally", 31 | "float", 32 | "for", 33 | "function", 34 | "goto", 35 | "if", 36 | "implements", 37 | "import", 38 | "in", 39 | "instanceof", 40 | "int", 41 | "interface", 42 | "long", 43 | "native", 44 | "new", 45 | "null", 46 | "package", 47 | "private", 48 | "protected", 49 | "public", 50 | "return", 51 | "short", 52 | "static", 53 | "super", 54 | "switch", 55 | "synchronized", 56 | "this", 57 | "throw", 58 | "throws", 59 | "transient", 60 | "true", 61 | "try", 62 | "typeof", 63 | "var", 64 | "void", 65 | "volatile", 66 | "while", 67 | "with", 68 | ]; 69 | -------------------------------------------------------------------------------- /tools/update-rules.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | import os from "os"; 4 | // import eslint from "eslint" 5 | import { rules } from "./lib/load-rules"; 6 | const isWin = os.platform().startsWith("win"); 7 | 8 | /** 9 | * Convert text to camelCase 10 | */ 11 | function camelCase(str: string) { 12 | return str.replace(/[-/_](\w)/gu, (_, c) => (c ? c.toUpperCase() : "")); 13 | } 14 | 15 | let content = `/* 16 | * IMPORTANT! 17 | * This file has been automatically generated, 18 | * in order to update its content execute "npm run update" 19 | */ 20 | import type { RuleModule } from "../types" 21 | ${rules 22 | .map( 23 | (rule) => 24 | `import ${camelCase(rule.meta.docs.ruleName)} from "../rules/${ 25 | rule.meta.docs.ruleName 26 | }"`, 27 | ) 28 | .join("\n")} 29 | 30 | export const rules = [ 31 | ${rules.map((rule) => camelCase(rule.meta.docs.ruleName)).join(",")} 32 | ] as RuleModule[] 33 | `; 34 | 35 | const filePath = path.resolve(__dirname, "../lib/utils/rules.ts"); 36 | 37 | if (isWin) { 38 | content = content 39 | .replace(/\r?\n/gu, "\n") 40 | .replace(/\r/gu, "\n") 41 | .replace(/\n/gu, "\r\n"); 42 | } 43 | 44 | // Update file. 45 | fs.writeFileSync(filePath, content); 46 | -------------------------------------------------------------------------------- /tests/lib/rules/comma-dangle.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/comma-dangle"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("comma-dangle", rule, { 13 | valid: ['{"key": "value"}'], 14 | invalid: [ 15 | { 16 | code: '{"key": "value",}', 17 | output: '{"key": "value"}', 18 | errors: ["Unexpected trailing comma."], 19 | }, 20 | { 21 | code: '{"key": [1,2],}', 22 | output: '{"key": [1,2,],}', 23 | options: [{ arrays: "always", objects: "never" }], 24 | errors: ["Missing trailing comma.", "Unexpected trailing comma."], 25 | }, 26 | { 27 | filename: "test.vue", 28 | code: `{"key": "value",}{"key": "value",}`, 29 | output: `{"key": "value"}{"key": "value",}`, 30 | errors: ["Unexpected trailing comma."], 31 | ...({ 32 | languageOptions: { 33 | parser: vueParser, 34 | }, 35 | } as any), 36 | }, 37 | ], 38 | }); 39 | -------------------------------------------------------------------------------- /lib/configs/flat/recommended-with-json5.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import type { Linter } from "eslint"; 5 | import base from "./base"; 6 | export default [ 7 | ...base, 8 | { 9 | rules: { 10 | // eslint-plugin-jsonc rules 11 | "jsonc/no-bigint-literals": "error", 12 | "jsonc/no-binary-expression": "error", 13 | "jsonc/no-binary-numeric-literals": "error", 14 | "jsonc/no-dupe-keys": "error", 15 | "jsonc/no-escape-sequence-in-identifier": "error", 16 | "jsonc/no-number-props": "error", 17 | "jsonc/no-numeric-separators": "error", 18 | "jsonc/no-octal-numeric-literals": "error", 19 | "jsonc/no-octal": "error", 20 | "jsonc/no-parenthesized": "error", 21 | "jsonc/no-regexp-literals": "error", 22 | "jsonc/no-sparse-arrays": "error", 23 | "jsonc/no-template-literals": "error", 24 | "jsonc/no-undefined-value": "error", 25 | "jsonc/no-unicode-codepoint-escapes": "error", 26 | "jsonc/no-useless-escape": "error", 27 | "jsonc/space-unary-ops": "error", 28 | "jsonc/vue-custom-block/no-parsing-error": "error", 29 | }, 30 | }, 31 | ] satisfies Linter.FlatConfig[]; 32 | -------------------------------------------------------------------------------- /docs/rules/no-bigint-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-bigint-literals" 5 | description: "disallow BigInt literals" 6 | since: "v0.2.0" 7 | --- 8 | 9 | # jsonc/no-bigint-literals 10 | 11 | > disallow BigInt literals 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule reports the use of BigInt literals. 18 | 19 | JSON, JSONC and JSON5 do not allow BigInt literals. 20 | 21 | 22 | 23 | 24 | 25 | ```json5 26 | /* eslint jsonc/no-bigint-literals: 'error' */ 27 | { 28 | /* ✓ GOOD */ 29 | "GOOD": 42, 30 | 31 | /* ✗ BAD */ 32 | "BAD": 42n 33 | } 34 | ``` 35 | 36 | 37 | 38 | ## :wrench: Options 39 | 40 | Nothing. 41 | 42 | ## :rocket: Version 43 | 44 | This rule was introduced in eslint-plugin-jsonc v0.2.0 45 | 46 | ## :mag: Implementation 47 | 48 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-bigint-literals.ts) 49 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-bigint-literals.ts) 50 | -------------------------------------------------------------------------------- /lib/configs/recommended-with-json5.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import path from "path"; 5 | const base = require.resolve("./base"); 6 | const baseExtend = 7 | path.extname(`${base}`) === ".ts" ? "plugin:jsonc/base" : base; 8 | export = { 9 | extends: [baseExtend], 10 | rules: { 11 | // eslint-plugin-jsonc rules 12 | "jsonc/no-bigint-literals": "error", 13 | "jsonc/no-binary-expression": "error", 14 | "jsonc/no-binary-numeric-literals": "error", 15 | "jsonc/no-dupe-keys": "error", 16 | "jsonc/no-escape-sequence-in-identifier": "error", 17 | "jsonc/no-number-props": "error", 18 | "jsonc/no-numeric-separators": "error", 19 | "jsonc/no-octal-numeric-literals": "error", 20 | "jsonc/no-octal": "error", 21 | "jsonc/no-parenthesized": "error", 22 | "jsonc/no-regexp-literals": "error", 23 | "jsonc/no-sparse-arrays": "error", 24 | "jsonc/no-template-literals": "error", 25 | "jsonc/no-undefined-value": "error", 26 | "jsonc/no-unicode-codepoint-escapes": "error", 27 | "jsonc/no-useless-escape": "error", 28 | "jsonc/space-unary-ops": "error", 29 | "jsonc/vue-custom-block/no-parsing-error": "error", 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /tests/lib/rules/no-binary-expression.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-binary-expression"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-binary-expression", rule, { 14 | valid: ['{"42": 42}', "42", "[42]"], 15 | invalid: [ 16 | { 17 | code: `[42-1, {"key": 42-1}]`, 18 | output: `[41, {"key": 41}]`, 19 | errors: [ 20 | { 21 | message: "The binary expressions are not allowed.", 22 | line: 1, 23 | column: 2, 24 | }, 25 | { 26 | message: "The binary expressions are not allowed.", 27 | line: 1, 28 | column: 16, 29 | }, 30 | ], 31 | }, 32 | { 33 | code: `42-1`, 34 | output: `41`, 35 | errors: ["The binary expressions are not allowed."], 36 | }, 37 | { 38 | code: `[42 * (42 - 3)]`, 39 | output: `[1638]`, 40 | errors: [ 41 | "The binary expressions are not allowed.", 42 | "The binary expressions are not allowed.", 43 | ], 44 | }, 45 | ], 46 | }); 47 | -------------------------------------------------------------------------------- /docs/rules/no-infinity.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-infinity" 5 | description: "disallow Infinity" 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-infinity 10 | 11 | > disallow Infinity 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule reports the use of Infinity. 18 | 19 | Cannot use Infinity when in JSON and JSONC. 20 | 21 | 22 | 23 | 24 | 25 | ```json5 26 | /* eslint jsonc/no-infinity: 'error' */ 27 | { 28 | /* ✓ GOOD */ 29 | "GOOD": 42, 30 | 31 | /* ✗ BAD */ 32 | "BAD": Infinity 33 | } 34 | ``` 35 | 36 | 37 | 38 | ## :wrench: Options 39 | 40 | Nothing. 41 | 42 | ## :couple: Related rules 43 | 44 | - [jsonc/valid-json-number] 45 | 46 | [jsonc/valid-json-number]: ./valid-json-number.md 47 | 48 | ## :rocket: Version 49 | 50 | This rule was introduced in eslint-plugin-jsonc v1.1.0 51 | 52 | ## :mag: Implementation 53 | 54 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-infinity.ts) 55 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-infinity.ts) 56 | -------------------------------------------------------------------------------- /tests/lib/rules/no-comments.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-comments"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("no-comments", rule, { 13 | valid: ['{"key": "value"}', '"string"', '["element"]'], 14 | invalid: [ 15 | { 16 | code: "{/* comment */}", 17 | errors: [ 18 | { 19 | message: "Unexpected comment.", 20 | line: 1, 21 | column: 2, 22 | endLine: 1, 23 | endColumn: 15, 24 | }, 25 | ], 26 | }, 27 | { 28 | code: "{// comment\n}", 29 | errors: [ 30 | { 31 | message: "Unexpected comment.", 32 | line: 1, 33 | column: 2, 34 | endLine: 1, 35 | endColumn: 12, 36 | }, 37 | ], 38 | }, 39 | { 40 | filename: "test.vue", 41 | code: ` 42 | // comment 43 | "a"`, 44 | errors: ["Unexpected comment."], 45 | ...({ 46 | languageOptions: { 47 | parser: vueParser, 48 | }, 49 | } as any), 50 | }, 51 | ], 52 | }); 53 | -------------------------------------------------------------------------------- /docs/rules/no-octal-escape.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-octal-escape" 5 | description: "disallow octal escape sequences in string literals" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/no-octal-escape 10 | 11 | > disallow octal escape sequences in string literals 12 | 13 | ## :book: Rule Details 14 | 15 | This rule disallows octal escape sequences in string literals. 16 | 17 | 18 | 19 | 20 | 21 | ```json5 22 | /* eslint jsonc/no-octal-escape: 'error' */ 23 | { 24 | /* ✓ GOOD */ 25 | "GOOD": "Copyright \u00A9", 26 | 27 | /* ✗ BAD */ 28 | "BAD": "Copyright \251" 29 | } 30 | ``` 31 | 32 | 33 | 34 | ## :wrench: Options 35 | 36 | Nothing. 37 | 38 | ## :couple: Related rules 39 | 40 | - [no-octal-escape] 41 | 42 | [no-octal-escape]: https://eslint.org/docs/rules/no-octal-escape 43 | 44 | ## :rocket: Version 45 | 46 | This rule was introduced in eslint-plugin-jsonc v0.1.0 47 | 48 | ## :mag: Implementation 49 | 50 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-octal-escape.ts) 51 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-octal-escape.ts) 52 | 53 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-octal-escape) 54 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/state/deserialize.js: -------------------------------------------------------------------------------- 1 | import pako from "pako"; 2 | 3 | /** 4 | * Deserialize a given serialized string then update this object. 5 | * @param {string} serializedString A serialized string. 6 | * @returns {object} The deserialized state. 7 | */ 8 | export function deserializeState(serializedString) { 9 | const state = { 10 | code: undefined, 11 | rules: undefined, 12 | }; 13 | 14 | if (serializedString === "") { 15 | return state; 16 | } 17 | 18 | try { 19 | const compressedString = window.atob(serializedString); 20 | const uint8Arr = pako.inflate( 21 | Uint8Array.from(compressedString, (c) => c.charCodeAt(0)), 22 | ); 23 | 24 | const jsonText = new TextDecoder().decode(uint8Arr); 25 | const json = JSON.parse(jsonText); 26 | 27 | if (typeof json === "object" && json != null) { 28 | if (typeof json.code === "string") { 29 | state.code = json.code; 30 | } 31 | if (typeof json.rules === "object" && json.rules != null) { 32 | state.rules = {}; 33 | for (const id of Object.keys(json.rules)) { 34 | state.rules[id] = json.rules[id] === 2 ? "error" : "off"; 35 | } 36 | } 37 | } 38 | } catch (error) { 39 | //eslint-disable-next-line no-console -- demo 40 | console.error(error); 41 | } 42 | 43 | return state; 44 | } 45 | -------------------------------------------------------------------------------- /tests/lib/rules/quotes.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/quotes"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("quotes", rule, { 13 | valid: ['{"key": "value"}', '"string"', '["element"]'], 14 | invalid: [ 15 | { 16 | code: "{'key': 'value'}", 17 | output: '{"key": "value"}', 18 | errors: [ 19 | "Strings must use doublequote.", 20 | "Strings must use doublequote.", 21 | ], 22 | }, 23 | { 24 | filename: "test.json", 25 | code: "'string'", 26 | output: '"string"', 27 | errors: ["Strings must use doublequote."], 28 | }, 29 | { 30 | code: "['element']", 31 | output: '["element"]', 32 | errors: ["Strings must use doublequote."], 33 | }, 34 | { 35 | filename: "test.vue", 36 | code: `['element']`, 37 | output: `["element"]`, 38 | errors: ["Strings must use doublequote."], 39 | ...({ 40 | languageOptions: { 41 | parser: vueParser, 42 | }, 43 | } as any), 44 | }, 45 | ], 46 | }); 47 | -------------------------------------------------------------------------------- /tests/lib/rules/no-unicode-codepoint-escapes.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-unicode-codepoint-escapes"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-unicode-codepoint-escapes", rule, { 14 | valid: ['"\\u0041"', '{"\\u0041": "string"}', "`\\u0042`"], 15 | invalid: [ 16 | { 17 | code: `"\\u{41}"`, 18 | output: `"\\u0041"`, 19 | errors: ["Unicode code point escape sequence should not be used."], 20 | }, 21 | { 22 | code: `{"\\u{41}": "string"}`, 23 | output: `{"\\u0041": "string"}`, 24 | errors: ["Unicode code point escape sequence should not be used."], 25 | }, 26 | { 27 | code: `{a\\u{41}: "string"}`, 28 | output: `{a\\u0041: "string"}`, 29 | errors: ["Unicode code point escape sequence should not be used."], 30 | }, 31 | { 32 | code: "`\\u{42}`", 33 | output: "`\\u0042`", 34 | errors: ["Unicode code point escape sequence should not be used."], 35 | }, 36 | { 37 | code: '"\\u{20BB7}"', 38 | output: '"\\uD842\\uDFB7"', 39 | errors: ["Unicode code point escape sequence should not be used."], 40 | }, 41 | ], 42 | }); 43 | -------------------------------------------------------------------------------- /docs/rules/no-multi-str.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-multi-str" 5 | description: "disallow multiline strings" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/no-multi-str 10 | 11 | > disallow multiline strings 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule is aimed at preventing the use of multiline strings. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/no-multi-str: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": "Line 1 \nLine 2", 28 | 29 | /* ✗ BAD */ 30 | "BAD": "Line 1 \ 31 | Line 2", 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :couple: Related rules 42 | 43 | - [no-multi-str] 44 | 45 | [no-multi-str]: https://eslint.org/docs/rules/no-multi-str 46 | 47 | ## :rocket: Version 48 | 49 | This rule was introduced in eslint-plugin-jsonc v0.1.0 50 | 51 | ## :mag: Implementation 52 | 53 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-multi-str.ts) 54 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-multi-str.ts) 55 | 56 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-multi-str) 57 | -------------------------------------------------------------------------------- /docs/rules/no-binary-expression.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-binary-expression" 5 | description: "disallow binary expression" 6 | since: "v2.0.0" 7 | --- 8 | 9 | # jsonc/no-binary-expression 10 | 11 | > disallow binary expression 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule disallow binary expressions. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-binary-expression: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": 86400, 29 | 30 | /* ✗ BAD */ 31 | "BAD": 60 * 60 * 24 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :rocket: Version 42 | 43 | This rule was introduced in eslint-plugin-jsonc v2.0.0 44 | 45 | ## :mag: Implementation 46 | 47 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-binary-expression.ts) 48 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-binary-expression.ts) 49 | -------------------------------------------------------------------------------- /tests/lib/rules/array-element-newline.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/array-element-newline"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("array-element-newline", rule, { 13 | valid: [ 14 | `[1, 15 | 2, 16 | 3]`, 17 | ], 18 | invalid: [ 19 | { 20 | code: "[1, 2, 3]", 21 | output: `[1, 22 | 2, 23 | 3]`, 24 | errors: [ 25 | "There should be a linebreak after this element.", 26 | "There should be a linebreak after this element.", 27 | ], 28 | }, 29 | { 30 | filename: "test.vue", 31 | code: `[1, 2, 3][1, 2, 3]`, 32 | output: `[1, 33 | 2, 34 | 3][1, 35 | 2, 36 | 3]`, 37 | errors: [ 38 | "There should be a linebreak after this element.", 39 | "There should be a linebreak after this element.", 40 | "There should be a linebreak after this element.", 41 | "There should be a linebreak after this element.", 42 | ], 43 | ...({ 44 | languageOptions: { 45 | parser: vueParser, 46 | }, 47 | } as any), 48 | }, 49 | ], 50 | }); 51 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/state/serialize.js: -------------------------------------------------------------------------------- 1 | import pako from "pako"; 2 | 3 | /** 4 | * Get only enabled rules to make the serialized data smaller. 5 | * @param {object} allRules The rule settings. 6 | * @returns {object} The rule settings for the enabled rules. 7 | */ 8 | function getEnabledRules(allRules) { 9 | return Object.keys(allRules).reduce((map, id) => { 10 | if (allRules[id] === "error") { 11 | map[id] = 2; 12 | } 13 | return map; 14 | }, {}); 15 | } 16 | 17 | /** 18 | * Serialize a given state as a base64 string. 19 | * @param {State} state The state to serialize. 20 | * @returns {string} The serialized string. 21 | */ 22 | export function serializeState(state) { 23 | const saveData = { 24 | code: state.code, 25 | rules: state.rules ? getEnabledRules(state.rules) : undefined, 26 | }; 27 | const jsonString = JSON.stringify(saveData); 28 | 29 | const uint8Arr = new TextEncoder().encode(jsonString); 30 | const compressedString = String.fromCharCode(...pako.deflate(uint8Arr)); 31 | const base64 = 32 | (typeof window !== "undefined" && window.btoa(compressedString)) || 33 | compressedString; 34 | 35 | //eslint-disable-next-line no-console -- demo 36 | console.log( 37 | `The compress rate of serialized string: ${( 38 | (100 * base64.length) / 39 | jsonString.length 40 | ).toFixed(1)}% (${jsonString.length}B → ${base64.length}B)`, 41 | ); 42 | 43 | return base64; 44 | } 45 | -------------------------------------------------------------------------------- /docs/rules/no-parenthesized.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-parenthesized" 5 | description: "disallow parentheses around the expression" 6 | since: "v2.0.0" 7 | --- 8 | 9 | # jsonc/no-parenthesized 10 | 11 | > disallow parentheses around the expression 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule always disallow parentheses around the expression. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-parenthesized: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": "foo", 29 | 30 | /* ✗ BAD */ 31 | "BAD": ("bar") 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :rocket: Version 42 | 43 | This rule was introduced in eslint-plugin-jsonc v2.0.0 44 | 45 | ## :mag: Implementation 46 | 47 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-parenthesized.ts) 48 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-parenthesized.ts) 49 | -------------------------------------------------------------------------------- /docs/rules/vue-custom-block/no-parsing-error.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/vue-custom-block/no-parsing-error" 5 | description: "disallow parsing errors in Vue custom blocks" 6 | since: "v0.8.0" 7 | --- 8 | 9 | # jsonc/vue-custom-block/no-parsing-error 10 | 11 | > disallow parsing errors in Vue custom blocks 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule reports JSON parsing errors in Vue custom blocks. 18 | 19 | 20 | 21 | 22 | 23 | ```vue 24 | 25 | { "foo": } 26 | 27 | 28 | 29 | { "foo": } 30 | 31 | 32 | 35 | ``` 36 | 37 | 38 | 39 | ## :wrench: Options 40 | 41 | Nothing. 42 | 43 | ## :rocket: Version 44 | 45 | This rule was introduced in eslint-plugin-jsonc v0.8.0 46 | 47 | ## :mag: Implementation 48 | 49 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/vue-custom-block/no-parsing-error.ts) 50 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/vue-custom-block/no-parsing-error.ts) 51 | -------------------------------------------------------------------------------- /docs/rules/no-octal.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-octal" 5 | description: "disallow legacy octal literals" 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-octal 10 | 11 | > disallow legacy octal literals 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | The rule disallows legacy octal literals. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/no-octal: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": 777, 28 | 29 | /* ✗ BAD */ 30 | "BAD": 0777 31 | } 32 | ``` 33 | 34 | 35 | 36 | ## :wrench: Options 37 | 38 | Nothing. 39 | 40 | ## :couple: Related rules 41 | 42 | - [no-octal] 43 | - [jsonc/valid-json-number] 44 | 45 | [no-octal]: https://eslint.org/docs/rules/no-octal 46 | [jsonc/valid-json-number]: ./valid-json-number.md 47 | 48 | ## :rocket: Version 49 | 50 | This rule was introduced in eslint-plugin-jsonc v1.1.0 51 | 52 | ## :mag: Implementation 53 | 54 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-octal.ts) 55 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-octal.ts) 56 | 57 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-octal) 58 | -------------------------------------------------------------------------------- /tests/lib/rules/no-undefined-value.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-undefined-value"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-undefined-value", rule, { 14 | valid: ["null", "[1,,2]", "{undefined:1}"], 15 | invalid: [ 16 | { 17 | code: "undefined", 18 | errors: ["`undefined` is not allowed."], 19 | }, 20 | { 21 | code: `[ 22 | undefined, 23 | { 24 | undefined: undefined 25 | } 26 | ]`, 27 | errors: [ 28 | { 29 | message: "`undefined` is not allowed.", 30 | line: 2, 31 | column: 17, 32 | endColumn: 26, 33 | }, 34 | { 35 | message: "`undefined` is not allowed.", 36 | line: 4, 37 | column: 32, 38 | endColumn: 41, 39 | }, 40 | ], 41 | }, 42 | { 43 | filename: "test.vue", 44 | code: `undefined`, 45 | errors: ["`undefined` is not allowed."], 46 | ...({ 47 | languageOptions: { 48 | parser: vueParser, 49 | }, 50 | } as any), 51 | }, 52 | ], 53 | }); 54 | -------------------------------------------------------------------------------- /tests/lib/rules/object-property-newline.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/object-property-newline"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("object-property-newline", rule, { 13 | valid: [ 14 | ` 15 | { 16 | "foo": "foo", 17 | "bar": "bar", 18 | "baz": "baz" 19 | } 20 | `, 21 | ], 22 | invalid: [ 23 | { 24 | code: ` 25 | { 26 | "foo": "foo", "bar": "bar", "baz": "baz" 27 | }`, 28 | output: ` 29 | { 30 | "foo": "foo", 31 | "bar": "bar", 32 | "baz": "baz" 33 | }`, 34 | errors: [ 35 | "Object properties must go on a new line.", 36 | "Object properties must go on a new line.", 37 | ], 38 | }, 39 | { 40 | filename: "test.vue", 41 | code: `{ "foo": "foo", "bar": "bar" }`, 42 | output: `{ "foo": "foo",\n"bar": "bar" }`, 43 | errors: ["Object properties must go on a new line."], 44 | ...({ 45 | languageOptions: { 46 | parser: vueParser, 47 | }, 48 | } as any), 49 | }, 50 | ], 51 | }); 52 | -------------------------------------------------------------------------------- /docs/rules/no-plus-sign.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-plus-sign" 5 | description: "disallow plus sign" 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-plus-sign 10 | 11 | > disallow plus sign 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule disallow plus sign. 19 | 20 | Cannot use plus sign when in JSON and JSONC. 21 | 22 | 23 | 24 | 25 | 26 | ```json5 27 | /* eslint jsonc/no-plus-sign: 'error' */ 28 | { 29 | /* ✓ GOOD */ 30 | "GOOD": 42, 31 | 32 | /* ✗ BAD */ 33 | "BAD": +42 34 | } 35 | ``` 36 | 37 | 38 | 39 | ## :wrench: Options 40 | 41 | Nothing. 42 | 43 | ## :couple: Related rules 44 | 45 | - [jsonc/valid-json-number] 46 | 47 | [jsonc/valid-json-number]: ./valid-json-number.md 48 | 49 | ## :rocket: Version 50 | 51 | This rule was introduced in eslint-plugin-jsonc v1.1.0 52 | 53 | ## :mag: Implementation 54 | 55 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-plus-sign.ts) 56 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-plus-sign.ts) 57 | -------------------------------------------------------------------------------- /docs/rules/no-template-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-template-literals" 5 | description: "disallow template literals" 6 | since: "v0.2.0" 7 | --- 8 | 9 | # jsonc/no-template-literals 10 | 11 | > disallow template literals 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule reports the use of template literals. 19 | 20 | JSON, JSONC and JSON5 do not allow template literal. 21 | 22 | 23 | 24 | 25 | 26 | ```json5 27 | /* eslint jsonc/no-template-literals: 'error' */ 28 | { 29 | /* ✓ GOOD */ 30 | "GOOD": "foo", 31 | 32 | /* ✗ BAD */ 33 | "BAD": `bar` 34 | } 35 | ``` 36 | 37 | 38 | 39 | ## :wrench: Options 40 | 41 | Nothing. 42 | 43 | ## :rocket: Version 44 | 45 | This rule was introduced in eslint-plugin-jsonc v0.2.0 46 | 47 | ## :mag: Implementation 48 | 49 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-template-literals.ts) 50 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-template-literals.ts) 51 | -------------------------------------------------------------------------------- /tests/lib/rules/no-numeric-separators.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-numeric-separators"; 3 | import { Linter } from "eslint"; 4 | import semver from "semver"; 5 | import * as jsonParser from "jsonc-eslint-parser"; 6 | import * as vueParser from "vue-eslint-parser"; 7 | 8 | if (semver.gte(Linter.version, "7.3.0")) { 9 | const tester = new RuleTester({ 10 | languageOptions: { 11 | ecmaVersion: 2021, 12 | parser: jsonParser, 13 | }, 14 | ignoreMomoa: true, 15 | }); 16 | 17 | tester.run("no-numeric-separators", rule, { 18 | valid: ['{"key": 1234}', "1234", "[1234]"], 19 | invalid: [ 20 | { 21 | code: `{"key": 1_234}`, 22 | output: `{"key": 1234}`, 23 | errors: ["Numeric separators are not allowed."], 24 | }, 25 | { 26 | code: `1_234`, 27 | output: `1234`, 28 | errors: ["Numeric separators are not allowed."], 29 | }, 30 | { 31 | code: `[1_234]`, 32 | output: `[1234]`, 33 | errors: ["Numeric separators are not allowed."], 34 | }, 35 | { 36 | filename: "test.vue", 37 | code: `{"a": 1_23}`, 38 | output: `{"a": 123}`, 39 | errors: ["Numeric separators are not allowed."], 40 | languageOptions: { 41 | parser: vueParser, 42 | }, 43 | }, 44 | ], 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /tests/lib/rules/no-sparse-arrays.ts: -------------------------------------------------------------------------------- 1 | import { ESLint } from "../test-lib/eslint-compat"; 2 | import { RuleTester } from "../test-lib/tester"; 3 | import rule from "../../../lib/rules/no-sparse-arrays"; 4 | import * as jsonParser from "jsonc-eslint-parser"; 5 | import * as vueParser from "vue-eslint-parser"; 6 | import semver from "semver"; 7 | 8 | const tester = new RuleTester({ 9 | languageOptions: { 10 | parser: jsonParser, 11 | }, 12 | ignoreMomoa: true, 13 | }); 14 | 15 | tester.run("no-sparse-arrays", rule, { 16 | valid: ["[1,2,3,4]", "[1,2,3,4,]"], 17 | invalid: [ 18 | { 19 | code: "[1,,,4]", 20 | errors: semver.gte(ESLint.version, "9.5.0") 21 | ? [ 22 | "Unexpected comma in middle of array.", 23 | "Unexpected comma in middle of array.", 24 | ] 25 | : ["Unexpected comma in middle of array."], 26 | }, 27 | { 28 | code: "[,2,3,4]", 29 | errors: ["Unexpected comma in middle of array."], 30 | }, 31 | { 32 | filename: "test.vue", 33 | code: `[,,]`, 34 | errors: semver.gte(ESLint.version, "9.5.0") 35 | ? [ 36 | "Unexpected comma in middle of array.", 37 | "Unexpected comma in middle of array.", 38 | ] 39 | : ["Unexpected comma in middle of array."], 40 | ...({ 41 | languageOptions: { 42 | parser: vueParser, 43 | }, 44 | } as any), 45 | }, 46 | ], 47 | }); 48 | -------------------------------------------------------------------------------- /tools/lib/load-rules.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | 4 | /** 5 | * Get the all rules 6 | * @returns {Array} The all rules 7 | */ 8 | function readRules() { 9 | const rules = []; 10 | const rulesLibRoot = path.resolve(__dirname, "../../lib/rules"); 11 | for (const name of fs 12 | .readdirSync(rulesLibRoot) 13 | .filter((n) => n.endsWith(".ts"))) { 14 | const ruleName = name.replace(/\.ts$/u, ""); 15 | const ruleId = `jsonc/${ruleName}`; 16 | // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires -- tool 17 | const rule = require(path.join(rulesLibRoot, name)).default; 18 | 19 | rule.meta.docs.ruleName = ruleName; 20 | rule.meta.docs.ruleId = ruleId; 21 | 22 | rules.push(rule); 23 | } 24 | const vueCustomBlockRulesLibRoot = path.resolve( 25 | __dirname, 26 | "../../lib/rules/vue-custom-block", 27 | ); 28 | for (const name of fs.readdirSync(vueCustomBlockRulesLibRoot)) { 29 | const ruleName = `vue-custom-block/${name.replace(/\.ts$/u, "")}`; 30 | const ruleId = `jsonc/${ruleName}`; 31 | // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires -- tool 32 | const rule = require(path.join(vueCustomBlockRulesLibRoot, name)).default; 33 | 34 | rule.meta.docs.ruleName = ruleName; 35 | rule.meta.docs.ruleId = ruleId; 36 | 37 | rules.push(rule); 38 | } 39 | return rules; 40 | } 41 | 42 | export const rules = readRules(); 43 | -------------------------------------------------------------------------------- /tests/lib/rules/array-bracket-newline.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/array-bracket-newline"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("array-bracket-newline", rule, { 13 | valid: ["[]", "[\n1,\n2\n]"], 14 | invalid: [ 15 | { 16 | code: "[\n1\n]", 17 | output: "[1]", 18 | errors: [ 19 | "There should be no linebreak after '['.", 20 | "There should be no linebreak before ']'.", 21 | ], 22 | }, 23 | { 24 | code: "[1,\n2]", 25 | output: "[\n1,\n2\n]", 26 | errors: [ 27 | "A linebreak is required after '['.", 28 | "A linebreak is required before ']'.", 29 | ], 30 | }, 31 | { 32 | filename: "test.vue", 33 | code: `[1,\n2][\n1\n]`, 34 | output: `[\n1,\n2\n][1]`, 35 | errors: [ 36 | "A linebreak is required after '['.", 37 | "A linebreak is required before ']'.", 38 | "There should be no linebreak after '['.", 39 | "There should be no linebreak before ']'.", 40 | ], 41 | ...({ 42 | languageOptions: { 43 | parser: vueParser, 44 | }, 45 | } as any), 46 | }, 47 | ], 48 | }); 49 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close stale issues and PRs 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | 6 | permissions: 7 | issues: write 8 | pull-requests: write 9 | 10 | jobs: 11 | stale: 12 | if: github.repository == 'ota-meshi/eslint-plugin-jsonc' 13 | name: Close stale issues with missing information 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/stale@v9 17 | with: 18 | any-of-labels: "needs repro,needs info,needs more info" 19 | days-before-stale: 60 20 | days-before-close: 14 21 | stale-issue-message: This issue is is stale because it missing information and has been open for 60 days with no activity. 22 | stale-pr-message: This PR is is stale because it missing information and has been open for 60 days with no activity. 23 | close-issue-message: > 24 | This issue has been automatically closed because we haven't received a 25 | response from the original author 🙈. This automation helps keep the issue 26 | tracker clean from issues that aren't actionable. Please reach out if you 27 | have more information for us! 🙂 28 | close-pr-message: > 29 | This PR has been automatically closed because we haven't received a 30 | response from the original author 🙈. This automation helps keep the issue 31 | tracker clean from PRs that aren't actionable. Please reach out if you 32 | have more information for us! 🙂 33 | -------------------------------------------------------------------------------- /docs/rules/no-unicode-codepoint-escapes.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-unicode-codepoint-escapes" 5 | description: "disallow Unicode code point escape sequences." 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-unicode-codepoint-escapes 10 | 11 | > disallow Unicode code point escape sequences. 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule disallow Unicode code point escape sequences. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-unicode-codepoint-escapes: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": "\u0041", 29 | 30 | /* ✗ BAD */ 31 | "BAD": "\u{41}" 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :rocket: Version 42 | 43 | This rule was introduced in eslint-plugin-jsonc v1.1.0 44 | 45 | ## :mag: Implementation 46 | 47 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-unicode-codepoint-escapes.ts) 48 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-unicode-codepoint-escapes.ts) 49 | -------------------------------------------------------------------------------- /docs/rules/no-number-props.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-number-props" 5 | description: "disallow number property keys" 6 | since: "v0.2.0" 7 | --- 8 | 9 | # jsonc/no-number-props 10 | 11 | > disallow number property keys 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule reports the use of number property keys. 19 | 20 | JSON, JSONC and JSON5 do not allow number property keys. 21 | 22 | 23 | 24 | 25 | 26 | ```json5 27 | /* eslint jsonc/no-number-props: 'error' */ 28 | { 29 | /* ✓ GOOD */ 30 | "GOOD": { 31 | "42": "foo" 32 | }, 33 | 34 | /* ✗ BAD */ 35 | "BAD": { 36 | 42: "foo" 37 | } 38 | } 39 | ``` 40 | 41 | 42 | 43 | ## :wrench: Options 44 | 45 | Nothing. 46 | 47 | ## :rocket: Version 48 | 49 | This rule was introduced in eslint-plugin-jsonc v0.2.0 50 | 51 | ## :mag: Implementation 52 | 53 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-number-props.ts) 54 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-number-props.ts) 55 | -------------------------------------------------------------------------------- /.github/workflows/pkg.pr.new.yml: -------------------------------------------------------------------------------- 1 | name: Publish to pkg.pr.new 2 | on: 3 | pull_request: 4 | branches: [master] 5 | push: 6 | branches: [master] 7 | tags: ["!**"] 8 | 9 | jobs: 10 | build: 11 | if: github.repository == 'ota-meshi/eslint-plugin-jsonc' 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v5 16 | - uses: actions/setup-node@v5 17 | - name: Install Packages 18 | run: npm install -f 19 | - name: Build 20 | run: npm run build 21 | env: 22 | SYNCKIT_TS_RUNNER: oxc 23 | - run: npx pkg-pr-new publish --compact '.' --json output.json --comment=off 24 | - name: Add metadata to output 25 | uses: actions/github-script@v8 26 | with: 27 | github-token: ${{ secrets.GITHUB_TOKEN }} 28 | script: | 29 | const fs = require('fs'); 30 | const output = JSON.parse(fs.readFileSync('output.json', 'utf8')); 31 | output.number = context.issue.number; 32 | output.event_name = context.eventName; 33 | output.ref = context.ref; 34 | output.sha = context.eventName === 'pull_request' 35 | ? context.payload.pull_request.head.sha 36 | : context.payload.after; 37 | fs.writeFileSync('output.json', JSON.stringify(output), 'utf8'); 38 | - name: Upload output 39 | uses: actions/upload-artifact@v4 40 | with: 41 | name: output 42 | path: ./output.json 43 | 44 | - run: ls -R . 45 | -------------------------------------------------------------------------------- /docs/rules/no-escape-sequence-in-identifier.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-escape-sequence-in-identifier" 5 | description: "disallow escape sequences in identifiers." 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-escape-sequence-in-identifier 10 | 11 | > disallow escape sequences in identifiers. 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule reports disallow escape sequences in identifiers. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-escape-sequence-in-identifier: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | GOOD: "GOOD", 29 | 30 | /* ✗ BAD */ 31 | \u0042\u{41}\u{44}: "BAD" 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :rocket: Version 42 | 43 | This rule was introduced in eslint-plugin-jsonc v1.1.0 44 | 45 | ## :mag: Implementation 46 | 47 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-escape-sequence-in-identifier.ts) 48 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-escape-sequence-in-identifier.ts) 49 | -------------------------------------------------------------------------------- /tests/lib/rules/no-useless-escape.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-useless-escape"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("no-useless-escape", rule, { 13 | valid: ['"\\""'], 14 | invalid: [ 15 | { 16 | filename: "test.json", 17 | code: '"hol\\a"', 18 | errors: [ 19 | { 20 | message: "Unnecessary escape character: \\a.", 21 | suggestions: [ 22 | { messageId: "removeEscape", output: `"hola"` }, 23 | { messageId: "escapeBackslash", output: String.raw`"hol\\a"` }, 24 | ], 25 | }, 26 | ], 27 | }, 28 | { 29 | filename: "test.vue", 30 | code: `"hol\\a"`, 31 | errors: [ 32 | { 33 | message: "Unnecessary escape character: \\a.", 34 | suggestions: [ 35 | { 36 | messageId: "removeEscape", 37 | output: `"hola"`, 38 | }, 39 | { 40 | messageId: "escapeBackslash", 41 | output: String.raw`"hol\\a"`, 42 | }, 43 | ], 44 | }, 45 | ], 46 | languageOptions: { 47 | parser: vueParser, 48 | }, 49 | }, 50 | ], 51 | }); 52 | -------------------------------------------------------------------------------- /docs/rules/no-dupe-keys.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-dupe-keys" 5 | description: "disallow duplicate keys in object literals" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/no-dupe-keys 10 | 11 | > disallow duplicate keys in object literals 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule disallows duplicate keys in object literals. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/no-dupe-keys: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": { 28 | "foo": "val", 29 | "bar": "val" 30 | }, 31 | 32 | /* ✗ BAD */ 33 | "BAD": { 34 | "foo": "val", 35 | "foo": "val" 36 | } 37 | } 38 | ``` 39 | 40 | 41 | 42 | ## :wrench: Options 43 | 44 | Nothing. 45 | 46 | ## :couple: Related rules 47 | 48 | - [no-dupe-keys] 49 | 50 | [no-dupe-keys]: https://eslint.org/docs/rules/no-dupe-keys 51 | 52 | ## :rocket: Version 53 | 54 | This rule was introduced in eslint-plugin-jsonc v0.1.0 55 | 56 | ## :mag: Implementation 57 | 58 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-dupe-keys.ts) 59 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-dupe-keys.ts) 60 | 61 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-dupe-keys) 62 | -------------------------------------------------------------------------------- /tests/lib/rules/no-template-literals.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-template-literals"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | ecmaVersion: 2020, 10 | }, 11 | ignoreMomoa: true, 12 | }); 13 | 14 | tester.run("no-template-literals", rule, { 15 | valid: ['{"key": "value"}', '"string"', '["element"]'], 16 | invalid: [ 17 | { 18 | code: "`template`", 19 | output: '"template"', 20 | errors: ["The template literals are not allowed."], 21 | }, 22 | { 23 | code: "[`template`]", 24 | output: '["template"]', 25 | errors: ["The template literals are not allowed."], 26 | }, 27 | { 28 | code: '{"foo":`template`}', 29 | output: '{"foo":"template"}', 30 | errors: ["The template literals are not allowed."], 31 | }, 32 | { 33 | code: "`temp\n\nlate`", 34 | output: '"temp\\n\\nlate"', 35 | errors: ["The template literals are not allowed."], 36 | }, 37 | { 38 | filename: "test.vue", 39 | code: `{"foo":\`template\`}`, 40 | output: `{"foo":"template"}`, 41 | errors: ["The template literals are not allowed."], 42 | ...({ 43 | languageOptions: { 44 | parser: vueParser, 45 | }, 46 | } as any), 47 | }, 48 | ], 49 | }); 50 | -------------------------------------------------------------------------------- /docs/rules/auto.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/auto" 5 | description: "apply jsonc rules similar to your configured ESLint core rules" 6 | since: "v0.8.0" 7 | --- 8 | 9 | # jsonc/auto 10 | 11 | > apply jsonc rules similar to your configured ESLint core rules 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | Automatically apply jsonc rules similar to your configured ESLint core rules to JSON. 18 | 19 | This rule checks the ESLint core rules you are already using in your configuration and automatically turns ON the equivalent [Extension Rules](./index.md#extension-rules) provided by this plugin. 20 | 21 | If you have already configured a particular jsonc rule, either explicitly or via a shared configuration, then that will take precedence over `jsonc/auto`. For example, if you use the `"plugin:jsonc/recommended-with-json"` configuration, the `auto` rule will not turn ON the `jsonc/comma-dangle` rule even if the `comma-dangle` rule is enabled in your core ESLint config. 22 | 23 | ## :wrench: Options 24 | 25 | Nothing. 26 | 27 | ## :rocket: Version 28 | 29 | This rule was introduced in eslint-plugin-jsonc v0.8.0 30 | 31 | ## :mag: Implementation 32 | 33 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/auto.ts) 34 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/auto.ts) 35 | -------------------------------------------------------------------------------- /docs/rules/no-numeric-separators.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-numeric-separators" 5 | description: "disallow numeric separators" 6 | since: "v0.6.0" 7 | --- 8 | 9 | # jsonc/no-numeric-separators 10 | 11 | > disallow numeric separators 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule reports the use of numeric separators. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-numeric-separators: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": 1234567890, 29 | 30 | /* ✗ BAD */ 31 | "BAD": 1_234_567_890 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :couple: Related rules 42 | 43 | - [jsonc/valid-json-number] 44 | 45 | [jsonc/valid-json-number]: ./valid-json-number.md 46 | 47 | ## :rocket: Version 48 | 49 | This rule was introduced in eslint-plugin-jsonc v0.6.0 50 | 51 | ## :mag: Implementation 52 | 53 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-numeric-separators.ts) 54 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-numeric-separators.ts) 55 | -------------------------------------------------------------------------------- /docs/rules/no-octal-numeric-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-octal-numeric-literals" 5 | description: "disallow octal numeric literals" 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-octal-numeric-literals 10 | 11 | > disallow octal numeric literals 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule disallow octal numeric literals. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-octal-numeric-literals: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": 511, 29 | 30 | /* ✗ BAD */ 31 | "BAD": 0o777 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :couple: Related rules 42 | 43 | - [jsonc/valid-json-number] 44 | 45 | [jsonc/valid-json-number]: ./valid-json-number.md 46 | 47 | ## :rocket: Version 48 | 49 | This rule was introduced in eslint-plugin-jsonc v1.1.0 50 | 51 | ## :mag: Implementation 52 | 53 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-octal-numeric-literals.ts) 54 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-octal-numeric-literals.ts) 55 | -------------------------------------------------------------------------------- /docs/rules/no-binary-numeric-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-binary-numeric-literals" 5 | description: "disallow binary numeric literals" 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-binary-numeric-literals 10 | 11 | > disallow binary numeric literals 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule disallow binary numeric literals 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-binary-numeric-literals: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": 10, 29 | 30 | /* ✗ BAD */ 31 | "BAD": 0b1010 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :couple: Related rules 42 | 43 | - [jsonc/valid-json-number] 44 | 45 | [jsonc/valid-json-number]: ./valid-json-number.md 46 | 47 | ## :rocket: Version 48 | 49 | This rule was introduced in eslint-plugin-jsonc v1.1.0 50 | 51 | ## :mag: Implementation 52 | 53 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-binary-numeric-literals.ts) 54 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-binary-numeric-literals.ts) 55 | -------------------------------------------------------------------------------- /.github/workflows/Release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | # prevents this action from running on forks 11 | if: github.repository == 'ota-meshi/eslint-plugin-jsonc' 12 | permissions: 13 | id-token: write # Required for OIDC 14 | contents: write # to create release (changesets/action) 15 | pull-requests: write # to create pull request (changesets/action) 16 | name: Release 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout Repo 20 | uses: actions/checkout@v4 21 | with: 22 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 23 | fetch-depth: 0 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v5 26 | with: 27 | node-version: 24 28 | - name: Install Dependencies 29 | run: npm install -f 30 | - name: Create Release Pull Request or Publish to npm 31 | id: changesets 32 | uses: changesets/action@v1 33 | with: 34 | # this expects you to have a npm script called version that runs some logic and then calls `changeset version`. 35 | version: npm run version:ci 36 | # This expects you to have a script called release which does a build for your packages and calls changeset publish 37 | publish: npm run release 38 | commit: "chore: release eslint-plugin-jsonc" 39 | title: "chore: release eslint-plugin-jsonc" 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | -------------------------------------------------------------------------------- /lib/configs/recommended-with-jsonc.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import path from "path"; 5 | const base = require.resolve("./base"); 6 | const baseExtend = 7 | path.extname(`${base}`) === ".ts" ? "plugin:jsonc/base" : base; 8 | export = { 9 | extends: [baseExtend], 10 | rules: { 11 | // eslint-plugin-jsonc rules 12 | "jsonc/no-bigint-literals": "error", 13 | "jsonc/no-binary-expression": "error", 14 | "jsonc/no-binary-numeric-literals": "error", 15 | "jsonc/no-dupe-keys": "error", 16 | "jsonc/no-escape-sequence-in-identifier": "error", 17 | "jsonc/no-floating-decimal": "error", 18 | "jsonc/no-hexadecimal-numeric-literals": "error", 19 | "jsonc/no-infinity": "error", 20 | "jsonc/no-multi-str": "error", 21 | "jsonc/no-nan": "error", 22 | "jsonc/no-number-props": "error", 23 | "jsonc/no-numeric-separators": "error", 24 | "jsonc/no-octal-numeric-literals": "error", 25 | "jsonc/no-octal": "error", 26 | "jsonc/no-parenthesized": "error", 27 | "jsonc/no-plus-sign": "error", 28 | "jsonc/no-regexp-literals": "error", 29 | "jsonc/no-sparse-arrays": "error", 30 | "jsonc/no-template-literals": "error", 31 | "jsonc/no-undefined-value": "error", 32 | "jsonc/no-unicode-codepoint-escapes": "error", 33 | "jsonc/no-useless-escape": "error", 34 | "jsonc/quote-props": "error", 35 | "jsonc/quotes": "error", 36 | "jsonc/space-unary-ops": "error", 37 | "jsonc/valid-json-number": "error", 38 | "jsonc/vue-custom-block/no-parsing-error": "error", 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /lib/configs/flat/recommended-with-jsonc.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import type { Linter } from "eslint"; 5 | import base from "./base"; 6 | export default [ 7 | ...base, 8 | { 9 | rules: { 10 | // eslint-plugin-jsonc rules 11 | "jsonc/no-bigint-literals": "error", 12 | "jsonc/no-binary-expression": "error", 13 | "jsonc/no-binary-numeric-literals": "error", 14 | "jsonc/no-dupe-keys": "error", 15 | "jsonc/no-escape-sequence-in-identifier": "error", 16 | "jsonc/no-floating-decimal": "error", 17 | "jsonc/no-hexadecimal-numeric-literals": "error", 18 | "jsonc/no-infinity": "error", 19 | "jsonc/no-multi-str": "error", 20 | "jsonc/no-nan": "error", 21 | "jsonc/no-number-props": "error", 22 | "jsonc/no-numeric-separators": "error", 23 | "jsonc/no-octal-numeric-literals": "error", 24 | "jsonc/no-octal": "error", 25 | "jsonc/no-parenthesized": "error", 26 | "jsonc/no-plus-sign": "error", 27 | "jsonc/no-regexp-literals": "error", 28 | "jsonc/no-sparse-arrays": "error", 29 | "jsonc/no-template-literals": "error", 30 | "jsonc/no-undefined-value": "error", 31 | "jsonc/no-unicode-codepoint-escapes": "error", 32 | "jsonc/no-useless-escape": "error", 33 | "jsonc/quote-props": "error", 34 | "jsonc/quotes": "error", 35 | "jsonc/space-unary-ops": "error", 36 | "jsonc/valid-json-number": "error", 37 | "jsonc/vue-custom-block/no-parsing-error": "error", 38 | }, 39 | }, 40 | ] satisfies Linter.FlatConfig[]; 41 | -------------------------------------------------------------------------------- /docs/rules/no-hexadecimal-numeric-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-hexadecimal-numeric-literals" 5 | description: "disallow hexadecimal numeric literals" 6 | since: "v1.1.0" 7 | --- 8 | 9 | # jsonc/no-hexadecimal-numeric-literals 10 | 11 | > disallow hexadecimal numeric literals 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule disallow hexadecimal numeric literals. 19 | 20 | Cannot use hexadecimal numeric literals when in JSON and JSONC. 21 | 22 | 23 | 24 | 25 | 26 | ```json5 27 | /* eslint jsonc/no-hexadecimal-numeric-literals: 'error' */ 28 | { 29 | /* ✓ GOOD */ 30 | "GOOD": 65535, 31 | 32 | /* ✗ BAD */ 33 | "BAD": 0xFFFF 34 | } 35 | ``` 36 | 37 | 38 | 39 | ## :wrench: Options 40 | 41 | Nothing. 42 | 43 | ## :couple: Related rules 44 | 45 | - [jsonc/valid-json-number] 46 | 47 | [jsonc/valid-json-number]: ./valid-json-number.md 48 | 49 | ## :rocket: Version 50 | 51 | This rule was introduced in eslint-plugin-jsonc v1.1.0 52 | 53 | ## :mag: Implementation 54 | 55 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-hexadecimal-numeric-literals.ts) 56 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-hexadecimal-numeric-literals.ts) 57 | -------------------------------------------------------------------------------- /docs/rules/no-useless-escape.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-useless-escape" 5 | description: "disallow unnecessary escape usage" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/no-useless-escape 10 | 11 | > disallow unnecessary escape usage 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). 15 | 16 | ## :book: Rule Details 17 | 18 | This rule flags escapes that can be safely removed without changing behavior. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/no-useless-escape: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": "\"", 29 | 30 | /* ✗ BAD */ 31 | "BAD": "hol\a" 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :couple: Related rules 42 | 43 | - [no-useless-escape] 44 | 45 | [no-useless-escape]: https://eslint.org/docs/rules/no-useless-escape 46 | 47 | ## :rocket: Version 48 | 49 | This rule was introduced in eslint-plugin-jsonc v0.1.0 50 | 51 | ## :mag: Implementation 52 | 53 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-useless-escape.ts) 54 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-useless-escape.ts) 55 | 56 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-useless-escape) 57 | -------------------------------------------------------------------------------- /docs/rules/no-sparse-arrays.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-sparse-arrays" 5 | description: "disallow sparse arrays" 6 | since: "v0.2.0" 7 | --- 8 | 9 | # jsonc/no-sparse-arrays 10 | 11 | > disallow sparse arrays 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule disallows sparse array literals which have "holes" where commas are not preceded by elements. It does not apply to a trailing comma following the last element. 18 | 19 | JSON, JSONC and JSON5 do not allow arrays contain empty slots. 20 | 21 | 22 | 23 | 24 | 25 | ```json5 26 | /* eslint jsonc/no-sparse-arrays: 'error' */ 27 | { 28 | /* ✓ GOOD */ 29 | "GOOD": [1, 2, 3, 4], 30 | "GOOD": [1, 2, 3, 4,], 31 | 32 | /* ✗ BAD */ 33 | "BAD": [1, , , 4], 34 | "BAD": [, 2, 3, 4] 35 | } 36 | ``` 37 | 38 | 39 | 40 | ## :wrench: Options 41 | 42 | Nothing. 43 | 44 | ## :couple: Related rules 45 | 46 | - [no-sparse-arrays] 47 | 48 | [no-sparse-arrays]: https://eslint.org/docs/rules/no-sparse-arrays 49 | 50 | ## :rocket: Version 51 | 52 | This rule was introduced in eslint-plugin-jsonc v0.2.0 53 | 54 | ## :mag: Implementation 55 | 56 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-sparse-arrays.ts) 57 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-sparse-arrays.ts) 58 | 59 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-sparse-arrays) 60 | -------------------------------------------------------------------------------- /tests/lib/rules/space-unary-ops.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/space-unary-ops"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | import * as vueParser from "vue-eslint-parser"; 5 | 6 | const tester = new RuleTester({ 7 | languageOptions: { 8 | parser: jsonParser, 9 | }, 10 | }); 11 | 12 | tester.run("space-unary-ops", rule, { 13 | valid: ["-1", "+1", "-0", "+0"], 14 | invalid: [ 15 | { 16 | code: "[- 1, + 1, - 0, + 0]", 17 | output: "[-1, +1, -0, +0]", 18 | errors: [ 19 | { 20 | message: "Unexpected space after unary operator '-'.", 21 | line: 1, 22 | column: 2, 23 | endColumn: 5, 24 | }, 25 | { 26 | message: "Unexpected space after unary operator '+'.", 27 | line: 1, 28 | column: 7, 29 | endColumn: 11, 30 | }, 31 | { 32 | message: "Unexpected space after unary operator '-'.", 33 | line: 1, 34 | column: 13, 35 | endColumn: 17, 36 | }, 37 | { 38 | message: "Unexpected space after unary operator '+'.", 39 | line: 1, 40 | column: 19, 41 | endColumn: 23, 42 | }, 43 | ], 44 | ignoreMomoa: true, 45 | }, 46 | { 47 | filename: "test.vue", 48 | code: `- 1`, 49 | output: `-1`, 50 | errors: ["Unexpected space after unary operator '-'."], 51 | ...({ 52 | languageOptions: { 53 | parser: vueParser, 54 | }, 55 | } as any), 56 | }, 57 | ], 58 | }); 59 | -------------------------------------------------------------------------------- /lib/configs/recommended-with-json.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import path from "path"; 5 | const base = require.resolve("./base"); 6 | const baseExtend = 7 | path.extname(`${base}`) === ".ts" ? "plugin:jsonc/base" : base; 8 | export = { 9 | extends: [baseExtend], 10 | rules: { 11 | // eslint-plugin-jsonc rules 12 | "jsonc/comma-dangle": "error", 13 | "jsonc/no-bigint-literals": "error", 14 | "jsonc/no-binary-expression": "error", 15 | "jsonc/no-binary-numeric-literals": "error", 16 | "jsonc/no-comments": "error", 17 | "jsonc/no-dupe-keys": "error", 18 | "jsonc/no-escape-sequence-in-identifier": "error", 19 | "jsonc/no-floating-decimal": "error", 20 | "jsonc/no-hexadecimal-numeric-literals": "error", 21 | "jsonc/no-infinity": "error", 22 | "jsonc/no-multi-str": "error", 23 | "jsonc/no-nan": "error", 24 | "jsonc/no-number-props": "error", 25 | "jsonc/no-numeric-separators": "error", 26 | "jsonc/no-octal-numeric-literals": "error", 27 | "jsonc/no-octal": "error", 28 | "jsonc/no-parenthesized": "error", 29 | "jsonc/no-plus-sign": "error", 30 | "jsonc/no-regexp-literals": "error", 31 | "jsonc/no-sparse-arrays": "error", 32 | "jsonc/no-template-literals": "error", 33 | "jsonc/no-undefined-value": "error", 34 | "jsonc/no-unicode-codepoint-escapes": "error", 35 | "jsonc/no-useless-escape": "error", 36 | "jsonc/quote-props": "error", 37 | "jsonc/quotes": "error", 38 | "jsonc/space-unary-ops": "error", 39 | "jsonc/valid-json-number": "error", 40 | "jsonc/vue-custom-block/no-parsing-error": "error", 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /lib/configs/flat/recommended-with-json.ts: -------------------------------------------------------------------------------- 1 | // IMPORTANT! 2 | // This file has been automatically generated, 3 | // in order to update its content execute "npm run update" 4 | import type { Linter } from "eslint"; 5 | import base from "./base"; 6 | export default [ 7 | ...base, 8 | { 9 | rules: { 10 | // eslint-plugin-jsonc rules 11 | "jsonc/comma-dangle": "error", 12 | "jsonc/no-bigint-literals": "error", 13 | "jsonc/no-binary-expression": "error", 14 | "jsonc/no-binary-numeric-literals": "error", 15 | "jsonc/no-comments": "error", 16 | "jsonc/no-dupe-keys": "error", 17 | "jsonc/no-escape-sequence-in-identifier": "error", 18 | "jsonc/no-floating-decimal": "error", 19 | "jsonc/no-hexadecimal-numeric-literals": "error", 20 | "jsonc/no-infinity": "error", 21 | "jsonc/no-multi-str": "error", 22 | "jsonc/no-nan": "error", 23 | "jsonc/no-number-props": "error", 24 | "jsonc/no-numeric-separators": "error", 25 | "jsonc/no-octal-numeric-literals": "error", 26 | "jsonc/no-octal": "error", 27 | "jsonc/no-parenthesized": "error", 28 | "jsonc/no-plus-sign": "error", 29 | "jsonc/no-regexp-literals": "error", 30 | "jsonc/no-sparse-arrays": "error", 31 | "jsonc/no-template-literals": "error", 32 | "jsonc/no-undefined-value": "error", 33 | "jsonc/no-unicode-codepoint-escapes": "error", 34 | "jsonc/no-useless-escape": "error", 35 | "jsonc/quote-props": "error", 36 | "jsonc/quotes": "error", 37 | "jsonc/space-unary-ops": "error", 38 | "jsonc/valid-json-number": "error", 39 | "jsonc/vue-custom-block/no-parsing-error": "error", 40 | }, 41 | }, 42 | ] satisfies Linter.FlatConfig[]; 43 | -------------------------------------------------------------------------------- /tests-integrations/lib/vue-eslint-parser-option.ts: -------------------------------------------------------------------------------- 1 | import cp from "child_process"; 2 | import assert from "assert"; 3 | import path from "path"; 4 | import { version } from "../../package.json"; 5 | 6 | // ----------------------------------------------------------------------------- 7 | // Tests 8 | // ----------------------------------------------------------------------------- 9 | 10 | const TEST_CWD = path.join(__dirname, "../fixtures/vue-eslint-parser-option"); 11 | const ESLINT = path.join(TEST_CWD, `./node_modules/.bin/eslint`); 12 | 13 | describe("Integration with vue-eslint-parser with option", () => { 14 | let originalCwd: string; 15 | 16 | before(() => { 17 | originalCwd = process.cwd(); 18 | process.chdir(TEST_CWD); 19 | cp.execSync(`npm i -D ../../../eslint-plugin-jsonc-${version}.tgz`, { 20 | stdio: "inherit", 21 | }); 22 | cp.execSync("npm i", { stdio: "inherit" }); 23 | }); 24 | after(() => { 25 | process.chdir(originalCwd); 26 | }); 27 | 28 | it("should lint errors", () => { 29 | try { 30 | const res = cp.execSync(`${ESLINT} "./test.json" --format json`, { 31 | env: { 32 | // eslint-disable-next-line no-process-env -- Legacy Config test 33 | ...process.env, 34 | ESLINT_USE_FLAT_CONFIG: "false", 35 | }, 36 | }); 37 | console.log(`${res}`); 38 | } catch (e: any) { 39 | const results = JSON.parse(`${e.stdout}`); 40 | 41 | assert.strictEqual(results.length, 1); 42 | assert.strictEqual(results[0].messages.length, 1); 43 | assert.strictEqual( 44 | results[0].messages[0].message, 45 | "Expected indentation of 4 spaces but found 0.", 46 | ); 47 | return; 48 | } 49 | assert.fail("Expect error"); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /tests-integrations/lib/eslint-plugin-markdown.ts: -------------------------------------------------------------------------------- 1 | import cp from "child_process"; 2 | import assert from "assert"; 3 | import path from "path"; 4 | import { version } from "../../package.json"; 5 | 6 | // ----------------------------------------------------------------------------- 7 | // Tests 8 | // ----------------------------------------------------------------------------- 9 | 10 | const TEST_CWD = path.join(__dirname, "../fixtures/eslint-plugin-markdown"); 11 | const ESLINT = path.join(TEST_CWD, `./node_modules/.bin/eslint`); 12 | 13 | describe("Integration with eslint-plugin-markdown", () => { 14 | let originalCwd: string; 15 | 16 | before(() => { 17 | originalCwd = process.cwd(); 18 | process.chdir(TEST_CWD); 19 | cp.execSync(`npm i -D ../../../eslint-plugin-jsonc-${version}.tgz`, { 20 | stdio: "inherit", 21 | }); 22 | cp.execSync("npm i", { stdio: "inherit" }); 23 | }); 24 | after(() => { 25 | process.chdir(originalCwd); 26 | }); 27 | 28 | it("should lint errors", () => { 29 | try { 30 | const res = cp.execSync(`${ESLINT} "./test.md" --format json`, { 31 | env: { 32 | // eslint-disable-next-line no-process-env -- Legacy Config test 33 | ...process.env, 34 | ESLINT_USE_FLAT_CONFIG: "false", 35 | }, 36 | }); 37 | console.log(`${res}`); 38 | } catch (e: any) { 39 | const results = JSON.parse(`${e.stdout}`); 40 | 41 | assert.strictEqual(results.length, 1); 42 | assert.strictEqual(results[0].messages.length, 1); 43 | assert.strictEqual( 44 | results[0].messages[0].message, 45 | "[jsonc/array-bracket-newline] There should be no linebreak before ']'.", 46 | ); 47 | return; 48 | } 49 | assert.fail("Expect error"); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /docs/rules/space-unary-ops.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/space-unary-ops" 5 | description: "disallow spaces after unary operators" 6 | since: "v0.2.0" 7 | --- 8 | 9 | # jsonc/space-unary-ops 10 | 11 | > disallow spaces after unary operators 12 | 13 | - :gear: This rule is included in all of `"plugin:jsonc/recommended-with-json"`, `"plugin:jsonc/recommended-with-json5"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule reports the space after the sign operator. 19 | 20 | JSON, JSONC and JSON5 do not allow spaces after the sign. 21 | 22 | 23 | 24 | 25 | 26 | ```json5 27 | /* eslint jsonc/space-unary-ops: 'error' */ 28 | { 29 | /* ✓ GOOD */ 30 | "GOOD": -42, 31 | 32 | /* ✗ BAD */ 33 | "BAD": - 42 34 | } 35 | ``` 36 | 37 | 38 | 39 | ## :wrench: Options 40 | 41 | Nothing. 42 | 43 | ## :couple: Related rules 44 | 45 | - [space-unary-ops] 46 | - [jsonc/valid-json-number] 47 | 48 | [space-unary-ops]: https://eslint.org/docs/rules/space-unary-ops 49 | [jsonc/valid-json-number]: ./valid-json-number.md 50 | 51 | ## :rocket: Version 52 | 53 | This rule was introduced in eslint-plugin-jsonc v0.2.0 54 | 55 | ## :mag: Implementation 56 | 57 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/space-unary-ops.ts) 58 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/space-unary-ops.ts) 59 | 60 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/space-unary-ops) 61 | -------------------------------------------------------------------------------- /docs/rules/array-bracket-spacing.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/array-bracket-spacing" 5 | description: "disallow or enforce spaces inside of brackets" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/array-bracket-spacing 10 | 11 | > disallow or enforce spaces inside of brackets 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforces consistent spacing inside array brackets. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/array-bracket-spacing: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": [1, 2, 3], 28 | 29 | /* ✗ BAD */ 30 | "BAD": [ 1, 2, 3 ] 31 | } 32 | ``` 33 | 34 | 35 | 36 | ## :wrench: Options 37 | 38 | ```json 39 | { 40 | "jsonc/array-bracket-spacing": ["error", 41 | "never" 42 | ] 43 | } 44 | ``` 45 | 46 | Same as [array-bracket-spacing] rule option. See [here](https://eslint.org/docs/rules/array-bracket-spacing#options) for details. 47 | 48 | ## :couple: Related rules 49 | 50 | - [array-bracket-spacing] 51 | 52 | [array-bracket-spacing]: https://eslint.org/docs/rules/array-bracket-spacing 53 | 54 | ## :rocket: Version 55 | 56 | This rule was introduced in eslint-plugin-jsonc v0.1.0 57 | 58 | ## :mag: Implementation 59 | 60 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/array-bracket-spacing.ts) 61 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/array-bracket-spacing.ts) 62 | 63 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/array-bracket-spacing) 64 | -------------------------------------------------------------------------------- /docs/rules/object-curly-spacing.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/object-curly-spacing" 5 | description: "enforce consistent spacing inside braces" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/object-curly-spacing 10 | 11 | > enforce consistent spacing inside braces 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforces consistent spacing inside braces of object literals. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/object-curly-spacing: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": {"foo": "bar"}, 28 | 29 | /* ✗ BAD */ 30 | "BAD": { "foo": "bar" }, 31 | } 32 | ``` 33 | 34 | 35 | 36 | ## :wrench: Options 37 | 38 | ```json 39 | { 40 | "jsonc/object-curly-spacing": ["error", 41 | "never" 42 | ] 43 | } 44 | ``` 45 | 46 | Same as [object-curly-spacing] rule option. See [here](https://eslint.org/docs/rules/object-curly-spacing#options) for details. 47 | 48 | ## :couple: Related rules 49 | 50 | - [object-curly-spacing] 51 | 52 | [object-curly-spacing]: https://eslint.org/docs/rules/object-curly-spacing 53 | 54 | ## :rocket: Version 55 | 56 | This rule was introduced in eslint-plugin-jsonc v0.1.0 57 | 58 | ## :mag: Implementation 59 | 60 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/object-curly-spacing.ts) 61 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/object-curly-spacing.ts) 62 | 63 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/object-curly-spacing) 64 | -------------------------------------------------------------------------------- /docs/rules/array-element-newline.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/array-element-newline" 5 | description: "enforce line breaks between array elements" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/array-element-newline 10 | 11 | > enforce line breaks between array elements 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforces line breaks between array elements. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/array-element-newline: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": [1, 28 | 2, 29 | 3], 30 | 31 | /* ✗ BAD */ 32 | "BAD": [1, 2, 3] 33 | } 34 | ``` 35 | 36 | 37 | 38 | ## :wrench: Options 39 | 40 | ```json 41 | { 42 | "jsonc/array-element-newline": ["error", 43 | "always" 44 | ] 45 | } 46 | ``` 47 | 48 | Same as [array-element-newline] rule option. See [here](https://eslint.org/docs/rules/array-element-newline#options) for details. 49 | 50 | ## :couple: Related rules 51 | 52 | - [array-element-newline] 53 | 54 | [array-element-newline]: https://eslint.org/docs/rules/array-element-newline 55 | 56 | ## :rocket: Version 57 | 58 | This rule was introduced in eslint-plugin-jsonc v0.1.0 59 | 60 | ## :mag: Implementation 61 | 62 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/array-element-newline.ts) 63 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/array-element-newline.ts) 64 | 65 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/array-element-newline) 66 | -------------------------------------------------------------------------------- /docs/rules/comma-style.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/comma-style" 5 | description: "enforce consistent comma style" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/comma-style 10 | 11 | > enforce consistent comma style 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforce consistent comma style in array literals and object literals. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/comma-style: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": ["apples", 28 | "oranges"], 29 | "GOOD": { 30 | "a": 1, 31 | "b": 2 32 | }, 33 | 34 | /* ✗ BAD */ 35 | "BAD": ["apples" 36 | , "oranges"] 37 | ,"BAD": { 38 | "a": 1 39 | , "b": 2 40 | } 41 | } 42 | ``` 43 | 44 | 45 | 46 | ## :wrench: Options 47 | 48 | ```json 49 | { 50 | "jsonc/comma-style": ["error", 51 | "last" 52 | ] 53 | } 54 | ``` 55 | 56 | Same as [comma-style] rule option. See [here](https://eslint.org/docs/rules/comma-style#options) for details. 57 | 58 | ## :couple: Related rules 59 | 60 | - [comma-style] 61 | 62 | [comma-style]: https://eslint.org/docs/rules/comma-style 63 | 64 | ## :rocket: Version 65 | 66 | This rule was introduced in eslint-plugin-jsonc v0.1.0 67 | 68 | ## :mag: Implementation 69 | 70 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/comma-style.ts) 71 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/comma-style.ts) 72 | 73 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/comma-style) 74 | -------------------------------------------------------------------------------- /docs/rules/indent.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/indent" 5 | description: "enforce consistent indentation" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/indent 10 | 11 | > enforce consistent indentation 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforces a consistent indentation style. The default style is `4 spaces`. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/indent: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": { 28 | "GOOD": "foo" 29 | }, 30 | 31 | /* ✗ BAD */ 32 | "BAD": { 33 | "BAD": "bar" 34 | } 35 | } 36 | ``` 37 | 38 | 39 | 40 | ## :wrench: Options 41 | 42 | ```json 43 | { 44 | "jsonc/indent": ["error", 45 | 4, 46 | {} 47 | ] 48 | } 49 | ``` 50 | 51 | Same as [indent] rule option. See [here](https://eslint.org/docs/rules/indent#options) for details. 52 | 53 | - First option ... Sets the indentation style. default `4` 54 | Set to `2` if you prefer 2 spaces indentation. 55 | Set to `"tab"` if you prefer tab indentation. 56 | - Second option ... You can set the object to customize it further. 57 | 58 | ## :couple: Related rules 59 | 60 | - [indent] 61 | 62 | [indent]: https://eslint.org/docs/rules/indent 63 | 64 | ## :rocket: Version 65 | 66 | This rule was introduced in eslint-plugin-jsonc v0.1.0 67 | 68 | ## :mag: Implementation 69 | 70 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/indent.ts) 71 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/indent.ts) 72 | 73 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/indent) 74 | -------------------------------------------------------------------------------- /docs/rules/no-floating-decimal.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-floating-decimal" 5 | description: "disallow leading or trailing decimal points in numeric literals" 6 | since: "v0.9.0" 7 | --- 8 | 9 | # jsonc/no-floating-decimal 10 | 11 | > disallow leading or trailing decimal points in numeric literals 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule is aimed at eliminating floating decimal points and will warn whenever a numeric value has a decimal point but is missing a number either before or after it. 19 | 20 | Cannot use floating decimal points when in JSON and JSONC. 21 | 22 | 23 | 24 | 25 | 26 | ```json5 27 | /* eslint jsonc/no-floating-decimal: 'error' */ 28 | { 29 | /* ✓ GOOD */ 30 | "GOOD": 42.0, 31 | 32 | /* ✗ BAD */ 33 | "BAD": 42. 34 | } 35 | ``` 36 | 37 | 38 | 39 | ## :wrench: Options 40 | 41 | Nothing. 42 | 43 | ## :couple: Related rules 44 | 45 | - [no-floating-decimal] 46 | - [jsonc/valid-json-number] 47 | 48 | [no-floating-decimal]: https://eslint.org/docs/rules/no-floating-decimal 49 | [jsonc/valid-json-number]: ./valid-json-number.md 50 | 51 | ## :rocket: Version 52 | 53 | This rule was introduced in eslint-plugin-jsonc v0.9.0 54 | 55 | ## :mag: Implementation 56 | 57 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-floating-decimal.ts) 58 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-floating-decimal.ts) 59 | 60 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-floating-decimal) 61 | -------------------------------------------------------------------------------- /docs/.vitepress/build-system/build.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Pre-build cjs packages that cannot be bundled well. 3 | */ 4 | import esbuild from "esbuild"; 5 | import path from "path"; 6 | import fs from "fs"; 7 | import { fileURLToPath } from "url"; 8 | 9 | const dirname = path.dirname( 10 | fileURLToPath( 11 | // @ts-expect-error -- Cannot change `module` option 12 | import.meta.url, 13 | ), 14 | ); 15 | 16 | build( 17 | path.join(dirname, "./src/vue-eslint-parser.mjs"), 18 | path.join(dirname, "./shim/vue-eslint-parser.mjs"), 19 | ["eslint", "path", "module", "events"], 20 | ); 21 | build( 22 | path.join(dirname, "./src/events.mjs"), 23 | path.join(dirname, "./shim/events.mjs"), 24 | [], 25 | ); 26 | 27 | function build(input: string, out: string, injects: string[] = []) { 28 | // eslint-disable-next-line no-console -- ignore 29 | console.log(`build@ ${input}`); 30 | let code = bundle(input, injects); 31 | code = transform(code, injects); 32 | fs.mkdirSync(path.dirname(out), { recursive: true }); 33 | fs.writeFileSync(out, code, "utf8"); 34 | } 35 | 36 | function bundle(entryPoint: string, externals: string[]) { 37 | const result = esbuild.buildSync({ 38 | entryPoints: [entryPoint], 39 | format: "esm", 40 | bundle: true, 41 | external: externals, 42 | write: false, 43 | }); 44 | 45 | return `${result.outputFiles[0].text}`; 46 | } 47 | 48 | function transform(code: string, injects: string[]) { 49 | const newCode = code.replace(/"[a-z]+" = "[a-z]+";/u, ""); 50 | return ` 51 | ${injects 52 | .map( 53 | (inject) => 54 | `import $inject_${inject.replace(/-/gu, "_")}$ from '${inject}';`, 55 | ) 56 | .join("\n")} 57 | const $_injects_$ = {${injects 58 | .map((inject) => `${inject.replace(/-/gu, "_")}:$inject_${inject}$`) 59 | .join(",\n")}}; 60 | function require(module, ...args) { 61 | return $_injects_$[module] || {} 62 | } 63 | ${newCode} 64 | 65 | if (typeof __require !== 'undefined') __require.cache = {}; 66 | `; 67 | } 68 | -------------------------------------------------------------------------------- /docs/rules/object-curly-newline.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/object-curly-newline" 5 | description: "enforce consistent line breaks inside braces" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/object-curly-newline 10 | 11 | > enforce consistent line breaks inside braces 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforces consistent line breaks inside braces of object literals. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/object-curly-newline: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": {"foo": "bar"}, 28 | "GOOD": { 29 | "foo": "bar" 30 | }, 31 | 32 | /* ✗ BAD */ 33 | "BAD": {"foo": "bar" 34 | }, 35 | "BAD": { 36 | "foo": "bar"} 37 | } 38 | ``` 39 | 40 | 41 | 42 | ## :wrench: Options 43 | 44 | ```json 45 | { 46 | "jsonc/object-curly-newline": ["error", 47 | { 48 | "consistent": true 49 | } 50 | ] 51 | } 52 | ``` 53 | 54 | Same as [object-curly-newline] rule option. See [here](https://eslint.org/docs/rules/object-curly-newline#options) for details. 55 | 56 | ## :couple: Related rules 57 | 58 | - [object-curly-newline] 59 | 60 | [object-curly-newline]: https://eslint.org/docs/rules/object-curly-newline 61 | 62 | ## :rocket: Version 63 | 64 | This rule was introduced in eslint-plugin-jsonc v0.1.0 65 | 66 | ## :mag: Implementation 67 | 68 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/object-curly-newline.ts) 69 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/object-curly-newline.ts) 70 | 71 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/object-curly-newline) 72 | -------------------------------------------------------------------------------- /docs/rules/key-spacing.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/key-spacing" 5 | description: "enforce consistent spacing between keys and values in object literal properties" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/key-spacing 10 | 11 | > enforce consistent spacing between keys and values in object literal properties 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforces consistent spacing between keys and values in object literal properties. In the case of long lines, it is acceptable to add a new line wherever whitespace is allowed. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/key-spacing: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": "foo", 28 | 29 | /* ✗ BAD */ 30 | "BAD" :"bar" 31 | } 32 | ``` 33 | 34 | 35 | 36 | ## :wrench: Options 37 | 38 | ```json 39 | { 40 | "jsonc/key-spacing": ["error", 41 | { 42 | "beforeColon": false, 43 | "afterColon": true, 44 | "mode": "strict" 45 | } 46 | ] 47 | } 48 | ``` 49 | 50 | Same as [key-spacing] rule option. See [here](https://eslint.org/docs/rules/key-spacing#options) for details. 51 | 52 | ## :couple: Related rules 53 | 54 | - [key-spacing] 55 | 56 | [key-spacing]: https://eslint.org/docs/rules/key-spacing 57 | 58 | ## :rocket: Version 59 | 60 | This rule was introduced in eslint-plugin-jsonc v0.1.0 61 | 62 | ## :mag: Implementation 63 | 64 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/key-spacing.ts) 65 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/key-spacing.ts) 66 | 67 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/key-spacing) 68 | -------------------------------------------------------------------------------- /docs/rules/key-name-casing.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/key-name-casing" 5 | description: "enforce naming convention to property key names" 6 | since: "v0.8.0" 7 | --- 8 | 9 | # jsonc/key-name-casing 10 | 11 | > enforce naming convention to property key names 12 | 13 | ## :book: Rule Details 14 | 15 | This rule enforces a naming convention to property key names. 16 | 17 | 18 | 19 | 20 | 21 | ```json5 22 | /* eslint jsonc/key-name-casing: 'error' */ 23 | { 24 | /* ✓ GOOD */ 25 | "camelCase": "camelCase", 26 | 27 | /* ✗ BAD */ 28 | "PascalCase": "PascalCase", 29 | "SCREAMING_SNAKE_CASE": "SCREAMING_SNAKE_CASE", 30 | "kebab-case": "kebab-case", 31 | "snake_case": "snake_case" 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | ```json5 40 | { 41 | "jsonc/key-name-casing": ["error", 42 | { 43 | "camelCase": true, 44 | "PascalCase": false, 45 | "SCREAMING_SNAKE_CASE": false, 46 | "kebab-case": false, 47 | "snake_case": false, 48 | "ignores": [] 49 | } 50 | ] 51 | } 52 | ``` 53 | 54 | - `"camelCase"` ... if `true`, allows camelCase naming. default `true` 55 | - `"PascalCase"` ... if `true`, allows PascalCase naming. default `false` 56 | - `"SCREAMING_SNAKE_CASE"` ... if `true`, allows SCREAMING_SNAKE_CASE naming. default `false` 57 | - `"kebab-case"` ... if `true`, allows kebab-case naming. default `false` 58 | - `"snake_case"` ... if `true`, allows snake_case naming. default `false` 59 | - `"ignores"` ... you can specify the patterns to ignore in the array. 60 | 61 | ## :rocket: Version 62 | 63 | This rule was introduced in eslint-plugin-jsonc v0.8.0 64 | 65 | ## :mag: Implementation 66 | 67 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/key-name-casing.ts) 68 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/key-name-casing.ts) 69 | -------------------------------------------------------------------------------- /docs/rules/array-bracket-newline.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/array-bracket-newline" 5 | description: "enforce line breaks after opening and before closing array brackets" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/array-bracket-newline 10 | 11 | > enforce line breaks after opening and before closing array brackets 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule enforces line breaks after opening and before closing array brackets. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/array-bracket-newline: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": [1, 2, 3], 28 | "GOOD": [ 29 | 1, 30 | 2, 31 | 3 32 | ], 33 | 34 | /* ✗ BAD */ 35 | "BAD": [ 36 | 1, 2, 3 37 | ], 38 | "BAD": [1, 39 | 2, 3] 40 | } 41 | ``` 42 | 43 | 44 | 45 | ## :wrench: Options 46 | 47 | ```json 48 | { 49 | "jsonc/array-bracket-newline": ["error", 50 | { 51 | "multiline": true, 52 | "minItems": null 53 | } 54 | ] 55 | } 56 | ``` 57 | 58 | Same as [array-bracket-newline] rule option. See [here](https://eslint.org/docs/rules/array-bracket-newline#options) for details. 59 | 60 | ## :couple: Related rules 61 | 62 | - [array-bracket-newline] 63 | 64 | [array-bracket-newline]: https://eslint.org/docs/rules/array-bracket-newline 65 | 66 | ## :rocket: Version 67 | 68 | This rule was introduced in eslint-plugin-jsonc v0.1.0 69 | 70 | ## :mag: Implementation 71 | 72 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/array-bracket-newline.ts) 73 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/array-bracket-newline.ts) 74 | 75 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/array-bracket-newline) 76 | -------------------------------------------------------------------------------- /lib/rules/no-escape-sequence-in-identifier.ts: -------------------------------------------------------------------------------- 1 | import type { AST } from "jsonc-eslint-parser"; 2 | import { createRule } from "../utils"; 3 | import { PatternMatcher } from "@eslint-community/eslint-utils"; 4 | 5 | export default createRule("no-escape-sequence-in-identifier", { 6 | meta: { 7 | docs: { 8 | description: "disallow escape sequences in identifiers.", 9 | recommended: ["json", "jsonc", "json5"], 10 | extensionRule: false, 11 | layout: false, 12 | }, 13 | fixable: "code", 14 | messages: { 15 | disallow: "Escape sequence in identifiers should not be used.", 16 | }, 17 | schema: [], 18 | type: "problem", 19 | }, 20 | create(context) { 21 | const sourceCode = context.sourceCode; 22 | if (!sourceCode.parserServices.isJSON) { 23 | return {}; 24 | } 25 | return { 26 | JSONIdentifier(node) { 27 | verify(node); 28 | }, 29 | }; 30 | 31 | /** 32 | * verify 33 | */ 34 | function verify(node: AST.JSONIdentifier) { 35 | const escapeMatcher = new PatternMatcher(/\\u\{[\dA-Fa-f]+\}|\\u\d{4}/gu); 36 | const text = sourceCode.text.slice(...node.range); 37 | for (const match of escapeMatcher.execAll(text)) { 38 | const start = match.index; 39 | const end = start + match[0].length; 40 | const range: [number, number] = [ 41 | start + node.range[0], 42 | end + node.range[0], 43 | ]; 44 | context.report({ 45 | loc: { 46 | start: sourceCode.getLocFromIndex(range[0]), 47 | end: sourceCode.getLocFromIndex(range[1]), 48 | }, 49 | messageId: "disallow", 50 | fix(fixer) { 51 | const codePointStr = 52 | match[0][2] === "{" 53 | ? text.slice(start + 3, end - 1) 54 | : text.slice(start + 2, end); 55 | const codePoint = Number(`0x${codePointStr}`); 56 | return fixer.replaceTextRange( 57 | range, 58 | String.fromCodePoint(codePoint), 59 | ); 60 | }, 61 | }); 62 | } 63 | } 64 | }, 65 | }); 66 | -------------------------------------------------------------------------------- /docs/rules/no-irregular-whitespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/no-irregular-whitespace" 5 | description: "disallow irregular whitespace" 6 | since: "v2.5.0" 7 | --- 8 | 9 | # jsonc/no-irregular-whitespace 10 | 11 | > disallow irregular whitespace 12 | 13 | ## :book: Rule Details 14 | 15 | This rule is aimed at catching invalid whitespace that is not a normal tab and space. 16 | 17 | 18 | 19 | 20 | 21 | ```json 22 | /* eslint jsonc/no-irregular-whitespace: 'error' */ 23 | { 24 | /* ✓ GOOD */ 25 | "GOOD": " ", 26 | 27 | /* ✗ BAD */ 28 | "BAD": "foo", 29 | } 30 | ``` 31 | 32 | 33 | 34 | ESLint core [no-irregular-whitespace] rule don't work well in JSON. Turn off that rule in JSON files and use `jsonc/no-irregular-whitespace` rule. 35 | 36 | ## :wrench: Options 37 | 38 | Nothing. 39 | 40 | ```json 41 | { 42 | "overrides": [ 43 | { 44 | "files": ["*.json", "*.json5"], 45 | "rules": { 46 | "no-irregular-whitespace": "off", 47 | "jsonc/no-irregular-whitespace": [ 48 | "error", 49 | { 50 | "skipStrings": true, 51 | "skipComments": false, 52 | "skipRegExps": false, 53 | "skipTemplates": false 54 | } 55 | ] 56 | } 57 | } 58 | ] 59 | } 60 | ``` 61 | 62 | Same as [no-irregular-whitespace] rule option. See [here](https://eslint.org/docs/rules/no-irregular-whitespace#options) for details. 63 | 64 | ## :couple: Related rules 65 | 66 | - [no-irregular-whitespace] 67 | 68 | [no-irregular-whitespace]: https://eslint.org/docs/rules/no-irregular-whitespace 69 | 70 | ## :rocket: Version 71 | 72 | This rule was introduced in eslint-plugin-jsonc v2.5.0 73 | 74 | ## :mag: Implementation 75 | 76 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-irregular-whitespace.ts) 77 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-irregular-whitespace.ts) 78 | 79 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-irregular-whitespace) 80 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | import type { RuleModule } from "./types"; 2 | import { rules as ruleList } from "./utils/rules"; 3 | import base from "./configs/base"; 4 | import autoConfig from "./configs/auto-config"; 5 | import recommendedWithJson from "./configs/recommended-with-json"; 6 | import recommendedWithJsonc from "./configs/recommended-with-jsonc"; 7 | import recommendedWithJson5 from "./configs/recommended-with-json5"; 8 | import prettier from "./configs/prettier"; 9 | import all from "./configs/all"; 10 | import flatBase from "./configs/flat/base"; 11 | import flatRecommendedWithJson from "./configs/flat/recommended-with-json"; 12 | import flatRecommendedWithJsonc from "./configs/flat/recommended-with-jsonc"; 13 | import flatRecommendedWithJson5 from "./configs/flat/recommended-with-json5"; 14 | import flatPrettier from "./configs/flat/prettier"; 15 | import flatAll from "./configs/flat/all"; 16 | import * as meta from "./meta"; 17 | 18 | import { 19 | parseForESLint, 20 | parseJSON, 21 | traverseNodes, 22 | AST, 23 | getStaticJSONValue, 24 | } from "jsonc-eslint-parser"; 25 | 26 | const configs = { 27 | base, 28 | "auto-config": autoConfig, 29 | "recommended-with-json": recommendedWithJson, 30 | "recommended-with-jsonc": recommendedWithJsonc, 31 | "recommended-with-json5": recommendedWithJson5, 32 | prettier, 33 | all, 34 | "flat/base": flatBase, 35 | "flat/recommended-with-json": flatRecommendedWithJson, 36 | "flat/recommended-with-jsonc": flatRecommendedWithJsonc, 37 | "flat/recommended-with-json5": flatRecommendedWithJson5, 38 | "flat/prettier": flatPrettier, 39 | "flat/all": flatAll, 40 | }; 41 | 42 | const rules = ruleList.reduce( 43 | (obj, r) => { 44 | obj[r.meta.docs.ruleName] = r; 45 | return obj; 46 | }, 47 | {} as { [key: string]: RuleModule }, 48 | ); 49 | 50 | export default { 51 | meta, 52 | configs, 53 | rules, 54 | 55 | // backward compatibility 56 | parseForESLint, 57 | parseJSON, 58 | traverseNodes, 59 | getStaticJSONValue, 60 | }; 61 | export { 62 | meta, 63 | configs, 64 | rules, 65 | // types 66 | AST, 67 | 68 | // backward compatibility 69 | parseForESLint, 70 | parseJSON, 71 | traverseNodes, 72 | getStaticJSONValue, 73 | }; 74 | -------------------------------------------------------------------------------- /lib/utils/get-auto-jsonc-rules-config/should-use-flat-config.ts: -------------------------------------------------------------------------------- 1 | /** copied from https://github.com/eslint/eslint/blob/v8.56.0/lib/eslint/flat-eslint.js#L1119 */ 2 | 3 | import path from "path"; 4 | import fs from "fs"; 5 | 6 | const FLAT_CONFIG_FILENAMES = [ 7 | "eslint.config.js", 8 | "eslint.config.mjs", 9 | "eslint.config.cjs", 10 | ]; 11 | /** 12 | * Returns whether flat config should be used. 13 | * @returns {Promise} Whether flat config should be used. 14 | */ 15 | export function shouldUseFlatConfig(cwd: string): boolean { 16 | // eslint-disable-next-line no-process-env -- ignore 17 | switch (process.env.ESLINT_USE_FLAT_CONFIG) { 18 | case "true": 19 | return true; 20 | case "false": 21 | return false; 22 | default: 23 | // If neither explicitly enabled nor disabled, then use the presence 24 | // of a flat config file to determine enablement. 25 | return Boolean(findFlatConfigFile(cwd)); 26 | } 27 | } 28 | 29 | /** 30 | * Searches from the current working directory up until finding the 31 | * given flat config filename. 32 | * @param {string} cwd The current working directory to search from. 33 | * @returns {string|undefined} The filename if found or `undefined` if not. 34 | */ 35 | function findFlatConfigFile(cwd: string) { 36 | return findUp(FLAT_CONFIG_FILENAMES, { cwd }); 37 | } 38 | 39 | /** We used https://github.com/sindresorhus/find-up/blob/b733bb70d3aa21b22fa011be8089110d467c317f/index.js#L94 as a reference */ 40 | function findUp(names: string[], options: { cwd: string }) { 41 | let directory = path.resolve(options.cwd); 42 | const { root } = path.parse(directory); 43 | const stopAt = path.resolve(directory, root); 44 | 45 | while (true) { 46 | for (const name of names) { 47 | const target = path.resolve(directory, name); 48 | const stat = fs.existsSync(target) 49 | ? fs.statSync(target, { 50 | throwIfNoEntry: false, 51 | }) 52 | : null; 53 | if (stat?.isFile()) { 54 | return target; 55 | } 56 | } 57 | 58 | if (directory === stopAt) { 59 | break; 60 | } 61 | 62 | directory = path.dirname(directory); 63 | } 64 | 65 | return null; 66 | } 67 | -------------------------------------------------------------------------------- /docs/rules/object-property-newline.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/object-property-newline" 5 | description: "enforce placing object properties on separate lines" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/object-property-newline 10 | 11 | > enforce placing object properties on separate lines 12 | 13 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 14 | 15 | ## :book: Rule Details 16 | 17 | This rule permits you to restrict the locations of property specifications in object literals. You may prohibit any part of any property specification from appearing on the same line as any part of any other property specification. You may make this prohibition absolute, or, by invoking an object option, you may allow an exception, permitting an object literal to have all parts of all of its property specifications on a single line. 18 | 19 | 20 | 21 | 22 | 23 | ```json5 24 | /* eslint jsonc/object-property-newline: 'error' */ 25 | { 26 | /* ✓ GOOD */ 27 | "GOOD": { 28 | "foo": "foo", 29 | "bar": "bar", 30 | "baz": "baz" 31 | }, 32 | 33 | /* ✗ BAD */ 34 | "BAD": { 35 | "foo": "foo", "bar": "bar", "baz": "baz" 36 | } 37 | } 38 | ``` 39 | 40 | 41 | 42 | ## :wrench: Options 43 | 44 | Same as [object-property-newline] rule option. See [here](https://eslint.org/docs/rules/object-property-newline#optional-exception) for details. 45 | 46 | ## :couple: Related rules 47 | 48 | - [object-property-newline] 49 | 50 | [object-property-newline]: https://eslint.org/docs/rules/object-property-newline 51 | 52 | ## :rocket: Version 53 | 54 | This rule was introduced in eslint-plugin-jsonc v0.1.0 55 | 56 | ## :mag: Implementation 57 | 58 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/object-property-newline.ts) 59 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/object-property-newline.ts) 60 | 61 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/object-property-newline) 62 | -------------------------------------------------------------------------------- /tests/lib/configs/recommended-with-json.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import plugin from "../../../lib/index"; 3 | import { LegacyESLint, ESLint } from "../test-lib/eslint-compat"; 4 | 5 | const code = `{ foo: 42 }`; 6 | describe("`recommended-with-json` config", () => { 7 | it("legacy `recommended-with-json` config should work. ", async () => { 8 | const linter = new LegacyESLint({ 9 | plugins: { 10 | svelte: plugin as never, 11 | }, 12 | baseConfig: { 13 | parserOptions: { 14 | ecmaVersion: 2020, 15 | }, 16 | extends: ["plugin:jsonc/recommended-with-json"], 17 | }, 18 | useEslintrc: false, 19 | }); 20 | const result = await linter.lintText(code, { filePath: "test.json" }); 21 | const messages = result[0].messages; 22 | 23 | assert.deepStrictEqual( 24 | messages.map((m) => ({ 25 | ruleId: m.ruleId, 26 | line: m.line, 27 | message: m.message, 28 | })), 29 | [ 30 | { 31 | message: "Unquoted property 'foo' found.", 32 | ruleId: "jsonc/quote-props", 33 | line: 1, 34 | }, 35 | ], 36 | ); 37 | }); 38 | it("`flat/recommended-with-json` config should work. ", async () => { 39 | const linter = new ESLint({ 40 | overrideConfigFile: true as never, 41 | overrideConfig: plugin.configs["flat/recommended-with-json"] as never, 42 | }); 43 | const result = await linter.lintText(code, { filePath: "test.json" }); 44 | const messages = result[0].messages; 45 | 46 | assert.deepStrictEqual( 47 | messages.map((m) => ({ 48 | ruleId: m.ruleId, 49 | line: m.line, 50 | message: m.message, 51 | })), 52 | [ 53 | { 54 | message: "Unquoted property 'foo' found.", 55 | ruleId: "jsonc/quote-props", 56 | line: 1, 57 | }, 58 | ], 59 | ); 60 | 61 | const resultWithJs = await linter.lintText(";", { filePath: "test.js" }); 62 | const messagesWithJs = resultWithJs[0].messages; 63 | 64 | assert.deepStrictEqual( 65 | messagesWithJs.map((m) => ({ 66 | ruleId: m.ruleId, 67 | line: m.line, 68 | message: m.message, 69 | })), 70 | [], 71 | ); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /docs/rules/valid-json-number.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/valid-json-number" 5 | description: "disallow invalid number for JSON" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/valid-json-number 10 | 11 | > disallow invalid number for JSON 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule reports numbers that cannot be parsed with JSON. 19 | 20 | 21 | 22 | 23 | 24 | ```json5 25 | /* eslint jsonc/valid-json-number: 'error' */ 26 | { 27 | /* ✓ GOOD */ 28 | "GOOD": [123, 0.4, -42], 29 | 30 | /* ✗ BAD */ 31 | "BAD": [123., .4, +42, Infinity, NaN] 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## :wrench: Options 38 | 39 | Nothing. 40 | 41 | ## :couple: Related rules 42 | 43 | - [jsonc/no-binary-numeric-literals] 44 | - [jsonc/no-floating-decimal] 45 | - [jsonc/no-hexadecimal-numeric-literals] 46 | - [jsonc/no-infinity] 47 | - [jsonc/no-nan] 48 | - [jsonc/no-numeric-separators] 49 | - [jsonc/no-octal-numeric-literals] 50 | - [jsonc/no-octal] 51 | - [jsonc/no-plus-sign] 52 | - [jsonc/space-unary-ops] 53 | 54 | [jsonc/no-binary-numeric-literals]: ./no-binary-numeric-literals.md 55 | [jsonc/no-floating-decimal]: ./no-floating-decimal.md 56 | [jsonc/no-hexadecimal-numeric-literals]: ./no-hexadecimal-numeric-literals.md 57 | [jsonc/no-infinity]: ./no-infinity.md 58 | [jsonc/no-nan]: ./no-nan.md 59 | [jsonc/no-numeric-separators]: ./no-numeric-separators.md 60 | [jsonc/no-octal-numeric-literals]: ./no-octal-numeric-literals.md 61 | [jsonc/no-octal]: ./no-octal.md 62 | [jsonc/no-plus-sign]: ./no-plus-sign.md 63 | [jsonc/space-unary-ops]: ./space-unary-ops.md 64 | 65 | ## :rocket: Version 66 | 67 | This rule was introduced in eslint-plugin-jsonc v0.1.0 68 | 69 | ## :mag: Implementation 70 | 71 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/valid-json-number.ts) 72 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/valid-json-number.ts) 73 | -------------------------------------------------------------------------------- /docs/rules/quotes.md: -------------------------------------------------------------------------------- 1 | --- 2 | pageClass: "rule-details" 3 | sidebarDepth: 0 4 | title: "jsonc/quotes" 5 | description: "enforce use of double or single quotes" 6 | since: "v0.1.0" 7 | --- 8 | 9 | # jsonc/quotes 10 | 11 | > enforce use of double or single quotes 12 | 13 | - :gear: This rule is included in `"plugin:jsonc/recommended-with-json"` and `"plugin:jsonc/recommended-with-jsonc"`. 14 | - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. 15 | 16 | ## :book: Rule Details 17 | 18 | This rule enforces the use of double or single quotes. 19 | 20 | JSON5 allows you to define a string in one of two ways: double quotes or single quotes. 21 | However, JSON and JSONC can only use double quotes. 22 | 23 | 24 | 25 | 26 | 27 | ```json5 28 | /* eslint jsonc/quotes: 'error' */ 29 | { 30 | /* ✓ GOOD */ 31 | "GOOD": "foo", 32 | 33 | /* ✗ BAD */ 34 | 'BAD': 'bar' 35 | } 36 | ``` 37 | 38 | 39 | 40 | ## :wrench: Options 41 | 42 | ```json 43 | { 44 | "jsonc/quotes": ["error", 45 | "double", 46 | {"avoidEscape": false} 47 | ] 48 | } 49 | ``` 50 | 51 | This rule has two options, a string option and an object option. 52 | 53 | String option: 54 | 55 | - `"double"` (default) ... requires the use of double quotes wherever possible 56 | - `"single"` ... requires the use of single quotes wherever possible 57 | 58 | Object option: 59 | 60 | - `"avoidEscape"` ... if `true`, allows strings to use single-quotes or double-quotes so long as the string contains a quote that would have to be escaped otherwise. default `false` 61 | 62 | See [here](https://eslint.org/docs/rules/quotes#options) for details. 63 | 64 | ## :couple: Related rules 65 | 66 | - [quotes] 67 | 68 | [quotes]: https://eslint.org/docs/rules/quotes 69 | 70 | ## :rocket: Version 71 | 72 | This rule was introduced in eslint-plugin-jsonc v0.1.0 73 | 74 | ## :mag: Implementation 75 | 76 | - [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/quotes.ts) 77 | - [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/quotes.ts) 78 | 79 | Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/quotes) 80 | -------------------------------------------------------------------------------- /tests/lib/rules/no-parenthesized.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "../test-lib/tester"; 2 | import rule from "../../../lib/rules/no-parenthesized"; 3 | import * as jsonParser from "jsonc-eslint-parser"; 4 | 5 | const tester = new RuleTester({ 6 | languageOptions: { 7 | parser: jsonParser, 8 | ecmaVersion: 2020, 9 | }, 10 | ignoreMomoa: true, 11 | }); 12 | 13 | tester.run("no-parenthesized", rule, { 14 | valid: ["{42: 42}", "42", "[42]"], 15 | invalid: [ 16 | { 17 | code: `[(42), {key: (42)}]`, 18 | output: `[42, {key: 42}]`, 19 | errors: [ 20 | { 21 | message: "Parentheses around expression should not be used.", 22 | line: 1, 23 | column: 2, 24 | }, 25 | { 26 | message: "Parentheses around expression should not be used.", 27 | line: 1, 28 | column: 5, 29 | }, 30 | { 31 | message: "Parentheses around expression should not be used.", 32 | line: 1, 33 | column: 14, 34 | }, 35 | { 36 | message: "Parentheses around expression should not be used.", 37 | line: 1, 38 | column: 17, 39 | }, 40 | ], 41 | }, 42 | { 43 | code: `(42)`, 44 | output: `42`, 45 | errors: [ 46 | { 47 | message: "Parentheses around expression should not be used.", 48 | line: 1, 49 | column: 1, 50 | }, 51 | { 52 | message: "Parentheses around expression should not be used.", 53 | line: 1, 54 | column: 4, 55 | }, 56 | ], 57 | }, 58 | { 59 | code: `[-(42), 42 + (42 - 3)]`, 60 | output: null, 61 | errors: [ 62 | { 63 | message: "Parentheses around expression should not be used.", 64 | line: 1, 65 | column: 3, 66 | }, 67 | { 68 | message: "Parentheses around expression should not be used.", 69 | line: 1, 70 | column: 6, 71 | }, 72 | { 73 | message: "Parentheses around expression should not be used.", 74 | line: 1, 75 | column: 14, 76 | }, 77 | { 78 | message: "Parentheses around expression should not be used.", 79 | line: 1, 80 | column: 21, 81 | }, 82 | ], 83 | }, 84 | ], 85 | }); 86 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/eslint-code-block.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 101 | -------------------------------------------------------------------------------- /tests-integrations/lib/eslint-plugin-markdown-nest-for-v6.ts: -------------------------------------------------------------------------------- 1 | import cp from "child_process"; 2 | import assert from "assert"; 3 | import path from "path"; 4 | import { version } from "../../package.json"; 5 | import type { ESLint } from "eslint"; 6 | 7 | // ----------------------------------------------------------------------------- 8 | // Tests 9 | // ----------------------------------------------------------------------------- 10 | 11 | const TEST_CWD = path.join( 12 | __dirname, 13 | "../fixtures/eslint-plugin-markdown-nest-for-v6", 14 | ); 15 | const ESLINT = path.join(TEST_CWD, `./node_modules/.bin/eslint`); 16 | 17 | describe("Integration with eslint-plugin-markdown with nesting config with eslint v6", () => { 18 | let originalCwd: string; 19 | 20 | before(() => { 21 | originalCwd = process.cwd(); 22 | // To test ESLint v6, remove `@eslint/eslintrc` module in the root. 23 | cp.execSync(`npx rimraf node_modules/@eslint/eslintrc`, { 24 | stdio: "inherit", 25 | }); 26 | 27 | process.chdir(TEST_CWD); 28 | cp.execSync(`npm i -D ../../../eslint-plugin-jsonc-${version}.tgz`, { 29 | stdio: "inherit", 30 | }); 31 | cp.execSync("npm i", { stdio: "inherit" }); 32 | }); 33 | after(() => { 34 | process.chdir(originalCwd); 35 | 36 | // `npm install` to get the removed module back. 37 | cp.execSync(`npm i`, { 38 | stdio: "inherit", 39 | }); 40 | }); 41 | 42 | it(`should lint errors`, () => { 43 | try { 44 | const res = cp.execSync( 45 | `${ESLINT} "./test.md" --format json --ext .md,.json`, 46 | { 47 | env: { 48 | // eslint-disable-next-line no-process-env -- Legacy Config test 49 | ...process.env, 50 | ESLINT_USE_FLAT_CONFIG: "false", 51 | }, 52 | }, 53 | ); 54 | console.log(`${res}`); 55 | } catch (e: any) { 56 | const results: ESLint.LintResult[] = JSON.parse(`${e.stdout}`); 57 | assert.deepStrictEqual( 58 | results[0].messages.map((message) => ({ 59 | message: message.message, 60 | ruleId: message.ruleId, 61 | line: message.line, 62 | })), 63 | [ 64 | { 65 | message: "Strings must use doublequote.", 66 | ruleId: "jsonc/quotes", 67 | line: 3, 68 | }, 69 | ], 70 | ); 71 | return; 72 | } 73 | assert.fail("Expect error"); 74 | }); 75 | }); 76 | --------------------------------------------------------------------------------