Skip to content

Be more aware of the workspace during clean #7752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
776801c
Be more aware of the workspace during clean
nojaf Aug 2, 2025
dff32e7
Only clean current package
nojaf Aug 2, 2025
119d553
fmt
nojaf Aug 2, 2025
78bfd88
Return is_child from packages make
nojaf Aug 4, 2025
81966e0
Invert if
nojaf Aug 4, 2025
7b84cb4
Introduce PackageMap to make things a bit more clear.
nojaf Aug 4, 2025
178a0ec
Use workspace extension if there is a link, otherwise root_package.
nojaf Aug 7, 2025
5b2e427
Add a TODO that we need to clean up some confusing bits.
nojaf Aug 7, 2025
08a146d
Refactor using project_context
nojaf Aug 9, 2025
860e6e2
A rescript.json with an unrelated parent can still be a monorepo.
nojaf Aug 9, 2025
8202315
Remove all from format command.
nojaf Aug 9, 2025
d29f977
Merge branch 'master' into detect-root
nojaf Aug 9, 2025
c2c9183
get_rescript_legacy inside rescript repository.
nojaf Aug 9, 2025
50baa0b
sigh
nojaf Aug 9, 2025
c19670e
StrippedVerbatimPath in before local dep check
nojaf Aug 10, 2025
2b8e412
Use proper --version
nojaf Aug 10, 2025
43097c8
Add playground to monorepo
nojaf Aug 10, 2025
c740f4e
Copilot nitpicks
nojaf Aug 11, 2025
e5b723c
Add test for only formatting the current project.
nojaf Aug 11, 2025
7b9b230
Add clean single project test
nojaf Aug 11, 2025
f76b55b
Add test for compiler-args
nojaf Aug 11, 2025
f993a71
Get root config from project_context
nojaf Aug 11, 2025
21b2758
Return Result for get_root_package
nojaf Aug 11, 2025
7892d7b
Make a conscious split between dev and non-dev local dependencies for…
nojaf Aug 11, 2025
958fac3
Add dev project to root of test-repo
nojaf Aug 11, 2025
66d62ec
Try and add test for format --dev
nojaf Aug 11, 2025
8348342
Respect --dev for packages::make in format
nojaf Aug 11, 2025
c87fa26
Improve success message
nojaf Aug 11, 2025
98cdcc2
Add test to ensure we clean dev-dependency with --dev.
nojaf Aug 11, 2025
1ccc44c
Pass in actual rescript.json
nojaf Aug 11, 2025
f83fb38
Ensure dependencies are cleaned as well.
nojaf Aug 12, 2025
dc05c76
restore instead of clean
nojaf Aug 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rescript.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name": "rescript",
"dependencies": ["@tests/gentype-react-example"]
"dependencies": ["@tests/gentype-react-example", "playground"]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"playground" is part of the workspace, so I need to be listed here for rewatch to pick up the correct node_modules folder.

The package.json has rescript clean in the commands.
This will now accurately only clean the playground package.

But it needs that link to the parent rescript json.

}
67 changes: 25 additions & 42 deletions rewatch/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ pub mod packages;
pub mod parse;
pub mod read_compile_state;

use self::compile::compiler_args;
use self::parse::parser_args;
use crate::build::compile::{mark_modules_with_deleted_deps_dirty, mark_modules_with_expired_deps_dirty};
use crate::helpers::emojis::*;
use crate::helpers::{self, get_workspace_root};
use crate::helpers::{self};
use crate::project_context::ProjectContext;
use crate::{config, sourcedirs};
use anyhow::{Result, anyhow};
use build_types::*;
Expand Down Expand Up @@ -55,33 +55,27 @@ pub struct CompilerArgs {
pub parser_args: Vec<String>,
}

pub fn get_compiler_args(path: &Path) -> Result<String> {
let filename = &helpers::get_abs_path(path);
let package_root =
helpers::get_abs_path(&helpers::get_nearest_config(path).expect("Couldn't find package root"));
let workspace_root = get_workspace_root(&package_root).map(|p| helpers::get_abs_path(&p));
let root_rescript_config =
packages::read_config(&workspace_root.to_owned().unwrap_or(package_root.to_owned()))?;
let rescript_config = packages::read_config(&package_root)?;
let is_type_dev = match filename.strip_prefix(&package_root) {
pub fn get_compiler_args(rescript_file_path: &Path) -> Result<String> {
let filename = &helpers::get_abs_path(rescript_file_path);
let current_package = helpers::get_abs_path(
&helpers::get_nearest_config(rescript_file_path).expect("Couldn't find package root"),
);
let project_context = ProjectContext::new(&current_package)?;

let is_type_dev = match filename.strip_prefix(&current_package) {
Err(_) => false,
Ok(relative_path) => root_rescript_config.find_is_type_dev_for_path(relative_path),
Ok(relative_path) => project_context
.get_current_rescript_config()
.find_is_type_dev_for_path(relative_path),
};

// make PathBuf from package root and get the relative path for filename
let relative_filename = filename.strip_prefix(PathBuf::from(&package_root)).unwrap();
let relative_filename = filename.strip_prefix(PathBuf::from(&current_package)).unwrap();

let file_path = PathBuf::from(&package_root).join(filename);
let file_path = PathBuf::from(&current_package).join(filename);
let contents = helpers::read_file(&file_path).expect("Error reading file");

let (ast_path, parser_args) = parser_args(
&rescript_config,
&root_rescript_config,
relative_filename,
&workspace_root,
workspace_root.as_ref().unwrap_or(&package_root),
&contents,
);
let (ast_path, parser_args) = parser_args(&project_context, relative_filename, &contents);
let is_interface = filename.to_string_lossy().ends_with('i');
let has_interface = if is_interface {
true
Expand All @@ -90,15 +84,13 @@ pub fn get_compiler_args(path: &Path) -> Result<String> {
interface_filename.push('i');
PathBuf::from(&interface_filename).exists()
};
let compiler_args = compiler_args(
&rescript_config,
&root_rescript_config,
let compiler_args = compile::compiler_args(
project_context.get_current_rescript_config(),
&ast_path,
relative_filename,
is_interface,
has_interface,
&package_root,
&workspace_root,
&project_context,
&None,
is_type_dev,
true,
Expand All @@ -120,24 +112,16 @@ pub fn initialize_build(
build_dev_deps: bool,
snapshot_output: bool,
) -> Result<BuildState> {
let project_root = helpers::get_abs_path(path);
let workspace_root = helpers::get_workspace_root(&project_root);
let bsc_path = helpers::get_bsc();
let root_config_name = packages::read_package_name(&project_root)?;
let project_context = ProjectContext::new(path)?;

if !snapshot_output && show_progress {
print!("{} {}Building package tree...", style("[1/7]").bold().dim(), TREE);
let _ = stdout().flush();
}

let timing_package_tree = Instant::now();
let packages = packages::make(
filter,
&project_root,
&workspace_root,
show_progress,
build_dev_deps,
)?;
let packages = packages::make(filter, &project_context, show_progress, build_dev_deps)?;
let timing_package_tree_elapsed = timing_package_tree.elapsed();

if !snapshot_output && show_progress {
Expand Down Expand Up @@ -167,7 +151,7 @@ pub fn initialize_build(
let _ = stdout().flush();
}

let mut build_state = BuildState::new(project_root, root_config_name, packages, workspace_root, bsc_path);
let mut build_state = BuildState::new(project_context, packages, bsc_path);
packages::parse_packages(&mut build_state);
let timing_source_files_elapsed = timing_source_files.elapsed();

Expand All @@ -190,7 +174,7 @@ pub fn initialize_build(
let _ = stdout().flush();
}
let timing_compile_state = Instant::now();
let compile_assets_state = read_compile_state::read(&mut build_state);
let compile_assets_state = read_compile_state::read(&mut build_state)?;
let timing_compile_state_elapsed = timing_compile_state.elapsed();

if !snapshot_output && show_progress {
Expand Down Expand Up @@ -563,9 +547,8 @@ pub fn build(

pub fn pass_through_legacy(mut args: Vec<OsString>) -> i32 {
let project_root = helpers::get_abs_path(Path::new("."));
let workspace_root = helpers::get_workspace_root(&project_root);

let rescript_legacy_path = helpers::get_rescript_legacy(&project_root, workspace_root);
let project_context = ProjectContext::new(&project_root).unwrap();
let rescript_legacy_path = helpers::get_rescript_legacy(&project_context);

args.insert(0, rescript_legacy_path.into());
let status = std::process::Command::new("node")
Expand Down
18 changes: 9 additions & 9 deletions rewatch/src/build/build_types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::build::packages::{Namespace, Package};
use crate::config::Config;
use crate::project_context::ProjectContext;
use ahash::{AHashMap, AHashSet};
use std::{fmt::Display, path::PathBuf, time::SystemTime};

Expand Down Expand Up @@ -89,14 +91,12 @@ impl Module {

#[derive(Debug)]
pub struct BuildState {
pub project_context: ProjectContext,
pub modules: AHashMap<String, Module>,
pub packages: AHashMap<String, Package>,
pub module_names: AHashSet<String>,
pub project_root: PathBuf,
pub root_config_name: String,
pub deleted_modules: AHashSet<String>,
pub bsc_path: PathBuf,
pub workspace_root: Option<PathBuf>,
pub deps_initialized: bool,
}

Expand All @@ -109,20 +109,16 @@ impl BuildState {
self.modules.get(module_name)
}
pub fn new(
project_root: PathBuf,
root_config_name: String,
project_context: ProjectContext,
packages: AHashMap<String, Package>,
workspace_root: Option<PathBuf>,
bsc_path: PathBuf,
) -> Self {
Self {
project_context,
module_names: AHashSet::new(),
modules: AHashMap::new(),
packages,
project_root,
root_config_name,
deleted_modules: AHashSet::new(),
workspace_root,
bsc_path,
deps_initialized: false,
}
Expand All @@ -132,6 +128,10 @@ impl BuildState {
self.modules.insert(module_name.to_owned(), module);
self.module_names.insert(module_name.to_owned());
}

pub fn get_root_config(&self) -> &Config {
self.project_context.get_root_config()
}
}

#[derive(Debug)]
Expand Down
134 changes: 66 additions & 68 deletions rewatch/src/build/clean.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use super::build_types::*;
use super::packages;
use crate::build::packages::Package;
use crate::config::Config;
use crate::helpers;
use crate::helpers::emojis::*;
use crate::project_context::ProjectContext;
use ahash::AHashSet;
use anyhow::Result;
use console::style;
Expand All @@ -28,10 +31,10 @@ fn remove_iast(package: &packages::Package, source_file: &Path) {
));
}

fn remove_mjs_file(source_file: &Path, suffix: &String) {
fn remove_mjs_file(source_file: &Path, suffix: &str) {
let _ = std::fs::remove_file(source_file.with_extension(
// suffix.to_string includes the ., so we need to remove it
&suffix.to_string()[1..],
&suffix[1..],
));
}

Expand All @@ -58,31 +61,37 @@ pub fn remove_compile_assets(package: &packages::Package, source_file: &Path) {
}
}

fn clean_source_files(build_state: &BuildState, root_package: &packages::Package) {
fn clean_source_files(build_state: &BuildState, root_config: &Config, suffix: &str) {
// get all rescript file locations
let rescript_file_locations = build_state
.modules
.values()
.filter_map(|module| match &module.source_type {
SourceType::SourceFile(source_file) => {
let package = build_state.packages.get(&module.package_name).unwrap();
Some(
root_package
.config
.get_package_specs()
.iter()
.filter_map(|spec| {
if spec.in_source {
Some((
package.path.join(&source_file.implementation.path),
root_package.config.get_suffix(spec),
))
} else {
None
}
})
.collect::<Vec<(PathBuf, String)>>(),
)
if !build_state.packages.contains_key(&module.package_name) {
None
} else {
let package = build_state.packages.get(&module.package_name).unwrap();
Some(
root_config
.get_package_specs()
.iter()
.filter_map(|spec| {
if spec.in_source {
Some((
package.path.join(&source_file.implementation.path),
match &spec.suffix {
None => suffix.to_owned(),
Some(suffix) => suffix.clone(),
},
))
} else {
None
}
})
.collect::<Vec<(PathBuf, String)>>(),
)
}
}
_ => None,
})
Expand Down Expand Up @@ -326,17 +335,10 @@ pub fn cleanup_after_build(build_state: &BuildState) {
});
}

pub fn clean(path: &Path, show_progress: bool, snapshot_output: bool, build_dev_deps: bool) -> Result<()> {
let project_root = helpers::get_abs_path(path);
let workspace_root = helpers::get_workspace_root(&project_root);
let packages = packages::make(
&None,
&project_root,
&workspace_root,
show_progress,
build_dev_deps,
)?;
let root_config_name = packages::read_package_name(&project_root)?;
pub fn clean(path: &Path, show_progress: bool, snapshot_output: bool, clean_dev_deps: bool) -> Result<()> {
let project_context = ProjectContext::new(path)?;

let packages = packages::make(&None, &project_context, show_progress, clean_dev_deps)?;
let bsc_path = helpers::get_bsc();

let timing_clean_compiler_assets = Instant::now();
Expand All @@ -348,30 +350,11 @@ pub fn clean(path: &Path, show_progress: bool, snapshot_output: bool, build_dev_
);
let _ = std::io::stdout().flush();
};
packages.iter().for_each(|(_, package)| {
if show_progress {
if snapshot_output {
println!("Cleaning {}", package.name)
} else {
print!(
"{}{} {}Cleaning {}...",
LINE_CLEAR,
style("[1/2]").bold().dim(),
SWEEP,
package.name
);
}
let _ = std::io::stdout().flush();
}

let path_str = package.get_build_path();
let path = std::path::Path::new(&path_str);
let _ = std::fs::remove_dir_all(path);
for (_, package) in &packages {
clean_package(show_progress, snapshot_output, package)
}

let path_str = package.get_ocaml_build_path();
let path = std::path::Path::new(&path_str);
let _ = std::fs::remove_dir_all(path);
});
let timing_clean_compiler_assets_elapsed = timing_clean_compiler_assets.elapsed();

if !snapshot_output && show_progress {
Expand All @@ -386,20 +369,10 @@ pub fn clean(path: &Path, show_progress: bool, snapshot_output: bool, build_dev_
}

let timing_clean_mjs = Instant::now();
let mut build_state = BuildState::new(
project_root.to_owned(),
root_config_name,
packages,
workspace_root,
bsc_path,
);
let mut build_state = BuildState::new(project_context, packages, bsc_path);
packages::parse_packages(&mut build_state);
let root_package = build_state
.packages
.get(&build_state.root_config_name)
.expect("Could not find root package");

let suffix = root_package.config.suffix.as_deref().unwrap_or(".res.mjs");
let root_config = build_state.get_root_config();
let suffix = build_state.project_context.get_suffix();

if !snapshot_output && show_progress {
println!(
Expand All @@ -411,7 +384,7 @@ pub fn clean(path: &Path, show_progress: bool, snapshot_output: bool, build_dev_
let _ = std::io::stdout().flush();
}

clean_source_files(&build_state, root_package);
clean_source_files(&build_state, root_config, &suffix);
let timing_clean_mjs_elapsed = timing_clean_mjs.elapsed();

if !snapshot_output && show_progress {
Expand All @@ -428,3 +401,28 @@ pub fn clean(path: &Path, show_progress: bool, snapshot_output: bool, build_dev_

Ok(())
}

fn clean_package(show_progress: bool, snapshot_output: bool, package: &Package) {
if show_progress {
if snapshot_output {
println!("Cleaning {}", package.name)
} else {
print!(
"{}{} {}Cleaning {}...",
LINE_CLEAR,
style("[1/2]").bold().dim(),
SWEEP,
package.name
);
}
let _ = std::io::stdout().flush();
}

let path_str = package.get_build_path();
let path = std::path::Path::new(&path_str);
let _ = std::fs::remove_dir_all(path);

let path_str = package.get_ocaml_build_path();
let path = std::path::Path::new(&path_str);
let _ = std::fs::remove_dir_all(path);
}
Loading
Loading