Skip to content

Conversation

finalchild
Copy link
Contributor

@finalchild finalchild commented Aug 7, 2025

Summary

This PR fixes an issue where API Extractor incorrectly resolves self-package imports to source .ts files instead of the intended .d.ts build artifacts.

Problem

When a .d.ts file imports the package itself by its name, TypeScript's module resolution redirects to source files instead of analyzing the build outputs. This occurs because TypeScript tries to avoid analyzing build outputs when outDir or declarationDir compiler options are set.

See the TypeScript compiler logic here: https://github.com/microsoft/TypeScript/blob/391616532d6827254a86dc266121fd5d1958ffb9/src/compiler/moduleNameResolver.ts#L2867

Solution

Remove outDir and declarationDir from the compiler options in CompilerState.ts. This prevents TypeScript from redirecting imports and ensures API Extractor analyzes the correct .d.ts files. Since API Extractor only uses the compiler for analysis and doesn't emit any files, these options are unnecessary.

Test Plan

  • Built the project successfully with rushx build
  • Verified that API Extractor still works correctly for analyzing .d.ts files
  • Fixes build issues for me in Alloy

Alloy issue

I found this issue by trying to build Alloy on a Windows machine. Strangely, this self-import issue causes cyclic dependency warnings only on Windows.

When you run pnpm exec api-extractor run -v --diagnostics in packages/core of the repository (regardless of the OS), you can see that the compiler is analyzing src directory.

============================================================
DIAGNOSTIC: Files analyzed by compiler
============================================================
...
/home/finalchild/projects/alloy/packages/core/src/symbols/symbol-slot.tsx
/home/finalchild/projects/alloy/packages/core/src/symbols/index.ts
/home/finalchild/projects/alloy/packages/core/src/tap.ts
/home/finalchild/projects/alloy/packages/core/src/write-output.ts
/home/finalchild/projects/alloy/packages/core/src/index.ts
/home/finalchild/projects/alloy/packages/core/src/jsx-runtime.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/MemberName.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/MemberScope.d.ts
...

After the fix, this changes:

============================================================
DIAGNOSTIC: Files analyzed by compiler
============================================================
...
/home/finalchild/projects/alloy/packages/core/dist/src/components/Declaration.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/List.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/For.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/Indent.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/MemberDeclaration.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/jsx-runtime.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/MemberName.d.ts
/home/finalchild/projects/alloy/packages/core/dist/src/components/MemberScope.d.ts
...

And the Windows issue is also gone.

api.json impact

The members with self-dynamic-import are affected. Others are unaffected.

Before:

...
{
  "kind": "Reference",
  "text": "Children",
  "canonicalReference": "@alloy-js/core!~Children:type"
}
...

After:

...
{
  "kind": "Reference",
  "text": "Children",
  "canonicalReference": "@alloy-js/core!Children:type"
}
...

As you can see, !~ is changed to !.

I don't completely understand what this change is, and which one is better. It seems !~ means local and ! means exported?Then ! looks fine. The markdown generation was the same (both did not generate the link to Children).

Generated Markdown

Home > @alloy-js/core > MemberName

MemberName() function

Signature:

export declare function MemberName(): import("@alloy-js/core/jsx-runtime").Children;

Returns:

import("@alloy-js/core/jsx-runtime").Children

…iler

When analyzing .d.ts files that import the package itself, TypeScript's module
resolution would redirect to source .ts files instead of analyzing the build
artifacts. This occurs because TypeScript tries to avoid analyzing build outputs
when outDir/declarationDir are set.

Fix by deleting outDir and declarationDir options from the compiler configuration,
as API Extractor only uses the compiler for analysis and doesn't emit files.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@finalchild
Copy link
Contributor Author

@microsoft-github-policy-service agree

// the .d.ts build artifacts, not the source files. Since API Extractor doesn't emit any
// files, these options are unnecessary and interfere with correct module resolution.
delete commandLine.options.outDir;
delete commandLine.options.declarationDir;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Very insightful! I've seen this problem before, but I didn't realize the import analysis was affected by outDir and declarationDir.

@octogonz octogonz merged commit ffa4992 into microsoft:main Aug 8, 2025
5 checks passed
@github-project-automation github-project-automation bot moved this from Needs triage to Closed in Bug Triage Aug 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Closed
Development

Successfully merging this pull request may close these issues.

2 participants