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

Erroneous recommendation for types exports #46

Closed
Conaclos opened this issue Jun 4, 2023 · 14 comments
Closed

Erroneous recommendation for types exports #46

Conaclos opened this issue Jun 4, 2023 · 14 comments
Labels
bug Something isn't working

Comments

@Conaclos
Copy link

Conaclos commented Jun 4, 2023

Hi!

Linting my project with publint raises a warning: the linter recommend adding a types exports.

However, if I follow this recommendation, this creates an issue according to a linter of TypeScript team member: "Types are ESM, but implementation is CJS.". The only way to correctly export types when dual publishing cjs and esm is to remove the types exports and adding .d.cts / .d.ts / .d.mts along with corresponding files.

I understand the reasoning behind requiring types exports.
publint could detect dual publishing and then, in this particular case, recommend removing types exports.

@Conaclos Conaclos changed the title Erroneous recommandation Erroneous recommendation Jun 4, 2023
@Conaclos Conaclos changed the title Erroneous recommendation Erroneous recommendation for types exports Jun 4, 2023
@Conaclos
Copy link
Author

Conaclos commented Jun 4, 2023

Another solution could be requiring two types exports:

  "exports": {
      "require": {
        "types": "./dist/index.d.cts",
        "default": "./dist/index.cjs"
      },
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
  },

@bluwy
Copy link
Owner

bluwy commented Jun 5, 2023

Hmm, yeah I think I missed checking for the adjacent .d.ts, .d.cts, .d.mts when checking the lint rule.

Doing the opposite is an interesting idea. I don't particularly like that TypeScript wants people to publish .d.ts, .d.cts, .d.mts files separately, as if publishing types couldn't be harder. But anyways if anyone wants to contribute that, I wouldn't oppose it 🥲

@nvie
Copy link
Contributor

nvie commented Jul 4, 2023

Yeah, this is something that many packages are doing wrong, and it gets worse because most packages just cargo cult off of what other (popular) packages are doing.

I think it would hugely help if what @Conaclos is proposing were the recommended approach.

Basically, if you have a require and an import, then I believe it's always a bug if you have a types condition at the same level, too. It would be nice to add a lint rule that forbids this.

Reasoning:

  • require and import cannot use the same file extension (because, if they did then CJS would be masquerading as ESM, or vice versa)
  • Because require and import have different file extensions, their type definitions must also have different type files

The solution, which would be nice to recommend as a best practice:

{
  "exports": {
    ".": {
      "require": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.js",
      },
      "import": {
        "types": "./dist/index.d.mts",
        "default": "./dist/index.mjs",
      },
    }
  }
}

@bluwy
Copy link
Owner

bluwy commented Jul 4, 2023

Yeah being able to detect those cases would be good. I had a small debate with Andrew and it's largely the reason why I didn't really push this. But at this point, I'm willing to have some sort of fix since it's what TS has set in stone.

I'm still somewhat on the side that having types, import, and require on the same level isn't always a bug though. A library could decide to only provide types for ESM or CJS. In this case, we can add information instead that the types will only work in ESM or CJS.

In the original issue, we can update our message more if the library exports both ESM and CJS. And also omit the warning if the the file has adjacent dts file (Maybe still good to recommend an explicit types condition instead? Just fix the recommendation to insert in the right condition nested)

@Conaclos
Copy link
Author

Conaclos commented Jul 4, 2023

Basically, if you have a require and an import, then I believe it's always a bug if you have a types condition at the same level, too. It would be nice to add a lint rule that forbids this.

Not necessarily: order is important. I am currently using the following approach:

  "exports": {
    "./package.json": "./package.json",
    ".": {
      "require": {
        "types": "./dist/index.d.cts",
        "default": "./dist/index.cjs"
      },
      "types": "./dist/index.d.ts",
      "module": "./dist/index.js",
      "default": "./dist/index.js"
    }
  },

@nvie
Copy link
Contributor

nvie commented Jul 4, 2023

I'm still somewhat on the side that having types, import, and require on the same level isn't always a bug though. A library could decide to only provide types for ESM or CJS. In this case, we can add information instead that the types will only work in ESM or CJS.

That's true. I agree, and providing a hint that the types won't work in one or the other would be nice to make it clear (because perhaps that's not the author's intention).

In the original issue, we can update our message more if the library exports both ESM and CJS. And also omit the warning if the the file has adjacent dts file (Maybe still good to recommend an explicit types condition instead? Just fix the recommendation to insert in the right condition nested)

Agreed!

Not necessarily: order is important. I am currently using the following approach:

A-ha, I see @Conaclos! Are you not getting the "types must come first" error? I was operating under the assumption that "types" would have to be defined before "require" according to the existing publint rule. If this setup doesn't lead to a linting error, then I agree this is also an option and it's indeed not always a bug.

@nvie
Copy link
Contributor

nvie commented Jul 4, 2023

Btw, @Conaclos – I just contributed a rule last weekend that will fail on your "module" line. In this setup, I would recommend changing to:

{
  "exports": {
    "./package.json": "./package.json",
    ".": {
      "require": {
        "types": "./dist/index.d.cts",
        "module": "./dist/index.js",  // 👈 Move it to here, maybe?
        "default": "./dist/index.cjs"
      },
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
}

@Hebilicious
Copy link

Fix that is possibly related landed here #47

@bluwy
Copy link
Owner

bluwy commented Jul 4, 2023

Yeah, the "types must come first" with import and require conditions is fixed at #47 (if require or import has it's own types nested). I think this issue is more specific to the recommendation detection, where:

  1. It has pkg.types
  2. But doesn't have pkg.exports.types

Since "moduleResolution": "bundler" would ignore pkg.types altogether. So we recommend some hints so bundler works, in this case the hints aren't perfect for dual publishing.

@Conaclos
Copy link
Author

Conaclos commented Jul 4, 2023

Btw, @Conaclos – I just #49 that will fail on your "module" line. In this setup, I would recommend changing to:

module is bundler-specific condition (supported by webpack, esbuild, and others). It should not be in require.
By the way, I am not sure if module must be placed before require.
module makes sense only for ESM? In this case the bundlers skip require?

So hard to get right...

Otherwise this could be as follows:

  "exports": {
    "./package.json": "./package.json",
    ".": {
      "module": "./dist/index.js",
      "require": {
        "types": "./dist/index.d.cts",
        "default": "./dist/index.cjs"
      },
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },

@nvie
Copy link
Contributor

nvie commented Jul 4, 2023

So hard to get right...

You can say that again! 🥵

module is bundler-specific condition (supported by webpack, esbuild, and others). It should not be in require. By the way, I am not sure if module must be placed before require. module makes sense only for ESM? In this case the bundlers skip require?

Not sure if that's true! Maybe it is? Now I don't know anymore 🥴

My understanding is that bundlers activate the module condition as well as import and require (depending on which construct is used to include the referenced module). So if a bundler encounters a require('xxx') call, they will normally resolve to index.cjs (through the require condition that they activated). Similarly, if they encounter an import "xxx" statement, they will normally resolve to index.mjs (through the import condition that they activated).

But bundlers also activate the module condition, so that you have the opportunity to influence and let them use the ESM module instead of the CJS module they would normally resolve to.

So assume that you have this:

{
  "exports": {
    ".": {
      "require": {
        "types": "./dist/index.d.cts",
        "module": "./dist/index.js",
        "default": "./dist/index.cjs"
      },
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
}

And your bundler processes this source code:

const x = require('xxx');
  1. Bundler sets require condition and module condition
  2. Scanning top-to-bottom finds first match at pkg.exports.require.module → resolves to ./dist/index.js (an ESM module!)
  3. This is fine in a bundler context only, because bundlers possess the special power to require() an ESM module (unlike Node)

Similarly, if your bundler processes this source code:

import * as x from 'xxx';
  1. Bundler sets import condition and module condition
  2. Top-to-bottom scanning happens.
  3. Skips over pkg.exports.require, because require condition isn't met
  4. Skips over pkg.exports.types, because types condition isn't met
  5. Finds pkg.exports.default → resolves to ./dist/index.js (also an ESM module!)

Maybe I'm wrong, but this is how I thought it works.

@nvie
Copy link
Contributor

nvie commented Jul 4, 2023

Btw, I'm mostly basing my understanding of this from the "How conditions work" section in the esbuild documentation. These parts in particular:

Screen Shot 2023-07-04 at 23 55 05@2x

Conaclos added a commit to bare-ts/lib that referenced this issue Jul 4, 2023
`module` should precede any condition.
See bluwy/publint#46 (comment)
for more context and details.
Conaclos added a commit to bare-ts/bare that referenced this issue Jul 4, 2023
`module` should precede any condition.
See bluwy/publint#46 (comment)
for more context and details.
Conaclos added a commit to bare-ts/bare that referenced this issue Jul 5, 2023
`module` should precede any condition.
See bluwy/publint#46 (comment)
for more context and details.
@bluwy
Copy link
Owner

bluwy commented Jul 25, 2023

I've fixed this in 28f1ec3 and 325b59f. I've walked back a bit on this:

I'm still somewhat on the side that having types, import, and require on the same level isn't always a bug though.

publint will now warn (for the root export only), if import and require both exist. Better to avoid bias wherever possible 😬

You can start testing this out in https://publint.dev now. The site is updated but the package isn't published yet. Since this might affect many projects using publint --strict, I'm holding off the release a bit until tonight to write a better release note.

Closing this as fixed.

image

@bluwy bluwy closed this as completed Jul 25, 2023
@bluwy
Copy link
Owner

bluwy commented Jul 26, 2023

This is now published in v0.2.0

renovate bot added a commit to tnez/starter-npm-pkg that referenced this issue Jul 31, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[@types/node](https://togithub.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://togithub.com/DefinitelyTyped/DefinitelyTyped)) |
[`20.4.4` ->
`20.4.5`](https://renovatebot.com/diffs/npm/@types%2fnode/20.4.4/20.4.5)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/20.4.5?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2fnode/20.4.5?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2fnode/20.4.4/20.4.5?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/20.4.4/20.4.5?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [eslint](https://eslint.org)
([source](https://togithub.com/eslint/eslint)) | [`8.45.0` ->
`8.46.0`](https://renovatebot.com/diffs/npm/eslint/8.45.0/8.46.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/eslint/8.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/eslint/8.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/eslint/8.45.0/8.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/eslint/8.45.0/8.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [jest](https://jestjs.io/)
([source](https://togithub.com/facebook/jest)) | [`29.6.1` ->
`29.6.2`](https://renovatebot.com/diffs/npm/jest/29.6.1/29.6.2) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/jest/29.6.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/jest/29.6.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/jest/29.6.1/29.6.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jest/29.6.1/29.6.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [publint](https://publint.dev)
([source](https://togithub.com/bluwy/publint)) | [`0.1.16` ->
`0.2.0`](https://renovatebot.com/diffs/npm/publint/0.1.16/0.2.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/publint/0.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/publint/0.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/publint/0.1.16/0.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/publint/0.1.16/0.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>eslint/eslint (eslint)</summary>

### [`v8.46.0`](https://togithub.com/eslint/eslint/releases/tag/v8.46.0)

[Compare
Source](https://togithub.com/eslint/eslint/compare/v8.45.0...v8.46.0)

#### Features

-
[`8a93438`](https://togithub.com/eslint/eslint/commit/8a9343871f7dade19d910ca8e2a4177bfca28b64)
feat: `require-unicode-regexp` support `v` flag
([#&#8203;17402](https://togithub.com/eslint/eslint/issues/17402))
(SUZUKI Sosuke)
-
[`1a2f966`](https://togithub.com/eslint/eslint/commit/1a2f966fabe35103141d2f936180d2f1a72154db)
feat: `no-useless-escape` support `v` flag
([#&#8203;17420](https://togithub.com/eslint/eslint/issues/17420))
(Yosuke Ota)
-
[`ee68d1d`](https://togithub.com/eslint/eslint/commit/ee68d1d9630892d99ae0d8dabe2f9f8d3b1338be)
feat: `no-empty-character-class` support `v` flag
([#&#8203;17419](https://togithub.com/eslint/eslint/issues/17419))
(Milos Djermanovic)
-
[`853d32b`](https://togithub.com/eslint/eslint/commit/853d32baa8934c08b59a738470b72522e1505f6f)
feat: deprecate no-return-await
([#&#8203;17417](https://togithub.com/eslint/eslint/issues/17417))
(Carlos Lopez)
-
[`d4f02e4`](https://togithub.com/eslint/eslint/commit/d4f02e4bf1b9ae4e1fc8f2bc4e4851ae3c36a127)
feat: `no-control-regex` support `v` flag
([#&#8203;17405](https://togithub.com/eslint/eslint/issues/17405))
(Yosuke Ota)
-
[`2a35f3e`](https://togithub.com/eslint/eslint/commit/2a35f3e6ed27deafbebba48b6aec570d3abf9974)
feat: `prefer-named-capture-group` support `v` flag
([#&#8203;17409](https://togithub.com/eslint/eslint/issues/17409))
(Yosuke Ota)
-
[`8ca8b50`](https://togithub.com/eslint/eslint/commit/8ca8b50b0425b3bad34a9505bc3095168e2f59d8)
feat: Better error message for flat config plugins
([#&#8203;17399](https://togithub.com/eslint/eslint/issues/17399))
(Nicholas C. Zakas)
-
[`509f753`](https://togithub.com/eslint/eslint/commit/509f75395035822280245772e2a95732a0dde0e1)
feat: `no-misleading-character-class` support `v` flag
([#&#8203;17406](https://togithub.com/eslint/eslint/issues/17406))
(Yosuke Ota)
-
[`3caf514`](https://togithub.com/eslint/eslint/commit/3caf51487decdf93a4b17765a2af2a51c337e974)
feat: `no-regex-spaces` support `v` flag
([#&#8203;17407](https://togithub.com/eslint/eslint/issues/17407))
(Yosuke Ota)
-
[`b7fad2b`](https://togithub.com/eslint/eslint/commit/b7fad2b52f23667628cf209663795a721c88d0ba)
feat: `prefer-regex-literals` support `v` flag
([#&#8203;17410](https://togithub.com/eslint/eslint/issues/17410))
(Yosuke Ota)
-
[`a6a3ad4`](https://togithub.com/eslint/eslint/commit/a6a3ad4ae438ea7fc3a1d97cd2555f6534b565f1)
feat: `no-useless-backreference` support `v` flag
([#&#8203;17408](https://togithub.com/eslint/eslint/issues/17408))
(Yosuke Ota)
-
[`94954a7`](https://togithub.com/eslint/eslint/commit/94954a715448d5794f2892bf212fe986b43228ed)
feat: `no-invalid-regexp` support `v` flag
([#&#8203;17404](https://togithub.com/eslint/eslint/issues/17404))
(Yosuke Ota)
-
[`1af6eac`](https://togithub.com/eslint/eslint/commit/1af6eac5727080c809e37c07dc729b44ef24483c)
feat: adds option for allowing empty object patterns as parameter
([#&#8203;17365](https://togithub.com/eslint/eslint/issues/17365))
(Tanuj Kanti)
-
[`cf03104`](https://togithub.com/eslint/eslint/commit/cf03104b278fea59ef46e09f667110f5eaaf95e3)
feat: Improve config error messages
([#&#8203;17385](https://togithub.com/eslint/eslint/issues/17385))
(Nicholas C. Zakas)

#### Bug Fixes

-
[`9803c7c`](https://togithub.com/eslint/eslint/commit/9803c7c04078f0672d8a480fd39cf3bbef8017e6)
fix: FlatESLint#getRulesMetaForResults shouldn't throw on unknown rules
([#&#8203;17393](https://togithub.com/eslint/eslint/issues/17393))
(Milos Djermanovic)
-
[`42faa17`](https://togithub.com/eslint/eslint/commit/42faa17b1c93f801b14bea2840d1d528e25c7211)
fix: Update no-loop-func to not overlap with no-undef
([#&#8203;17358](https://togithub.com/eslint/eslint/issues/17358)) (Matt
Wilkinson)

#### Documentation

-
[`4d474e3`](https://togithub.com/eslint/eslint/commit/4d474e351ba6ce0242f18e55c27cb3ae17b84f63)
docs: update with TypeScript info
([#&#8203;17423](https://togithub.com/eslint/eslint/issues/17423))
(James)
-
[`091f44e`](https://togithub.com/eslint/eslint/commit/091f44e4c72007edb2ac6d4db4eafa5501e41e94)
docs: File extension named processor deprecation
([#&#8203;17362](https://togithub.com/eslint/eslint/issues/17362)) (Matt
Wilkinson)
-
[`9254a6c`](https://togithub.com/eslint/eslint/commit/9254a6cea845dfaf2f3f52f718cb9b071853aa09)
docs: Update README (GitHub Actions Bot)
-
[`6d6dc51`](https://togithub.com/eslint/eslint/commit/6d6dc5141f535728029eef8735854a421bc08eba)
docs: fix overlapping of `open in playground` button
([#&#8203;17403](https://togithub.com/eslint/eslint/issues/17403))
(Tanuj Kanti)
-
[`7fc3a2c`](https://togithub.com/eslint/eslint/commit/7fc3a2ce68979a2c2a6fc779e647b3004ab6f4ac)
docs: Add private class features info to no-underscore-dangle
([#&#8203;17386](https://togithub.com/eslint/eslint/issues/17386)) (Matt
Wilkinson)
-
[`da73e58`](https://togithub.com/eslint/eslint/commit/da73e583e1703a420551d8fa8f7c70b56dc88dd5)
docs: Migrating `eslint-env` configuration comments
([#&#8203;17390](https://togithub.com/eslint/eslint/issues/17390))
(Francesco Trotta)
-
[`80dffed`](https://togithub.com/eslint/eslint/commit/80dffed4c81dcc71fb72bc187aff2f87d141a6ed)
docs: fix Ignoring Files section in config migration guide
([#&#8203;17392](https://togithub.com/eslint/eslint/issues/17392))
(Milos Djermanovic)
-
[`8a9abb7`](https://togithub.com/eslint/eslint/commit/8a9abb7cf424bd49d45c09345dc45ae95f29cc9d)
docs: Update README (GitHub Actions Bot)
-
[`7e9be4b`](https://togithub.com/eslint/eslint/commit/7e9be4bd7331d0e8e8e0af0b075a2f6d28d1bea3)
docs: Update README (GitHub Actions Bot)
-
[`0b0bbe0`](https://togithub.com/eslint/eslint/commit/0b0bbe07d4fb0870f3916e975b8ec6978f838077)
docs: Update README (GitHub Actions Bot)

#### Chores

-
[`d1eb7e4`](https://togithub.com/eslint/eslint/commit/d1eb7e46e954c64af8d7d13d087b3a18f43e6d72)
chore: Update ecosystem dependencies
([#&#8203;17427](https://togithub.com/eslint/eslint/issues/17427))
(Nicholas C. Zakas)
-
[`fab9e97`](https://togithub.com/eslint/eslint/commit/fab9e97ef9dff40e98a5b3b97bdd3b0ff5439d46)
chore: package.json update for eslint-config-eslint release (ESLint
Jenkins)
-
[`6246711`](https://togithub.com/eslint/eslint/commit/6246711e0650d03afe044c36acde048ed2d39ee3)
chore: package.json update for
[@&#8203;eslint/js](https://togithub.com/eslint/js) release (ESLint
Jenkins)
-
[`0aa0bc3`](https://togithub.com/eslint/eslint/commit/0aa0bc365a5425440c8e86c96104d0053a51b602)
chore: Add PRs to triage project
([#&#8203;17421](https://togithub.com/eslint/eslint/issues/17421))
(Nicholas C. Zakas)

</details>

<details>
<summary>facebook/jest (jest)</summary>

###
[`v29.6.2`](https://togithub.com/facebook/jest/blob/HEAD/CHANGELOG.md#2962)

[Compare
Source](https://togithub.com/facebook/jest/compare/v29.6.1...v29.6.2)

##### Fixes

- `[jest-circus]` Fix snapshot matchers in concurrent tests when nr of
tests exceeds `maxConcurrency`
([#&#8203;14335](https://togithub.com/jestjs/jest/pull/14335))
- `[@jest/core]` When running global setup and teardown, do not try to
change the `message` property of the thrown error object when the
`message` property is unwritable
([#&#8203;14113](https://togithub.com/jestjs/jest/pull/14113))
- `[jest-snapshot]` Move `@types/prettier` from `dependencies` to
`devDependencies`
([#&#8203;14328](https://togithub.com/jestjs/jest/pull/14328))
- `[jest-snapshot]` Throw an explicit error if Prettier v3 is used
([#&#8203;14367](https://togithub.com/jestjs/jest/pull/14367))
- `[jest-reporters]` Add "skipped" and "todo" symbols to Github Actions
Reporter ([#&#8203;14309](https://togithub.com/jestjs/jest/pull/14309))

##### Chore & Maintenance

- `[@jest/core]` Use `pluralize` from `jest-util` rather than own
internal ([#&#8203;14322](https://togithub.com/jestjs/jest/pull/14322))

</details>

<details>
<summary>bluwy/publint (publint)</summary>

### [`v0.2.0`](https://togithub.com/bluwy/publint/releases/tag/v0.2.0)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.1.16...v0.2.0)

##### Breaking changes

**Note:** If you're using `publint` from the CLI, these breaking changes
should not affect you.

- `publint()` now returns an object with `messages` instead of the
`messages` array directly. This makes way for future APIs where
`publint` will return more information than just `messages`.

    ```diff
    - const messages = await publint()
    + const { messages } = await publint()
    ```

- Rename `printMessage` API to `formatMessage` to better reflect it's
intent.
([bluwy/publint#43)

    ```diff
    - import { printMessage } from "publint/utils"
    + import { formatMessage } from "publint/utils"

    const { messages } = await publint()

    for (const message of messages) {
    - console.log(printMessage(message))
    + console.log(formatMessage(message))
    }
    ```

-   Remove `filePath` `arg` for the `FILE_DOES_NOT_EXIST` message.

    ```diff
    import type { Message } from "publint"
    import { getPkgPathValue } from "publint/utils"

function messageToString(message: Message, pkg: Record<string, any>) {
      switch (message.code) {
        case "FILE_DOES_NOT_EXIST":
    -     return `The file "${message.args.filePath}" does not exist.`
+ return `The file "${getPkgPathValue(pkg, message.path)}" does not
exist.`
      }
    }
    ```

- Remove the `import` condition for the `publint` package. This provides
a better error message if you call `require("publint")`.

##### Features

- Improve warnings when the exported `"types"` condition has an invalid
format in ESM or CJS. This ensures your library's types will work in
both environments when dual publishing.
([bluwy/publint#46)

    It affects packages commonly packaged like:

    ```json
    {
      "exports": {
        ".": {
          "types": "./index.d.ts", <-- only works in CJS
          "import": "./index.mjs",
          "require": "./index.js",
        }
      }
    }
    ```

For more information, visit the [rules
documentation](https://publint.dev/rules#export_types_invalid_format).
This feature is inspired by https://arethetypeswrong.github.io.

##### Bug fixes

- Suppress warnings when exported JS files using the `"exports"` field
have adjacent `.d.ts` files and no `"types"` condition. This follows
TypeScript's resolution algorithm. For more information, visit the
[rules documentation](https://publint.dev/rules#types_not_exported).
([bluwy/publint#46)

**Full Changelog**:
bluwy/publint@v0.1.16...v0.2.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - "before 4am on Monday" (UTC).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://togithub.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/tnez/starter-npm-pkg).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi4xMS4wIiwidXBkYXRlZEluVmVyIjoiMzYuMjQuMiIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
kodiakhq bot pushed a commit to ascorbic/unpic-img that referenced this issue Sep 3, 2023
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [publint](https://publint.dev) ([source](https://togithub.com/bluwy/publint)) | [`^0.1.12` -> `^0.2.0`](https://renovatebot.com/diffs/npm/publint/0.1.12/0.2.2) | [![age](https://developer.mend.io/api/mc/badges/age/npm/publint/0.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/publint/0.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/publint/0.1.12/0.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/publint/0.1.12/0.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>bluwy/publint (publint)</summary>

### [`v0.2.2`](https://togithub.com/bluwy/publint/releases/tag/v0.2.2)

[Compare Source](https://togithub.com/bluwy/publint/compare/v0.2.1...v0.2.2)

##### Features

-   Lint `"typings"` field file existence ([bluwy/publint#60)
-   Check packed files when globbing exports locally ([bluwy/publint#61)
-   Improve `"browser"` field suggestion for using `"imports"` and `"exports"` fields instead ([bluwy/publint#59)

##### Bug fixes

-   Lower deprecated trailing slash glob syntax as `suggestion` instead of a `warning` when it's used for backwards compatibility only ([bluwy/publint#62)
-   Suppress invalid globbed file format if has correct adjacent file
-   Fix extension replacement in messages
-   Improve invalid types format message and docs

##### Site

-   Fix invalid package name not found message
-   Highlight code blocks in rules page

##### New Contributors

-   [@&#8203;btea](https://togithub.com/btea) made their first contribution in [bluwy/publint#64

**Full Changelog**: bluwy/publint@v0.2.1...v0.2.2

### [`v0.2.1`](https://togithub.com/bluwy/publint/releases/tag/v0.2.1)

[Compare Source](https://togithub.com/bluwy/publint/compare/v0.2.0...v0.2.1)

##### Bug fixes

-   Fix `"types"` condition check with `"exports"` array format
-   Disable packed files search when a `vfs` is passed
-   Fix `"browser"` field file existence extensions check
-   Fix file existence check with trailing slash

##### Site

-   Site-wide design touch-up
-   New "Popular packages" section
-   New package version select switcher ([bluwy/publint#56)
-   New navigation header design
-   Update bottom documentation for clarity
-   Improve repo URL parsing

##### New Contributors

-   [@&#8203;lachlancollins](https://togithub.com/lachlancollins) made their first contribution in [bluwy/publint#53

**Full Changelog**: bluwy/publint@v0.2.0...v0.2.1

### [`v0.2.0`](https://togithub.com/bluwy/publint/releases/tag/v0.2.0)

[Compare Source](https://togithub.com/bluwy/publint/compare/v0.1.16...v0.2.0)

##### Breaking changes

**Note:** If you're using `publint` from the CLI, these breaking changes should not affect you.

-   `publint()` now returns an object with `messages` instead of the `messages` array directly. This makes way for future APIs where `publint` will return more information than just `messages`.

    ```diff
    - const messages = await publint()
    + const { messages } = await publint()
    ```

-   Rename `printMessage` API to `formatMessage` to better reflect it's intent. ([bluwy/publint#43)

    ```diff
    - import { printMessage } from "publint/utils"
    + import { formatMessage } from "publint/utils"

    const { messages } = await publint()

    for (const message of messages) {
    - console.log(printMessage(message))
    + console.log(formatMessage(message))
    }
    ```

-   Remove `filePath` `arg` for the `FILE_DOES_NOT_EXIST` message.

    ```diff
    import type { Message } from "publint"
    import { getPkgPathValue } from "publint/utils"

    function messageToString(message: Message, pkg: Record<string, any>) {
      switch (message.code) {
        case "FILE_DOES_NOT_EXIST":
    -     return `The file "${message.args.filePath}" does not exist.`
    +     return `The file "${getPkgPathValue(pkg, message.path)}" does not exist.`
      }
    }
    ```

-   Remove the `import` condition for the `publint` package. This provides a better error message if you call `require("publint")`.

##### Features

-   Improve warnings when the exported `"types"` condition has an invalid format in ESM or CJS. This ensures your library's types will work in both environments when dual publishing. ([bluwy/publint#46)

    It affects packages commonly packaged like:

    ```json
    {
      "exports": {
        ".": {
          "types": "./index.d.ts", <-- only works in CJS
          "import": "./index.mjs",
          "require": "./index.js",
        }
      }
    }
    ```

    For more information, visit the [rules documentation](https://publint.dev/rules#export_types_invalid_format). This feature is inspired by https://arethetypeswrong.github.io.

##### Bug fixes

-   Suppress warnings when exported JS files using the `"exports"` field have adjacent `.d.ts` files and no `"types"` condition. This follows TypeScript's resolution algorithm. For more information, visit the [rules documentation](https://publint.dev/rules#types_not_exported). ([bluwy/publint#46)

**Full Changelog**: bluwy/publint@v0.1.16...v0.2.0

### [`v0.1.16`](https://togithub.com/bluwy/publint/releases/tag/v0.1.16)

[Compare Source](https://togithub.com/bluwy/publint/compare/v0.1.15...v0.1.16)

##### Bug fixes

-   Don't enforce the `module` condition to precede `import` per se. It is now ensured to precede `require` only as otherwise the condition isn't effective ([bluwy/publint#50)

**Full Changelog**: bluwy/publint@v0.1.15...v0.1.16

### [`v0.1.15`](https://togithub.com/bluwy/publint/releases/tag/v0.1.15)

[Compare Source](https://togithub.com/bluwy/publint/compare/v0.1.14...v0.1.15)

##### Bug fixes

-   Fix "precede" typo

**Full Changelog**: bluwy/publint@v0.1.14...v0.1.15

### [`v0.1.14`](https://togithub.com/bluwy/publint/releases/tag/v0.1.14)

[Compare Source](https://togithub.com/bluwy/publint/compare/v0.1.13...v0.1.14)

##### Features

-   Check that the `"module"` condition precedes the `"import"` and `"require"` in exports conditions ([bluwy/publint#49)

##### Bug fixes

-   Skip linting flow files
-   Improve exports array logging format

##### Site

-   Fix `isPathDir` check

##### New Contributors

-   [@&#8203;nvie](https://togithub.com/nvie) made their first contribution in [bluwy/publint#49

**Full Changelog**: bluwy/publint@v0.1.13...v0.1.14

### [`v0.1.13`](https://togithub.com/bluwy/publint/releases/tag/v0.1.13)

[Compare Source](https://togithub.com/bluwy/publint/compare/v0.1.12...v0.1.13)

##### Bug fixes

-   Fix `"types"` condition-is-first check when there's preceding conditions that has it's `"types"` condition too. This is common for dual ESM-CJS packages where `"types"` are located within `"require"` and `"import"` conditions. ([bluwy/publint#47)
-   Temporarily skip `"types"` condition check when `"typesVersions"` key exist. The `"typesVersions"` key requires a complex resolution algorithm that is harder to implement, so a quick patch is applied to remove the false errors for now. ([bluwy/publint#42)

**Full Changelog**: bluwy/publint@v0.1.12...v0.1.13

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 9pm on sunday" (UTC), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/ascorbic/unpic-img).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi43OC44IiwidXBkYXRlZEluVmVyIjoiMzYuNzguOCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->
tnez pushed a commit to tnez/actions that referenced this issue Dec 30, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [publint](https://publint.dev)
([source](https://togithub.com/bluwy/publint/tree/HEAD/pkg)) | [`0.1.16`
-> `0.2.7`](https://renovatebot.com/diffs/npm/publint/0.1.16/0.2.7) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/publint/0.2.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/publint/0.2.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/publint/0.1.16/0.2.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/publint/0.1.16/0.2.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>bluwy/publint (publint)</summary>

### [`v0.2.7`](https://togithub.com/bluwy/publint/releases/tag/v0.2.7)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.2.6...v0.2.7)

##### Features

- If the library exports from both `"main"`/`"module"` and `"exports"`
fields, but the `"exports"` field doesn't export the root entrypoint,
warn about the inconsistency. When `"exports"` is defined, it takes the
highest priority, so all the library's entrypoint (root and deep) needs
to be specified here.
([bluwy/publint#88)
- Suggest using the `"type"` field. In [Node.js
v20.10.0](https://nodejs.org/en/blog/release/v20.10.0), it introduces a
new `--experimental-default-type` flag to flip the default module system
from "CJS-as-default" to "ESM-as-default". It's recommended for
libraries to specify the `"type"` field explicitly to prevent CJS files
from being incorrectly interpreted as ESM. This suggestion helps push
towards a better ESM experience in the future.
([bluwy/publint#83)

**Full Changelog**:
bluwy/publint@v0.2.6...v0.2.7

### [`v0.2.6`](https://togithub.com/bluwy/publint/releases/tag/v0.2.6)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.2.5...v0.2.6)

##### Features

- Warn if the deprecated `jsnext:main` or `jsnext` fields are used by
[@&#8203;sapphi-red](https://togithub.com/sapphi-red)
([bluwy/publint#85)

##### Site

- Fix command on site by [@&#8203;wooorm](https://togithub.com/wooorm)
([bluwy/publint#82)

##### New Contributors

- [@&#8203;wooorm](https://togithub.com/wooorm) made their first
contribution in
[bluwy/publint#82

**Full Changelog**:
bluwy/publint@v0.2.5...v0.2.6

### [`v0.2.5`](https://togithub.com/bluwy/publint/releases/tag/v0.2.5)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.2.4...v0.2.5)

##### Bug fixes

- Fix missing published files check when resolving a path with fallback
extensions
([bluwy/publint#79)

**Full Changelog**:
bluwy/publint@v0.2.4...v0.2.5

### [`v0.2.4`](https://togithub.com/bluwy/publint/releases/tag/v0.2.4)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.2.3...v0.2.4)

##### Bug fixes

- Check for packed files locally before providing the `"files"`
suggestion. An incorrect suggestion was given when you're using
`.npmignore` or `.gitignore` to limit publishing certain files.

##### Site

-   Fix rules page mobile responsiveness

**Full Changelog**:
bluwy/publint@v0.2.3...v0.2.4

### [`v0.2.3`](https://togithub.com/bluwy/publint/releases/tag/v0.2.3)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.2.2...v0.2.3)

##### Features

- Error if `package.json` has fields with invalid string, boolean,
object, etc type
([bluwy/publint#73)

- Suggest using the `"files"` field if detected test or config files are
published
([bluwy/publint#77)

- Warn on `"exports"` and `"browser"` object conflict for browser-ish
environments
([bluwy/publint#58)

    For example, given this setup:

    ```json
    {
      "browser": {
        "./lib.server.js": "./lib.browser.js"
      },
      "exports": {
        ".": {
          "worker": "./lib.server.js",
          "browser": "./lib.browser.js",
          "default": "./lib.server.js"
        }
      }
    }
    ```

When matching the `"worker"` condition, it will resolve to
`"./lib.server.js"` which is intended to work in a worker environment.
However, the `"browser"` field also has a matching mapping for
`"./lib.server.js"`, causing the final resolved path to be
`"./lib.browser.js"`. This is usually not intended and causes the wrong
file to be loaded.

- Error on invalid JSX extensions, such as `.cjsx`, `.mjsx`, `.ctsx`,
and `.mtsx`
([bluwy/publint#76)

These extensions are usually mistaken as ESM and CJS variants of JSX,
which is not valid. Instead they should be written in ESM with the
`.jsx` extension instead.

##### Bug fixes

-   Skip file format checks only for globbed files
- Fix `"main"` field with ESM content detection
([bluwy/publint#75)

##### Site

- Add sidebar menu to rules page by
[@&#8203;btea](https://togithub.com/btea)
([bluwy/publint#65)
- Quickly scroll to the prompt information location by
[@&#8203;btea](https://togithub.com/btea)
([bluwy/publint#68)
- Fix version switch title not updated by
[@&#8203;btea](https://togithub.com/btea)
([bluwy/publint#72)
-   Improve documentation for `"types"` format
-   Fix message border styles
-   Fix docs list missing dot

**Full Changelog**:
bluwy/publint@v0.2.2...v0.2.3

### [`v0.2.2`](https://togithub.com/bluwy/publint/releases/tag/v0.2.2)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.2.1...v0.2.2)

##### Features

- Lint `"typings"` field file existence
([bluwy/publint#60)
- Check packed files when globbing exports locally
([bluwy/publint#61)
- Improve `"browser"` field suggestion for using `"imports"` and
`"exports"` fields instead
([bluwy/publint#59)

##### Bug fixes

- Lower deprecated trailing slash glob syntax as `suggestion` instead of
a `warning` when it's used for backwards compatibility only
([bluwy/publint#62)
-   Suppress invalid globbed file format if has correct adjacent file
-   Fix extension replacement in messages
-   Improve invalid types format message and docs

##### Site

-   Fix invalid package name not found message
-   Highlight code blocks in rules page

##### New Contributors

- [@&#8203;btea](https://togithub.com/btea) made their first
contribution in
[bluwy/publint#64

**Full Changelog**:
bluwy/publint@v0.2.1...v0.2.2

### [`v0.2.1`](https://togithub.com/bluwy/publint/releases/tag/v0.2.1)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.2.0...v0.2.1)

##### Bug fixes

-   Fix `"types"` condition check with `"exports"` array format
-   Disable packed files search when a `vfs` is passed
-   Fix `"browser"` field file existence extensions check
-   Fix file existence check with trailing slash

##### Site

-   Site-wide design touch-up
-   New "Popular packages" section
- New package version select switcher
([bluwy/publint#56)
-   New navigation header design
-   Update bottom documentation for clarity
-   Improve repo URL parsing

##### New Contributors

- [@&#8203;lachlancollins](https://togithub.com/lachlancollins) made
their first contribution in
[bluwy/publint#53

**Full Changelog**:
bluwy/publint@v0.2.0...v0.2.1

### [`v0.2.0`](https://togithub.com/bluwy/publint/releases/tag/v0.2.0)

[Compare
Source](https://togithub.com/bluwy/publint/compare/v0.1.16...v0.2.0)

##### Breaking changes

**Note:** If you're using `publint` from the CLI, these breaking changes
should not affect you.

- `publint()` now returns an object with `messages` instead of the
`messages` array directly. This makes way for future APIs where
`publint` will return more information than just `messages`.

    ```diff
    - const messages = await publint()
    + const { messages } = await publint()
    ```

- Rename `printMessage` API to `formatMessage` to better reflect it's
intent.
([bluwy/publint#43)

    ```diff
    - import { printMessage } from "publint/utils"
    + import { formatMessage } from "publint/utils"

    const { messages } = await publint()

    for (const message of messages) {
    - console.log(printMessage(message))
    + console.log(formatMessage(message))
    }
    ```

-   Remove `filePath` `arg` for the `FILE_DOES_NOT_EXIST` message.

    ```diff
    import type { Message } from "publint"
    import { getPkgPathValue } from "publint/utils"

function messageToString(message: Message, pkg: Record<string, any>) {
      switch (message.code) {
        case "FILE_DOES_NOT_EXIST":
    -     return `The file "${message.args.filePath}" does not exist.`
+ return `The file "${getPkgPathValue(pkg, message.path)}" does not
exist.`
      }
    }
    ```

- Remove the `import` condition for the `publint` package. This provides
a better error message if you call `require("publint")`.

##### Features

- Improve warnings when the exported `"types"` condition has an invalid
format in ESM or CJS. This ensures your library's types will work in
both environments when dual publishing.
([bluwy/publint#46)

    It affects packages commonly packaged like:

    ```json
    {
      "exports": {
        ".": {
          "types": "./index.d.ts", <-- only works in CJS
          "import": "./index.mjs",
          "require": "./index.js",
        }
      }
    }
    ```

For more information, visit the [rules
documentation](https://publint.dev/rules#export_types_invalid_format).
This feature is inspired by https://arethetypeswrong.github.io.

##### Bug fixes

- Suppress warnings when exported JS files using the `"exports"` field
have adjacent `.d.ts` files and no `"types"` condition. This follows
TypeScript's resolution algorithm. For more information, visit the
[rules documentation](https://publint.dev/rules#types_not_exported).
([bluwy/publint#46)

**Full Changelog**:
bluwy/publint@v0.1.16...v0.2.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/tnez/actions).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi4xMS4wIiwidXBkYXRlZEluVmVyIjoiMzcuMTAzLjEiLCJ0YXJnZXRCcmFuY2giOiJtYWluIn0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants