JamieMason/syncpack

feat(format): lint formatting of a single file

jameshearttech opened this issue · 8 comments

I use lint-staged in local development for linting files in Git staging prior to commit. I would like to lint package.json files using syncpack using the same approach. It would be great if I could do something like pnpm exec syncpack lint /path/to/package.json and it would override --source using the config from the root project in the monorepo.

Hey @jameshearttech,
As you mentioned, you can target specific files with --source like so: syncpack format --source some/package.json, but it only tends to make sense with format and list.

For linting single files there are probably a few things missing as syncpack is expecting to check that a whole project is correct.

What kind of things did you have in mind for a single file? That its formatting matches? Or something more?

@JamieMason I looked through the help for each command. Looks like --source works for every command except lint. I believe lint is the only command that checks formatting. Is that right?

What kind of things did you have in mind for a single file? That its formatting matches? Or something more?

I think you're saying you only want to check formatting and that sounds good, I'll take a look so that can be supported for single files.

Thanks a lot

What kind of things did you have in mind for a single file?

I apologize for not being more concise. What does syncpack do? Please correct me if I'm wrong.

Check formatting: syncpack lint seems to check formatting but does not support --source.
Fix formatting: syncpack format --source

Check semver ranges: syncpack lint-semver-ranges --source
Fix semver ranges: syncpack fix-mismatches --source

Check versions: syncpack list-mismatches --source
Fix versions: syncpack fix-mismatches --source

Here's a mock up of my lint-staged configuration.

// lint-staged.config.mjs
export default {
    check: {
        '*.{js,cjs,mjs}': ['eslint', 'prettier --check'],
        '*.{scss,css,json,yaml,yml,html}': ['prettier --check'],
        '*.md': ['remark', 'prettier --check'],
        'package.json': [
            // 'syncpack check-format --source',
            'syncpack lint-semver-ranges --source',
            'syncpack list-mismatches --source'
        ]
    },
    fix: {
        '*.{js,cjs,mjs}': ['eslint --fix', 'prettier --write'],
        '*.{scss,css,json,yaml,yml,html}': ['prettier --write'],
        '*.md': ['remark --output', 'prettier --write'],
        'package.json': ['syncpack format --source', 'syncpack fix-mismatches --source']
    }
};

Thanks a lot for this detail @jameshearttech and yes you're absolutely right, your lint-staged config looks good but there are some gaps in syncpack, I'll summarise:

What syncpack can/can't do currently:

  • ✅ you can format a single file syncpack format --source
  • ❌ you can't yet check the format of a single file
  • ⚠️ you can check version mismatches for a single file (syncpack list-mismatches --source) but I don't think it makes sense to only check one file because a version mismatch is almost always something that happens between 2-* files. A typical mismatch is when eg typescript is used with eg. version 5.4.4 in one file and 5.4.5 in another.
  • ⚠️ you can check semver range mismatches for a single file (syncpack lint-semver-ranges --source) and you might be ok – it would make sure eg all of your devDependencies use ~ versions for example, depending on your config. If you have multiple package.json files in a monorepo though there is a chance you might introduce mismatches between files by only changing one file.
  • ✅ I just noticed in your lint-staged config you are using 'package.json' and not '**/package.json' – if your project only has one package.json file, the warnings above don't apply to you and you're fine.

If you or someone reading this has multiple package.json files, I would check all package.json files whenever any of them change, which should be possible with something like:

// lint-staged.config.mjs
export default {
  check: {
    "*.{js,cjs,mjs}": ["eslint", "prettier --check"],
    "*.{scss,css,json,yaml,yml,html}": ["prettier --check"],
    "*.md": ["remark", "prettier --check"],
    "**/package.json": () => "syncpack lint",
  },
  fix: {
    "*.{js,cjs,mjs}": ["eslint --fix", "prettier --write"],
    "*.{scss,css,json,yaml,yml,html}": ["prettier --write"],
    "*.md": ["remark --output", "prettier --write"],
    "**/package.json": () => ["syncpack format", "syncpack fix-mismatches"],
  },
};

For the missing functionality of checking formatting of a single file, I'm working on a rewrite in #222 and will make that possible as part of that work. I'll keep this open to track that.

Let me know if I've missed anything, thanks.

I'm using pnpm so syncpack uses workspaces and I don't necessarily need to use globs, but good to clarify for future readers.

Can you clarify what you mean, are you referring to the globs in the lint-staged config? or globs that you might pass to syncpack via --source?

Oh, I was thinking of the globs I might pass to syncpack via --source, but these globs are in the lint-staged config. Why did you write "**/package.json": () => "syncpack lint",?