Skip to content

Commit 7cedcc5

Browse files
committed
feat: init workspace implementation
1 parent c5da070 commit 7cedcc5

File tree

6 files changed

+252
-9
lines changed

6 files changed

+252
-9
lines changed

Cargo.lock

Lines changed: 61 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/workspace_std/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ git-cliff-core = "2.6.1"
2929
itertools = "0.13.0"
3030
petgraph = "0.6.5"
3131
semver = { version = "1.0.23", features = ["serde"] }
32-
version-compare = "0.2"
32+
wax = { version = "0.6.0", features = ["walk"] }

crates/workspace_std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ pub mod paths;
2222
pub mod test;
2323
pub mod types;
2424
pub mod utils;
25+
pub mod workspace;

crates/workspace_std/src/package.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,26 @@ pub struct PackageInfo {
2727
pub pkg_json: Value,
2828
}
2929

30+
#[derive(Debug, Deserialize, Serialize)]
31+
pub struct PackageJson {
32+
pub workspaces: Option<Vec<String>>,
33+
pub name: String,
34+
pub version: String,
35+
pub description: Option<String>,
36+
pub private: Option<bool>,
37+
pub license: Option<String>,
38+
pub author: Option<String>,
39+
pub homepage: Option<String>,
40+
pub repository: Option<Value>,
41+
pub dependencies: Option<Value>,
42+
pub dev_dependencies: Option<Value>,
43+
pub peer_dependencies: Option<Value>,
44+
pub optional_dependencies: Option<Value>,
45+
pub engines: Option<Value>,
46+
pub scripts: Option<Value>,
47+
pub bin: Option<Value>,
48+
}
49+
3050
impl Node for PackageInfo {
3151
type DependencyType = Dependency;
3252

crates/workspace_std/src/test.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,21 @@ sort_commits = "newest"
730730
Ok(())
731731
}
732732

733+
pub fn create_workspace(
734+
&self,
735+
package_manager: &CorePackageManager,
736+
) -> Result<(), std::io::Error> {
737+
self.create_repository(package_manager)?;
738+
self.create_changes()?;
739+
self.create_package_bar()?;
740+
self.create_package_foo()?;
741+
self.create_package_baz()?;
742+
self.create_package_charlie()?;
743+
self.create_package_major()?;
744+
self.create_package_tom()?;
745+
Ok(())
746+
}
747+
733748
pub fn delete_repository(&self) -> bool {
734749
remove_dir_all(&self.root).is_ok()
735750
}

crates/workspace_std/src/workspace.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use std::{fs::File, io::BufReader, path::PathBuf};
2+
use wax::{CandidatePath, Glob, Pattern};
3+
4+
use crate::{
5+
config::{get_workspace_config, WorkspaceConfig},
6+
manager::CorePackageManager,
7+
package::{Dependency, PackageJson},
8+
};
9+
10+
pub struct Workspace {
11+
pub config: WorkspaceConfig,
12+
}
13+
14+
impl From<PathBuf> for Workspace {
15+
fn from(root: PathBuf) -> Self {
16+
let config = get_workspace_config(Some(root));
17+
Workspace { config }
18+
}
19+
}
20+
21+
impl From<WorkspaceConfig> for Workspace {
22+
fn from(config: WorkspaceConfig) -> Self {
23+
Workspace { config }
24+
}
25+
}
26+
27+
impl Workspace {
28+
pub fn new(root: PathBuf) -> Self {
29+
let config = get_workspace_config(Some(root));
30+
Workspace { config }
31+
}
32+
33+
pub fn get_packages(&self) {
34+
let manager = self.config.package_manager;
35+
36+
match manager {
37+
CorePackageManager::Npm | CorePackageManager::Yarn => {
38+
self.get_packages_from_npm();
39+
}
40+
CorePackageManager::Bun => {
41+
todo!("Implement Bun package manager")
42+
}
43+
CorePackageManager::Pnpm => {
44+
todo!("Implement Pnpm package manager")
45+
}
46+
}
47+
}
48+
49+
fn get_root_package_json(&self) -> PackageJson {
50+
let package_json_path = self.config.workspace_root.join("package.json");
51+
52+
let package_json_file = File::open(package_json_path.as_path()).expect("File not found");
53+
let package_json_buffer = BufReader::new(package_json_file);
54+
55+
serde_json::from_reader(package_json_buffer).expect("Error parsing package.json")
56+
}
57+
58+
#[allow(clippy::needless_borrows_for_generic_args)]
59+
fn get_packages_from_npm(&self) {
60+
let path = self.config.workspace_root.as_path();
61+
let PackageJson { workspaces, .. } = self.get_root_package_json();
62+
let mut workspaces = workspaces.unwrap_or_default();
63+
64+
let globs = workspaces
65+
.iter_mut()
66+
.map(|workspace| {
67+
if workspace.ends_with("/*") {
68+
workspace.push_str("*/package.json");
69+
Glob::new(workspace).expect("Error parsing glob")
70+
} else {
71+
workspace.push_str("/package.json");
72+
Glob::new(workspace).expect("Error parsing glob")
73+
}
74+
})
75+
.collect::<Vec<Glob>>();
76+
77+
let patterns = wax::any(globs).expect("Error creating patterns");
78+
let glob = Glob::new("**/package.json").expect("Error parsing glob");
79+
80+
for entry in glob
81+
.walk(self.config.workspace_root.as_path())
82+
.not([
83+
"**/node_modules/**",
84+
"**/src/**",
85+
"**/dist/**",
86+
"**/tests/**",
87+
"**/__tests__/**",
88+
])
89+
.expect("Error walking glob")
90+
{
91+
let entry = entry.expect("Error reading entry");
92+
let rel_path = entry
93+
.path()
94+
.strip_prefix(&path)
95+
.expect("Error getting entry path")
96+
.display()
97+
.to_string();
98+
let entry_path = entry.path().strip_prefix(&path).expect("Error getting entry path");
99+
100+
if patterns.is_match(CandidatePath::from(entry_path)) {
101+
let package_json_file = File::open(&entry.path()).expect("File not found");
102+
let package_json_reader = BufReader::new(package_json_file);
103+
let pkg_json: PackageJson = serde_json::from_reader(package_json_reader)
104+
.expect("Failed to parse package json file");
105+
106+
let mut package_dependencies = vec![];
107+
108+
let dependencies = pkg_json.dependencies.unwrap_or_default();
109+
let dev_dependencies = pkg_json.dev_dependencies.unwrap_or_default();
110+
let peer_dependencies = pkg_json.peer_dependencies.unwrap_or_default();
111+
let optional_dependencies = pkg_json.optional_dependencies.unwrap_or_default();
112+
113+
if dependencies.is_object() {
114+
package_dependencies.push(dependencies);
115+
}
116+
117+
if dev_dependencies.is_object() {
118+
package_dependencies.push(dev_dependencies);
119+
}
120+
121+
if peer_dependencies.is_object() {
122+
package_dependencies.push(peer_dependencies);
123+
}
124+
125+
if optional_dependencies.is_object() {
126+
package_dependencies.push(optional_dependencies);
127+
}
128+
129+
//let dependencies = dependencies.into_iter().flatten().collect::<Vec<_>>();
130+
}
131+
}
132+
}
133+
}
134+
135+
#[cfg(test)]
136+
mod tests {
137+
use super::*;
138+
use crate::manager::CorePackageManager;
139+
use crate::test::MonorepoWorkspace;
140+
141+
#[test]
142+
fn test_workspace() -> Result<(), std::io::Error> {
143+
let monorepo = MonorepoWorkspace::new();
144+
let root = monorepo.get_monorepo_root().clone();
145+
monorepo.create_workspace(&CorePackageManager::Npm)?;
146+
147+
let workspace = Workspace::from(root);
148+
workspace.get_packages();
149+
150+
monorepo.delete_repository();
151+
152+
Ok(())
153+
}
154+
}

0 commit comments

Comments
 (0)