Skip to content

feat(no-sync)!: move ts-declaration-location to peerDependencies #451

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

risantos
Copy link

@risantos risantos commented Jun 26, 2025

Description

  • Move ts-declaration-location from dependencies to devDependencies and peerDependencies, declaring it as optional on peerDependenciesMeta, which has typescript as a peer dependency.
    As ts-declaration-location is already tentatively loaded for n/no-sync, the plugin keeps working as expected, throwing with a message identifying the missing package in case it'd be needed while trying to use the ignores option with a non-string value.
  • Update the n/no-sync documentation to refer the updated peer dependency requirement.
  • Update n/no-sync rule to conditionally require ts-declaration-location only when advanced ignores are used.
  • Add typescript as an optional peer dependency for the n/no-sync rule, used on lib/util/get-full-type-name.js, removing unused eslint-disable directive n/no-unpublished-require.

Note

Set as feat as this should be at least a minor bump, as it may break a lint build.
Updated to feat! after discussion, as it's a breaking change for TypeScript users using advanced TypeScript-based ignores.

Related issues

  • Warning received while installing eslint-plugin-n on JS projects without typescript:

    warning "eslint-plugin-n > @typescript-eslint/[email protected]" has unmet peer dependency "typescript@>=4.8.4 <5.9.0".
    warning "eslint-plugin-n > [email protected]" has unmet peer dependency "typescript@>=4.0.0".
    warning "eslint-plugin-n > @typescript-eslint/utils > @typescript-eslint/[email protected]" has unmet peer dependency "typescript@>=4.8.4 <5.9.0".
    warning "eslint-plugin-n > @typescript-eslint/utils > @typescript-eslint/typescript-estree > @typescript-eslint/[email protected]" has unmet peer dependency "typescript@>=4.8.4 <5.9.0".
    warning "eslint-plugin-n > @typescript-eslint/utils > @typescript-eslint/typescript-estree > @typescript-eslint/[email protected]" has unmet peer dependency "typescript@>=4.8.4 <5.9.0".
    warning "eslint-plugin-n > @typescript-eslint/utils > @typescript-eslint/typescript-estree > [email protected]" has unmet peer dependency "typescript@>=4.8.4".
  • chore(no-sync): remove @typescript-eslint/utils #449 addressed @typescript-eslint/utils.

@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch 2 times, most recently from 271865c to 02db95b Compare June 26, 2025 11:54
Copy link

@aladdin-add aladdin-add left a comment

Choose a reason for hiding this comment

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

is it possible to move the require(), so it is loaded only when the option is configured?

Copy link
Member

@MichaelDeBoey MichaelDeBoey left a comment

Choose a reason for hiding this comment

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

This would be a breaking change for people using the ignores option of the no-sync rule

@MichaelDeBoey MichaelDeBoey changed the title feat(no-sync): move ts-declaration-location to peerDependencies feat(no-sync)!: move ts-declaration-location to peerDependencies Jun 26, 2025
@aladdin-add
Copy link

the option was introduced in a minor (https://github.com/eslint-community/eslint-plugin-n/releases/tag/v17.19.0), but it unexpectedly introduced ts requirement.

so technically it can be a bugfix?

@risantos
Copy link
Author

@aladdin-add

is it possible to move the require(), so it is loaded only when the option is configured?

Yeah, moved below with a check for the existence of non-string option.ignores.


@MichaelDeBoey

This would be a breaking change for people using the ignores option of the no-sync rule

Likely so, I had read it as minor, given it "might break your lint build", being specific to TS users using n/no-sync with advanced ignores.

However, as I have no data/visibility over how this is used, "likely to break your lint build" also applies.


@aladdin-add

so technically it can be a bugfix?

I could see it working as such having been introduced 24d ago, although if someone's using it, it'd throw. Solvable by adding ts-declaration-location, but still "breaking".

@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from 02db95b to eeb4127 Compare June 26, 2025 14:28
@scagood
Copy link

scagood commented Jun 27, 2025

Could we added typescript as optional peer dependency to mitigate this instead of ts-declaration-location?

@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from eeb4127 to 54166a2 Compare June 27, 2025 18:22
@risantos
Copy link
Author

@scagood

Could we added typescript as optional peer dependency to mitigate this instead of ts-declaration-location?

I've tested adding typescript as an optional peer dependency instead, but the warning remains:

warning "eslint-plugin-n > [email protected]" has unmet peer dependency "typescript@>=4.0.0".

However, I believe it should be added too nevertheless, given typescript is required on lib/util/get-full-type-name.js

@aladdin-add
Copy link

aladdin-add commented Jun 27, 2025

After some thought, I was wondering if we could ask ts-declaration-location to make some changes -- change ts to optional. (I'm guessing that looking for the declared location isn't really needed to run tsc 😄 )


update: it was needed: https://github.com/RebeccaStevens/ts-declaration-location/blob/d86b36fc0dcba98fb964e58b8c2e7e7614fffd23/src/main.ts#L5 😂

Copy link

@aladdin-add aladdin-add left a comment

Choose a reason for hiding this comment

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

the change LGTM, thanks for taking care of it! 👍

@aladdin-add
Copy link

aladdin-add commented Jun 27, 2025

If we can go back to reintroduce this feature—I thought it was currently the only option (without breaking non-TypeScript projects).

Set as feat as this should be at least a minor bump, as it may break a lint build.

I agreed it to be a minor. thoughts? @scagood @MichaelDeBoey

@scagood
Copy link

scagood commented Jun 27, 2025

mmm, this is a breaking change though, I would rather stick with semver for this if we do go ahead with it. 👀

@RebeccaStevens what do you think about this?

@RebeccaStevens
Copy link

I'm in favour of this change.

It is technically a breaking chance so I would recommend a version bump but that's up to you whether or not you want to do that.

@@ -124,6 +112,29 @@ module.exports = {
const selector = options.allowAtRootLevel
? selectors.map(selector => `:function ${selector}`)
: selectors

// Only require `ts-declaration-location` if needed.
let typeMatchesSpecifier =
Copy link

@RebeccaStevens RebeccaStevens Jun 27, 2025

Choose a reason for hiding this comment

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

Let's keep the variable defined at the top level and add a check below to see if it's undefined or not before loading the library. That way the library isn't loaded multiple times.

Additionally we could add a check to not try and load it if we've already tried before.

The way I'd do this is have the variable initialized to undefined. When we encounter the code below, if the variable is set to undefined, test if we need to load the library, if we do, do so and set this variable to it, otherwise set the variable to null.

Copy link

@aladdin-add aladdin-add Jun 27, 2025

Choose a reason for hiding this comment

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

it may be a bit faster, even requires() are always cached. :)

Copy link
Author

Choose a reason for hiding this comment

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

Updated based on what I understood from your comments, please check whether the change is aligned. 🙏🏼

@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from 54166a2 to 1d93fdf Compare June 28, 2025 17:47
@risantos risantos requested a review from RebeccaStevens June 28, 2025 17:54
@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from 1d93fdf to 9c75763 Compare June 30, 2025 11:50
@risantos risantos requested a review from RebeccaStevens June 30, 2025 11:50
@risantos
Copy link
Author

@aladdin-add

If we can go back to reintroduce this feature—I thought it was currently the only option (without breaking non-TypeScript projects).

Set as feat as this should be at least a minor bump, as it may break a lint build.

I agreed it to be a minor. thoughts? @scagood @MichaelDeBoey

Updated the PR description to reflect that it's a breaking change, too.

@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from 9c75763 to 686880f Compare June 30, 2025 11:56
Comment on lines 125 to 139
if (hasAdvancedIgnores) {
if (typeMatchesSpecifier === undefined) {
try {
typeMatchesSpecifier =
/** @type {import('ts-declaration-location').default} */ (
/** @type {unknown} */ (
require("ts-declaration-location")
)
)
} catch {
typeMatchesSpecifier === null
}
} else {
throw new Error(
'ts-declaration-location not available. Rule "n/no-sync" is configured to use "ignores" option with a non-string value. This requires ts-declaration-location to be available.'
)
}
}

Copy link

@aladdin-add aladdin-add Jun 30, 2025

Choose a reason for hiding this comment

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

Isn't this the most intuitive way?

        try{
            typeMatchesSpecifier = typeMatchesSpecifier || require("ts-declaration-location");
        } catch(e) {
            throw new Error(
                'ts-declaration-location not available. Rule "n/no-sync" is configured to use "ignores" option with a non-string value. This requires ts-declaration-location to be available.',
                { cause: e }
            );
        }

Copy link
Author

Choose a reason for hiding this comment

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

It is clearer, thank you.
Applied now with the Logical OR assignment operator.

@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from 686880f to a108985 Compare June 30, 2025 15:27
@scagood
Copy link

scagood commented Jun 30, 2025

The code is 👍 from me, so thank you!

The one thing I am missing here is a couple of tests. For example: when ts-declaration-location is not installed, when typescript is not installed, and when neither are installed.

I am not sure what the best way to pull this off though:
We could use something like Sinon or even mock.module when it becomes stable.
The other option I can think of is to make some "fixture" style tests that we run separately.

What do you think?


I don't mean to block this PR with this comment, I am happy for it to go as is, I would just prefer tests! 😅

@risantos
Copy link
Author

risantos commented Jul 2, 2025

@scagood

The one thing I am missing here is a couple of tests. For example: when ts-declaration-location is not installed, when typescript is not installed, and when neither are installed.

I am not sure what the best way to pull this off though: We could use something like Sinon or even mock.module when it becomes stable. The other option I can think of is to make some "fixture" style tests that we run separately.

What do you think?

Agreed on the need for tests. I'm used to jest or vitest for these, having mocking built-in mocking capability. I've already used the native MockModuleContext too, though it's still in an Experimental/development stage.

If using mocha, would it be ok to add sinon and proxyquire to test these?

@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from a108985 to 627f17b Compare July 2, 2025 17:08
@scagood
Copy link

scagood commented Jul 3, 2025

If using mocha, would it be ok to add sinon and proxyquire to test these?

I think we'd only need sinon, right? If you need proxyquire do add it, and we can go from there :D

- Add `typescript` as an optional peer dependency for the `n/no-sync` rule, used on `lib/util/get-full-type-name.js`.
- Set `ts-declaration-location` as an optional peer dependency for the `n/no-sync` rule.
- Move `ts-declaration-location` to `devDependencies` for development and testing.
- Update the `n/no-sync` documentation to refer the updated peer dependency requirement.
- Update `n/no-sync` rule to conditionally require `ts-declaration-location` only when advanced ignores are used.
- Remove unused eslint-disable directive n/no-unpublished-require on `lib/util/get-full-type-name.js`, as `typescript` is now an optional peer dependency.
- Add tests to ensure the rule throws an error when `ts-declaration-location` or TypeScript parser services are not available.
- Add `sinon` as a dev dependency, used for mocking in tests.
@risantos risantos force-pushed the feat/no-sync/optional-ts-declaration-location branch from 627f17b to 8e626ca Compare July 9, 2025 00:17
@risantos
Copy link
Author

risantos commented Jul 9, 2025

@scagood

If using mocha, would it be ok to add sinon and proxyquire to test these?

I think we'd only need sinon, right? If you need proxyquire do add it, and we can go from there :D

Thanks for confirming. I've added tests using sinon for the 3 scenarios you had described:

  • If missing ts-declaration-location.
  • If missing typescript.
  • If missing both.

WDYT?

Copy link

@scagood scagood 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 good to me 👍

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants