summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-08-07 09:43:05 +0200
committerGitHub <noreply@github.com>2024-08-07 07:43:05 +0000
commit04473c04ed59cc2a987af3405074591fbc1341a4 (patch)
tree50d56d1990328a6d32627e74ef73514525d78fde
parent4fa8869f2487749a9f190cb3047f4f3e6d571f27 (diff)
fix(compile): support workspace members importing other members (#24909)
-rw-r--r--Cargo.lock12
-rw-r--r--cli/Cargo.toml6
-rw-r--r--cli/args/mod.rs1
-rw-r--r--cli/errors.rs5
-rw-r--r--cli/graph_util.rs3
-rw-r--r--cli/lsp/config.rs1
-rw-r--r--cli/lsp/jsr.rs27
-rw-r--r--cli/lsp/resolver.rs1
-rw-r--r--cli/resolver.rs6
-rw-r--r--cli/standalone/binary.rs21
-rw-r--r--cli/standalone/mod.rs15
-rw-r--r--cli/tools/doc.rs1
-rw-r--r--cli/tools/lint/rules/no_sloppy_imports.rs6
-rw-r--r--cli/tools/registry/unfurl.rs15
-rw-r--r--cli/tools/vendor/test.rs1
-rw-r--r--tests/integration/lsp_tests.rs5
-rw-r--r--tests/specs/compile/workspace/__test__.jsonc22
-rw-r--r--tests/specs/compile/workspace/add/deno.json5
-rw-r--r--tests/specs/compile/workspace/add/mod.test.ts6
-rw-r--r--tests/specs/compile/workspace/add/mod.ts3
-rw-r--r--tests/specs/compile/workspace/deno.json9
-rw-r--r--tests/specs/compile/workspace/deno.lock26
-rw-r--r--tests/specs/compile/workspace/main.out1
-rw-r--r--tests/specs/compile/workspace/main.ts3
-rw-r--r--tests/specs/compile/workspace/subtract/deno.json5
-rw-r--r--tests/specs/compile/workspace/subtract/mod.test.ts6
-rw-r--r--tests/specs/compile/workspace/subtract/mod.ts5
-rw-r--r--tests/specs/run/workspaces/basic/main.out6
28 files changed, 171 insertions, 52 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e3f51056c..b962ef131 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1329,9 +1329,9 @@ dependencies = [
[[package]]
name = "deno_config"
-version = "0.26.1"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8188c39699541affc0c0f89bbba07d31212385fa0c4e1a5a9e530b0f3cbc776f"
+checksum = "fc1f3c577bf7fdbb449cb99c2560309364c71cc3dcc7af94387ef8810b089173"
dependencies = [
"anyhow",
"deno_package_json",
@@ -1552,9 +1552,9 @@ dependencies = [
[[package]]
name = "deno_graph"
-version = "0.81.0"
+version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31f1f965754dcdbaa5c9433a8c8da4a3cb7d93f29b58aa84b5617fe887f57415"
+checksum = "d2cada0d9fd56536d3208cff2b130096e396ee2716466850cf0b7927249e40a0"
dependencies = [
"anyhow",
"async-trait",
@@ -1955,9 +1955,9 @@ dependencies = [
[[package]]
name = "deno_semver"
-version = "0.5.7"
+version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e23ce551a58eeefc05a48042a9c76d3409c96a1a6a522a82c4ced26930ece201"
+checksum = "9fb7520ac21cb236c6f8cc81964e8bf22c72fc58c7b5f762f99b9a95abfe3212"
dependencies = [
"monch",
"once_cell",
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 510c10ea9..6d9e1b7b2 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -65,17 +65,17 @@ winres.workspace = true
[dependencies]
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
deno_cache_dir = { workspace = true }
-deno_config = { version = "=0.26.1", features = ["workspace", "sync"] }
+deno_config = { version = "=0.28.0", features = ["workspace", "sync"] }
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_doc = { version = "0.145.0", features = ["html", "syntect"] }
deno_emit = "=0.44.0"
-deno_graph = { version = "=0.81.0" }
+deno_graph = { version = "=0.81.1" }
deno_lint = { version = "=0.62.0", features = ["docs"] }
deno_lockfile.workspace = true
deno_npm = "=0.21.4"
deno_package_json.workspace = true
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
-deno_semver = "=0.5.7"
+deno_semver = "=0.5.9"
deno_task_shell = "=0.17.0"
deno_terminal.workspace = true
eszip = "=0.73.0"
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index fcc1a8d7c..ddfdb95c4 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -1435,7 +1435,6 @@ impl CliOptions {
self
.workspace()
.jsr_packages()
- .into_iter()
.map(|pkg| config_to_deno_graph_workspace_member(&pkg.config_file))
.collect::<Result<Vec<_>, _>>()
}
diff --git a/cli/errors.rs b/cli/errors.rs
index a8fde6e76..25b3fc332 100644
--- a/cli/errors.rs
+++ b/cli/errors.rs
@@ -29,7 +29,6 @@ fn get_diagnostic_class(_: &ParseDiagnostic) -> &'static str {
fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str {
use deno_graph::JsrLoadError;
use deno_graph::NpmLoadError;
- use deno_graph::WorkspaceLoadError;
match err {
ModuleGraphError::ResolutionError(err)
@@ -71,10 +70,6 @@ fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str {
| JsrLoadError::PackageVersionNotFound(_)
| JsrLoadError::UnknownExport { .. } => "NotFound",
},
- ModuleLoadError::Workspace(err) => match err {
- WorkspaceLoadError::MemberInvalidExportPath { .. } => "TypeError",
- WorkspaceLoadError::MissingMemberExports { .. } => "NotFound",
- },
},
},
}
diff --git a/cli/graph_util.rs b/cli/graph_util.rs
index 91549472e..77d086fa8 100644
--- a/cli/graph_util.rs
+++ b/cli/graph_util.rs
@@ -500,8 +500,6 @@ impl ModuleGraphBuilder {
.maybe_file_watcher_reporter
.as_ref()
.map(|r| r.as_reporter());
- let workspace_members =
- self.options.resolve_deno_graph_workspace_members()?;
let mut locker = self
.lockfile
.as_ref()
@@ -515,7 +513,6 @@ impl ModuleGraphBuilder {
imports: maybe_imports,
is_dynamic: options.is_dynamic,
passthrough_jsr_specifiers: false,
- workspace_members: &workspace_members,
executor: Default::default(),
file_system: &DenoGraphFsAdapter(self.fs.as_ref()),
jsr_url_provider: &CliJsrUrlProvider,
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs
index c48544a2d..bbfe3a6df 100644
--- a/cli/lsp/config.rs
+++ b/cli/lsp/config.rs
@@ -1518,6 +1518,7 @@ impl ConfigData {
WorkspaceResolver::new_raw(
scope.clone(),
None,
+ member_dir.workspace.resolver_jsr_pkgs().collect(),
member_dir.workspace.package_jsons().cloned().collect(),
pkg_json_dep_resolution,
)
diff --git a/cli/lsp/jsr.rs b/cli/lsp/jsr.rs
index b02e01fb6..9ffcdf9e6 100644
--- a/cli/lsp/jsr.rs
+++ b/cli/lsp/jsr.rs
@@ -20,7 +20,6 @@ use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use deno_semver::Version;
use serde::Deserialize;
-use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::Arc;
@@ -157,7 +156,7 @@ impl JsrCacheResolver {
let maybe_nv = self.req_to_nv(&req);
let nv = maybe_nv.as_ref()?;
let info = self.package_version_info(nv)?;
- let path = info.export(&normalize_export_name(req_ref.sub_path()))?;
+ let path = info.export(&req_ref.export_name())?;
if let Some(workspace_scope) = self.workspace_scope_by_name.get(&nv.name) {
workspace_scope.join(path).ok()
} else {
@@ -267,30 +266,6 @@ fn read_cached_url(
.ok()?
}
-// TODO(nayeemrmn): This is duplicated from a private function in deno_graph
-// 0.65.1. Make it public or cleanup otherwise.
-fn normalize_export_name(sub_path: Option<&str>) -> Cow<str> {
- let Some(sub_path) = sub_path else {
- return Cow::Borrowed(".");
- };
- if sub_path.is_empty() || matches!(sub_path, "/" | ".") {
- Cow::Borrowed(".")
- } else {
- let sub_path = if sub_path.starts_with('/') {
- Cow::Owned(format!(".{}", sub_path))
- } else if !sub_path.starts_with("./") {
- Cow::Owned(format!("./{}", sub_path))
- } else {
- Cow::Borrowed(sub_path)
- };
- if let Some(prefix) = sub_path.strip_suffix('/') {
- Cow::Owned(prefix.to_string())
- } else {
- sub_path
- }
- }
-}
-
#[derive(Debug)]
pub struct CliJsrSearchApi {
file_fetcher: Arc<FileFetcher>,
diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs
index d6fc3096c..dec46566f 100644
--- a/cli/lsp/resolver.rs
+++ b/cli/lsp/resolver.rs
@@ -523,6 +523,7 @@ fn create_graph_resolver(
Arc::new(ModuleSpecifier::parse("file:///").unwrap()),
None,
Vec::new(),
+ Vec::new(),
PackageJsonDepResolution::Disabled,
))
},
diff --git a/cli/resolver.rs b/cli/resolver.rs
index 18804c025..b72fcd322 100644
--- a/cli/resolver.rs
+++ b/cli/resolver.rs
@@ -535,6 +535,9 @@ impl Resolver for CliGraphResolver {
MappedResolutionError::ImportMap(err) => {
ResolveError::Other(err.into())
}
+ MappedResolutionError::Workspace(err) => {
+ ResolveError::Other(err.into())
+ }
});
let result = match result {
Ok(resolution) => match resolution {
@@ -552,6 +555,9 @@ impl Resolver for CliGraphResolver {
Ok(specifier)
}
}
+ MappedResolution::WorkspaceJsrPackage { specifier, .. } => {
+ Ok(specifier)
+ }
MappedResolution::WorkspaceNpmPackage {
target_pkg_json: pkg_json,
sub_path,
diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs
index 8fb640be3..ed38e164b 100644
--- a/cli/standalone/binary.rs
+++ b/cli/standalone/binary.rs
@@ -19,6 +19,7 @@ use std::process::Command;
use deno_ast::ModuleSpecifier;
use deno_config::workspace::PackageJsonDepResolution;
+use deno_config::workspace::ResolverWorkspaceJsrPackage;
use deno_config::workspace::Workspace;
use deno_config::workspace::WorkspaceResolver;
use deno_core::anyhow::bail;
@@ -33,6 +34,7 @@ use deno_npm::NpmSystemInfo;
use deno_runtime::deno_node::PackageJson;
use deno_semver::npm::NpmVersionReqParseError;
use deno_semver::package::PackageReq;
+use deno_semver::Version;
use deno_semver::VersionReqSpecifierParseError;
use eszip::EszipRelativeFileBaseUrl;
use indexmap::IndexMap;
@@ -80,9 +82,18 @@ pub struct SerializedWorkspaceResolverImportMap {
pub json: String,
}
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SerializedResolverWorkspaceJsrPackage {
+ pub relative_base: String,
+ pub name: String,
+ pub version: Option<Version>,
+ pub exports: IndexMap<String, String>,
+}
+
#[derive(Deserialize, Serialize)]
pub struct SerializedWorkspaceResolver {
pub import_map: Option<SerializedWorkspaceResolverImportMap>,
+ pub jsr_pkgs: Vec<SerializedResolverWorkspaceJsrPackage>,
pub package_jsons: BTreeMap<String, serde_json::Value>,
pub pkg_json_resolution: PackageJsonDepResolution,
}
@@ -620,6 +631,16 @@ impl<'a> DenoCompileBinaryWriter<'a> {
json: i.to_json(),
}
}),
+ jsr_pkgs: self
+ .workspace_resolver
+ .jsr_packages()
+ .map(|pkg| SerializedResolverWorkspaceJsrPackage {
+ relative_base: root_dir_url.specifier_key(&pkg.base).into_owned(),
+ name: pkg.name.clone(),
+ version: pkg.version.clone(),
+ exports: pkg.exports.clone(),
+ })
+ .collect(),
package_jsons: self
.workspace_resolver
.package_jsons()
diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs
index e4661051a..635293cc9 100644
--- a/cli/standalone/mod.rs
+++ b/cli/standalone/mod.rs
@@ -8,6 +8,7 @@
use deno_ast::MediaType;
use deno_config::workspace::MappedResolution;
use deno_config::workspace::MappedResolutionError;
+use deno_config::workspace::ResolverWorkspaceJsrPackage;
use deno_config::workspace::WorkspaceResolver;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
@@ -169,6 +170,9 @@ impl ModuleLoader for EmbeddedModuleLoader {
self.shared.workspace_resolver.resolve(specifier, &referrer);
match mapped_resolution {
+ Ok(MappedResolution::WorkspaceJsrPackage { specifier, .. }) => {
+ Ok(specifier)
+ }
Ok(MappedResolution::WorkspaceNpmPackage {
target_pkg_json: pkg_json,
sub_path,
@@ -613,6 +617,17 @@ pub async fn run(
WorkspaceResolver::new_raw(
root_dir_url.clone(),
import_map,
+ metadata
+ .workspace_resolver
+ .jsr_pkgs
+ .iter()
+ .map(|pkg| ResolverWorkspaceJsrPackage {
+ base: root_dir_url.join(&pkg.relative_base).unwrap(),
+ name: pkg.name.clone(),
+ version: pkg.version.clone(),
+ exports: pkg.exports.clone(),
+ })
+ .collect(),
pkg_jsons,
metadata.workspace_resolver.pkg_json_resolution,
)
diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs
index bc0d81cc9..e7eab9b91 100644
--- a/cli/tools/doc.rs
+++ b/cli/tools/doc.rs
@@ -59,7 +59,6 @@ async fn generate_doc_nodes_for_builtin_types(
imports: Vec::new(),
is_dynamic: false,
passthrough_jsr_specifiers: false,
- workspace_members: &[],
executor: Default::default(),
file_system: &NullFileSystem,
jsr_url_provider: Default::default(),
diff --git a/cli/tools/lint/rules/no_sloppy_imports.rs b/cli/tools/lint/rules/no_sloppy_imports.rs
index b5e057bfc..1ae792e08 100644
--- a/cli/tools/lint/rules/no_sloppy_imports.rs
+++ b/cli/tools/lint/rules/no_sloppy_imports.rs
@@ -203,10 +203,14 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> {
None => Ok(specifier),
}
}
- deno_config::workspace::MappedResolution::WorkspaceNpmPackage {
+ deno_config::workspace::MappedResolution::WorkspaceJsrPackage {
+ ..
+ }
+ | deno_config::workspace::MappedResolution::WorkspaceNpmPackage {
..
}
| deno_config::workspace::MappedResolution::PackageJson { .. } => {
+ // this error is ignored
Err(ResolveError::Other(anyhow!("")))
}
}
diff --git a/cli/tools/registry/unfurl.rs b/cli/tools/registry/unfurl.rs
index a28ba445a..489c9a1be 100644
--- a/cli/tools/registry/unfurl.rs
+++ b/cli/tools/registry/unfurl.rs
@@ -75,6 +75,9 @@ impl SpecifierUnfurler {
match resolved {
MappedResolution::Normal(specifier)
| MappedResolution::ImportMap(specifier) => Some(specifier),
+ MappedResolution::WorkspaceJsrPackage { pkg_req_ref, .. } => {
+ Some(ModuleSpecifier::parse(&pkg_req_ref.to_string()).unwrap())
+ }
MappedResolution::WorkspaceNpmPackage {
target_pkg_json: pkg_json,
pkg_name,
@@ -388,11 +391,14 @@ mod tests {
use super::*;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
+ use deno_config::workspace::ResolverWorkspaceJsrPackage;
use deno_core::serde_json::json;
use deno_core::url::Url;
use deno_runtime::deno_fs::RealFs;
use deno_runtime::deno_node::PackageJson;
+ use deno_semver::Version;
use import_map::ImportMapWithDiagnostics;
+ use indexmap::IndexMap;
use pretty_assertions::assert_eq;
use test_util::testdata_path;
@@ -436,6 +442,13 @@ mod tests {
let workspace_resolver = WorkspaceResolver::new_raw(
Arc::new(ModuleSpecifier::from_directory_path(&cwd).unwrap()),
Some(import_map),
+ vec![ResolverWorkspaceJsrPackage {
+ base: ModuleSpecifier::from_directory_path(cwd.join("jsr-package"))
+ .unwrap(),
+ name: "@denotest/example".to_string(),
+ version: Some(Version::parse_standard("1.0.0").unwrap()),
+ exports: IndexMap::from([(".".to_string(), "mod.ts".to_string())]),
+ }],
vec![Arc::new(package_json)],
deno_config::workspace::PackageJsonDepResolution::Enabled,
);
@@ -458,6 +471,7 @@ import b from "./b.js";
import b2 from "./b";
import "./mod.ts";
import url from "url";
+import "@denotest/example";
// TODO: unfurl these to jsr
// import "npm:@jsr/std__fs@1/file";
// import "npm:@jsr/std__fs@1";
@@ -507,6 +521,7 @@ import b from "./b.ts";
import b2 from "./b.ts";
import "./mod.ts";
import url from "node:url";
+import "jsr:@denotest/example@^1.0.0";
// TODO: unfurl these to jsr
// import "npm:@jsr/std__fs@1/file";
// import "npm:@jsr/std__fs@1";
diff --git a/cli/tools/vendor/test.rs b/cli/tools/vendor/test.rs
index dc851858e..65f37efdc 100644
--- a/cli/tools/vendor/test.rs
+++ b/cli/tools/vendor/test.rs
@@ -300,6 +300,7 @@ fn build_resolver(
Arc::new(ModuleSpecifier::from_directory_path(root_dir).unwrap()),
maybe_original_import_map,
Vec::new(),
+ Vec::new(),
deno_config::workspace::PackageJsonDepResolution::Enabled,
)),
maybe_jsx_import_source_config,
diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs
index d89061683..28c36cd20 100644
--- a/tests/integration/lsp_tests.rs
+++ b/tests/integration/lsp_tests.rs
@@ -14198,7 +14198,10 @@ fn lsp_deno_json_workspace_jsr_resolution() {
json!({
"contents": {
"kind": "markdown",
- "value": format!("**Resolved Dependency**\n\n**Code**: jsr&#8203;:&#8203;@org/project1&#8203;@^1.0.0 (<{}project1/mod.ts>)\n", temp_dir.uri()),
+ "value": format!(
+ "**Resolved Dependency**\n\n**Code**: file&#8203;://{}\n",
+ temp_dir.uri().join("project1/mod.ts").unwrap().path(),
+ ),
},
"range": {
"start": { "line": 0, "character": 7 },
diff --git a/tests/specs/compile/workspace/__test__.jsonc b/tests/specs/compile/workspace/__test__.jsonc
new file mode 100644
index 000000000..be2bbd1e4
--- /dev/null
+++ b/tests/specs/compile/workspace/__test__.jsonc
@@ -0,0 +1,22 @@
+{
+ "tempDir": true,
+ "steps": [{
+ "if": "unix",
+ "args": "compile --output main main.ts",
+ "output": "[WILDCARD]"
+ }, {
+ "if": "unix",
+ "commandName": "./main",
+ "args": [],
+ "output": "main.out"
+ }, {
+ "if": "windows",
+ "args": "compile --output main.exe main.ts",
+ "output": "[WILDCARD]"
+ }, {
+ "if": "windows",
+ "commandName": "./main.exe",
+ "args": [],
+ "output": "main.out"
+ }]
+}
diff --git a/tests/specs/compile/workspace/add/deno.json b/tests/specs/compile/workspace/add/deno.json
new file mode 100644
index 000000000..ad6afb93e
--- /dev/null
+++ b/tests/specs/compile/workspace/add/deno.json
@@ -0,0 +1,5 @@
+{
+ "name": "@david/add",
+ "version": "0.0.1",
+ "exports": "./mod.ts"
+}
diff --git a/tests/specs/compile/workspace/add/mod.test.ts b/tests/specs/compile/workspace/add/mod.test.ts
new file mode 100644
index 000000000..6de834e17
--- /dev/null
+++ b/tests/specs/compile/workspace/add/mod.test.ts
@@ -0,0 +1,6 @@
+import { add } from "./mod.ts";
+import { assertEquals } from "@std/assert";
+
+Deno.test("add", () => {
+ assertEquals(add(1, 2), 3);
+});
diff --git a/tests/specs/compile/workspace/add/mod.ts b/tests/specs/compile/workspace/add/mod.ts
new file mode 100644
index 000000000..8d9b8a22a
--- /dev/null
+++ b/tests/specs/compile/workspace/add/mod.ts
@@ -0,0 +1,3 @@
+export function add(a: number, b: number): number {
+ return a + b;
+}
diff --git a/tests/specs/compile/workspace/deno.json b/tests/specs/compile/workspace/deno.json
new file mode 100644
index 000000000..4504c4276
--- /dev/null
+++ b/tests/specs/compile/workspace/deno.json
@@ -0,0 +1,9 @@
+{
+ "workspace": [
+ "./add",
+ "./subtract"
+ ],
+ "imports": {
+ "@std/assert": "jsr:@std/assert@^1.0.2"
+ }
+}
diff --git a/tests/specs/compile/workspace/deno.lock b/tests/specs/compile/workspace/deno.lock
new file mode 100644
index 000000000..7ceb772c6
--- /dev/null
+++ b/tests/specs/compile/workspace/deno.lock
@@ -0,0 +1,26 @@
+{
+ "version": "3",
+ "packages": {
+ "specifiers": {
+ "jsr:@std/assert@^1.0.2": "jsr:@std/assert@1.0.2",
+ "jsr:@std/internal@^1.0.1": "jsr:@std/internal@1.0.1"
+ },
+ "jsr": {
+ "@std/assert@1.0.2": {
+ "integrity": "ccacec332958126deaceb5c63ff8b4eaf9f5ed0eac9feccf124110435e59e49c",
+ "dependencies": [
+ "jsr:@std/internal@^1.0.1"
+ ]
+ },
+ "@std/internal@1.0.1": {
+ "integrity": "6f8c7544d06a11dd256c8d6ba54b11ed870aac6c5aeafff499892662c57673e6"
+ }
+ }
+ },
+ "remote": {},
+ "workspace": {
+ "dependencies": [
+ "jsr:@std/assert@^1.0.2"
+ ]
+ }
+}
diff --git a/tests/specs/compile/workspace/main.out b/tests/specs/compile/workspace/main.out
new file mode 100644
index 000000000..a83d1d524
--- /dev/null
+++ b/tests/specs/compile/workspace/main.out
@@ -0,0 +1 @@
+-3
diff --git a/tests/specs/compile/workspace/main.ts b/tests/specs/compile/workspace/main.ts
new file mode 100644
index 000000000..896f107ad
--- /dev/null
+++ b/tests/specs/compile/workspace/main.ts
@@ -0,0 +1,3 @@
+import { subtract } from "@david/subtract";
+
+console.log(subtract(2, 5));
diff --git a/tests/specs/compile/workspace/subtract/deno.json b/tests/specs/compile/workspace/subtract/deno.json
new file mode 100644
index 000000000..d2bdfbec7
--- /dev/null
+++ b/tests/specs/compile/workspace/subtract/deno.json
@@ -0,0 +1,5 @@
+{
+ "name": "@david/subtract",
+ "version": "0.0.1",
+ "exports": "./mod.ts"
+}
diff --git a/tests/specs/compile/workspace/subtract/mod.test.ts b/tests/specs/compile/workspace/subtract/mod.test.ts
new file mode 100644
index 000000000..1bc00da1e
--- /dev/null
+++ b/tests/specs/compile/workspace/subtract/mod.test.ts
@@ -0,0 +1,6 @@
+import { subtract } from "./mod.ts";
+import { assertEquals } from "@std/assert";
+
+Deno.test("subtract", () => {
+ assertEquals(subtract(4, 2), 2);
+});
diff --git a/tests/specs/compile/workspace/subtract/mod.ts b/tests/specs/compile/workspace/subtract/mod.ts
new file mode 100644
index 000000000..3d8ba39af
--- /dev/null
+++ b/tests/specs/compile/workspace/subtract/mod.ts
@@ -0,0 +1,5 @@
+import { add } from "@david/add";
+
+export function subtract(a: number, b: number): number {
+ return add(a, -b);
+}
diff --git a/tests/specs/run/workspaces/basic/main.out b/tests/specs/run/workspaces/basic/main.out
index 9806f7d63..256b380af 100644
--- a/tests/specs/run/workspaces/basic/main.out
+++ b/tests/specs/run/workspaces/basic/main.out
@@ -1,11 +1,7 @@
[WILDCARD]Workspace config generated this import map {
"imports": {
"chalk": "npm:chalk",
- "chalk/": "npm:/chalk/",
- "asdfasdfasdf": "jsr:asdfasdfasdf@^0.0.0",
- "asdfasdfasdf/": "jsr:/asdfasdfasdf@^0.0.0/",
- "qwerqwer": "jsr:qwerqwer@^0.0.0",
- "qwerqwer/": "jsr:/qwerqwer@^0.0.0/"
+ "chalk/": "npm:/chalk/"
},
"scopes": {
"./bar/": {