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

Formatting imports jumps between prettier formatting #91

Open
Nxt3 opened this issue Jan 23, 2023 · 17 comments
Open

Formatting imports jumps between prettier formatting #91

Nxt3 opened this issue Jan 23, 2023 · 17 comments
Labels
help wanted Extra attention is needed Q&A Questions due to information gaps and unclear documentations. No code fix needed.

Comments

@Nxt3
Copy link

Nxt3 commented Jan 23, 2023

Describe the bug
Auto Imports seems to be interfering with prettier formatting still. Might be related to #39

To Reproduce
Format this file:

import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';

// use the imports to avoid removal
console.log('HttpResponse', HttpResponse);
console.log('HttpParams', HttpParams);
console.log('HttpHeaders', HttpHeaders);
console.log('HttpErrorResponse', HttpErrorResponse);
console.log('HttpClient', HttpClient);

with following VS Code settings:

  "tsImportSorter.configuration.autoFormat": "off",
  "tsImportSorter.configuration.development.enableDebug": false,
  "tsImportSorter.configuration.wrappingStyle": "prettier",
  
  "[typescript]": {
    "editor.codeActionsOnSave": [
      "source.addMissingImports",
      "source.organizeImports.sortImports",
      "source.formatDocument",
      "source.fixAll.eslint"
    ]
  },

Expected behavior
TS Import sorter should allow prettier to handle the formatting for line length.

Actual behavior
Formatting for long lines jumps between formatted an unformatted.

Screenshots
import_formatting_issues

OS (please complete the following information):

  • OS: Mac
  • Version: v7.5.1

VS Code (please complete the following information):

Version: 1.72.0-insider (Universal)
Commit: 64bbfbf67ada9953918d72e1df2f4d8e537d340e
Date: 2022-10-04T23:18:32.134Z
Electron: 19.0.17
Chromium: 102.0.5005.167
Node.js: 16.14.2
V8: 10.2.154.15-electron.0
OS: Darwin arm64 21.6.0
Sandboxed: Yes

Installed VS Code extensions

rohit-gohri.format-code-action: https://github.com/rohit-gohri/vscode-format-code-action

.prettier.yml

tabWidth: 2
semi: true
singleQuote: true
printWidth: 100
trailingComma: none

.eslintrc.json

{
  "root": true,
  "ignorePatterns": [
    "projects/**/*",
    "!**/*.ts",
    "!**/*.html"
  ],
  "overrides": [
    {
      "files": [
        "*.ts"
      ],
      "parser": "@typescript-eslint/parser",
      "parserOptions": {
        "ecmaVersion": 2018,
        "project": [
          "tsconfig.json"
        ],
        "createDefaultProgram": false
      },
      "plugins": [
        "ban"
      ],
      "extends": [
        "plugin:@angular-eslint/recommended",
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking",
        "plugin:@angular-eslint/template/process-inline-templates",
        "plugin:@angular-eslint/recommended--extra"
      ],
      "rules": {
        "@angular-eslint/component-class-suffix": "error",
        "@angular-eslint/contextual-lifecycle": "warn",
        "@angular-eslint/directive-class-suffix": "error",
        "@angular-eslint/no-conflicting-lifecycle": "warn",
        "@angular-eslint/no-forward-ref": "off",
        "@angular-eslint/no-host-metadata-property": "warn",
        "@angular-eslint/no-input-rename": "warn",
        "@angular-eslint/no-output-native": "warn",
        "@angular-eslint/no-output-on-prefix": "warn",
        "@angular-eslint/no-output-rename": "error",
        "@angular-eslint/use-lifecycle-interface": "error",
        "@typescript-eslint/adjacent-overload-signatures": "warn",
        "@typescript-eslint/await-thenable": "warn",
        "@typescript-eslint/ban-ts-comment": "warn",
        "@typescript-eslint/ban-types": "warn",
        "@typescript-eslint/explicit-module-boundary-types": "off",
        "@typescript-eslint/indent": [
          "error",
          2
        ],
        "@typescript-eslint/member-ordering": "warn",
        "@typescript-eslint/naming-convention": [
          "error",
          {
            "selector": "class",
            "format": [
              "PascalCase"
            ]
          }
        ],
        "@typescript-eslint/no-empty-function": "error",
        "@typescript-eslint/no-empty-interface": "warn",
        "@typescript-eslint/no-explicit-any": "warn",
        "@typescript-eslint/no-floating-promises": "warn",
        "@typescript-eslint/no-inferrable-types": "off",
        "@typescript-eslint/no-misused-promises": "warn",
        "@typescript-eslint/no-namespace": "warn",
        "@typescript-eslint/no-shadow": "error",
        "@typescript-eslint/no-this-alias": "warn",
        "@typescript-eslint/no-unnecessary-type-assertion": "warn",
        "@typescript-eslint/no-unsafe-assignment": "warn",
        "@typescript-eslint/no-unsafe-call": "warn",
        "@typescript-eslint/no-unsafe-member-access": "warn",
        "@typescript-eslint/no-unsafe-return": "warn",
        "@typescript-eslint/no-use-before-define": [
          "warn",
          {
            "functions": false,
            "classes": false,
            "typedefs": true
          }
        ],
        "@typescript-eslint/no-var-requires": "warn",
        "@typescript-eslint/prefer-regexp-exec": "warn",
        "@typescript-eslint/require-await": "off",
        "@typescript-eslint/restrict-plus-operands": "warn",
        "@typescript-eslint/restrict-template-expressions": "warn",
        "@typescript-eslint/type-annotation-spacing": "error",
        "@typescript-eslint/unbound-method": "warn",
        "ban/ban": [
          "error",
          {
            "name": "fit",
            "message": "Don't keep jasmine focus methods"
          },
          {
            "name": "fdescribe",
            "message": "Don't keep jasmine focus methods"
          }
        ],
        "brace-style": [
          "error",
          "1tbs"
        ],
        "curly": "error",
        "eol-last": "error",
        "eqeqeq": [
          "error",
          "always",
          {
            "null": "ignore"
          }
        ],
        "getter-return": "warn",
        "id-blacklist": "off",
        "id-match": "off",
        "indent": "off",
        "keyword-spacing": "error",
        "max-len": [
          "error",
          {
            "ignorePattern": "^import [^,]+ from |^export | implements | ('|\")(http|https):",
            "code": 140
          }
        ],
        "no-bitwise": "error",
        "no-caller": "error",
        "no-console": "error",
        "no-debugger": "error",
        "no-duplicate-imports": "error",
        "no-empty": "error",
        "no-empty-pattern": "warn",
        "no-eval": "error",
        "no-extra-boolean-cast": "warn",
        "no-fallthrough": "warn",
        "no-irregular-whitespace": "error",
        "no-new-wrappers": "error",
        "no-prototype-builtins": "warn",
        "no-redeclare": "warn",
        "no-restricted-imports": [
          "error",
          {
            "paths": [
              {
                "name": "@synerg/components",
                "message": "Please specify full Synerg component path starting with @synerg/components/"
              },
              {
                "name": "rxjs/Rx",
                "message": "No import from rxjs/Rx"
              },
              {
                "name": "rxjs/src",
                "message": "No import from rxjs/src. Import from rxjs"
              },
              {
                "name": "rxjs/internal/operators",
                "message": "No import from rxjs/internal/operators. Import from rxjs/operators"
              },
              {
                "name": "rxjs/internal",
                "message": "No import from rxjs/internal. Import from rxjs"
              },
              {
                "name": "rxjs/index",
                "message": "No import from rxjs/index. Import from rxjs"
              },
              {
                "name": "node_modules",
                "message": "No import from node_modules"
              }
            ],
            "patterns": ["rxjs/internal/*"]
          }
        ],
        "no-trailing-spaces": "error",
        "no-underscore-dangle": "off",
        "no-unused-expressions": "warn",
        "no-unused-vars": [
          "error",
          {
            "argsIgnorePattern": "^_"
          }
        ],
        "no-useless-escape": "warn",
        "no-var": "warn",
        "object-curly-spacing": [
          "error",
          "always"
        ],
        "prefer-const": "warn",
        "prefer-rest-params": "warn",
        "semi-spacing": "error",
        "quotes": [
          "error",
          "single",
          {
            "allowTemplateLiterals": true,
            "avoidEscape": true
          }
        ],
        "semi": "error",
        "semi-style": [
          "error",
          "last"
        ],
        "space-before-function-paren": [
          "error",
          {
            "anonymous": "never",
            "named": "never",
            "asyncArrow": "always"
          }
        ],
        "space-in-parens": "error",
        "spaced-comment": "error"
      }
    },
    {
      "files": [
        "*.html"
      ],
      "extends": [
        "plugin:@angular-eslint/template/recommended"
      ],
      "parser": "@angular-eslint/template-parser",
      "rules": {
        "@angular-eslint/template/no-negated-async": "warn",
        "@angular-eslint/template/eqeqeq": "warn"
      }
    }
  ]
}
@daidodo
Copy link
Owner

daidodo commented Jan 26, 2023

Thanks for the feedback!

You can set line wrapping style to be compatible with Prettier. More details: https://github.com/daidodo/format-imports/wiki/Line-Wrapping-Style#prettier-compatibility

Please tell me if you still have questions.

@daidodo daidodo added the Q&A Questions due to information gaps and unclear documentations. No code fix needed. label Jan 26, 2023
@Nxt3
Copy link
Author

Nxt3 commented Jan 26, 2023

I already have this setting enabled: "tsImportSorter.configuration.wrappingStyle": "prettier" and it doesn't seem to fix the problem. Can there be a setting to only sort/organize? Having this extension also handle formatting seems more problematic than it's worth given it can easily conflict with external formatting tools.

@Nxt3
Copy link
Author

Nxt3 commented Jan 26, 2023

The correct output should be having those imports split across several lines. If I disable this extension and let prettier handle formatting, the code is formatted properly.

If I disable prettier and let this extension format the code, the output is incorrect with all of the imports on a single line, even with "tsImportSorter.configuration.wrappingStyle": "prettier"

Disabling eslint has no effect on the formatting.

@daidodo daidodo added the help wanted Extra attention is needed label Feb 4, 2023
@jamesgpearce
Copy link

I had the "jumping around on every save" issue, and setting "tsImportSorter.configuration.wrappingStyle": "prettier" fixed it for me. Thank you.

@Nxt3
Copy link
Author

Nxt3 commented May 31, 2023

I had the "jumping around on every save" issue, and setting "tsImportSorter.configuration.wrappingStyle": "prettier" fixed it for me. Thank you.

In the above, I already have this setting and it hasn't fixed the issue.

@Nxt3
Copy link
Author

Nxt3 commented May 31, 2023

The real fix here would be to remove formatting responsibilities from this extension and have it purely handle sorting.

@binarykitchen
Copy link

I'm having this issue too and it's very frustrating.

remove formatting responsibilities

@Nxt3 How?

@Nxt3
Copy link
Author

Nxt3 commented Jan 23, 2024

I don't have an answer to that. Someone needs to submit a PR with those changes. There isn't a fix for this currently.

@daidodo
Copy link
Owner

daidodo commented Jan 24, 2024

Sorry for the late response!

The long-term solution is to migrate the extension to a Prettier plugin. But I don't have time ATM. I'd appreciate if anyone want to help.

Another workaround is to add the following settings with help of this extension:

  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": [
    "source.formatDocument",
    "source.organizeImports.sortImports"
  ],

@Nxt3
Copy link
Author

Nxt3 commented Jan 24, 2024

Unfortunately that doesn't solve the problem as it just makes TS Importer/Sorter the formatter for imports; if someone else working in your project doesn't have this VS Code extension, their Prettier will undo the formatting changes causing an unnecessary diff.

@daidodo
Copy link
Owner

daidodo commented Jan 24, 2024

Did you try to swap the code actions so prettier can prevail?

@Nxt3
Copy link
Author

Nxt3 commented Jan 24, 2024

    "editor.codeActionsOnSave": [
      "source.addMissingImports",
      "source.organizeImports.sortImports",
      "source.formatDocument", // prettier
      "source.fixAll.eslint"
    ]

It still causes the imports to change formatting on every save.

This is referenced in the OP

@Nxt3
Copy link
Author

Nxt3 commented Jan 24, 2024

I think I fixed this by adding another prettier call:

    "editor.codeActionsOnSave": [
      "source.addMissingImports",
      "source.organizeImports.sortImports",
      "source.formatDocument",
      "source.formatDocument",
      "source.fixAll.eslint"
    ],

I not longer have the jump in formatting.

@binarykitchen
Copy link

It's frustrating. Thinking of uninstalling this extension, I'm afraid.

@Nxt3
Copy link
Author

Nxt3 commented Apr 12, 2024

I think I came up with a better solution when compared to running formatDocument twice.

Download this extension: stereokai.vscode-run-commands-as-code-actions

It allows us to add delays to code actions run on save so you can "waterfall" the commands.

Add this to your settings.json:

  "run-commands-as-code-actions.jsTsFormatAndLint": [
    {
      "command": "tsImportSorter.command.sortImports",
      "delay": 100
    },
    {
      "command": "prettier.forceFormatDocument",
      "delay": 150
    },
    {
      "command": "eslint.executeAutofix",
      "delay": 200
    },
    {
      "command": "workbench.action.files.saveWithoutFormatting",
      "delay": 250
    }
  ],
    "[typescript]": {
    // here's the magic
    "editor.codeActionsOnSave": ["source.addMissingImports", "source.runCommandsAsCodeActions.jsTsFormatAndLint"],
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": false,
  },

This will add missing imports, then run the actions defined under jsTsFormatAndLint: Sort imports, format using prettier, eslint fix, and then save the file. This has been working great for me for a couple of weeks now.

@binarykitchen
Copy link

Thanks for sharing, still a problem with the delays of 100, 150 or 200 - how will you know the previous action did really complete before starting the next one? Especially in large code bases.

@Nxt3
Copy link
Author

Nxt3 commented Apr 12, 2024

Thanks for sharing, still a problem with the delays of 100, 150 or 200 - how will you know the previous action did really complete before starting the next one? Especially in large code bases.

The extension author could probably answer that better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed Q&A Questions due to information gaps and unclear documentations. No code fix needed.
Projects
None yet
Development

No branches or pull requests

4 participants