daidodo / format-imports-vscode

Format imports and exports for JavaScript and TypeScript in VS Code.
https://marketplace.visualstudio.com/items?itemName=dozerg.tsimportsorter
MIT License
62 stars 5 forks source link

Formatting imports jumps between prettier formatting #91

Open Nxt3 opened 1 year ago

Nxt3 commented 1 year ago

Describe the bug Auto Imports seems to be interfering with prettier formatting still. Might be related to https://github.com/daidodo/format-imports-vscode/issues/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):

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 commented 1 year ago

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.

Nxt3 commented 1 year ago

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 commented 1 year ago

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.

jamesgpearce commented 1 year ago

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

Nxt3 commented 1 year ago

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 commented 1 year ago

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

binarykitchen commented 10 months ago

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

remove formatting responsibilities

@Nxt3 How?

Nxt3 commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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

Nxt3 commented 10 months ago
    "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 commented 10 months ago

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 commented 7 months ago

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

Nxt3 commented 7 months ago

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 commented 7 months ago

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 commented 7 months ago

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.

jamesgpearce commented 4 months ago

After months of working fine, I got this again (after moving some eslint config files around). Very frustrating. But then I restarted VSCode and it worked again. Shrug.

jamesgpearce commented 3 months ago

....and it happened again. I had to restart a couple of times before it worked correctly. My guess is that every time you start VS Code, the 'order' of extensions that can format-on-save changes, and you just have to keep restarting until Prettier beats this (or vv, which ever you prefer)