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

[api-extractor] Class/interface with the same name as something from lib.dom is renamed #2976

Closed
sporritt opened this issue Oct 22, 2021 · 7 comments

Comments

@sporritt
Copy link

sporritt commented Oct 22, 2021

Summary

If you have this class, for instance:

export class Selection {
  
}

you'll get a class called Selection_2 in your apidocs.

In the .d.ts rollup file it will be renamed to this:

export declare class Selection_2 {
...

This also happens with a class in my project called Node - it comes out as Node_2. Both Node and Selection are names that lib.dom exports.

Repro steps

  • create a class called Selection
export class Selection {
/**
* This is foo
* @public
*/ 
  foo() {}
}
  • in your compilerOptions in tsconfig.json make sure you're importing dom:
"compilerOptions:{
...
 "lib": [ "esnext", "dom", "dom.iterable" ],
...
}
  • run the api extractor.

If I run with --diagnostics I can see that the api-extractor processes a whole bunch of .d.ts files in node_modules; I don't know if this is to be expected or not.

Standard questions

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

Question Answer
@microsoft/api-extractor version? 7.18.7
Operating system? Mac
API Extractor scenario? All - .md, .json and rollup
Would you consider contributing a PR? Yes. I have fixed this issue in a fork. But the fix consisted of basically reverting two commits made by project members...
TypeScript compiler version? 4.3.5
Node.js version (node -v)? 14.17.3
@sporritt
Copy link
Author

sporritt commented Oct 22, 2021

I noticed when running with --diagnostics lines like this:

Ignoring reference to global variable "Element" in /path/to/my-typings-file.d.ts:7:16

which would have come from something like this:

export interface MyInterface {
    container: Element;

Here, Element is a symbol exported by lib.dom. So in this case api-extractor is able to identify a "global" symbol and ignore it, but seemingly in the case I described above it cannot?

@sporritt
Copy link
Author

sporritt commented Oct 22, 2021

Looking into the source code I see this occurs inside Collector.js, in this block of code:

// If the idealNameForEmit happens to be the same as one of the exports, then we're safe to use that...
if (entity.exportNames.has(idealNameForEmit)) {
    // ...except that if it conflicts with a global name, then the global name wins         <-----------------
    if (!this.globalVariableAnalyzer.hasGlobalName(idealNameForEmit)) {                   <-----------------
        // ...also avoid "default" which can interfere with "export { default } from 'some-module;'"
        if (idealNameForEmit !== 'default') {
            entity.nameForEmit = idealNameForEmit;
            continue;
        }
    }
}

Why does the global name "win" if the name of something in my package, whose API we are currently documenting, happens to match a global symbol? This doesn't seem to make any sense.

I am currently running the API extractor with that global check removed:

if (entity.exportNames.has(idealNameForEmit)) {
    entity.nameForEmit = idealNameForEmit;
    continue;
}

and I don't have the problem with my symbols being rewritten. I know of course that I have also removed the check against me exporting a symbol with the name default but I have a hard time figuring out how, if tsc is being used, it would be possible to arrive at this point if one of my symbols was a reserved word anyway.

@sporritt
Copy link
Author

This is the change that added this code:

62d9a65

Is there a record somewhere of what instigated this change?

@adventure-yunfei
Copy link
Contributor

This is caused by global name conflict.
It's the same with #2534 and I've created a fix #2608.
The code here is trying to avoid conflict names (such as, two entities with the same "Foo" name or a local "Foo" entity and a global "Foo" declaration. Those will cause ts type errors). But it won't affect export name, and ideally won't affect api doc name.

BTW I'm not sure why your dts rollup result is also wrong.
With following input:

// index.d.ts
export class Selection {
}

generates correct dts-rollup result:

declare class Selection_2 {
}
export { Selection_2 as Selection }

export { }

You may try again. Note that api-extractor accepts .d.ts files, not .ts files. Your repro example is not.

@sporritt
Copy link
Author

Ok, that's interesting - I do see Selection_2 re-exported in the dts rollup:

export { Selection_2 as Selection }

and also after backing out my change and running it again I can't reproduce the error of Selection_2 being exported. It's declared but not exported.

However, the apidocs have files like this:

image

Selection_2 appears throughout the related .api.json and .api.md files. This mechanism does affect the name of apidoc files and it also affects the content of the apidocs:

<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@jsplumbtoolkit/core](./core.md) &gt; [Selection\_2](./core.selection_2.md) &gt; [(constructor)](./core.selection_2._constructor_.md)

## Selection\_2.(constructor)

@adventure-yunfei
Copy link
Contributor

As I said, api doc has a bug. You can try my fix.

@sporritt
Copy link
Author

ok yes this is a duplicate of #2534. closing. thanks for the feedback.

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

No branches or pull requests

2 participants