1007 lines · 30.2 KB · Rust
RawDownload
use agentos_execution::javascript::ModuleResolutionTestHarness;use serde::Deserialize;use serde_json::Value;use std::fs;use std::os::unix::fs::symlink;use std::path::PathBuf;use tempfile::TempDir; struct Fixture {    temp: TempDir,} impl Fixture {    fn new() -> Self {        Self {            temp: TempDir::new().expect("create temp dir"),        }    }     fn host_path(&self, relative: &str) -> PathBuf {        self.temp.path().join(relative)    }     fn write(&self, relative: &str, contents: &str) {        let path = self.host_path(relative);        if let Some(parent) = path.parent() {            fs::create_dir_all(parent).expect("create parent dirs");        }        fs::write(path, contents).expect("write fixture file");    }     fn write_json(&self, relative: &str, value: Value) {        self.write(            relative,            &serde_json::to_string_pretty(&value).expect("serialize json"),        );    }     fn mkdir(&self, relative: &str) {        fs::create_dir_all(self.host_path(relative)).expect("create fixture dir");    }     fn symlink_dir(&self, target_relative: &str, link_relative: &str) {        let target = self.host_path(target_relative);        let link = self.host_path(link_relative);        if let Some(parent) = link.parent() {            fs::create_dir_all(parent).expect("create symlink parent");        }        symlink(target, link).expect("create directory symlink");    }     fn resolver(&self) -> ModuleResolutionTestHarness {        ModuleResolutionTestHarness::new(self.temp.path())    }} fn assert_import(fixture: &Fixture, specifier: &str, from_path: &str, expected: &str) {    let mut resolver = fixture.resolver();    assert_eq!(        resolver.resolve_import(specifier, from_path),        Some(String::from(expected))    );} fn assert_require(fixture: &Fixture, specifier: &str, from_path: &str, expected: &str) {    let mut resolver = fixture.resolver();    assert_eq!(        resolver.resolve_require(specifier, from_path),        Some(String::from(expected))    );} fn assert_require_missing(fixture: &Fixture, specifier: &str, from_path: &str) {    let mut resolver = fixture.resolver();    assert_eq!(resolver.resolve_require(specifier, from_path), None);} #[derive(Debug, Deserialize)]struct SharedModuleResolutionFixture {    cases: Vec<SharedModuleResolutionCase>,    formats: Vec<SharedModuleFormatCase>,} #[derive(Debug, Deserialize)]struct SharedModuleResolutionCase {    name: String,    files: std::collections::BTreeMap<String, String>,    resolves: Vec<SharedModuleResolutionExpectation>,} #[derive(Debug, Deserialize)]struct SharedModuleResolutionExpectation {    specifier: String,    from: String,    mode: String,    expected: Option<String>,} #[derive(Debug, Deserialize)]struct SharedModuleFormatCase {    name: String,    files: std::collections::BTreeMap<String, String>,    path: String,    expected: Option<String>,} #[test]fn matches_shared_native_browser_conformance_fixture() {    let fixture: SharedModuleResolutionFixture = serde_json::from_str(include_str!(        "../../../tests/fixtures/module-resolution-conformance.json"    ))    .expect("parse shared module resolution fixture");     for test_case in fixture.cases {        let fs_fixture = Fixture::new();        for (path, contents) in &test_case.files {            fs_fixture.write(path, contents);        }         for resolution in &test_case.resolves {            let mut resolver = fs_fixture.resolver();            let actual = match resolution.mode.as_str() {                "import" => resolver.resolve_import(&resolution.specifier, &resolution.from),                "require" => resolver.resolve_require(&resolution.specifier, &resolution.from),                other => panic!("unsupported shared fixture mode {other}"),            };            assert_eq!(                actual, resolution.expected,                "{}: {} from {} in {} mode",                test_case.name, resolution.specifier, resolution.from, resolution.mode            );        }    }     for format_case in fixture.formats {        let fs_fixture = Fixture::new();        for (path, contents) in &format_case.files {            fs_fixture.write(path, contents);        }         let mut resolver = fs_fixture.resolver();        let actual = resolver.module_format(&format_case.path).map(String::from);        assert_eq!(            actual, format_case.expected,            "{}: format for {}",            format_case.name, format_case.path        );    }} #[test]fn builtin_bare_fs_normalizes_to_node_prefix() {    let fixture = Fixture::new();    assert_import(&fixture, "fs", "/root/project/index.js", "node:fs");} #[test]fn builtin_node_prefix_is_preserved_for_require() {    let fixture = Fixture::new();    assert_require(&fixture, "node:path", "/root/project/index.js", "node:path");} #[test]fn builtin_subpath_normalizes_to_node_prefix() {    let fixture = Fixture::new();    assert_import(        &fixture,        "fs/promises",        "/root/project/index.js",        "node:fs/promises",    );} #[test]fn relative_import_probes_js_extension() {    let fixture = Fixture::new();    fixture.write("project/src/foo.js", "export default 1;");    assert_import(        &fixture,        "./foo",        "/root/project/src/index.js",        "/root/project/src/foo.js",    );} #[test]fn relative_parent_import_probes_json_extension() {    let fixture = Fixture::new();    fixture.write("project/data/config.json", r#"{"ok":true}"#);    assert_import(        &fixture,        "../data/config",        "/root/project/src/index.js",        "/root/project/data/config.json",    );} #[test]fn absolute_import_resolves_from_guest_root() {    let fixture = Fixture::new();    fixture.write("shared/util.mjs", "export const ok = true;");    assert_import(        &fixture,        "/root/shared/util",        "/root/project/src/index.js",        "/root/shared/util.mjs",    );} #[test]fn directory_import_uses_package_main_field() {    let fixture = Fixture::new();    fixture.write_json(        "project/pkg/package.json",        serde_json::json!({ "main": "./dist/main.cjs" }),    );    fixture.write("project/pkg/dist/main.cjs", "module.exports = 1;");    assert_require(        &fixture,        "./pkg",        "/root/project/index.js",        "/root/project/pkg/dist/main.cjs",    );} #[test]fn bare_package_main_only_type_module_resolves() {    // Regression guard: a bare ESM package whose package.json has `main` but NO    // `exports` map (e.g. @agentclientprotocol/sdk@0.16.1) must still resolve via    // the `main` fallback. `exports` and `main` are separate code paths; this case    // exercises the latter for a scoped package looked up through node_modules.    let fixture = Fixture::new();    fixture.write_json(        "node_modules/@scope/pkg/package.json",        serde_json::json!({ "type": "module", "main": "dist/acp.js" }),    );    fixture.write("node_modules/@scope/pkg/dist/acp.js", "export default 1;");    assert_import(        &fixture,        "@scope/pkg",        "/root/project/src/adapter.js",        "/root/node_modules/@scope/pkg/dist/acp.js",    );} #[test]fn directory_import_falls_back_to_index_file() {    let fixture = Fixture::new();    fixture.write("project/lib/index.cjs", "module.exports = 1;");    assert_require(        &fixture,        "./lib",        "/root/project/index.js",        "/root/project/lib/index.cjs",    );} #[test]fn extension_probe_finds_existing_js_file_directly() {    let fixture = Fixture::new();    fixture.write("project/src/direct.js", "export default 1;");    assert_import(        &fixture,        "./direct.js",        "/root/project/src/index.js",        "/root/project/src/direct.js",    );} #[test]fn extension_probe_finds_mjs_file() {    let fixture = Fixture::new();    fixture.write("project/src/mod.mjs", "export default 1;");    assert_import(        &fixture,        "./mod",        "/root/project/src/index.js",        "/root/project/src/mod.mjs",    );} #[test]fn extension_probe_finds_cjs_file() {    let fixture = Fixture::new();    fixture.write("project/src/common.cjs", "module.exports = 1;");    assert_require(        &fixture,        "./common",        "/root/project/src/index.js",        "/root/project/src/common.cjs",    );} #[test]fn extension_probe_finds_json_file() {    let fixture = Fixture::new();    fixture.write("project/src/data.json", r#"{"name":"fixture"}"#);    assert_require(        &fixture,        "./data",        "/root/project/src/index.js",        "/root/project/src/data.json",    );} #[test]fn dot_specifier_resolves_current_package_directory() {    let fixture = Fixture::new();    fixture.write_json(        "project/pkg/package.json",        serde_json::json!({ "main": "./entry.js" }),    );    fixture.write("project/pkg/entry.js", "module.exports = 1;");    assert_require(        &fixture,        ".",        "/root/project/pkg/index.js",        "/root/project/pkg/entry.js",    );} #[test]fn exports_string_shorthand_resolves_package_root() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({ "exports": "./dist/index.js" }),    );    fixture.write("node_modules/pkg/dist/index.js", "export default 1;");    assert_import(        &fixture,        "pkg",        "/root/project/src/index.js",        "/root/node_modules/pkg/dist/index.js",    );} #[test]fn exports_conditions_prefer_import_for_esm_resolution() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({            "exports": {                ".": {                    "import": "./dist/import.mjs",                    "require": "./dist/require.cjs",                    "default": "./dist/default.js"                }            }        }),    );    fixture.write("node_modules/pkg/dist/import.mjs", "export default 1;");    fixture.write("node_modules/pkg/dist/require.cjs", "module.exports = 1;");    fixture.write("node_modules/pkg/dist/default.js", "export default 1;");    assert_import(        &fixture,        "pkg",        "/root/project/src/index.js",        "/root/node_modules/pkg/dist/import.mjs",    );} #[test]fn exports_conditions_prefer_require_for_cjs_resolution() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({            "exports": {                ".": {                    "import": "./dist/import.mjs",                    "require": "./dist/require.cjs",                    "default": "./dist/default.js"                }            }        }),    );    fixture.write("node_modules/pkg/dist/import.mjs", "export default 1;");    fixture.write("node_modules/pkg/dist/require.cjs", "module.exports = 1;");    fixture.write("node_modules/pkg/dist/default.js", "export default 1;");    assert_require(        &fixture,        "pkg",        "/root/project/src/index.js",        "/root/node_modules/pkg/dist/require.cjs",    );} #[test]fn exports_nested_conditions_recurse_for_import_mode() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({            "exports": {                ".": {                    "import": {                        "node": "./dist/node.mjs",                        "default": "./dist/default.mjs"                    },                    "default": "./dist/fallback.js"                }            }        }),    );    fixture.write("node_modules/pkg/dist/node.mjs", "export default 1;");    fixture.write("node_modules/pkg/dist/default.mjs", "export default 1;");    fixture.write("node_modules/pkg/dist/fallback.js", "export default 1;");    assert_import(        &fixture,        "pkg",        "/root/project/src/index.js",        "/root/node_modules/pkg/dist/node.mjs",    );} #[test]fn exports_wildcard_subpaths_expand_requested_segment() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({            "exports": {                "./features/*": "./dist/features/*.mjs"            }        }),    );    fixture.write(        "node_modules/pkg/dist/features/alpha.mjs",        "export default 1;",    );    assert_import(        &fixture,        "pkg/features/alpha",        "/root/project/src/index.js",        "/root/node_modules/pkg/dist/features/alpha.mjs",    );} #[test]fn exports_wildcard_subpaths_prefer_the_more_specific_pattern() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({            "exports": {                "./*.js": "./esm/*.js",                "./*": "./esm/*.js"            }        }),    );    fixture.write("node_modules/pkg/esm/sdk/user.js", "export class User {};");    assert_import(        &fixture,        "pkg/sdk/user.js",        "/root/project/src/index.js",        "/root/node_modules/pkg/esm/sdk/user.js",    );} #[test]fn exports_explicit_subpath_resolves_direct_mapping() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({            "exports": {                "./feature": "./dist/feature.js"            }        }),    );    fixture.write("node_modules/pkg/dist/feature.js", "export default 1;");    assert_import(        &fixture,        "pkg/feature",        "/root/project/src/index.js",        "/root/node_modules/pkg/dist/feature.js",    );} #[test]fn exports_array_fallback_uses_first_resolvable_target() {    let fixture = Fixture::new();    fixture.write_json(        "node_modules/pkg/package.json",        serde_json::json!({            "exports": [                null,                "./dist/index.js"            ]        }),    );    fixture.write("node_modules/pkg/dist/index.js", "export default 1;");    assert_import(        &fixture,        "pkg",        "/root/project/src/index.js",        "/root/node_modules/pkg/dist/index.js",    );

Lines 1–500 of 1007.