diff --git a/Cargo.lock b/Cargo.lock
index 552c9fb9b85..187cc016e90 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1943,6 +1943,7 @@ dependencies = [
"enso-build",
"enso-build-base",
"enso-formatter",
+ "ensogl-pack",
"futures",
"futures-util",
"glob",
diff --git a/app/ide-desktop/lib/client/src/file-associations.ts b/app/ide-desktop/lib/client/src/file-associations.ts
index 038f2ecfd59..b73e229653c 100644
--- a/app/ide-desktop/lib/client/src/file-associations.ts
+++ b/app/ide-desktop/lib/client/src/file-associations.ts
@@ -111,7 +111,6 @@ export function onFileOpened(event: Event, path: string): string | null {
if (!electron.app.isReady() && CLIENT_ARGUMENTS.length === 0) {
event.preventDefault()
logger.log(`Opening file '${path}'.`)
- // eslint-disable-next-line no-restricted-syntax
return handleOpenFile(path)
} else {
// Another copy of the application needs to be started, as the first one is
diff --git a/app/ide-desktop/lib/content-config/src/index.ts b/app/ide-desktop/lib/content-config/src/index.ts
index c840f743d99..b27f11f2658 100644
--- a/app/ide-desktop/lib/content-config/src/index.ts
+++ b/app/ide-desktop/lib/content-config/src/index.ts
@@ -2,7 +2,7 @@
import * as semver from 'semver'
-import * as linkedDist from '../../../../../target/ensogl-pack/linked-dist/index'
+import * as linkedDist from '../../../../../target/ensogl-pack/linked-dist'
import BUILD_INFO from '../../../build.json' assert { type: 'json' }
// Aliases with the same name as the original.
diff --git a/app/ide-desktop/lib/content/src/index.ts b/app/ide-desktop/lib/content/src/index.ts
index ee53fbefdf3..602e0714649 100644
--- a/app/ide-desktop/lib/content/src/index.ts
+++ b/app/ide-desktop/lib/content/src/index.ts
@@ -7,7 +7,7 @@ import * as semver from 'semver'
import * as authentication from 'enso-authentication'
import * as contentConfig from 'enso-content-config'
-import * as app from '../../../../../target/ensogl-pack/linked-dist/index'
+import * as app from '../../../../../target/ensogl-pack/linked-dist'
import GLOBAL_CONFIG from '../../../../gui/config.yaml' assert { type: 'yaml' }
const logger = app.log.logger
diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/dashboard.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/dashboard.tsx
index 830dc9e2158..68467555ba9 100644
--- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/dashboard.tsx
+++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/dashboard.tsx
@@ -476,8 +476,7 @@ function Dashboard(props: DashboardProps) {
}
}}
>
- {fileInfo.fileIcon(fileInfo.fileExtension(file.title))}{' '}
- {file.title}
+ {fileInfo.fileIcon()} {file.title}
),
}
diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/uploadFileModal.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/uploadFileModal.tsx
index 77e87a519f0..f0a1bf40661 100644
--- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/uploadFileModal.tsx
+++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/uploadFileModal.tsx
@@ -110,13 +110,7 @@ function UploadFileModal(props: UploadFileModalProps) {
{file ? fileInfo.toReadableSize(file.size) : '\u00a0'}
-
- {file ? (
- fileInfo.fileIcon(fileInfo.fileExtension(file.name))
- ) : (
- <>>
- )}
-
+ {file && fileInfo.fileIcon()}
diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/fileInfo.ts b/app/ide-desktop/lib/dashboard/src/authentication/src/fileInfo.ts
index 2d21ab75d26..5abe4fee09f 100644
--- a/app/ide-desktop/lib/dashboard/src/authentication/src/fileInfo.ts
+++ b/app/ide-desktop/lib/dashboard/src/authentication/src/fileInfo.ts
@@ -10,8 +10,8 @@ export function fileExtension(fileName: string) {
return fileName.match(/\.(.+?)$/)?.[1] ?? ''
}
-/** Return the appropriate icon for a specific file extension. */
-export function fileIcon(_extension: string) {
+/** Returns the appropriate icon for a specific file extension. */
+export function fileIcon() {
return svg.FILE_ICON
}
diff --git a/app/ide-desktop/lib/types/globals.d.ts b/app/ide-desktop/lib/types/globals.d.ts
index 53caf383a26..62a17d97865 100644
--- a/app/ide-desktop/lib/types/globals.d.ts
+++ b/app/ide-desktop/lib/types/globals.d.ts
@@ -3,6 +3,9 @@
* monkeypatching on `window` and generated code.
*
* This file MUST `export {}` for the globals to be visible to other files. */
+// This file is being imported for its types.
+// eslint-disable-next-line no-restricted-syntax
+import * as buildJson from './build.json' assert { type: 'json' }
// =============
// === Types ===
@@ -18,14 +21,6 @@ interface Enso {
main: (inputConfig?: StringConfig) => Promise
}
-/** Build information injected by the build script. */
-interface BuildInfo {
- commit: string
- version: string
- engineVersion: string
- name: string
-}
-
// ==========================
// === Authentication API ===
// ==========================
@@ -74,7 +69,7 @@ declare global {
// These are used in other files (because they're globals)
/* eslint-disable @typescript-eslint/naming-convention */
const BUNDLED_ENGINE_VERSION: string
- const BUILD_INFO: BuildInfo
+ const BUILD_INFO: buildJson.BuildInfo
const PROJECT_MANAGER_IN_BUNDLE_PATH: string
const IS_DEV_MODE: boolean
// This will be `undefined` when it is not defined by esbuild.
@@ -82,5 +77,3 @@ declare global {
const REDIRECT_OVERRIDE: string | undefined
/* eslint-disable @typescript-eslint/naming-convention */
}
-
-export {}
diff --git a/app/ide-desktop/lib/types/modules.d.ts b/app/ide-desktop/lib/types/modules.d.ts
index 1564bae805b..50d52e8cdc8 100644
--- a/app/ide-desktop/lib/types/modules.d.ts
+++ b/app/ide-desktop/lib/types/modules.d.ts
@@ -6,6 +6,20 @@
// === Module declarations ===
// ===========================
+// Required because this is a build artifact, which does not exist on a clean repository.
+declare module '*/build.json' {
+ /** Build metadata generated by the build CLI. */
+ export interface BuildInfo {
+ commit: string
+ version: string
+ engineVersion: string
+ name: string
+ }
+
+ const BUILD_INFO: BuildInfo
+ export default BUILD_INFO
+}
+
declare module '*/gui/config.yaml' {
/** Content of the GUI config file. */
interface Config {
@@ -67,7 +81,7 @@ declare module 'create-servers' {
/** Configuration options for `create-servers`. */
interface CreateServersOptions {
http: number
- handler: http.RequestListener
+ handler: http.RequestListener
}
/** An error passed to a callback when a HTTP request fails. */
diff --git a/app/ide-desktop/lib/types/tsconfig.json b/app/ide-desktop/lib/types/tsconfig.json
new file mode 100644
index 00000000000..50af4660a58
--- /dev/null
+++ b/app/ide-desktop/lib/types/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "compilerOptions": {
+ "skipLibCheck": false
+ },
+ "extends": "../../tsconfig.json"
+}
diff --git a/app/ide-desktop/package.json b/app/ide-desktop/package.json
index f9a45a0a4fe..82fe8f51056 100644
--- a/app/ide-desktop/package.json
+++ b/app/ide-desktop/package.json
@@ -36,6 +36,6 @@
"watch": "npm run watch --workspace enso-content",
"watch-dashboard": "npm run watch --workspace enso-dashboard",
"build-dashboard": "npm run build --workspace enso-dashboard",
- "typecheck": "npm run typecheck --workspace enso && npm run typecheck --workspace enso-content && npm run typecheck --workspace enso-dashboard && npm run typecheck --workspace enso-authentication"
+ "typecheck": "npx tsc -p lib/types/tsconfig.json && npm run typecheck --workspace enso && npm run typecheck --workspace enso-content && npm run typecheck --workspace enso-dashboard && npm run typecheck --workspace enso-authentication"
}
}
diff --git a/app/ide-desktop/tsconfig.json b/app/ide-desktop/tsconfig.json
index 05c497e8c6d..cf3cc70c0c4 100644
--- a/app/ide-desktop/tsconfig.json
+++ b/app/ide-desktop/tsconfig.json
@@ -6,6 +6,7 @@
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "node",
+ "noEmit": true,
"allowJs": true,
"checkJs": true,
"strict": true,
diff --git a/build/ci_utils/src/fs.rs b/build/ci_utils/src/fs.rs
index 12393462e85..10d71460476 100644
--- a/build/ci_utils/src/fs.rs
+++ b/build/ci_utils/src/fs.rs
@@ -128,7 +128,7 @@ pub fn symlink_auto(src: impl AsRef, dst: impl AsRef) -> Result {
symlink::symlink_auto(&src, &dst).anyhow_err()
}
-/// Remove a symlink if it exists.
+/// Remove a symlink to a directory if it exists.
#[context("Failed to remove symlink {}", path.as_ref().display())]
pub fn remove_symlink_dir_if_exists(path: impl AsRef) -> Result {
let result = symlink::remove_symlink_dir(&path);
@@ -138,6 +138,12 @@ pub fn remove_symlink_dir_if_exists(path: impl AsRef) -> Result {
}
}
+/// Create a symlink to a directory, or remove and recreate it if it already exists.
+pub fn create_or_update_symlink_dir(src: impl AsRef, dst: impl AsRef) -> Result {
+ remove_symlink_dir_if_exists(&dst)?;
+ symlink_auto(&src, &dst)
+}
+
/// `fs_extra`'s error type is not friendly to `anyhow`, so we need to convert it manually.
///
/// Otherwise, we get just the message to look into the error kind, but the kind information is
diff --git a/build/cli/Cargo.toml b/build/cli/Cargo.toml
index 8e0c4025ed3..27e4167e306 100644
--- a/build/cli/Cargo.toml
+++ b/build/cli/Cargo.toml
@@ -13,6 +13,7 @@ derivative = { workspace = true }
enso-build-base = { path = "../base" }
enso-build = { path = "../build" }
enso-formatter = { path = "../enso-formatter" }
+ensogl-pack = { path = "../../lib/rust/ensogl/pack" }
futures = { workspace = true }
futures-util = "0.3.17"
glob = "0.3.0"
diff --git a/build/cli/src/lib.rs b/build/cli/src/lib.rs
index 7ab115122e0..f07aae61050 100644
--- a/build/cli/src/lib.rs
+++ b/build/cli/src/lib.rs
@@ -86,6 +86,8 @@ use ide_ci::programs::git;
use ide_ci::programs::git::clean;
use ide_ci::programs::rustc;
use ide_ci::programs::Cargo;
+use ide_ci::programs::Npm;
+use ide_ci::programs::Npx;
use std::time::Duration;
use tempfile::tempdir;
use tokio::process::Child;
@@ -834,7 +836,12 @@ pub async fn main_internal(config: Option) -> Result
.run_ok()
.await?;
+ ensogl_pack::build_ts_sources_only().await?;
prettier::check(&ctx.repo_root).await?;
+ let js_modules_root = ctx.repo_root.join("app/ide-desktop");
+ Npm.cmd()?.current_dir(&js_modules_root).args(["install"]).run_ok().await?;
+ Npm.cmd()?.current_dir(&js_modules_root).args(["run", "typecheck"]).run_ok().await?;
+ Npx.cmd()?.current_dir(&js_modules_root).args(["eslint", "."]).run_ok().await?;
}
Target::Fmt => {
let prettier = prettier::write(&ctx.repo_root);
diff --git a/lib/rust/ensogl/pack/src/lib.rs b/lib/rust/ensogl/pack/src/lib.rs
index 5c11558b56a..7a98dd09bc0 100644
--- a/lib/rust/ensogl/pack/src/lib.rs
+++ b/lib/rust/ensogl/pack/src/lib.rs
@@ -353,7 +353,7 @@ fn check_if_ts_needs_rebuild(paths: &Paths) -> Result {
}
/// Compile TypeScript sources of this crate in case they were not compiled yet.
-async fn compile_this_crate_ts_sources(paths: &Paths) -> Result<()> {
+pub async fn compile_this_crate_ts_sources(paths: &Paths) -> Result<()> {
println!("compile_this_crate_ts_sources");
if check_if_ts_needs_rebuild(paths)? {
info!("EnsoGL Pack TypeScript sources changed, recompiling.");
@@ -447,6 +447,16 @@ async fn extract_assets(paths: &Paths) -> Result<()> {
.await
}
+/// Just builds the TypeScript sources, and creates (or recreates) the symlink to `linked_dist`.
+pub async fn build_ts_sources_only() -> Result {
+ let paths = Paths::new().await?;
+ compile_this_crate_ts_sources(&paths).await?;
+ ide_ci::fs::create_or_update_symlink_dir(
+ &paths.target.ensogl_pack.dist,
+ &paths.target.ensogl_pack.linked_dist,
+ )
+}
+
/// Wrapper over `wasm-pack build` command.
///
/// # Arguments
@@ -464,6 +474,8 @@ pub async fn build(
assets::build(&paths).await?;
let out_dir = Path::new(&outputs.out_dir);
ide_ci::fs::copy(&paths.target.ensogl_pack.dist, out_dir)?;
- ide_ci::fs::remove_symlink_dir_if_exists(&paths.target.ensogl_pack.linked_dist)?;
- ide_ci::fs::symlink_auto(&paths.target.ensogl_pack.dist, &paths.target.ensogl_pack.linked_dist)
+ ide_ci::fs::create_or_update_symlink_dir(
+ &paths.target.ensogl_pack.dist,
+ &paths.target.ensogl_pack.linked_dist,
+ )
}