Skip to content

Conversation

@narthur
Copy link
Contributor

@narthur narthur commented Jun 11, 2025

This PR adds a plugin for Hey API.

https://heyapi.dev/

Copilot AI review requested due to automatic review settings June 11, 2025 14:00

This comment was marked as outdated.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jun 11, 2025

Open in StackBlitz

npm i https://pkg.pr.new/knip@1132

commit: 8a18da7

@narthur
Copy link
Contributor Author

narthur commented Jun 11, 2025

To pass my tests, since I'm using toDeferResolve, I committed my fixture's node_modules folder, but this feels weird. Is this the correct way to handle this? Should I instead hand-craft the files in my node_modules folder to keep things minimal?

@webpro
Copy link
Member

webpro commented Jun 11, 2025

Yeah please see other plugin fixtures

@narthur
Copy link
Contributor Author

narthur commented Jun 11, 2025

@webpro Should be better now!

Copy link
Member

@webpro webpro left a comment

Choose a reason for hiding this comment

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

Nice one! Just a few small issues left I think.

const resolveConfig: ResolveConfig<PluginConfig> = async (config): Promise<Input[]> => {
const plugins = (config.plugins ?? []).map(plugin => {
const pluginName = typeof plugin === 'string' ? plugin : plugin.name;
return toDeferResolve(pluginName);
Copy link
Member

Choose a reason for hiding this comment

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

If the plugins are always dependencies (i.e. not local files) we can use toDependency (it's faster as there's no need to resolve anything on the fs).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@narthur narthur requested a review from Copilot June 13, 2025 14:24
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Adds a new "hey-api" plugin to detect dependencies and generated entries from Hey API OpenAPI-TS configs.

  • Introduces hey-api in plugin registration, schema, and type definitions.
  • Implements hey-api plugin logic to detect @hey-api/openapi-ts usage and resolve dependencies plus generated file globs.
  • Adds fixtures and a basic test to verify counters for the new plugin.

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/knip/src/types/PluginNames.ts Registers 'hey-api' in the plugin name union and list
packages/knip/src/schema/plugins.ts Adds schema entry for the 'hey-api' plugin
packages/knip/src/plugins/index.ts Imports and exposes the hey-api plugin
packages/knip/src/plugins/hey-api/types.ts Defines PluginConfig for hey-api
packages/knip/src/plugins/hey-api/index.ts Implements isEnabled, config patterns, and resolveConfig for hey-api
packages/knip/schema.json Adds JSON schema definition for hey-api
packages/knip/test/plugins/hey-api.test.ts Adds test to ensure hey-api plugin counts files
packages/knip/fixtures/plugins/hey-api/* Provides package, config, and generated SDK fixtures
Comments suppressed due to low confidence (2)

packages/knip/test/plugins/hey-api.test.ts:10

  • [nitpick] Add a test case for when config.output is provided as an object (with a path property), such as in the CJS config, to verify resolveConfig includes the correct entries.
test('Find dependencies with the hey-api plugin', async () => {

packages/knip/src/plugins/hey-api/types.ts:1

  • PluginConfig is missing the required 'input' property that the Hey API config uses (e.g. input: string;). Add it to align with the UserConfig interface from @hey-api/openapi-ts.
export type PluginConfig = {

@narthur
Copy link
Contributor Author

narthur commented Jun 16, 2025

@webpro I'm not sure how to debug this CI error, and I don't see that I have the option to rerun the failed checks.

Run npm install [email protected] @types/node@18 --ignore-scripts
npm error code E[4](https://github.com/webpro-nl/knip/actions/runs/15637574744/job/44056620965?pr=1132#step:4:5)00
npm error 400 Bad Request - GET https://registry.npmjs.org/@release-it%2fbumper - Bad request
npm error A complete log of this run can be found in: /Users/runner/.npm/_logs/202[5](https://github.com/webpro-nl/knip/actions/runs/15637574744/job/44056620965?pr=1132#step:4:6)-06-13T14_57_16_228Z-debug-0.log
Error: Process completed with exit code 1.

https://github.com/webpro-nl/knip/actions/runs/15637574744/job/44056620965?pr=1132

Copy link
Member

@webpro webpro left a comment

Choose a reason for hiding this comment

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

Is there a public repo available where we can exercise this plugin to make sure loading config files works fine and we're not missing something obvious?

return acc;
}

const dependencies = plugin._dependencies ?? [];
Copy link
Member

Choose a reason for hiding this comment

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

Is there documentation or code available regarding this _dependencies property?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm. When I look up types in my local machine, I find this:

interface Meta<Config extends BaseConfig> {
  /**
   * Dependency plugins will be always processed, regardless of whether user
   * explicitly defines them in their `plugins` config.
   */
  _dependencies?: ReadonlyArray<AnyPluginName>;
  // ...
}

But when I look in their repo I find this:

interface Meta<Config extends BaseConfig> {
  /**
   * Dependency plugins will be always processed, regardless of whether user
   * explicitly defines them in their `plugins` config.
   */
  dependencies?: ReadonlyArray<AnyPluginName>;
  // ...
}

When I look at their docs it shows dependencies being set in the custom plugin's config, but it also says this:

Reserved fields are prefixed with an underscore and are not exposed to the user.

So as best I can tell, it's specified as dependencies in the custom plugin's configuration, and then is changed to _dependencies when the plugin is loaded in.

That said, since this is all a bit vague, and their docs says the custom plugin API is currently unstable, maybe I should remove the custom plugin support from this PR for now?

Copy link
Member

Choose a reason for hiding this comment

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

maybe I should remove the custom plugin support from this PR for now?

Not sure. Is there a public repo available where we can exercise this plugin to make sure loading config files works fine and we're not missing something obvious?

@webpro webpro force-pushed the main branch 4 times, most recently from 5a2d249 to 6bd250a Compare June 17, 2025 17:36
@narthur
Copy link
Contributor Author

narthur commented Jun 18, 2025

Is there a public repo available where we can exercise this plugin to make sure loading config files works fine and we're not missing something obvious?

Just created one:

https://github.com/narthur/hey-api-demo

I included a custom plugin in that repo. Its types forced me to use _dependencies, not dependencies, so not sure what to make of that--maybe the docs are out of date?

I also discovered that in some places in their docs they show including default plugins when adding your own plugins:

https://heyapi.dev/openapi-ts/plugins/tanstack-query#installation

Which means I need to figure out how to make the knip plugin handle that without flagging those default dependencies as unlisted.

@narthur
Copy link
Contributor Author

narthur commented Jun 19, 2025

Trying to think this through... feels like a bit of a catch-22. If the user interpolates default plugins and I allow them through as usual, they may be caught as unlisted. If I instead filter out default plugins from the user's provided plugins, then they may end up flagged as unused if the user also includes them in their direct dependencies.

I'm leaning toward just letting them through and allowing them to be caught as unlisted.

  • The user is explicitly providing that list of default plugins, so it seems arguably correct to call them unlisted if the user does this and doesn't include them in direct dependencies.
  • Handling it this way is the simplest way when it comes to implementation.

@webpro
Copy link
Member

webpro commented Jun 20, 2025

We could do something like this for the default plugins:

  const defaultPlugins = ['@hey-api/typescript', '@hey-api/sdk'];
  const plugins = (config.plugins ?? []).reduce<Input[]>((acc, plugin) => {
    if (typeof plugin === 'string') {
      if (!defaultPlugins.includes(plugin)) acc.push(toDependency(plugin));
      return acc;
    }

From a Knip perspective, are _dependencies transitive dependencies? I.e. we can ignore those?

@narthur
Copy link
Contributor Author

narthur commented Jun 20, 2025

@webpro Seems like it's working well now, both by test and demo. Maybe ready for another review?

@webpro
Copy link
Member

webpro commented Jun 25, 2025

There's quite a few projects using it seems: https://github.com/hey-api/openapi-ts/network/dependents, we don't we check some of those out and smoke-test a bit? My guess is that this might shed some light to some of the doubts we're having?

@narthur
Copy link
Contributor Author

narthur commented Jun 25, 2025

Hmm, interesting. I wonder if there's a way I can filter that list for projects that use Hey API.

@narthur
Copy link
Contributor Author

narthur commented Jun 25, 2025

@webpro
Copy link
Member

webpro commented Jun 28, 2025

The page I linked to is the list of projects using Hey API which this PR adds a plugin for. If any of those projects is already using Knip that's cool, but what we're mostly interested in is the configuration any project using Hey API does not need with this Knip plugin added. If a project is using Hey API and Knip, and assuming the Knip configuration was good, then what we want to see is the Knip configuration they can remove due to the new plugin.

To this end, I'll test drive a few projects in the coming days.

@narthur
Copy link
Contributor Author

narthur commented Jul 10, 2025

@webpro Gotcha, ok. I've reverted my additions to the automated tests since it sounds like that wasn't the correct way to do this.

@narthur
Copy link
Contributor Author

narthur commented Jul 10, 2025

For what it's worth, I've installed this version of Knip in the project that initially prompted me to make this PR, and it's working well so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants