Skip to content

Conversation

Milly
Copy link
Contributor

@Milly Milly commented Aug 12, 2025

Summary

This PR adds support for the importMap property in Deno configuration files (deno.json / deno.jsonc), allowing plugins to specify external import map files for module resolution.

This PR maybe conflicts with #455, so after rebasing if needed.

Motivation

When providing multiple denops plugins in a single repository, each plugin directory
currently requires its own import_map.json file, leading to dependency duplication
across related plugins. This makes maintenance difficult as the same dependencies
must be updated in multiple files.

This PR adds support for the importMap property in deno.json/deno.jsonc files,
enabling plugins to reference shared import maps located elsewhere in the repository
structure.

Example use case:

denops/
├── my_relation_app/
│   ├── deno.jsonc  # "importMap": "../myapp/common-import-map.json"
│   └── main.ts
└── myapp/
    ├── deno.jsonc  # "importMap": "./common-import-map.json"
    ├── common-import-map.json  # Shared dependencies
    └── main.ts

This allows multiple related plugins to share a common import map, reducing
duplication and centralizing dependency management within the repository.

Changes

Support for importMap property

  • When a deno.json or deno.jsonc file contains an importMap property, the specified import map file will be loaded and used for module resolution
  • Import maps can be specified using relative paths from the path of the configuration file
  • If imports or scopes properties exist in the configuration, they take precedence over importMap (following Deno's standard behavior)

Additionally, Internal refactoring to use URL type

  • Refactored plugin script handling to use URL type internally throughout the loading process
  • Improved type safety by ensuring script paths are always valid URLs

Testing

  • with_deno_json/: Test case for importMap property referencing an external file
  • with_deno_json2/: Test case where both importMap and imports exist (imports takes precedence)

Summary by CodeRabbit

  • New Features

    • Plugin loading now supports import maps defined in deno.json/deno.jsonc and import_map.json/jsonc, including relative paths and imports-based overrides; script URLs are handled more reliably for loading/reloading.
  • Tests

    • Added tests verifying deno.json/deno.jsonc import-map support, relative import resolution, and import-map override behavior.
  • Chores

    • Updated tooling configuration to exclude new test data directories.

Previously, the script variable in the Plugin class was always treated as a URL
string, but since it was passed as a string type, there was no guarantee that
the content was actually a URL. This refactoring ensures type safety by using
URL type internally throughout the plugin loading process.
Copy link

coderabbitai bot commented Aug 12, 2025

Walkthrough

Migrates plugin loading to URL-driven imports, adds deno.json/deno.jsonc and import_map.json[c] import-map resolution (including overrides), updates reload/fragment handling, converts Plugin.script to a getter backed by a private URL, adds tests and testdata for deno.json-based import maps, and updates deno.jsonc excludes.

Changes

Cohort / File(s) Summary
Config exclusions
deno.jsonc
Adds tests/denops/testdata/with_deno_json/ and tests/denops/testdata/with_deno_json2/ to the exclude array.
Core loader refactor + import map
denops/@denops-private/plugin.ts
Switches script handling from strings to URL objects; adds #scriptUrl and get script(); replaces suffix-based reload with fragment+timestamp; introduces JSONC parsing and import-map resolution (deno.json, deno.jsonc, import_map.json, import_map.jsonc); uses ImportMapImporter when available; updates related runtime checks.
Plugin tests
denops/@denops-private/plugin_test.ts
Adds "importMap property support" tests covering deno.json import maps, relative import-map resolution, and imports override semantics (three scenarios).
Testdata: deno.json import map
tests/denops/testdata/with_deno_json/*
Adds deno.json pointing to other_path/other_name.json; adds other_path/helper.ts, other_path/other_name.json, and plugin_with_deno_json.ts plugin that uses @test/helper.
Testdata: deno.jsonc with imports override
tests/denops/testdata/with_deno_json2/*
Adds deno.jsonc with importMap and imports override; adds other_path/other_name.json, other_path/helper.ts, top-level helper.ts, and plugin_with_deno_json.ts demonstrating override behavior.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Plugin
  participant FS as FileSystem
  participant ImportMapImporter

  Caller->>Plugin: importPlugin(scriptUrl: URL)
  Plugin->>Plugin: resolveScriptUrl(scriptUrl)
  Plugin->>Plugin: refreshScriptFragment(scriptUrl)
  alt scriptUrl is file:
    Plugin->>FS: tryLoadImportMap(dirOf(scriptUrl))
    FS-->>Plugin: ImportMap or null
  else
    Plugin-->>Plugin: skip import-map lookup
  end
  alt ImportMap available
    Plugin->>ImportMapImporter: import(scriptUrl.href, importMap)
    ImportMapImporter-->>Plugin: module
  else
    Plugin->>Plugin: dynamic import(scriptUrl.href)
    Plugin-->>Plugin: module
  end
  Plugin-->>Caller: plugin module loaded
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • lambdalisue
  • Shougo

Poem

I hop on URLs, nose to the map,
deno.json guides my little lap.
Imports overridden, fragments new,
I load, I test, I nibble through.
A rabbit patch — happy and spry 🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3adcbdc and 9d640ba.

📒 Files selected for processing (12)
  • deno.jsonc (1 hunks)
  • denops/@denops-private/plugin.ts (7 hunks)
  • denops/@denops-private/plugin_test.ts (2 hunks)
  • tests/denops/testdata/with_deno_json/deno.json (1 hunks)
  • tests/denops/testdata/with_deno_json/other_path/helper.ts (1 hunks)
  • tests/denops/testdata/with_deno_json/other_path/other_name.json (1 hunks)
  • tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts (1 hunks)
  • tests/denops/testdata/with_deno_json2/deno.jsonc (1 hunks)
  • tests/denops/testdata/with_deno_json2/helper.ts (1 hunks)
  • tests/denops/testdata/with_deno_json2/other_path/helper.ts (1 hunks)
  • tests/denops/testdata/with_deno_json2/other_path/other_name.json (1 hunks)
  • tests/denops/testdata/with_deno_json2/plugin_with_deno_json.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/denops/testdata/with_deno_json2/other_path/other_name.json
🚧 Files skipped from review as they are similar to previous changes (10)
  • deno.jsonc
  • tests/denops/testdata/with_deno_json/deno.json
  • tests/denops/testdata/with_deno_json2/helper.ts
  • tests/denops/testdata/with_deno_json2/deno.jsonc
  • tests/denops/testdata/with_deno_json/other_path/helper.ts
  • tests/denops/testdata/with_deno_json/other_path/other_name.json
  • tests/denops/testdata/with_deno_json2/other_path/helper.ts
  • tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts
  • tests/denops/testdata/with_deno_json2/plugin_with_deno_json.ts
  • denops/@denops-private/plugin_test.ts
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: Milly
PR: vim-denops/denops.vim#418
File: tests/denops/runtime/functions/plugin/check_type_test.ts:6-6
Timestamp: 2024-09-14T17:09:30.174Z
Learning: In this project, import paths prefixed with `/denops-testdata/` are defined in `deno.jsonc` via an import map, and these import paths are valid.
📚 Learning: 2025-08-12T20:02:22.038Z
Learnt from: Milly
PR: vim-denops/denops.vim#456
File: denops/@denops-private/plugin.ts:138-144
Timestamp: 2025-08-12T20:02:22.038Z
Learning: On Windows, calling `new URL("C:\foo\bar")` incorrectly interprets "C:" as a URL scheme rather than treating it as a Windows file path. Therefore, when resolving script paths that could be either file paths or URLs, it's important to try `toFileUrl()` first to properly handle Windows file paths, then fall back to `new URL()` for actual URL schemes.

Applied to files:

  • denops/@denops-private/plugin.ts
📚 Learning: 2024-09-14T17:09:30.174Z
Learnt from: Milly
PR: vim-denops/denops.vim#418
File: tests/denops/runtime/functions/plugin/check_type_test.ts:6-6
Timestamp: 2024-09-14T17:09:30.174Z
Learning: In this project, import paths prefixed with `/denops-testdata/` are defined in `deno.jsonc` via an import map, and these import paths are valid.

Applied to files:

  • denops/@denops-private/plugin.ts
📚 Learning: 2024-07-08T01:52:22.851Z
Learnt from: lambdalisue
PR: vim-denops/denops.vim#344
File: denops/@denops-private/service.ts:183-183
Timestamp: 2024-07-08T01:52:22.851Z
Learning: In the `denops/denops-private/service.ts` file, initializing properties like `#loadedWaiter` in the constructor is a common and acceptable pattern.

Applied to files:

  • denops/@denops-private/plugin.ts
⏰ 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). (9)
  • GitHub Check: test (macos-latest, 1.45.0, v9.1.0448, v0.10.0)
  • GitHub Check: test (ubuntu-latest, 1.45.0, v9.1.0448, v0.10.0)
  • GitHub Check: test (ubuntu-latest, 2.x, v9.1.0448, v0.10.0)
  • GitHub Check: test (macos-latest, 2.x, v9.1.0448, v0.10.0)
  • GitHub Check: test (macos-latest, 1.x, v9.1.0448, v0.10.0)
  • GitHub Check: test (ubuntu-latest, 1.x, v9.1.0448, v0.10.0)
  • GitHub Check: test (windows-latest, 2.x, v9.1.0448, v0.10.0)
  • GitHub Check: test (windows-latest, 1.45.0, v9.1.0448, v0.10.0)
  • GitHub Check: test (windows-latest, 1.x, v9.1.0448, v0.10.0)
🔇 Additional comments (9)
denops/@denops-private/plugin.ts (9)

1-3: Good addition of type check utilities.

These imports support the new import map property detection logic and enhance type safety throughout the file.


25-31: LGTM: Clean transition to URL-based script handling.

The migration from readonly script: string to a private #scriptUrl: URL with a public getter maintains API compatibility while improving internal type safety. The getter appropriately returns href to preserve the original string interface.


36-36: LGTM: Constructor properly initializes URL-based script handling.

The change to store the resolved URL in #scriptUrl aligns with the new URL-centric architecture.


47-47: LGTM: Plugin loading now uses URL-based import.

The change from string-based script handling to URL-based importPlugin(this.#scriptUrl) is consistent with the architectural improvement.


118-128: LGTM: Improved fragment handling for reload functionality.

The refactored refreshScriptFragment function properly handles URL objects and preserves existing fragments while adding timestamps for reloads. The logic correctly maintains the loaded scripts set using href as the key.


159-163: LGTM: JSONC parser for configuration files.

The loadJson function appropriately uses JSONC parsing to handle both JSON and JSONC files permissively, which is essential for Deno configuration file support.


165-170: LGTM: Proper import map property detection.

The hasImportMapProperty validator correctly checks for:

  • Required importMap string property
  • Absence of imports and scopes (which take precedence per Deno's behavior)

This aligns with the PR objective to follow Deno's standard precedence rules.


173-216: LGTM: Comprehensive import map loading logic.

The enhanced tryLoadImportMap function properly:

  • Accepts URL parameters for consistency
  • Restricts to file: protocol (appropriate security measure)
  • Handles both direct import maps and Deno config files with importMap property
  • Resolves relative import map paths correctly
  • Uses proper error handling for file operations

The implementation follows Deno's import map resolution behavior accurately.


218-227: LGTM: URL-based plugin import with import map support.

The importPlugin function correctly:

  • Refreshes script fragments for reload functionality
  • Attempts to load import maps for the script
  • Uses ImportMapImporter when available, falling back to direct import
  • Maintains consistent URL-based handling throughout

This completes the integration of import map support as specified in the PR objectives.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch importmap-path

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

Copy link

codecov bot commented Aug 12, 2025

Codecov Report

❌ Patch coverage is 98.18182% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 97.26%. Comparing base (b0ee649) to head (9d640ba).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
denops/@denops-private/plugin.ts 98.18% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #456      +/-   ##
==========================================
+ Coverage   96.77%   97.26%   +0.48%     
==========================================
  Files          11       11              
  Lines         962      986      +24     
  Branches      143      149       +6     
==========================================
+ Hits          931      959      +28     
+ Misses         28       24       -4     
  Partials        3        3              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@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 (5)
denops/@denops-private/plugin.ts (2)

158-163: Add context-rich error on JSON parse failure (optional).

Parsing errors from JSON/JSONC currently bubble with no file context. Wrapping them with the file URL greatly improves debuggability.

Apply this diff:

 async function loadJson(fileUrl: URL): Promise<unknown> {
-  const content = await Deno.readTextFile(fileUrl);
-  // Always parse as JSONC to be more permissive
-  return parseJsonc(content);
+  const content = await Deno.readTextFile(fileUrl);
+  // Always parse as JSONC to be more permissive
+  try {
+    return parseJsonc(content);
+  } catch (e) {
+    throw new Error(`Failed to parse JSON/JSONC: ${fileUrl.href}\n${e instanceof Error ? e.message : String(e)}`);
+  }
 }

117-127: Fragment-based cache busting is correct; minor polish optional.

The fragment-preserving reload logic works. If you want slightly cleaner fragments, you can avoid nested # by stripping the leading # from scriptUrl.hash before concatenation.

Apply this diff:

-  if (loadedScripts.has(scriptUrl.href)) {
-    // Keep the original fragment and add a timestamp
-    const fragment = `${scriptUrl.hash}#${performance.now()}`;
-    return new URL(fragment, scriptUrl);
-  }
+  if (loadedScripts.has(scriptUrl.href)) {
+    // Keep the original fragment (without leading '#') and add a timestamp
+    const baseFrag = scriptUrl.hash.startsWith("#")
+      ? scriptUrl.hash.slice(1)
+      : scriptUrl.hash;
+    const fragment = `#${baseFrag ? `${baseFrag}#` : ""}${performance.now()}`;
+    return new URL(fragment, scriptUrl);
+  }
tests/denops/testdata/with_deno_json2/plugin_with_deno_json.ts (1)

1-13: Avoid shell-quoting issues when echoing dynamic strings (test robustness).

Embedding unescaped strings in Vim script can break when the string contains quotes. Using JSON.stringify ensures safe quoting in tests.

Apply this diff:

-      await denops.cmd(`echo '${message}'`);
+      await denops.cmd(`echomsg ${JSON.stringify(message)}`);
tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts (1)

8-12: Guard against Vimscript quoting issues in echoed strings

Using single quotes around interpolated values can break if the string contains a single quote. While this is acceptable for a controlled test fixture, a safer pattern is to let Vim parse a JSON string literal.

If you want to harden this (note: tests would need corresponding expectation updates), prefer:

-      await denops.cmd(`echo '${message}'`);
+      await denops.cmd(`echo ${JSON.stringify(message)}`);

-  await denops.cmd("echo 'Deno json plugin initialized'");
+  await denops.cmd(`echo ${JSON.stringify("Deno json plugin initialized")}`);
denops/@denops-private/plugin_test.ts (1)

573-652: Avoid dangling plugin instances: unload after each subtest

Unloading avoids potential cross-test leakage and keeps lifecycle symmetrical with other tests that cover unload scenarios. Suggested additions are safe since assertions occur before unload.

@@
     await t.step("loads plugin with deno.json", async () => {
@@
       assertSpyCall(_denops_cmd, 0, {
         args: ["echo 'Deno json plugin initialized'"],
       });
     });
+    // Optional: clean up
+    await plugin.unload();
@@
     await t.step("plugin can use mapped imports", async () => {
@@
       // Should return the greeting from the mapped import
       assertEquals(result, "Hello from relative import map!");
     });
+    // Optional: clean up
+    await plugin.unload();
@@
     await t.step("importMap is overridden by imports", async () => {
@@
       // Should return the greeting from the mapped import
       assertEquals(result, "Hello from mapped import!");
     });
+    // Optional: clean up
+    await plugin.unload();
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b0ee649 and 3adcbdc.

📒 Files selected for processing (12)
  • deno.jsonc (1 hunks)
  • denops/@denops-private/plugin.ts (7 hunks)
  • denops/@denops-private/plugin_test.ts (2 hunks)
  • tests/denops/testdata/with_deno_json/deno.json (1 hunks)
  • tests/denops/testdata/with_deno_json/other_path/helper.ts (1 hunks)
  • tests/denops/testdata/with_deno_json/other_path/other_name.json (1 hunks)
  • tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts (1 hunks)
  • tests/denops/testdata/with_deno_json2/deno.jsonc (1 hunks)
  • tests/denops/testdata/with_deno_json2/helper.ts (1 hunks)
  • tests/denops/testdata/with_deno_json2/other_path/helper.ts (1 hunks)
  • tests/denops/testdata/with_deno_json2/other_path/other_name.json (1 hunks)
  • tests/denops/testdata/with_deno_json2/plugin_with_deno_json.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: Milly
PR: vim-denops/denops.vim#418
File: tests/denops/runtime/functions/plugin/check_type_test.ts:6-6
Timestamp: 2024-09-14T17:09:30.174Z
Learning: In this project, import paths prefixed with `/denops-testdata/` are defined in `deno.jsonc` via an import map, and these import paths are valid.
📚 Learning: 2024-09-14T17:09:30.174Z
Learnt from: Milly
PR: vim-denops/denops.vim#418
File: tests/denops/runtime/functions/plugin/check_type_test.ts:6-6
Timestamp: 2024-09-14T17:09:30.174Z
Learning: In this project, import paths prefixed with `/denops-testdata/` are defined in `deno.jsonc` via an import map, and these import paths are valid.

Applied to files:

  • tests/denops/testdata/with_deno_json2/deno.jsonc
  • tests/denops/testdata/with_deno_json2/helper.ts
  • tests/denops/testdata/with_deno_json/deno.json
  • tests/denops/testdata/with_deno_json/other_path/other_name.json
  • deno.jsonc
  • tests/denops/testdata/with_deno_json2/other_path/other_name.json
  • tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts
  • tests/denops/testdata/with_deno_json/other_path/helper.ts
  • denops/@denops-private/plugin_test.ts
  • denops/@denops-private/plugin.ts
📚 Learning: 2024-07-08T01:52:22.851Z
Learnt from: lambdalisue
PR: vim-denops/denops.vim#344
File: denops/@denops-private/service.ts:183-183
Timestamp: 2024-07-08T01:52:22.851Z
Learning: In the `denops/denops-private/service.ts` file, initializing properties like `#loadedWaiter` in the constructor is a common and acceptable pattern.

Applied to files:

  • denops/@denops-private/plugin.ts
🧬 Code Graph Analysis (6)
tests/denops/testdata/with_deno_json2/plugin_with_deno_json.ts (2)
tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts (1)
  • main (4-13)
tests/denops/testdata/with_deno_json2/helper.ts (2)
  • getMessage (3-5)
  • greeting (1-1)
tests/denops/testdata/with_deno_json2/helper.ts (2)
tests/denops/testdata/with_deno_json/other_path/helper.ts (2)
  • greeting (1-1)
  • getMessage (3-5)
tests/denops/testdata/with_deno_json2/other_path/helper.ts (2)
  • greeting (1-1)
  • getMessage (3-5)
tests/denops/testdata/with_deno_json2/other_path/helper.ts (2)
tests/denops/testdata/with_deno_json/other_path/helper.ts (2)
  • greeting (1-1)
  • getMessage (3-5)
tests/denops/testdata/with_deno_json2/helper.ts (2)
  • greeting (1-1)
  • getMessage (3-5)
tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts (3)
tests/denops/testdata/with_deno_json/other_path/helper.ts (2)
  • getMessage (3-5)
  • greeting (1-1)
tests/denops/testdata/with_deno_json2/helper.ts (2)
  • getMessage (3-5)
  • greeting (1-1)
tests/denops/testdata/with_deno_json2/other_path/helper.ts (2)
  • getMessage (3-5)
  • greeting (1-1)
tests/denops/testdata/with_deno_json/other_path/helper.ts (1)
tests/denops/testdata/with_deno_json2/helper.ts (2)
  • greeting (1-1)
  • getMessage (3-5)
denops/@denops-private/plugin_test.ts (2)
tests/denops/testdata/resolve.ts (1)
  • resolveTestDataURL (9-11)
denops/@denops-private/plugin.ts (1)
  • Plugin (19-109)
🔇 Additional comments (19)
tests/denops/testdata/with_deno_json2/other_path/other_name.json (1)

1-5: Import map entry looks correct and appropriately scoped

The single-specifier mapping and relative target path are valid and align with Deno’s import map resolution (relative to the map file). Good for the test scenario.

deno.jsonc (2)

18-19: Excluding new testdata fixtures is consistent with existing config

Adding these directories to exclude is aligned with how other testdata fixtures are handled and should prevent tooling from traversing them inadvertently.


18-19: Top-level “exclude” is applied to all Deno subcommands (check, test, fmt, lint)

Deno’s config automatically honors the top-level "exclude" entries for every subcommand—even when you pass glob patterns on the CLI. In your deno.jsonc, the lines:

  • "tests/denops/testdata/with_deno_json/",
  • "tests/denops/testdata/with_deno_json2/",

will be excluded from deno check, deno test, deno fmt, and deno lint by default. To include them:

• Add a negated glob in the appropriate tool-specific section (supported in Deno v1.41.2+). For example:

"test": {
  "include": ["tests/**/*.ts"],
  "exclude": [
    "tests/denops/testdata/with_deno_json/",
    "tests/denops/testdata/with_deno_json2/",
    // “Un-exclude” these paths:
    "!tests/denops/testdata/with_deno_json/",
    "!tests/denops/testdata/with_deno_json2/"
  ]
}

• Note: A known bug in Deno 2.4.1 may prevent deno fmt from un-excluding certain globs—consider upgrading or adjusting your patterns if you encounter issues.

tests/denops/testdata/with_deno_json2/helper.ts (1)

1-5: Test helper content is clear and minimal

Exports and messaging are straightforward and distinct from the relative-map variant, which helps assert precedence and resolution paths.

tests/denops/testdata/with_deno_json2/other_path/helper.ts (1)

1-5: Relative import-map helper is correct

Matches the mapping intent from the external import map file and provides clear, deterministic output for assertions.

tests/denops/testdata/with_deno_json/other_path/helper.ts (1)

1-5: LGTM: mirrors the relative import-map variant for the first test suite

Consistent with the with_deno_json fixtures; exports are minimal and test-friendly.

denops/@denops-private/plugin.ts (4)

171-218: Import map resolution logic is sound and mirrors Deno’s precedence.

  • Only attempts for file: URLs.
  • Checks deno.json/deno.jsonc first, honors imports/scopes over importMap, then falls back to import_map.json[c].
  • Stops searching once a config exists but doesn’t yield an import map (matching Deno behavior).

Looks good.


164-170: Good: importMap gating respects Deno precedence.

The hasImportMapProperty guard correctly ignores importMap when imports or scopes exist, aligning with Deno’s “inline imports/scopes take precedence” behavior.


220-229: Importer fallback and URL-based import are clean.

  • Uses ImportMapImporter when available; otherwise falls back to dynamic import.
  • Passes href consistently.

LGTM.


24-30: Public script getter backed by URL is a safe API refinement.

The getter preserves the original shape (string) while improving internal type safety with URL.

tests/denops/testdata/with_deno_json/other_path/other_name.json (1)

1-5: Import map test fixture LGTM.

Minimal and correct mapping for the test case.

tests/denops/testdata/with_deno_json2/deno.jsonc (1)

1-8: Config correctly models “imports overrides importMap.”

Accurately captures Deno precedence for tests.

tests/denops/testdata/with_deno_json/deno.json (1)

1-3: Config for external import map reference LGTM.

Straightforward importMap reference for the test dataset.

tests/denops/testdata/with_deno_json/plugin_with_deno_json.ts (1)

1-13: Test fixture aligns with PR intent and uses Entrypoint + mapped imports correctly

This plugin is minimal, focuses on mapped imports via deno.json importMap, and matches the expectations asserted in tests. Looks good.

denops/@denops-private/plugin_test.ts (5)

30-35: New test data script constants look correct

Paths are resolved via resolveTestDataURL and point to the intended fixtures. No issues.


573-604: “loads plugin with deno.json” — assertions correctly validate load path and events

This verifies importMap property support through deno.json and checks event emissions and init echo. Solid coverage.


605-627: “plugin can use mapped imports” — effectively verifies import map resolution via deno.json

Resets spy counts, calls dispatcher, and asserts both echo side-effect and return value. LGTM.


629-651: “importMap is overridden by imports” — confirms Deno precedence semantics

This ensures imports overrides importMap, matching Deno behavior and PR objectives. Well targeted.


573-652: Import map fixtures configuration verified

All of the repository and fixture import-map settings are correct:

  • Root deno.jsonc excludes both
    tests/denops/testdata/with_deno_json/ and
    tests/denops/testdata/with_deno_json2/.
  • tests/denops/testdata/with_deno_json/deno.json declares
    importMap: "./other_path/other_name.json",
    and that file exists with the expected imports mapping.
  • tests/denops/testdata/with_deno_json2/deno.jsonc declares
    importMap: "./other_path/other_name.json"
    and defines a local imports block that correctly overrides the same specifier.

No further action required.

@lambdalisue
Copy link
Member

@lambdalisue
Copy link
Member

lambdalisue commented Aug 16, 2025

Wait, I may mis-read. Could you explain what this PR for (rather than what this PR is)

This adds support for the `importMap` property in deno configuration
files. When a deno.json or deno.jsonc file with an `importMap` property,
the specified import map file will be loaded and used for module
resolution.
@Milly
Copy link
Contributor Author

Milly commented Aug 21, 2025

Wait, I may mis-read. Could you explain what this PR for (rather than what this PR is)

I'm added Motivation section to PR top comment.

@Milly
Copy link
Contributor Author

Milly commented Aug 21, 2025

https://docs.deno.com/runtime/fundamentals/workspaces/#configuring-built-in-deno-tools

Exclusive with imports and scopes per config file. Additionally, it is not supported to have importMap in the workspace config, and imports in the package config.

Oops, including importMap in the workspace config is not officially supported by Deno.
Unfortunately, this PR closes.

@lambdalisue
Copy link
Member

So can we close?

@Milly Milly closed this Aug 24, 2025
@Shougo Shougo deleted the importmap-path branch August 24, 2025 08:41
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