Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Bug: TypeError: Error while loading rule 'no-irregular-whitespace': sourceCode.getAllComments is not a function #56

Closed
1 task done
adamlui opened this issue Nov 11, 2024 · 7 comments
Labels
bug Something isn't working repro:yes Issues with a reproducible example wontfix This will not be worked on

Comments

@adamlui
Copy link

adamlui commented Nov 11, 2024

Environment

ESLint version: v9.14.0
@eslint/json version: v0.6.0
Node version: v22.9.0
npm version: v10.9.0
Operating System: Win10

Which language are you using?

json

What did you do?

Configuration
import js from '@eslint/js'
import globals from 'globals'
import json from '@eslint/json'

export default [
    js.configs.recommended,
    { ignores: ['**/*.min.js', '**/sandbox/*'] },
    {
        rules: {
            'indent': 'off', 'no-unexpected-multiline': 'off', 'key-spacing': 'off', // allow whitespace anywhere
            'quotes': ['error', 'single', { 'allowTemplateLiterals': true }], // enforce single quotes except backticks to avoid escaping quotes
            'comma-dangle': ['error', 'never'], // enforce no trailing commas in arrays or objects
            'no-async-promise-executor': 'off', // allow promise executor functions to be async (to accomodate await lines)
            'no-constant-condition': 'off', // allow constant conditions
            'no-empty': 'off', // allow empty blocks
            'no-inner-declarations': 'off', // allow function declarations anywhere
            'no-useless-escape': 'off', // allow all escape chars cause ESLint sucks at detecting truly useless ones
            'no-unused-vars': ['error', { 'caughtErrors': 'none' }] // allow unused named args in catch blocks
        },
        languageOptions: {
            ecmaVersion: 'latest', sourceType: 'script',
            globals: { ...globals.browser, ...globals.node }
        }
    },
    { files: ['**/*.mjs'], languageOptions: { sourceType: 'module' }},
    { files: ['**/*.json'], ignores: ['**/package-lock.json'], language: 'json/json', ...json.configs.recommended }
]
{
  "name": "generate-ip",
  "version": "2.4.3",
  "description": "Randomly generate, format, and validate IPv4 + IPv6 + MAC addresses.",
  "author": {
    "name": "Adam Lui",
    "email": "[email protected]",
    "url": "https://github.com/adamlui"
  },
  "homepage": "https://generate-ip.org",
  "license": "MIT",
  "funding": [
    {
      "type": "github",
      "url": "http://github.com/sponsors/adamlui"
    },
    {
      "type": "ko-fi",
      "url": "https://ko-fi.com/adamlui"
    }
  ],
  "main": "dist/generate-ip.min.js",
  "files": [
    "docs"
  ],
  "directories": {
    "bin": "./bin",
    "lib": "./dist",
    "doc": "./docs"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "bash utils/build.sh",
    "bump:patch": "bash utils/bump.sh patch",
    "bump:minor": "bash utils/bump.sh minor",
    "bump:major": "bash utils/bump.sh major",
    "publish:patch": "bash utils/bump.sh patch --publish",
    "publish:minor": "bash utils/bump.sh minor --publish",
    "publish:major": "bash utils/bump.sh major --publish"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/adamlui/js-utils.git"
  },
  "keywords": [
    "ip",
    "generator",
    "unique",
    "generate",
    "api",
    "cli",
    "address",
    "ipv4",
    "ipv6",
    "mac"
  ],
  "bugs": {
    "url": "https://js-utils.org/issues"
  },
  "devDependencies": {
    "@adamlui/minify.js": "^1.8.5"
  }
}

What did you expect to happen?

Lint the package.json

What actually happened?

Oops! Something went wrong! :(

ESLint: 9.14.0

TypeError: Error while loading rule 'no-irregular-whitespace': sourceCode.getAllComments is not a function
Occurred while linting e:\js\utils\generate-ip\package.json
    at Object.create (e:\js\utils\node_modules\eslint\lib\rules\no-irregular-whitespace.js:87:41)
    at createRuleListeners (e:\js\utils\node_modules\eslint\lib\linter\linter.js:943:21)
    at e:\js\utils\node_modules\eslint\lib\linter\linter.js:1068:84
    at Array.forEach (<anonymous>)
    at runRules (e:\js\utils\node_modules\eslint\lib\linter\linter.js:999:34)
    at #flatVerifyWithoutProcessors (e:\js\utils\node_modules\eslint\lib\linter\linter.js:1911:31)
    at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (e:\js\utils\node_modules\eslint\lib\linter\linter.js:1992:49)
    at Linter._verifyWithFlatConfigArray (e:\js\utils\node_modules\eslint\lib\linter\linter.js:2081:21)
    at Linter.verify (e:\js\utils\node_modules\eslint\lib\linter\linter.js:1528:61)
    at Linter.verifyAndFix (e:\js\utils\node_modules\eslint\lib\linter\linter.js:2319:29)

Oops! Something went wrong! :(

ESLint: 9.14.0

AbortError: The operation was aborted
    at checkAborted (node:internal/fs/promises:473:11)
    at Object.readFile (node:internal/fs/promises:1236:3)
    at retrier.retry.signal (e:\js\utils\node_modules\eslint\lib\eslint\eslint.js:803:47)
    at #call (e:\js\utils\node_modules\@humanwhocodes\retry\dist\retrier.cjs:298:22)
    at e:\js\utils\node_modules\@humanwhocodes\retry\dist\retrier.cjs:360:44
    at #processPending (e:\js\utils\node_modules\@humanwhocodes\retry\dist\retrier.cjs:399:19)
    at e:\js\utils\node_modules\@humanwhocodes\retry\dist\retrier.cjs:313:33
    at <anonymous>

Oops! Something went wrong! :(

ESLint: 9.14.0

AbortError: The operation was aborted
    at checkAborted (node:internal/fs/promises:473:11)
    at readFileHandle (node:internal/fs/promises:516:3)
    at Object.readFile (node:internal/fs/promises:1239:24)

Link to Minimal Reproducible Example

https://github.com/adamlui/js-utils

Participation

  • I am willing to submit a pull request for this issue.

Additional comments

Just testing to replace 3rd-party eslint-plugin-json which hums along but this one immediately crashes.

Using npm run lint:all to run eslint .

@adamlui adamlui added bug Something isn't working repro:needed This issue should include a reproducible example labels Nov 11, 2024
@adamlui adamlui changed the title TypeError: Error while loading rule 'no-irregular-whitespace': sourceCode.getAllComments is not a function Bug: TypeError: Error while loading rule 'no-irregular-whitespace': sourceCode.getAllComments is not a function Nov 11, 2024
@adamlui
Copy link
Author

adamlui commented Nov 11, 2024

I temporarily added rules: { 'no-irregular-whitespace': 'off' } to the config to bypass error until the bug is patched

@fasttime fasttime added this to Triage Nov 11, 2024
@github-project-automation github-project-automation bot moved this to Needs Triage in Triage Nov 11, 2024
@fasttime fasttime moved this from Needs Triage to Triaging in Triage Nov 11, 2024
@fasttime fasttime added wontfix This will not be worked on repro:yes Issues with a reproducible example and removed repro:needed This issue should include a reproducible example labels Nov 11, 2024
@fasttime
Copy link
Member

Thanks for the issue @adamlui, I am able to reproduce the error. The problem is that your conifg is applying JavaScript-only rules to JSON files, which is not an expected use case. Note that the recommended config in @eslint/json should be used in conjunction with files (see the usage examples), and so should the third config object in your config file, since it configures JavaScript rules and language options.

Config objects that don't include files will apply to all files matched by the whole config, including JSON files (!) in your specific case.

Here's an updated version of your config file that fixes the error by ensuring that JavaScript rules only apply to files with the extension .js or .mjs:

import js from '@eslint/js'
import globals from 'globals'
import json from '@eslint/json'

export default [
-   js.configs.recommended,
+   {
+       files: ['**/*.js', '**/*.mjs'],
+       ...js.configs.recommended
+   },
    { ignores: ['**/*.min.js', '**/sandbox/*'] },
    {
+       files: ['**/*.js', '**/*.mjs'],
        rules: {
            'indent': 'off', 'no-unexpected-multiline': 'off', 'key-spacing': 'off', // allow whitespace anywhere
            'quotes': ['error', 'single', { 'allowTemplateLiterals': true }], // enforce single quotes except backticks to avoid escaping quotes
            'comma-dangle': ['error', 'never'], // enforce no trailing commas in arrays or objects
            'no-async-promise-executor': 'off', // allow promise executor functions to be async (to accomodate await lines)
            'no-constant-condition': 'off', // allow constant conditions
            'no-empty': 'off', // allow empty blocks
            'no-inner-declarations': 'off', // allow function declarations anywhere
            'no-useless-escape': 'off', // allow all escape chars cause ESLint sucks at detecting truly useless ones
            'no-unused-vars': ['error', { 'caughtErrors': 'none' }] // allow unused named args in catch blocks
        },
        languageOptions: {
            ecmaVersion: 'latest', sourceType: 'script',
            globals: { ...globals.browser, ...globals.node }
        }
    },
    { files: ['**/*.mjs'], languageOptions: { sourceType: 'module' }},
    { files: ['**/*.json'], ignores: ['**/package-lock.json'], language: 'json/json', ...json.configs.recommended }
]

For more information about targeting specific files, see the configuration files documentation.

@fasttime fasttime closed this as not planned Won't fix, can't repro, duplicate, stale Nov 11, 2024
@github-project-automation github-project-automation bot moved this from Triaging to Complete in Triage Nov 11, 2024
@adamlui
Copy link
Author

adamlui commented Nov 11, 2024

Thanks @fasttime it works like this!

import js from '@eslint/js'
import globals from 'globals'
import json from '@eslint/json'
import markdown from '@eslint/markdown'

export default [
    ...markdown.configs.recommended,
    { ignores: ['**/*.min.js', '**/sandbox/*'] },
    {
        files: ['**/*.js', '**/*.mjs'], ...js.configs.recommended,
        rules: {
            'indent': 'off', 'no-unexpected-multiline': 'off', 'key-spacing': 'off', // allow whitespace anywhere
            'quotes': ['error', 'single', { 'allowTemplateLiterals': true }], // enforce single quotes except backticks to avoid escaping quotes
            'comma-dangle': ['error', 'never'], // enforce no trailing commas in arrays or objects
            'no-async-promise-executor': 'off', // allow promise executor functions to be async (to accomodate await lines)
            'no-constant-condition': 'off', // allow constant conditions
            'no-empty': 'off', // allow empty blocks
            'no-inner-declarations': 'off', // allow function declarations anywhere
            'no-useless-escape': 'off', // allow all escape chars cause ESLint sucks at detecting truly useless ones
            'no-unused-vars': ['error', { 'caughtErrors': 'none' }] // allow unused named args in catch blocks
        },
        languageOptions: {
            ecmaVersion: 'latest', sourceType: 'script',
            globals: { ...globals.browser, ...globals.node }
        }
    },
    { files: ['**/*.mjs'], languageOptions: { sourceType: 'module' }},
    { files: ['**/*.json'], ignores: ['**/package-lock.json'], language: 'json/json', ...json.configs.recommended },
    {
        files: ['**/*.md'],
        rules: {
            'markdown/heading-increment': 'off', // allow headings to skip levels
            'markdown/fenced-code-language': 'off' // allow code blocks w/ no language specified
        }
    }
]

However, when I try to move ...markdown.configs.recommended into the MD block (exactly like the working move of ...js.configs.recommended into JS block):

import js from '@eslint/js'
import globals from 'globals'
import json from '@eslint/json'
import markdown from '@eslint/markdown'

export default [
-   ...markdown.configs.recommended,
    { ignores: ['**/*.min.js', '**/sandbox/*'] },
    {
        files: ['**/*.js', '**/*.mjs'], ...js.configs.recommended,
        rules: {
            'indent': 'off', 'no-unexpected-multiline': 'off', 'key-spacing': 'off', // allow whitespace anywhere
            'quotes': ['error', 'single', { 'allowTemplateLiterals': true }], // enforce single quotes except backticks to avoid escaping quotes
            'comma-dangle': ['error', 'never'], // enforce no trailing commas in arrays or objects
            'no-async-promise-executor': 'off', // allow promise executor functions to be async (to accomodate await lines)
            'no-constant-condition': 'off', // allow constant conditions
            'no-empty': 'off', // allow empty blocks
            'no-inner-declarations': 'off', // allow function declarations anywhere
            'no-useless-escape': 'off', // allow all escape chars cause ESLint sucks at detecting truly useless ones
            'no-unused-vars': ['error', { 'caughtErrors': 'none' }] // allow unused named args in catch blocks
        },
        languageOptions: {
            ecmaVersion: 'latest', sourceType: 'script',
            globals: { ...globals.browser, ...globals.node }
        }
    },
    { files: ['**/*.mjs'], languageOptions: { sourceType: 'module' }},
    { files: ['**/*.json'], ignores: ['**/package-lock.json'], language: 'json/json', ...json.configs.recommended },
    {
-       files: ['**/*.md'],
+       files: ['**/*.md'], ...markdown.configs.recommended,
        rules: {
            'markdown/heading-increment': 'off', // allow headings to skip levels
            'markdown/fenced-code-language': 'off' // allow code blocks w/ no language specified
        }
    }
]

I get this error:

Oops! Something went wrong! :(

ESLint: 9.14.0

ConfigError: Config (unnamed): Unexpected key "0" found.
    at rethrowConfigError (e:\js\utils\node_modules\@eslint\config-array\dist\cjs\index.cjs:303:8)
    at e:\js\utils\node_modules\@eslint\config-array\dist\cjs\index.cjs:1098:5
    at Array.reduce (<anonymous>)
    at FlatConfigArray.getConfigWithStatus (e:\js\utils\node_modules\@eslint\config-array\dist\cjs\index.cjs:1091:43)
    at FlatConfigArray.getConfig (e:\js\utils\node_modules\@eslint\config-array\dist\cjs\index.cjs:1120:15)
    at entryFilter (e:\js\utils\node_modules\eslint\lib\eslint\eslint-helpers.js:286:40)
    at async NodeHfs.<anonymous> (file:///e:/js/utils/node_modules/@humanfs/core/src/hfs.js:574:24)
    at async NodeHfs.<anonymous> (file:///e:/js/utils/node_modules/@humanfs/core/src/hfs.js:604:6)
    at async NodeHfs.walk (file:///e:/js/utils/node_modules/@humanfs/core/src/hfs.js:614:3)
    at async globSearch (e:\js\utils\node_modules\eslint\lib\eslint\eslint-helpers.js:327:26)

Do you know why? Also it's interesting https://github.com/eslint/markdown?tab=readme-ov-file#configurations advises adding to top like

...
export default [
    ...markdown.configs.recommended
...

... yet the JS recommended obj didn't require destructuring in the working original config:

...
export default [
   js.configs.recommended
...

@fasttime
Copy link
Member

I double-checked the code and the recommended @eslint/markdown config is actually defined as an array with a single object and it's already restricted to .md files:

plugin.configs.recommended = [
	/** @type {Config & {language:string}} */
	({
		name: "markdown/recommended",
		files: ["**/*.md"],
		language: "markdown/commonmark",
		plugins: {
			markdown: plugin,
		},
		rules: /** @type {RulesRecord} */ (recommendedRules),
	}),
];

From https://github.com/eslint/markdown/blob/05196f59dd1d22e7bcc98ee5e5b857e69807a5ce/src/index.js#L94-L105

In this case, it is fine to use the spread syntax at the outer level:

    ...markdown.configs.recommended,
    {
        files: ['**/*.md'],
        rules: {
            'markdown/heading-increment': 'off', // allow headings to skip levels
            'markdown/fenced-code-language': 'off' // allow code blocks w/ no language specified
        }
    }

I agree that this inconsistency is confusing, because you have to check the docs every time to know how to include a config. On the other hand the @eslint/js plugin is a special case because JavaScript is the default language of built-in rules. When the built-in rules will be moved into @eslint/js, the exported configs of that plugin will have the same structure as the configs exported by @eslint/markdown, as an array whose elements have a files property. Until then, I'd just stick with the syntax suggested in the docs.

@adamlui
Copy link
Author

adamlui commented Nov 11, 2024

I didn't get this:

When the built-in rules will be moved into @eslint/js, the exported configs of that plugin will have the same structure as the configs exported by @eslint/markdown, as an array whose elements have a files property

You mean it is in roadmap to make @eslint/js config same structure as @eslint/markdown such that the recommended object should be specified at outer level? If so that's bad, even the @eslint/json config is so intuitive:

...
    { files: ['**/*.json'], ignores: ['**/package-lock.json'], language: 'json/json', ...json.configs.recommended },
...

Also I think this is how most 3rd-party plugins sturcture it (including the eslint-json-plugin this replaced) so making @eslint/markdown that way too would be really good and make my configs (of which 30+ of my repos utilize) much more readable + easier to maintain

@adamlui
Copy link
Author

adamlui commented Nov 11, 2024

I just installed eslint-plugin-yml because the eslint-plugin-json that @eslint/json replaced linted YAML, and its example config is:

import eslintPluginYml from 'eslint-plugin-yml';
export default [
  // add more generic rule sets here, such as:
  // js.configs.recommended,
  ...eslintPluginYml.configs['flat/recommended'],
  {
    rules: {
      // override/add rules settings here, such as:
    // 'yml/rule-name': 'error'
    }
  }
];

...but because ...markdown.configs.recommended is also at the outer-level...

...
export default [
    ...markdown.configs.recommended, ...eslintPluginYml.configs['flat/standard'],
    {
        files: ['**/*.js', '**/*.mjs'], ...js.configs.recommended,
        rules: {
...

... I get a similar error as before:

Oops! Something went wrong! :(

ESLint: 9.14.0

TypeError: Error while loading rule 'yml/block-mapping-question-indicator-newline': Cannot read properties of undefined (reading 'defineCustomBlocksVisitor')
Occurred while linting e:\js\ai-apps\amazongpt\docs\PRIVACY.md
    at Object.create (e:\js\ai-apps\node_modules\eslint-plugin-yml\lib\utils\index.js:38:50)
    at createRuleListeners (e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:943:21)
    at e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:1068:84
    at Array.forEach (<anonymous>)
    at runRules (e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:999:34)
    at #flatVerifyWithoutProcessors (e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:1911:31)
    at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:1992:49)
    at Linter._verifyWithFlatConfigArray (e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:2081:21)
    at Linter.verify (e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:1528:61)
    at Linter.verifyAndFix (e:\js\ai-apps\node_modules\eslint\lib\linter\linter.js:2319:29)

Oops! Something went wrong! :(

ESLint: 9.14.0

AbortError: The operation was aborted

@fasttime
Copy link
Member

You mean it is in roadmap to make @eslint/js config same structure as @eslint/markdown such that the recommended object should be specified at outer level?

The details aren't settled yet, but if parts of the default config are moved into @eslint/js then we'll have to use an array because there will be at least two different configs for CommonJS files and ESM files respectively.

...
{ files: ['/*.json'], ignores: ['/package-lock.json'], language: 'json/json', ...json.configs.recommended },
...

Also I think this is how most 3rd-party plugins sturcture it (including the eslint-json-plugin this replaced) so making @eslint/markdown that way too would be really good and make my configs (of which 30+ of my repos utilize) much more readable + easier to maintain

We have a proposal to enable extends inside config objects at eslint/eslint#19116. That would make array-style configs easier to combine with other options (e.g. files). Since you have some experience in writing ESLint configs you may want to follow the discussion there and leave your feedback if necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working repro:yes Issues with a reproducible example wontfix This will not be worked on
Projects
Archived in project
Development

No branches or pull requests

2 participants