microsoft/rushstack

[api-extractor] [api-extractor] Incompatible release tags across package boundaries don't trigger `ae-incompatible-release-tags` with `bundledPackages`

Opened this issue · 4 comments

Summary

Consider the following example where a mono-repo contains 2 packages: package-a and package-b, where package-b depends on package-a and specifies it in bundledPackages.

package-a

/**
 * @alpha
 */
export interface Foo {...}

package-b (depends on package-a)

import { Foo } from "package-a";

/**
 * @public
 */
export interface Bar extends Foo {...}

package-b's api-extractor config contains:

"bundledPackages": ["package-a"],

and

"ae-incompatible-release-tags": {
	"logLevel": "error",
	"addToApiReportFile": false
}

The expected outcome in this situation is that running api-extractor in package-b should trigger the ae-incompatible-release-tags error, but it doesn't.

Note that if Foo is re-exported by package-b, the error is triggered as expected. But since package-b specifies package-a in bundledPackages, the error should occur in either case.

Repro steps

I have created a small mono-repro that is configured with a fairly minimal repro of the issue: https://github.com/Josmithr/api-extractor-playground/tree/incompatible-release-tag-bug-repro

Standard questions

Please answer these questions to help us investigate your issue more quickly:

Question Answer
@microsoft/api-extractor version? 7.38.3
Operating system? Linux
API Extractor scenario? rollups (.d.ts)
Would you consider contributing a PR? No
TypeScript compiler version? 5.1.6
Node.js version (node -v)? 18.17.1

I am likely missing some context here, but it seems like this check here should be extracted from the outer conditional - incompatible release tags and missing exports are orthogonal and should be verified independently.

The expected outcome in this situation is that running api-extractor in package-b should trigger the ae-incompatible-release-tags error, but it doesn't.

I'm not sure about that.

bundledPackages is one of those simple-seeming features that leads to a pile of tricky edge cases. 😄

Here's two rather different use cases to consider:

  1. "My package imports someone else's NPM package, and but I'm bundling it "simpify" things." In this case, they want the other package's .d.ts files to get rolled up into your own .d.ts file. The other package maintainer may have their own designations about @alpha that are completely unrelated to the current package. It's also possible that they never heard of API Extractor and wrote @alpha in a comment with some totally different meaning, although isAedocSupportedFor() is supposed to detect that based on the absence of our tsdoc-metadata.json file.

  2. "I'm publishing one package, but for organizational purposes I want to split the code into multiple package folders that combined during the build." In this case, the same team manages all the source code, and it is possible for @alpha to have a consistent meaning across those projects. And I would agree for this case that it is expected for ae-incompatible-release-tags to have a consistent meaning.

As with your issue #4425, perhaps we need a setting to distinguish the intent? (Should it be a separate setting?)

Thanks for the response. Alongside your notes in #4425, I have a much better understanding of how these features were intended to compose, which didn't align with my understanding.

The distinction between these two cases is a fair one. I think I agree that a setting is probably sufficient to accomplish this.

But now that I better understand the intention of bundledPackages, I wonder if there are cases where both cases may want to be used simultaneously for orthogonal sets of dependencies? E.g. I want to bundle other packages in my mono-repo with validation of release tag compat, but I also want to bundle some external library, making no assumptions of its release semantics (i.e. treat everything from that as public).

A single, global option might be the easiest place to start, but I could also see an argument for allowing users to specify package-name/config pairs that specify the desired level of validation.

What do you think?

The other package maintainer may have their own designations about @Alpha that are completely unrelated to the current package. It's also possible that they never heard of API Extractor and wrote @Alpha in a comment with some totally different meaning, although isAedocSupportedFor() is supposed to detect that based on the absence of our tsdoc-metadata.json file.

@octogonz Given this, would unconditionally validating the tag compatibility when isAedocSupportedFor be a reasonable short-term mitigation for the issue here? I'm still very much in favor of a more intentional design for bundling, but I wonder if this is a reasonable short-term fix. My team is still maintaining a local pnpm patch for this, and we would love to stop maintaining that.