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

chore: Introduce Knip #18005

Merged
merged 19 commits into from Mar 11, 2024
Merged

chore: Introduce Knip #18005

merged 19 commits into from Mar 11, 2024

Conversation

webpro
Copy link
Contributor

@webpro webpro commented Jan 18, 2024

Prerequisites checklist

What is the purpose of this pull request? (put an "X" next to an item)

[ ] Documentation update
[ ] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofix to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain: add Knip, a project linter to keep codebase tidy

After having a "go" to explore the usefulness of Knip for the ESLint repository, and a meeting with @JoshuaKGoldberg the other day in which we've set up a first configuration, here's the follow up to that meeting in the form of a pull request.

EDIT: Knip is a project linter. Roughly speaking, where ESLint lints files in isolation, Knip lints codebases as a whole. This line could be drawn at the export keyword:

export const myExport = 1;

Knip creates a map of exports and imports to find unused exports. Additionally, it also finds unused dependencies, by mapping external imports against dependencies in package.json files. After all, it's only human to forget to delete unused files, exports and dependencies when they're no longer used. Knip is increasingly able to automate that process. Knip becomes smarter over time, resulting in less configuration. Using Knip in CI, just like ESLint, is beneficial to projects small and large to prevent regressions. Also see https://knip.dev/explanations/why-use-knip for some more in-depth explanations about what Knip has to offer. Knip has a lot more features than fit in this description, feel free to check them out on the website.

This PR is ready for review, but there's a few things I'd like you to decide upon:

  • Is Knip useful at all?
  • Do we want to merge the basics first (basically this PR as it stands with 2 commits)?
  • Do we want to actually clean up the codebase with the findings in this PR?
  • Do we want to add it the CI workflow in this PR?

What changes did you make? (Give an overview)

  • Add Knip + configuration (including comments)
  • Modified a few exports to accommodate for the ambiguity of CommonJS-styled (default) exports

This last bullet point might be seen as controversial. The thing is that Knip takes a rather conservative stance when it comes to named versus named exports in CommonJS modules. This is because the meaning of module.exports = is ambiguous (is it a default export or does it contain named exports?). The changes in this PR reflect that (I believe it's a small price to pay and validates Knip behavior).

Is there anything you'd like reviewers to focus on?

When running npm run lint:knip from the root, we'll see:

$ npm run lint:knip
Unused files (3)
lib/cli-engine/xml-escape.js
lib/shared/deprecation-warnings.js
tools/internal-testers/test-parser.js
Unused devDependencies (12)
dom-parser                     docs/package.json
eleventy-plugin-page-assets    docs/package.json
eleventy-plugin-reading-time   docs/package.json
imagemin                       docs/package.json
netlify-cli                    docs/package.json
eslint-plugin-eslint-comments  package.json     
eslint-plugin-jsdoc            package.json     
eslint-plugin-n                package.json     
eslint-plugin-unicorn          package.json     
lint-staged                    package.json     
webdriverio                    package.json     
yorkie                         package.json
Unlisted dependencies (1)
estree  lib/rules/no-useless-assignment.js
Unlisted binaries (1)
svgo  package.json
Unresolved imports (3)
../cli-engine/config-array  lib/linter/linter.js:61:35                         
./types                     lib/rules/utils/lazy-loading-rule-map.js:9:22      
../lib/shared/types         packages/js/src/configs/eslint-recommended.js:11:19
Unused exports (3)
default           unknown  lib/cli.js:492:18                 
isGlobPattern     unknown  lib/eslint/eslint-helpers.js:910:5
defineInMemoryFs  unknown  tests/_utils/index.js:61:5

Before actually cleaning up unused elements, I'd like to discuss a few results:

  1. eslint-plugin-eslint-comments is installed and used in packages/eslint-config-eslint so I think can be removed from the root package.json
  2. Is the mere presence of the "n/no-process-exit" rule enough to consider eslint-plugin-n a required plugin? Shouldn't n or eslint-plugin-n explicitly be added to the array of plugins?
  3. How is lint-staged or the gitHooks in package.json actually used? lint-staged is reported since there's no reference to it (e.g. in one of the package.json#scripts

@eslint-github-bot
Copy link

Hi @webpro!, thanks for the Pull Request

The pull request title isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases.

  • The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"?
  • There should be a space following the initial tag and colon, for example 'feat: Message'.
  • The first letter of the tag should be in lowercase

To Fix: You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page.

Read more about contributing to ESLint here

Copy link

netlify bot commented Jan 18, 2024

Deploy Preview for docs-eslint ready!

Name Link
🔨 Latest commit 83de5e5
🔍 Latest deploy log https://app.netlify.com/sites/docs-eslint/deploys/65ef22ea07d3d40008eb18ae
😎 Deploy Preview https://deploy-preview-18005--docs-eslint.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

linux-foundation-easycla bot commented Jan 18, 2024

CLA Signed

The committers listed above are authorized under a signed CLA.

@webpro webpro changed the title Introduce Knip feat: Introduce Knip Jan 18, 2024
@eslint-github-bot eslint-github-bot bot added the feature This change adds a new feature to ESLint label Jan 18, 2024
@webpro webpro changed the title feat: Introduce Knip chore: Introduce Knip Jan 18, 2024
@eslint-github-bot eslint-github-bot bot added the chore This change is not user-facing label Jan 18, 2024
@webpro webpro marked this pull request as ready for review January 18, 2024 10:05
@webpro webpro requested a review from a team as a code owner January 18, 2024 10:05
Copy link
Member

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together. Overall, what this PR is missing is an explanation of what Knip is and what benefit it is to the project as a whole. If you can add that information into the original description, it would greatly facilitate conversation around this PR.

@@ -0,0 +1,46 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful if you could explain what all of this does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the configuration comes down to providing entry files in order for Knip to do its thing.

This repository is much like a monorepo, but without explicitly defined workspaces as package managers like npm and pnpm recognize them. Knip normally hooks into package.json#workspaces, but those folders with a package.json manifest can also be manually added to the Knip configuration file. So the keys of the workspaces object are the paths to those folders.

@@ -157,6 +160,7 @@
"semver": "^7.5.3",
"shelljs": "^0.8.2",
"sinon": "^11.0.0",
"typescript": "^5.3.3",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need TypeScript?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Knip uses typescript and @types/node as peer dependencies to parse JavaScript and TypeScript files, build ASTs to find imports and exports, and as a foundation for module resolution. They're not regular dependencies of Knip as not to cause incompatibility issues with projects that do use TypeScript. Both devDependencies are already in node_modules, so they're not further impacting the size of the project.

@webpro
Copy link
Contributor Author

webpro commented Jan 18, 2024

Thanks for putting this together. Overall, what this PR is missing is an explanation of what Knip is and what benefit it is to the project as a whole. If you can add that information into the original description, it would greatly facilitate conversation around this PR.

Sorry, there was indeed no proper introduction. There's a new section added to the description.

Feel free to ask me anything you'd like to discuss or want to know more about.

Copy link
Contributor

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool stuff! Left a few clarifying questions in lieu of a full review.

knip.jsonc Show resolved Hide resolved
knip.jsonc Outdated Show resolved Hide resolved
knip.jsonc Show resolved Hide resolved
knip.jsonc Outdated Show resolved Hide resolved
knip.jsonc Show resolved Hide resolved
knip.jsonc Show resolved Hide resolved
knip.jsonc Show resolved Hide resolved
Makefile.js Show resolved Hide resolved
knip.jsonc Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
@webpro
Copy link
Contributor Author

webpro commented Jan 23, 2024

To move this pull request forward, it would help to discuss questions number 2 and 3 I've listed at the end of the description. And then, eventually, the list of configuration options and things in the codebase we can delete.

@mdjermanovic
Copy link
Member

  1. eslint-plugin-eslint-comments is installed and used in packages/eslint-config-eslint so I think can be removed from the root package.json
  2. Is the mere presence of the "n/no-process-exit" rule enough to consider eslint-plugin-n a required plugin? Shouldn't n or eslint-plugin-n explicitly be added to the array of plugins?
  3. How is lint-staged or the gitHooks in package.json actually used? lint-staged is reported since there's no reference to it (e.g. in one of the package.json#scripts

1 and 2: These dependencies are needed when eslint is used with .eslintrc.js config file.

eslint/.eslintrc.js

Lines 64 to 66 in 8c1b8dd

extends: [
"eslint/eslintrc"
],

extends: [
"eslint:recommended",
"plugin:n/recommended",
"plugin:jsdoc/recommended",
"plugin:eslint-comments/recommended"
],

We'll probably remove this config file and the dependencies soon (#18011).

  1. yorkie creates git hooks and runs lint-staged.

@webpro
Copy link
Contributor Author

webpro commented Feb 1, 2024

1 and 2: These dependencies are needed when eslint is used with .eslintrc.js config file.

We'll probably remove this config file and the dependencies soon (#18011).

Let's await that then to circumvent unnecessary complexity/issues.

  1. yorkie creates git hooks and runs lint-staged.

Added a yorkie plugin to Knip (and upgraded to that version here).

Copy link
Member

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Interested to get this integrated and see what else we find along the way.

Would like @mdjermanovic and @JoshuaKGoldberg to approve before merging.

Copy link
Contributor

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Progress! 🚀

I left a status summary comment on package.json. I think it'd make sense to perform the deletions as part of this PR so that the repo's in a clean slate. WDYT?

Requesting changes to also indicate the PR as blocked on #18011 per the comments.

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------

const assert = require("chai").assert,
ConfigRule = require("../../tools/config-rule"),
{ generateConfigsFromSchema } = require("../../tools/config-rule"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ConfigRule.createCoreRuleConfigs below also needs to be updated:

Suggested change
{ generateConfigsFromSchema } = require("../../tools/config-rule"),
{ createCoreRuleConfigs, generateConfigsFromSchema } = require("../../tools/config-rule"),

package.json Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
@nzakas
Copy link
Member

nzakas commented Feb 6, 2024

It looks like the CI is breaking, can you take a look?

@webpro
Copy link
Contributor Author

webpro commented Feb 7, 2024

It looks like the CI is breaking, can you take a look?

I've fixed the issues to make tests pass. This is the only way I see that satisfies both proxyquire and knip.

knip.jsonc Outdated Show resolved Hide resolved
@@ -162,6 +162,7 @@ function version() {
//------------------------------------------------------------------------------

module.exports = {
__esModule: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a bad idea...what's the purpose of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. First I refactored to this syntax, but proxquire does not play well with it (so tests were failing):
{ environment, version } = require("./shared/runtime-info"),

So I had no choice but to revert that change to use the "default import":

RuntimeInfo = require("./shared/runtime-info"),

That causes ambiguity in terms of intention, so I've added the property. I've explained more about this here:

The name of the property could be anything, I think __esModule is common (in bundled code) and describes intent well, but if we think it might cause issues we can rename it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, makes sense. Can you add a comment above explaining that this property makes Knip treat the default export correctly? I could see people getting confused and perhaps unintentionally removing it in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done.

package.json Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
@nzakas
Copy link
Member

nzakas commented Feb 13, 2024

@mdjermanovic still looking for your feedback here.

Copy link
Member

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Would still like @mdjermanovic and @JoshuaKGoldberg to approve before merging.

Copy link
Contributor

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me!

I would love to get the list of unused reports down to 0 and add npm run lint:imports to CI. But if other folks are happy to have that be a followup, then I am too. This is a directly positive change! And, I've pestered @webpro quite a lot already for a very kind change. 😄

I asked in Discord about an issue template for repo tooling followups and can file followup issues for the existing comment threads.

🔥 🙌

],
"ignoreDependencies": [
"c8",
// Ignore until Knip has a wdio plugin:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Ignore until Knip has a wdio plugin:
// Ignore until Knip has a wdio plugin:
// https://github.com/webpro/knip/issues/483#issuecomment-1925751516

Copy link
Contributor

@snitin315 snitin315 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good. Can we:

  • Add a CI job for this to run on all commits?
  • Delete/remove unused files/exports/dependencies as reported in the output?

knip.jsonc Show resolved Hide resolved
@github-actions github-actions bot added cli Relates to ESLint's command-line interface core Relates to ESLint's core APIs and features github actions labels Feb 27, 2024
@webpro
Copy link
Contributor Author

webpro commented Feb 27, 2024

Also added lint task to CI.

Copy link
Member

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this latest branch and everything is working great! Thanks!

Would like @JoshuaKGoldberg and @mdjermanovic to verify before merging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Style] Unrelated changes to whitespace all around?

Copy link
Contributor

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 still looks good to me!

I have a few open comments but nothing blocking IMO.

@mdjermanovic mdjermanovic added the accepted There is consensus among the team that this change meets the criteria for inclusion label Mar 6, 2024
Copy link
Member

@mdjermanovic mdjermanovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me overall, though it still doesn't work for me locally. But it seems to work for everyone else and, most importantly, it works in CI, so it's fine.

I left only two small suggestions.

lib/rules/utils/lazy-loading-rule-map.js Show resolved Hide resolved
knip.jsonc Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
@webpro
Copy link
Contributor Author

webpro commented Mar 11, 2024

Just saying: since there are no more issues or blocking matters, I believe my work is done here. Please follow up with PRs for maintenance as you please.

@fasttime
Copy link
Member

@webpro There are some suggestions on this issue that need to be addressed before it can be merged. Have you missed them or would you prefer not to put more work into this PR?

@webpro
Copy link
Contributor Author

webpro commented Mar 11, 2024

@fasttime The comments keep coming, where does it end? I prefer not to put more work in this PR.

@fasttime
Copy link
Member

I prefer not to put more work in this PR.

Fine, thanks a lot for your time working on this! I really appreciate it.

At this point, we'll need someone else to finish the PR.

@webpro
Copy link
Contributor Author

webpro commented Mar 11, 2024

At this point, we'll need someone else to finish the PR.

Perhaps my badly worded point was that I think this PR is fine as it stands. The lights are green. The rest is more a matter of fine-tuning and other things not directly related to the intentions of this PR: introduce Knip. There will always be some maintenance in configuration, just like any other tool.

I wonder what must be done in order to start using Knip properly?

@JoshuaKGoldberg
Copy link
Contributor

I can take over, if that's helpful. As webpro says - it looks like it's mostly fine-tuning at this point.

package.json Outdated Show resolved Hide resolved
Copy link
Member

@mdjermanovic mdjermanovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@mdjermanovic mdjermanovic merged commit acc2e06 into eslint:main Mar 11, 2024
19 checks passed
@webpro webpro deleted the introduce-knip branch March 11, 2024 17:10
@webpro webpro mentioned this pull request Apr 5, 2024
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion chore This change is not user-facing cli Relates to ESLint's command-line interface contributor pool core Relates to ESLint's core APIs and features feature This change adds a new feature to ESLint github actions rule Relates to ESLint's core rules
Projects
Status: Complete
Development

Successfully merging this pull request may close these issues.

None yet

7 participants