Skip to content

support import path aliases#7310

Merged
ardatan merged 5 commits intoardatan:masterfrom
HunterLarco:hunter/import-alias
Jul 22, 2025
Merged

support import path aliases#7310
ardatan merged 5 commits intoardatan:masterfrom
HunterLarco:hunter/import-alias

Conversation

@HunterLarco
Copy link
Contributor

@HunterLarco HunterLarco commented Jul 22, 2025

Description

GraphQL schemas in large projects, especially monorepos, suffer from fragile and verbose relative import paths that become difficult to maintain as projects grow. This PR brings TypeScript's popular tsconfig.json#paths aliasing syntax to GraphQL imports, enabling clean, maintainable import statements across your GraphQL schema files.

Before - Brittle relative imports:

#import "../../../shared/models/User.graphql"
#import "../../../../common/types/Product.graphql"

After - Clean, semantic aliases:

#import "@models/User.graphql"
#import "@types/Product.graphql"

Configuration Example

{
  mappings: {
    '@models/*': path.join(__dirname, './models/*'),
    '@types/*': path.join(__dirname, './shared/types/*'),
  }
}

This change is introduced in a backwards compatible way to ensure no existing use cases are broken while using familiar patterns to typescript developers for structuring import aliases.

Related #7311

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

npm test -- packages/import/tests/schema/import-schema.spec.ts

Test Environment:

  • OS: MasOS
  • @graphql-tools/...: import
  • NodeJS: v22.14.0

Checklist:

  • I have followed the
    CONTRIBUTING doc and the
    style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests and linter rules pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@changeset-bot
Copy link

changeset-bot bot commented Jul 22, 2025

🦋 Changeset detected

Latest commit: 2e793af

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@graphql-tools/graphql-file-loader Minor
@graphql-tools/import Minor
@graphql-tools/node-require Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 22, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for TypeScript-style path aliasing in GraphQL schema imports, allowing use of semantic import aliases in schema files.
    • Path alias configuration is now available in relevant loader and import options for improved import flexibility and maintainability.
  • Tests

    • Introduced comprehensive test cases covering exact, wildcard, multi-level, mixed, and circular path alias scenarios in schema imports.
  • Documentation

    • Updated documentation to describe the new path aliasing feature and provide example configurations.

Walkthrough

This update introduces path alias support for GraphQL import statements, modeled after TypeScript's tsconfig.json#paths syntax. It adds a PathAliases interface, updates import processing functions to accept alias configurations, and enhances path resolution logic. Extensive test fixtures and test cases are included to verify various aliasing scenarios, including circular and multi-level imports.

Changes

Files/Groups Change Summary
packages/import/src/index.ts Added PathAliases interface; updated import processing functions to accept path alias configs; enhanced file path resolution to support alias mapping.
packages/import/tests/schema/fixtures/path-aliases/** (all .graphql files) Added test fixture schemas covering exact, wildcard, circular, multi-level, and mixed alias scenarios.
packages/import/tests/schema/import-schema.spec.ts Extended test suite: added tests for path alias resolution, updated helper to accept pathAliases.
packages/loaders/graphql-file/src/index.ts Updated loader to accept pathAliases in options; passes aliases to import processing logic.

Sequence Diagram(s)

sequenceDiagram
    participant Loader as GraphQLFileLoader
    participant Import as processImport
    participant Resolver as resolveFilePath
    participant FS as File System

    Loader->>Import: processImport(pointer, cwd, ..., pathAliases)
    Import->>Resolver: resolveFilePath(importPath, pathAliases)
    alt Alias matches
        Resolver->>FS: Resolve mapped path (using alias)
    else No alias match
        Resolver->>FS: Resolve original path
    end
    FS-->>Resolver: Return resolved path
    Resolver-->>Import: Resolved file path
    Import-->>Loader: Imported schema
Loading

Estimated code review effort

4 (~90 minutes)

Possibly related issues

Suggested reviewers

  • ardatan

Poem

In burrows deep, with clever hops,
I mapped my paths and closed the gaps.
Aliases wild, exact, and neat,
Now schemas join and tests repeat.
With every import, joy expands—
The warren’s code in bunny hands! 🐇✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@HunterLarco HunterLarco marked this pull request as ready for review July 22, 2025 03:39
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
packages/import/tests/schema/fixtures/path-aliases/mixed-use/schema.graphql (1)

1-3: Standardise the # import directive and double-check the last path

  1. The first two statements omit the space after #, the third keeps the same style, yet in the rest of the fixture set you use # import … (with a space). Pick one convention (the spec & graphql-tools docs show # import …) and use it everywhere.

  2. "c-graphql" lacks an extension and is the only import that relies on an implicit resolver. Unless you intentionally test that branch, suffix it with .graphql to avoid false negatives when another import resolver is used.

-#import "@mixed-use/a.graphql"
-#import "./b.graphql"
-#import "c-graphql"
+# import "@mixed-use/a.graphql"
+# import "./b.graphql"
+# import "c-graphql.graphql"

Ensure the alias map in the test config resolves c-graphql(.graphql) exactly once; otherwise the test may silently pass with an unintended file.

packages/import/tests/schema/fixtures/path-aliases/circular/b.graphql (1)

1-1: Minor: keep directive style consistent

Other fixtures use # import, here you already follow that style – good. Just make sure the surrounding files in the same folder do the same to keep grep/regex rules simple.

packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level1.graphql (1)

1-1: Consistent quoting & directive spacing

This fixture adopts the # import + single quotes convention, which is preferred. Consider normalising the mixed-use fixture to match (see above) so the test corpus is homogeneous.

packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level2.graphql (1)

1-1: Nit: drop the leading @ in the comment to align with other fixtures

Not blocking, but the other multi-level files omit the @ before import in the comment itself (# import …). Uniform comments make pattern matching for fixtures easier.

packages/import/src/index.ts (2)

669-694: Path resolution logic correctly prioritizes aliases.

The implementation properly attempts alias resolution first before falling back to the original logic, maintaining backward compatibility.

Consider adding error handling for edge cases:

 function resolveFilePath(filePath: string, importFrom: string, pathAliases?: PathAliases): string {
   // First, check if importFrom matches any path aliases.
   if (pathAliases != null) {
     for (const [prefixPattern, mapping] of Object.entries(pathAliases.mappings)) {
       const matchedMapping = applyPathAlias(prefixPattern, mapping, importFrom);
       if (matchedMapping == null) {
         continue;
       }
 
       const resolvedMapping = resolveFrom(pathAliases.rootDir ?? process.cwd(), matchedMapping);
-      return realpathSync(resolvedMapping);
+      try {
+        return realpathSync(resolvedMapping);
+      } catch (e: any) {
+        // If alias resolution fails, continue to next alias or fall back
+        if (e.code !== 'ENOENT') {
+          throw e;
+        }
+      }
     }
   }

672-673: Consider validating path alias mappings.

While the implementation is correct, consider adding validation to ensure mapping patterns are well-formed to provide better error messages to users.

   if (pathAliases != null) {
+    // Validate mappings
+    for (const [pattern, mapping] of Object.entries(pathAliases.mappings)) {
+      if (!pattern || typeof mapping !== 'string') {
+        throw new Error(`Invalid path alias mapping: "${pattern}" -> "${mapping}"`);
+      }
+    }
     for (const [prefixPattern, mapping] of Object.entries(pathAliases.mappings)) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a36776 and edaf50a.

📒 Files selected for processing (15)
  • packages/import/src/index.ts (8 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/circular/a.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/circular/b.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/exact/a.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/exact/b.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/mixed-use/a.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/mixed-use/b.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/mixed-use/c.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/mixed-use/schema.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level1.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level2.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level3.graphql (1 hunks)
  • packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level4.graphql (1 hunks)
  • packages/import/tests/schema/import-schema.spec.ts (2 hunks)
  • packages/loaders/graphql-file/src/index.ts (3 hunks)
🧠 Learnings (2)
📓 Common learnings
Learnt from: ardatan
PR: ardatan/graphql-tools#0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The `isUrl` helper in @graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.
packages/import/tests/schema/import-schema.spec.ts (1)

Learnt from: ardatan
PR: ardatan/graphql-tools#0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The isUrl helper in @graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.

🧬 Code Graph Analysis (1)
packages/loaders/graphql-file/src/index.ts (1)
packages/import/src/index.ts (2)
  • PathAliases (68-127)
  • processImport (134-166)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ardatan
PR: ardatan/graphql-tools#0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The `isUrl` helper in @graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.
packages/import/tests/schema/import-schema.spec.ts (1)

Learnt from: ardatan
PR: ardatan/graphql-tools#0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The isUrl helper in @graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.

🧬 Code Graph Analysis (1)
packages/loaders/graphql-file/src/index.ts (1)
packages/import/src/index.ts (2)
  • PathAliases (68-127)
  • processImport (134-166)
🔇 Additional comments (16)
packages/import/tests/schema/fixtures/path-aliases/mixed-use/c.graphql (1)

1-3: Fixture is concise and valid.

GraphQL syntax and minimal field set are perfect for the alias-resolution test case.

packages/import/tests/schema/fixtures/path-aliases/exact/b.graphql (1)

1-3: LGTM.

TypeB is well-formed and adequate for the exact-alias fixture.

packages/import/tests/schema/fixtures/path-aliases/mixed-use/a.graphql (1)

1-3: No issues detected.

Schema is syntactically correct and serves its purpose in the mixed-alias scenario.

packages/import/tests/schema/fixtures/path-aliases/mixed-use/b.graphql (1)

1-3: Looks good.

B type definition is valid and appropriate for the test fixture.

packages/import/tests/schema/fixtures/path-aliases/exact/a.graphql (2)

1-1: Confirm loader accepts # import syntax.

The import directive uses # import (with a space). Ensure the updated loader continues supporting both #import and # import forms so this fixture is parsed.


3-10: Schema content is valid.

Types and fields are well-structured for the exact-alias test case.

packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level4.graphql (1)

1-7: Fixture looks good

Pure type definitions, schema is syntactically valid and fulfils its role in the deep-alias chain.

packages/import/tests/schema/fixtures/path-aliases/circular/a.graphql (1)

1-11: Test fixture correctly sets up circular dependency scenario.

The schema properly defines the circular reference test case with TypeA referencing TypeB through the relatedB field, and the import statement uses the path alias syntax as expected.

packages/import/tests/schema/fixtures/path-aliases/multiple-levels/level3.graphql (1)

1-11: Multi-level import test fixture is well-structured.

The schema correctly demonstrates multi-level path alias imports by referencing Products type from level4.graphql through the aliased import path.

packages/loaders/graphql-file/src/index.ts (3)

7-7: Import statement correctly includes PathAliases type.

The addition of PathAliases to the import statement properly supports the new feature.


38-41: Interface extension properly documents path aliases option.

The pathAliases property is well-documented and correctly typed as optional.


218-218: processImport call correctly passes path aliases parameter.

The function call properly includes the new parameters with appropriate default values for predefinedImports and visitedFiles.

packages/import/tests/schema/import-schema.spec.ts (2)

2-13: Helper function correctly updated to support path aliases.

The importSchema function properly accepts and passes the pathAliases parameter to processImport.


1154-1324: Comprehensive test coverage for path aliasing feature.

The test suite excellently covers various path aliasing scenarios including:

  • Exact path aliases
  • Wildcard patterns
  • Mixed usage with relative imports
  • Multi-level nested aliases
  • Circular dependencies
  • Root directory resolution

All test cases properly use path.join for cross-platform compatibility.

packages/import/src/index.ts (2)

64-127: Well-designed PathAliases interface with excellent documentation.

The interface follows TypeScript conventions and provides comprehensive documentation with clear examples. The support for both exact and wildcard mappings aligns perfectly with the PR objectives.


696-732: applyPathAlias correctly implements TypeScript path mapping semantics.

The function properly handles all the documented mapping patterns including exact matches and wildcards with proper remainder handling.

@ardatan
Copy link
Owner

ardatan commented Jul 22, 2025

Thanks for the PR!
Could you create a (minor bump) changeset with yarn changeset? Then we can merge and release a new version!

@HunterLarco
Copy link
Contributor Author

@ardatan

Thanks for the PR! Could you create a (minor bump) changeset with yarn changeset? Then we can merge and release a new version!

done! thanks for the review :)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
.changeset/tired-foxes-join.md (1)

30-30: Use the compound adjective “backward-compatible”

Minor language nit:

-This change is introduced in a backwards compatible way
+This change is introduced in a backward-compatible way
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19f233b and 2e793af.

📒 Files selected for processing (1)
  • .changeset/tired-foxes-join.md (1 hunks)
🧠 Learnings (1)
📓 Common learnings
Learnt from: ardatan
PR: ardatan/graphql-tools#0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The `isUrl` helper in @graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.
🪛 LanguageTool
.changeset/tired-foxes-join.md

[uncategorized] ~30-~30: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...} } ``` This change is introduced in a backwards compatible way to ensure no existing use cases are...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.17.2)
.changeset/tired-foxes-join.md

20-20: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: ardatan
PR: ardatan/graphql-tools#0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The `isUrl` helper in @graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.
🪛 LanguageTool
.changeset/tired-foxes-join.md

[uncategorized] ~30-~30: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...} } ``` This change is introduced in a backwards compatible way to ensure no existing use cases are...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.17.2)
.changeset/tired-foxes-join.md

20-20: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Full Check on GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Bun
🔇 Additional comments (1)
.changeset/tired-foxes-join.md (1)

20-27: Align config snippet with the actual option name exposed by the code

In the implementation, the option was added under pathAliases (see GraphQLFileLoaderOptions.pathAliases).
The snippet here shows mappings, which could mislead users and break copy-pasted examples.

Please double-check the exported option name and keep the doc consistent with the code.

@ardatan ardatan merged commit 692cfeb into ardatan:master Jul 22, 2025
15 checks passed
@HunterLarco HunterLarco deleted the hunter/import-alias branch July 22, 2025 13:07
@HunterLarco
Copy link
Contributor Author

HunterLarco commented Aug 26, 2025

Thanks for the PR! Could you create a (minor bump) changeset with yarn changeset? Then we can merge and release a new version!

@ardatan I'd love to start using this change :) is there anything I can do to help expedite #7314? Thanks!

@ardatan
Copy link
Owner

ardatan commented Aug 26, 2025

Merged 👍

@HunterLarco HunterLarco mentioned this pull request Aug 27, 2025
12 tasks
ardatan pushed a commit that referenced this pull request Sep 22, 2025
* import aliases

* self review

* fix typo

* address comments

* changeset
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

Successfully merging this pull request may close these issues.

2 participants