[api-extractor] Improve symbol analyzer to support "export * from" constructs#1002
[api-extractor] Improve symbol analyzer to support "export * from" constructs#1002
Conversation
|
@natalieethell FYI #Resolved |
|
FYI: The review file generating will break with export from external package like following: export { SemVer } from 'semver';The error is: Note that the test case And, in such case that I found this problem when trying to add support for |
|
And another one, also for the case: export { SemVer } from 'semver';The generated api.json would include detail type declarations for |
|
@adventure-yunfei I just pushed an update I was working on that hopefully should address this case. BTW the main idea behind The algorithm in my PR branch is still missing a major case. It should now correctly handle these cases: src/index.ts export * from './SomeFile';
export * from 'other-package';...if we have src/SomeFile.ts: export class X { }But it does not yet handle this case: src/index.ts export { X } from './OtherFile';...if we have src/OtherFile.ts: export * from 'other-package';I don't believe there is an easy solution for that. Replacing ts.TypeChecker.getExportsOfModule() was not too difficult, because I'm hoping to get some time over the holiday to finish this. Originally I was going to defer this work until after version 7 was released, but several teams at work are encountering these issues, so they can't use version 7 without this fix. #Resolved |
|
I've discovered some designs of api-extractor. To solving this kind of "export from external package" problem, my idea is to always analyze them no matter local or external, instead of blocking analyzing for external. api-extractor is treating external symbols too specially and I wonder it may lead to potential risks. For *.d.ts rollup or review file generator, detail external declarations may not be helpful (as they simply output the original Consider the case (for api.json generator): export { ExternalModule } from 'external-package';For api.json (or related api-documenter output), what it should be? Two choices:
From the api sight, I would prefer the second one. And, for any other generators including those that may be added in future, I would prefer to give all details (declaration details, reexport informations) to the generator and let themselves to choose what the want to generate. e.g.:
When the *.d.ts and review file generators see an external symbol, they generate a reexport statement; When the api.json generator (or any other generator taking case of declaration details instead of reexport info), it generate the declaration details. Just my simple thoughts. I'm learning api-extractor ~ #Resolved |
|
@adventure-yunfei wrote:
I'm not sure I agree with this. We are encountering this situation in real world scenarios, e.g. office-ui-fabric-react has a number of instances as part of a transitional step to split up a monolithic NPM package into smaller packages. In my view, this sort of thing: export { ExternalModule } from 'external-package';...is its own kind of API item that is similar to a TypeScript type alias. The API reference web site will already have a full set documentation for For the *.d.ts rollup, it would be technically incorrect to duplicate the declarations. (For example, the TypeScript compiler will not consider class types to be interchangeable if they contain any private members.) The *.api.ts review file is a somewhat special scenario. Since this is used to detect compatibility breaks, it may be useful to inline the full signature of the external declaration. Issue #896 is essentially asking for this. In the comments for that issue I gave some reasons why it should perhaps be an "opt-in" behavior. In any case, it seems clear that API Extractor's analyzer needs to know which package a declaration comes from, in order to solve these sorts of problems. #Resolved |
Hmm... Here and here I came across some usages of the term "nominal" to mean "type compatibility based on the name of a type, not just its signature". I wonder if API Extractor should choose a different name for our concept. @nickpape-msft @iclanton #Resolved |
[api-extractor] Add unit tests for PR #1002
… * from" constructs
… declarations (i.e. where both CollectorEntity.exported=true and AstSymbol.imported=true)
…ted multiple times (fixes GitHub issue #950)
5b870cc to
432d977
Compare
Agree with you now. Reexported items from external packages should be handled in user side, not the api-extractor core. It's a special case to merge some packages' contents. #Resolved |
b83f09b to
29be5e0
Compare
|
|
||
| // tslint:disable-next-line:no-any | ||
| return (ts as any).getResolvedModule(sourceFile, moduleNameText); | ||
| } |
There was a problem hiding this comment.
Can you split the compiler internals into a separate file so it's clear that's what they are. It'll also be easier to find problems if the compiler internals change. #Resolved
There was a problem hiding this comment.
| if (this._shouldIncludeReleaseTag(releaseTag, dtsKind)) { | ||
| if (!this._shouldIncludeReleaseTag(releaseTag, dtsKind)) { | ||
| indentedWriter.writeLine(); | ||
| indentedWriter.writeLine(`/* Excluded from this release type: ${entity.nameForEmit} */`); |
There was a problem hiding this comment.
nameForEmit [](start = 81, length = 11)
Sanetize? #WontFix
| * This is true if exportNames contains only one string, and the declaration can be exported using the inline syntax | ||
| * such as "export class X { }" instead of "export { X }". | ||
| */ | ||
| public get emitWithExportKeyword(): boolean { |
There was a problem hiding this comment.
emitWithExportKeyword [](start = 13, length = 21)
Maybe shouldInlineExport #Resolved
There was a problem hiding this comment.
|
This is fixed now. In reply to: 449750119 [](ancestors = 449750119) |
|
I renamed it to "nominalAnalysis" In reply to: 451778545 [](ancestors = 451778545) |
fae4865 to
f2e0fd8
Compare
|
This PR was published as the beta release api-extractor@7.0.10 and api-documenter@7.0.15. To try it, do |
This PR turned into a full rewrite of the symbol analyzer, adding the following capabilities:
Support
export * from './localFile';by merging those declaration into the entry point as beforeSupport
export * from 'external-package'by emitting anexport *in the outputSupport
export { A } from './localFile';where ./localFile.ts obtainsAby doingexport * from 'external-package';Allow a declaration to be exported more than once: