refactor: resolve workspace imports via /f/,/u/ not $f/,$u/ aliases (#9438)

* refactor: resolve workspace imports via /f/,/u/ not $f/,$u/ aliases

Keep the CLI managed tsconfig.wmill.json / `refresh tsconfig` / Deno
import-map QoL from #9378, but re-key it on the existing /f/,/u/ workspace
paths instead of the new $f/,$u/ specifiers. Verified /f/,/u/ resolves in
tsc, Bun, Deno, the in-app ATA editor, and the worker, so the $-prefixed
alias added no value. Drop the $f/,$u/ handling from the parser, dep-map,
deno_executor, bun loaders, ATA, relative_imports and monaco paths; revert
the windmill-parser-wasm-ts bump (1.714.0 -> 1.695.0). Also fold in the
cli/package-lock.json sync for the already-committed pg-gateway dependency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: drop duplicate relative-path check and restore rustfmt formatting

Follow-up cleanups to the previous commit's full-file reverts, which
restored pre-#9378 state that main had since improved:

- relative_imports.ts: remove the redundant duplicate d.startsWith('/')
  (pre-#9378 had it; #9378 had repurposed that line, so main has no dup).
- windmill-parser-ts/src/lib.rs: restore the multi-line new_source_file(...)
  formatting required by backend/rustfmt.toml (the single-line revert would
  fail `cargo fmt --check`). Now differs from main only by the $f//$u/ removal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hugocasa
2026-06-03 19:27:24 +02:00
committed by GitHub
parent e4e0984e55
commit 468aa230e5
15 changed files with 60 additions and 180 deletions
+4 -11
View File
@@ -197,10 +197,8 @@ pub fn parse_relative_imports(code: &str, path: &str) -> anyhow::Result<Vec<Stri
// Remove .ts extension if present
let imp = imp.strip_suffix(".ts").unwrap_or(&imp);
if imp.starts_with("/") || imp.starts_with("$f/") || imp.starts_with("$u/") {
// Absolute path (e.g., /f/folder/script) or its local-friendly alias
// (e.g., $f/folder/script) - strip the leading `/` or `$` to get the
// workspace-rooted path.
if imp.starts_with("/") {
// Absolute path (e.g., /f/folder/script) - remove leading slash
imp[1..].to_string()
} else {
// Relative path (e.g., ./script or ../folder/script)
@@ -215,14 +213,9 @@ pub fn parse_relative_imports(code: &str, path: &str) -> anyhow::Result<Vec<Stri
Ok(resolved)
}
/// Check if an import path is a relative import (starts with `./`, `../`, `/`, or the
/// local-friendly workspace aliases `$f/`/`$u/`)
/// Check if an import path is a relative import (starts with `./`, `../`, or `/`)
fn is_relative_import(import_path: &str) -> bool {
import_path.starts_with("./")
|| import_path.starts_with("../")
|| import_path.starts_with("/")
|| import_path.starts_with("$f/")
|| import_path.starts_with("$u/")
import_path.starts_with("./") || import_path.starts_with("../") || import_path.starts_with("/")
}
/// Normalize a path by resolving `.` and `..` components
@@ -891,40 +891,18 @@ mod tests {
assert_eq!(result, vec!["f/shared/utils"]);
}
#[test]
fn test_relative_imports_dollar_alias() {
// `$f/`/`$u/` are local-friendly aliases for the absolute workspace paths
// `/f/`/`/u/` and must resolve to the same workspace-rooted path.
let code = r#"
import { shared } from "$f/shared/utils.ts";
import { mine } from "$u/me/lib";
export async function main() { return shared() + mine(); }
"#;
let result = parse_relative_imports(code, "f/folder/script").unwrap();
assert_eq!(result, vec!["f/shared/utils", "u/me/lib"]);
}
#[test]
fn test_relative_imports_mixed() {
let code = r#"
import { helper } from "./helper";
import { utils } from "../utils";
import { shared } from "/f/shared/lib";
import { aliased } from "$f/shared/aliased.ts";
import lodash from "lodash";
export async function main() { return helper() + utils() + shared() + aliased(); }
export async function main() { return helper() + utils() + shared(); }
"#;
let result = parse_relative_imports(code, "f/folder/script").unwrap();
// Should only include relative imports, not external packages like lodash
assert_eq!(
result,
vec![
"f/folder/helper",
"f/shared/aliased",
"f/shared/lib",
"f/utils"
]
);
assert_eq!(result, vec!["f/folder/helper", "f/shared/lib", "f/utils"]);
}
#[test]
-43
View File
@@ -4763,28 +4763,6 @@ export async function main() {
Ok(())
}
#[sqlx::test(fixtures("base", "relative_bun"))]
async fn test_relative_imports_bun_dollar_alias(db: Pool<Postgres>) -> anyhow::Result<()> {
// `$f/` is a local-friendly alias for the absolute workspace path `/f/` and must
// resolve identically on the worker. Mix it with relative imports to confirm both
// paths coexist.
let content = r#"
import { main as test1 } from "$f/system/same_folder_script.ts";
import { main as test2 } from "./same_folder_script.ts";
import { main as test3 } from "$f/system_relative/different_folder_script.ts";
import { main as test4 } from "../system_relative/different_folder_script.ts";
export async function main() {
return [test1(), test2(), test3(), test4()];
}
"#
.to_string();
run_deployed_relative_imports(&db, content.clone(), ScriptLang::Bun).await?;
run_preview_relative_imports(&db, content, ScriptLang::Bun).await?;
Ok(())
}
#[cfg(feature = "deno_core")]
#[sqlx::test(fixtures("base", "relative_bun"))]
async fn test_nested_imports_bun(db: Pool<Postgres>) -> anyhow::Result<()> {
@@ -4821,27 +4799,6 @@ export async function main() {
Ok(())
}
#[sqlx::test(fixtures("base", "relative_deno"))]
async fn test_relative_imports_deno_dollar_alias(db: Pool<Postgres>) -> anyhow::Result<()> {
// `$f/` is a local-friendly alias for the absolute workspace path `/f/` and must
// resolve identically via the Deno import map. Mix it with relative imports.
let content = r#"
import { main as test1 } from "$f/system/same_folder_script.ts";
import { main as test2 } from "./same_folder_script.ts";
import { main as test3 } from "$f/system_relative/different_folder_script.ts";
import { main as test4 } from "../system_relative/different_folder_script.ts";
export async function main() {
return [test1(), test2(), test3(), test4()];
}
"#
.to_string();
run_deployed_relative_imports(&db, content.clone(), ScriptLang::Deno).await?;
run_preview_relative_imports(&db, content, ScriptLang::Deno).await?;
Ok(())
}
#[sqlx::test(fixtures("base", "relative_deno"))]
async fn test_nested_imports_deno(db: Pool<Postgres>) -> anyhow::Result<()> {
let content = r#"
-5
View File
@@ -50,11 +50,6 @@ fn parse_ts_relative_imports(
let import = import.trim_end_matches(".ts");
if import.starts_with("/") {
relative_imports.push(import.trim_start_matches("/").to_string());
} else if import.starts_with("$f/") || import.starts_with("$u/") {
// `$f/...`/`$u/...` are local-friendly aliases for the absolute workspace
// paths `/f/...`/`/u/...`. Stripping the leading `$` yields the same
// workspace-rooted path the rest of the dependency machinery expects.
relative_imports.push(import.trim_start_matches("$").to_string());
} else if import.starts_with(".") {
let normalized = try_normalize(std::path::Path::new(&format!(
"{}/../{}",
+2 -2
View File
@@ -915,7 +915,7 @@ pub async fn run_deployed_relative_imports(
.unwrap();
// Regression guard for the Deno lock-gen import map (generate_deno_lock):
// it must resolve the `$f/`/`$u/` aliases, otherwise `deno cache --lock`
// it must resolve workspace `/f/`/`/u/` imports, otherwise `deno cache --lock`
// fails with "not a dependency and not in import map". We match that
// specific failure rather than asserting lock_error_logs is empty —
// the field also captures benign, non-fatal lock-job output (e.g. Bun's
@@ -930,7 +930,7 @@ pub async fn run_deployed_relative_imports(
if let Some(err) = &lock_error {
assert!(
!err.contains("not in import map"),
"lock generation failed to resolve a workspace import (likely $f//$u/): {err}"
"lock generation failed to resolve a workspace import: {err}"
);
}
+8 -18
View File
@@ -38,9 +38,7 @@ const p = {
if (
(imp.path.startsWith(".") ||
imp.path.startsWith("/u/") ||
imp.path.startsWith("/f/") ||
imp.path.startsWith("$u/") ||
imp.path.startsWith("$f/")) &&
imp.path.startsWith("/f/")) &&
!imp.path.endsWith(".ts")
) {
code = code.replaceAll(imp.path, imp.path + ".ts");
@@ -99,29 +97,21 @@ const p = {
? current_path
: args.importer.replace(cdir + "/", "");
// `$f/...`/`$u/...` are local-friendly aliases for the absolute workspace
// paths `/f/...`/`/u/...`; rewrite to the `/`-prefixed form so the absolute
// resolution branch below handles them identically.
const importPath =
args.path.startsWith("$f/") || args.path.startsWith("$u/")
? "/" + args.path.slice(1)
: args.path;
const isRelative = !importPath.startsWith("/");
const endExt = importPath.endsWith(".ts") ? "" : ".ts";
const pathNoExt = importPath.replace(/\.ts$/, "");
const isRelative = !args.path.startsWith("/");
const endExt = args.path.endsWith(".ts") ? "" : ".ts";
const pathNoExt = args.path.replace(/\.ts$/, "");
// Lookup temp script hash
const normalized = (isRelative ? join(dirname(file_path), pathNoExt) : pathNoExt.slice(1)).replace(/\\/g, "/");
const hash = TEMP_SCRIPT_REFS?.[normalized];
const url = (isRelative
? `${base_internal_url}/api/w/${w_id}/scripts/raw_unpinned/p/${file_path}/../${importPath}${endExt}`
: `${base_internal_url}/api/w/${w_id}/scripts/raw_unpinned/p/${importPath}${endExt}`
? `${base_internal_url}/api/w/${w_id}/scripts/raw_unpinned/p/${file_path}/../${args.path}${endExt}`
: `${base_internal_url}/api/w/${w_id}/scripts/raw_unpinned/p/${args.path}${endExt}`
) + (hash ? `?temp_script_hash=${hash}` : "");
const file = isRelative
? resolve("./" + file_path + "/../" + importPath + ".url")
: resolve("./" + importPath + ".url");
? resolve("./" + file_path + "/../" + args.path + ".url")
: resolve("./" + args.path + ".url");
mkdirSync(dirname(file), { recursive: true });
writeFileSync(file, url);
return {
+2 -10
View File
@@ -44,9 +44,7 @@ const p = {
if (
(imp.path.startsWith(".") ||
imp.path.startsWith("/u/") ||
imp.path.startsWith("/f/") ||
imp.path.startsWith("$u/") ||
imp.path.startsWith("$f/")) &&
imp.path.startsWith("/f/")) &&
!imp.path.endsWith(".ts")
) {
code = code.replaceAll(imp.path, imp.path + ".ts");
@@ -69,13 +67,7 @@ const p = {
// Resolve a windmill script import path relative to an importer path.
// Bun on Windows may prefix args with "windmill-url:" or strip leading "/".
function resolveWindmillImport(importerPath, importPath) {
// Strip the "windmill-url:" namespace prefix, an optional leading "/"
// (absolute `/f/`,`/u/`), and the local-friendly "$" alias prefix
// (`$f/`,`$u/`) so absolute workspace imports normalize to `f/`,`u/`.
const path = importPath
.replace(/^windmill-url:/, "")
.replace(/^\//, "")
.replace(/^\$(?=[fu]\/)/, "");
const path = importPath.replace(/^windmill-url:/, "").replace(/^\//, "");
const isAbsolute = path.startsWith("f/") || path.startsWith("u/");
const endExt = path.endsWith(".ts") ? "" : ".ts";
const rawScriptPath = isAbsolute
+1 -8
View File
@@ -170,15 +170,10 @@ pub async fn generate_deno_lock(
let _ = write_file(job_dir, "main.ts", code)?;
let import_map_path = format!("{job_dir}/import_map.json");
// `$f/`/`$u/` are local-friendly aliases for the absolute workspace paths `/f/`,`/u/`.
// The runtime import map (`build_import_map`) maps them too; without these keys here,
// `deno cache --lock` can't resolve `$f/...` imports and lock generation fails.
let import_map = format!(
r#"{{
"imports": {{
"/": "{base_internal_url}/api/scripts_u/empty_ts/",
"$f/": "{base_internal_url}/api/scripts_u/empty_ts/f/",
"$u/": "{base_internal_url}/api/scripts_u/empty_ts/u/"
"/": "{base_internal_url}/api/scripts_u/empty_ts/"
}}
}}"#,
);
@@ -586,8 +581,6 @@ pub(crate) async fn build_import_map(
"{base_internal_url}/api/w/{w_id}/scripts/raw/p/": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/",
"{base_internal_url}": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/",
"/": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/",
"$f/": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/f/",
"$u/": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/u/",
"./wrapper.ts": "./wrapper.ts",
"./main.ts": "./main.ts"{relative_mounts}
{extra_import_map}
+2 -2
View File
@@ -29,7 +29,7 @@
"windmill-parser-wasm-regex": "1.692.0",
"windmill-parser-wasm-ruby": "1.526.1",
"windmill-parser-wasm-rust": "1.647.1",
"windmill-parser-wasm-ts": "1.714.0",
"windmill-parser-wasm-ts": "1.695.0",
"windmill-parser-wasm-yaml": "1.593.0",
"windmill-yaml-validator": "1.1.1",
"ws": "8.18.0",
@@ -308,7 +308,7 @@
"windmill-parser-wasm-rust": ["windmill-parser-wasm-rust@1.647.1", "", {}, "sha512-9yGLYZX2Hn9TdTqGY/5Fp50ftzgUsrfBkSK9vJkKJd5Amyg+yXLBGzd8pz6Org+4uxMenz/16wpsgijvo6uhhQ=="],
"windmill-parser-wasm-ts": ["windmill-parser-wasm-ts@1.714.0", "", {}, "sha512-IvkR+tMupzIviST6IahLyNt+feK1A6ZBFUGHWl0NwJQUT0FHdjSk1BmSULSVdwSXTvvp+xcd2WrkB9pBEM5Giw=="],
"windmill-parser-wasm-ts": ["windmill-parser-wasm-ts@1.695.0", "", {}, "sha512-9EFxeRZWmfb7EyhSlcG7dzTTKETPRYAvpRlxxLkhhtI5I219wFgI7kwrMpz4stXHJj/aqBknVv66NQHRstSJmw=="],
"windmill-parser-wasm-yaml": ["windmill-parser-wasm-yaml@1.593.0", "", {}, "sha512-Gyx4aR2jsJYuDrD3mCNTmz7LWOQQXPw5yKNCC1xRgUOPfjsD/tINAFfsBLwVOSmlQQcFZO+wHm4KtDtXOcnGVw=="],
+11 -4
View File
@@ -17,6 +17,7 @@
"jszip": "3.8.0",
"minimatch": "^10.0.0",
"open": "^10.0.0",
"pg-gateway": "0.3.0-beta.4",
"svelte": "^5.45.2",
"tar-stream": "^3.1.7",
"windmill-parser-wasm-csharp": "1.510.1",
@@ -29,7 +30,7 @@
"windmill-parser-wasm-regex": "1.692.0",
"windmill-parser-wasm-ruby": "1.526.1",
"windmill-parser-wasm-rust": "1.647.1",
"windmill-parser-wasm-ts": "1.714.0",
"windmill-parser-wasm-ts": "1.695.0",
"windmill-parser-wasm-yaml": "1.593.0",
"windmill-yaml-validator": "1.1.1",
"ws": "8.18.0",
@@ -1236,6 +1237,12 @@
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/pg-gateway": {
"version": "0.3.0-beta.4",
"resolved": "https://registry.npmjs.org/pg-gateway/-/pg-gateway-0.3.0-beta.4.tgz",
"integrity": "sha512-CTjsM7Z+0Nx2/dyZ6r8zRsc3f9FScoD5UAOlfUx1Fdv/JOIWvRbF7gou6l6vP+uypXQVoYPgw8xZDXgMGvBa4Q==",
"license": "MIT"
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -1453,9 +1460,9 @@
"integrity": "sha512-9yGLYZX2Hn9TdTqGY/5Fp50ftzgUsrfBkSK9vJkKJd5Amyg+yXLBGzd8pz6Org+4uxMenz/16wpsgijvo6uhhQ=="
},
"node_modules/windmill-parser-wasm-ts": {
"version": "1.714.0",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm-ts/-/windmill-parser-wasm-ts-1.714.0.tgz",
"integrity": "sha512-IvkR+tMupzIviST6IahLyNt+feK1A6ZBFUGHWl0NwJQUT0FHdjSk1BmSULSVdwSXTvvp+xcd2WrkB9pBEM5Giw=="
"version": "1.695.0",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm-ts/-/windmill-parser-wasm-ts-1.695.0.tgz",
"integrity": "sha512-9EFxeRZWmfb7EyhSlcG7dzTTKETPRYAvpRlxxLkhhtI5I219wFgI7kwrMpz4stXHJj/aqBknVv66NQHRstSJmw=="
},
"node_modules/windmill-parser-wasm-yaml": {
"version": "1.593.0",
+1 -1
View File
@@ -38,7 +38,7 @@
"windmill-parser-wasm-regex": "1.692.0",
"windmill-parser-wasm-ruby": "1.526.1",
"windmill-parser-wasm-rust": "1.647.1",
"windmill-parser-wasm-ts": "1.714.0",
"windmill-parser-wasm-ts": "1.695.0",
"windmill-parser-wasm-yaml": "1.593.0",
"windmill-yaml-validator": "1.1.1",
"ws": "8.18.0",
+21 -24
View File
@@ -11,16 +11,13 @@ import * as log from "../../core/log.ts";
import { readConfigFile } from "../../core/conf.ts";
/**
* Local-friendly aliases for the absolute workspace import paths `/f/...` and
* `/u/...`. Unlike the `/`-prefixed form (which every local tool treats as a
* filesystem-root path), `$f/`/`$u/` are bare specifiers that can be remapped to
* the on-disk `f/`/`u/` folders via tsconfig `paths` and Deno import maps, so the
* same import resolves both on the Windmill worker and in a local editor.
* The on-disk folders (`f/`, `u/`) that the absolute workspace import paths
* `/f/...` and `/u/...` map to. tsconfig `paths` and Deno import maps remap the
* `/f/`,`/u/` prefixes to these local folders, so the same workspace import
* resolves both on the Windmill worker and in a local editor (tsc/Bun/Deno all
* honor the `/`-prefixed key).
*/
const WORKSPACE_IMPORT_ALIASES: Record<string, string> = {
$f: "f",
$u: "u",
};
const WORKSPACE_IMPORT_DIRS = ["f", "u"];
// wmill-managed files holding the recommended config. They are always
// (re)written so we can ship updated recommendations over time; users keep
@@ -51,25 +48,25 @@ function buildManagedTsconfig(): {
compilerOptions: Record<string, unknown>;
include: string[];
} {
// Map "$f/*" -> ["./f/*"], "$u/*" -> ["./u/*"] so the editor resolves
// Map "/f/*" -> ["./f/*"], "/u/*" -> ["./u/*"] so the editor resolves
// workspace imports against the local script folders.
//
// Known limitation: this resolves imports written with a plain `.ts` extension
// (the canonical form). Scripts stored with a flavor-specific extension —
// `.bun.ts`/`.deno.ts`/`.fetch.ts` for languages other than the project default
// (see filePathExtensionFromContentType) — won't resolve via these aliases in a
// (see filePathExtensionFromContentType) — won't resolve via these `paths` in a
// local editor. The worker (extension-agnostic API) and the in-app editor (ATA
// normalizes to `.ts`) handle those fine; only local tsc / VS Code is affected.
const paths: Record<string, string[]> = {};
for (const [alias, dir] of Object.entries(WORKSPACE_IMPORT_ALIASES)) {
paths[`${alias}/*`] = [`./${dir}/*`];
for (const dir of WORKSPACE_IMPORT_DIRS) {
paths[`/${dir}/*`] = [`./${dir}/*`];
}
return {
compilerOptions: {
target: "ESNext",
module: "ESNext",
moduleResolution: "bundler",
// Workspace imports carry an explicit `.ts` extension (e.g. "$f/foo/bar.ts");
// Workspace imports carry an explicit `.ts` extension (e.g. "/f/foo/bar.ts");
// allow it so the editor doesn't flag every cross-script import.
allowImportingTsExtensions: true,
noEmit: true,
@@ -147,7 +144,7 @@ type WireMode = { interactive: boolean; assumeYes: boolean };
/**
* (Re)generate the wmill-managed TypeScript/Deno IDE config so the editor
* resolves `$f/`/`$u/` workspace imports against the local script folders.
* resolves `/f/`/`/u/` workspace imports against the local script folders.
*
* Split into a managed base file (always refreshed) and a user-owned file that
* references it. We only ever touch files that are ours: the managed file is
@@ -211,8 +208,8 @@ async function refreshManagedTsconfig(defaultTs: "bun" | "deno", mode: WireMode)
wire: (parsed) => {
// TypeScript does NOT merge `compilerOptions.paths` across `extends` — the
// nearest config that defines `paths` wins wholesale. So a config with its
// own `paths` would shadow the managed `$f/`/`$u/` mappings and the aliases
// would silently fail to resolve. We don't touch the user's paths — warn
// own `paths` would shadow the managed `/f/`/`/u/` mappings and they would
// silently fail to resolve. We don't touch the user's paths — warn
// and leave it for them to wire manually.
const co = parsed.compilerOptions;
const paths =
@@ -227,7 +224,7 @@ async function refreshManagedTsconfig(defaultTs: "bun" | "deno", mode: WireMode)
) {
return (
"defines its own `compilerOptions.paths` (TS won't merge ours in via " +
'`extends`); add "$f/*": ["./f/*"] and "$u/*": ["./u/*"] to it'
'`extends`); add "/f/*": ["./f/*"] and "/u/*": ["./u/*"] to it'
);
}
const ext = parsed.extends;
@@ -252,10 +249,10 @@ async function refreshManagedTsconfig(defaultTs: "bun" | "deno", mode: WireMode)
}
async function refreshManagedDenoImportMap(mode: WireMode) {
// Import-map prefix keys must end with "/": "$f/" -> "./f/", "$u/" -> "./u/".
// Import-map prefix keys must end with "/": "/f/" -> "./f/", "/u/" -> "./u/".
const imports: Record<string, string> = {};
for (const [alias, dir] of Object.entries(WORKSPACE_IMPORT_ALIASES)) {
imports[`${alias}/`] = `./${dir}/`;
for (const dir of WORKSPACE_IMPORT_DIRS) {
imports[`/${dir}/`] = `./${dir}/`;
}
// Deno import maps only allow `imports`/`scopes`, so no comment header here.
@@ -354,7 +351,7 @@ async function ensureUserReferencesManaged(opts: {
} catch {
log.warn(
`${existingName} couldn't be auto-edited (it may contain comments). Add ${opts.hint} ` +
`to pick up wmill's recommended settings (incl. $f//$u/ import aliases).`
`to pick up wmill's recommended settings (incl. workspace /f/, /u/ import resolution).`
);
return;
}
@@ -379,7 +376,7 @@ async function ensureUserReferencesManaged(opts: {
if (wired !== true) {
log.warn(
`${existingName}: ${wired}. Add ${opts.hint} manually to pick up wmill's ` +
`recommended settings (incl. $f//$u/ import aliases).`
`recommended settings (incl. workspace /f/, /u/ import resolution).`
);
return;
}
@@ -399,7 +396,7 @@ async function ensureUserReferencesManaged(opts: {
log.info(
colors.gray(
`Left ${existingName} unchanged — add ${opts.hint} when ready to enable ` +
`$f//$u/ import aliases (or re-run \`wmill refresh tsconfig\`).`
`workspace /f/, /u/ import resolution (or re-run \`wmill refresh tsconfig\`).`
)
);
return;
+5 -11
View File
@@ -131,18 +131,12 @@ export const setupTypeAcquisition = (config: ATABootstrapConfig) => {
if (depth == 0) {
const relativeDeps = depsToGet.filter((f) => isTypescriptRelativePath(f.raw))
relativeDeps.forEach(async (f) => {
// `$f/`/`$u/` are local-friendly aliases for the absolute workspace paths
// `/f/`,`/u/`. Normalize to the absolute form so the fetch URL and the
// registered extra-lib path match what the worker resolves (the editor's
// `paths` config maps `$f/` -> `/f/` back to this lib).
const raw =
f.raw.startsWith('$f/') || f.raw.startsWith('$u/') ? '/' + f.raw.slice(1) : f.raw
let path = raw.startsWith('/')
? raw
: '/' + config.scriptPath + (raw.startsWith('../') ? '/../' : '/.') + raw
let path = f.raw.startsWith('/')
? f.raw
: '/' + config.scriptPath + (f.raw.startsWith('../') ? '/../' : '/.') + f.raw
let url = config.root + path
let localPath = raw
if ((raw.startsWith('.') || raw.startsWith('/')) && !raw.endsWith('.ts')) {
let localPath = f.raw
if ((f.raw.startsWith('.') || f.raw.startsWith('/')) && !f.raw.endsWith('.ts')) {
url += '.ts'
localPath += '.ts'
}
@@ -100,14 +100,6 @@ export function setMonacoTypescriptOptions() {
allowImportingTsExtensions: true,
allowSyntheticDefaultImports: true,
moduleResolution: ModuleResolutionKind.NodeJs,
// `$f/`/`$u/` are local-friendly aliases for the absolute workspace paths
// `/f/`,`/u/`. ATA registers imported scripts as extra libs under their
// absolute `/f/...` path, so map the aliases back so type acquisition resolves.
baseUrl: '/',
paths: {
'$f/*': ['/f/*'],
'$u/*': ['/u/*']
},
jsx: JsxEmit.React
})
}
+1 -9
View File
@@ -11,15 +11,7 @@ export function parseTypescriptDeps(code: string): string[] {
}
export function isTypescriptRelativePath(d: string) {
return (
d.startsWith('./') ||
d.startsWith('../') ||
d.startsWith('/') ||
d.startsWith('.../') ||
// `$f/`/`$u/` are local-friendly aliases for the absolute workspace paths `/f/`,`/u/`.
d.startsWith('$f/') ||
d.startsWith('$u/')
)
return d.startsWith('./') || d.startsWith('../') || d.startsWith('/') || d.startsWith('.../')
}
export function approximateFindPythonRelativePath(code: string) {