From 0337974923db87527a599b8fbb353cf9c218c27b Mon Sep 17 00:00:00 2001 From: sanjin Date: Fri, 22 May 2026 13:17:21 +0200 Subject: [PATCH] Document workspace package graphs --- .llm/BETA_5_PACKAGE_WORKSPACE_DISCIPLINE.md | 2 + README.md | 6 ++- compiler/src/docgen.rs | 43 +++++++++++++++++++-- compiler/tests/dx_v1_7.rs | 32 +++++++++++++++ docs/POST_BETA_ROADMAP.md | 3 +- docs/compiler/RELEASE_NOTES.md | 2 + docs/compiler/ROADMAP.md | 4 +- docs/language/RELEASE_NOTES.md | 2 + docs/language/ROADMAP.md | 4 +- docs/language/SPEC-v1.md | 5 +++ 10 files changed, 92 insertions(+), 11 deletions(-) diff --git a/.llm/BETA_5_PACKAGE_WORKSPACE_DISCIPLINE.md b/.llm/BETA_5_PACKAGE_WORKSPACE_DISCIPLINE.md index a16240e..04e3ffe 100644 --- a/.llm/BETA_5_PACKAGE_WORKSPACE_DISCIPLINE.md +++ b/.llm/BETA_5_PACKAGE_WORKSPACE_DISCIPLINE.md @@ -20,12 +20,14 @@ ABI promise. - Diagnose missing `default_package` references during workspace loading. - Diagnose duplicate workspace members after path normalization before package loading. +- Add workspace package and dependency summaries to `glagol doc`. - Keep dependency resolution local-path-only and deterministic. ## Acceptance Gates - `cargo test --test project_mode workspace_default_package` - `cargo test --test project_mode workspace_package_boundaries` +- `cargo test --test dx_v1_7 doc_generates_workspace_package_summary` - `cargo fmt --check` - `git diff --check` diff --git a/README.md b/README.md index 6d2b782..cbeed97 100644 --- a/README.md +++ b/README.md @@ -156,8 +156,10 @@ After `1.0.0-beta.4`, `main` is tracking a package/workspace discipline slice. Local workspaces may declare `[workspace] default_package = "name"` to select the build/run entry package when multiple packages have entry modules. Duplicate normalized workspace members and missing default-package references -are now dedicated diagnostics. Remote registries, lockfiles, semantic-version -solving, package publishing, and stable package ABI/layout remain deferred. +are now dedicated diagnostics. `glagol doc -o ` includes a +workspace package/dependency summary. Remote registries, lockfiles, +semantic-version solving, package publishing, and stable package ABI/layout +remain deferred. ## Documentation diff --git a/compiler/src/docgen.rs b/compiler/src/docgen.rs index f96fb23..eac7dab 100644 --- a/compiler/src/docgen.rs +++ b/compiler/src/docgen.rs @@ -4,14 +4,14 @@ use crate::{ ast::Program, diag::Diagnostic, lexer, lower, - project::{self, SourceFile, ToolFailure}, + project::{self, ProjectArtifact, SourceFile, ToolFailure, WorkspaceArtifact}, sexpr::{Atom, SExpr, SExprKind}, }; pub fn generate(input: &str, output_dir: &str) -> Result<(), ToolFailure> { let docs = if project::is_project_input(input) { let loaded = project::load_project_sources_for_tools(input)?; - render_project(&loaded.artifact.project_name, &loaded.sources)? + render_project(&loaded.artifact, &loaded.sources)? } else { let source = fs::read_to_string(input).map_err(|err| ToolFailure { diagnostics: vec![Diagnostic::new( @@ -52,11 +52,17 @@ pub fn generate(input: &str, output_dir: &str) -> Result<(), ToolFailure> { }) } -fn render_project(title: &str, sources: &[SourceFile]) -> Result { +fn render_project( + artifact: &ProjectArtifact, + sources: &[SourceFile], +) -> Result { let mut out = String::new(); out.push_str("# Project "); - out.push_str(title); + out.push_str(&artifact.project_name); out.push_str("\n\n"); + if let Some(workspace) = &artifact.workspace { + render_workspace(&mut out, workspace); + } for source in sources { let module = document_source(source)?; render_module(&mut out, &module); @@ -64,6 +70,35 @@ fn render_project(title: &str, sources: &[SourceFile]) -> Result>(); + render_list(out, "Packages", &packages); + + let dependencies = workspace + .dependencies + .iter() + .map(|dependency| { + format!( + "{} -> {} ({}, {})", + dependency.from, dependency.to, dependency.kind, dependency.path + ) + }) + .collect::>(); + render_list(out, "Package Dependencies", &dependencies); +} + fn render_file(title: &str, sources: &[SourceFile]) -> Result { let mut out = String::new(); out.push_str("# File "); diff --git a/compiler/tests/dx_v1_7.rs b/compiler/tests/dx_v1_7.rs index a8cddd5..66f9f60 100644 --- a/compiler/tests/dx_v1_7.rs +++ b/compiler/tests/dx_v1_7.rs @@ -351,6 +351,38 @@ fn doc_generates_markdown_for_file_and_project() { assert!(project_index.contains("- `math`")); } +#[test] +fn doc_generates_workspace_package_summary() { + let workspace = unique_path("doc-workspace"); + let new_output = run_glagol([ + "new".as_ref(), + workspace.as_os_str(), + "--template".as_ref(), + "workspace".as_ref(), + ]); + assert_success("doc workspace scaffold", &new_output); + + let workspace_docs = unique_path("doc-workspace-out"); + let doc_output = run_glagol([ + "doc".as_ref(), + workspace.as_os_str(), + "-o".as_ref(), + workspace_docs.as_os_str(), + ]); + assert_success("doc workspace", &doc_output); + + let index = fs::read_to_string(workspace_docs.join("index.md")).expect("read workspace docs"); + assert!(index.contains("## Workspace")); + assert!(index.contains("### Members")); + assert!(index.contains("- `packages/app`")); + assert!(index.contains("- `packages/libutil`")); + assert!(index.contains("### Packages")); + assert!(index.contains("- `app 0.1.0 (entry main)`")); + assert!(index.contains("- `libutil 0.1.0 (entry main)`")); + assert!(index.contains("### Package Dependencies")); + assert!(index.contains("- `app -> libutil (local-path, packages/libutil)`")); +} + #[cfg(unix)] #[test] fn project_tooling_rejects_symlinked_module_escape() { diff --git a/docs/POST_BETA_ROADMAP.md b/docs/POST_BETA_ROADMAP.md index df755f8..f6484c9 100644 --- a/docs/POST_BETA_ROADMAP.md +++ b/docs/POST_BETA_ROADMAP.md @@ -134,7 +134,8 @@ Work: In progress after `1.0.0-beta.4`: local workspaces can declare `default_package` to select the build/run entry package when multiple packages have entry modules. Duplicate normalized member paths and missing default -package references are dedicated diagnostics. Lockfiles, remote registries, +package references are dedicated diagnostics. Workspace documentation now +includes package and local dependency summaries. Lockfiles, remote registries, semver solving, publishing, optional/dev/target dependencies, and stable package ABI/layout remain out of scope. diff --git a/docs/compiler/RELEASE_NOTES.md b/docs/compiler/RELEASE_NOTES.md index 20dab70..a7f4100 100644 --- a/docs/compiler/RELEASE_NOTES.md +++ b/docs/compiler/RELEASE_NOTES.md @@ -18,6 +18,8 @@ integration/readiness release, not the first real beta. - Workspace loading now diagnoses a missing `default_package` reference with `WorkspaceDefaultPackageMissing`, and build/run diagnose a selected package that lacks its entry module with `WorkspaceDefaultPackageEntryMissing`. +- `glagol doc -o ` now includes a deterministic workspace + summary with members, packages, and local package dependency edges. ## 1.0.0-beta.4 diff --git a/docs/compiler/ROADMAP.md b/docs/compiler/ROADMAP.md index 3d0098e..ba4c3e0 100644 --- a/docs/compiler/ROADMAP.md +++ b/docs/compiler/ROADMAP.md @@ -33,8 +33,8 @@ diagnostics. Current unreleased work is the package/workspace discipline slice. It adds `[workspace] default_package = "name"` for deterministic build/run entry selection in multi-entry workspaces and tightens workspace-member/default -package diagnostics while keeping registries, lockfiles, semver solving, and -publishing deferred. +package diagnostics. Workspace docs now include package/dependency summaries. +Registries, lockfiles, semver solving, and publishing remain deferred. The final experimental precursor scope is `exp-125`. Its unsigned direct-value flow, parse/format runtime lanes, and matching staged stdlib helper breadth diff --git a/docs/language/RELEASE_NOTES.md b/docs/language/RELEASE_NOTES.md index 3616287..0f34a77 100644 --- a/docs/language/RELEASE_NOTES.md +++ b/docs/language/RELEASE_NOTES.md @@ -26,6 +26,8 @@ diagnostics bundle. `WorkspaceDefaultPackageMissing` diagnostic. A selected default package that lacks its configured entry module is diagnosed as `WorkspaceDefaultPackageEntryMissing` during build/run. +- Workspace documentation generated by `glagol doc` now includes a + deterministic summary of members, packages, and local dependency edges. ## 1.0.0-beta.4 diff --git a/docs/language/ROADMAP.md b/docs/language/ROADMAP.md index 8ba9904..f3acbbc 100644 --- a/docs/language/ROADMAP.md +++ b/docs/language/ROADMAP.md @@ -20,8 +20,8 @@ standard-library stabilization release, entry-specific project/workspace Current unreleased work is the package/workspace discipline slice. It adds `[workspace] default_package = "name"` for deterministic build/run entry selection in multi-entry workspaces and tightens duplicate-member/default -package diagnostics while keeping registries, lockfiles, semver solving, and -publishing deferred. +package diagnostics. Workspace docs now include package/dependency summaries. +Registries, lockfiles, semver solving, and publishing remain deferred. The final experimental precursor scope is `exp-125`, defined in `.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its diff --git a/docs/language/SPEC-v1.md b/docs/language/SPEC-v1.md index fcec885..a5d4836 100644 --- a/docs/language/SPEC-v1.md +++ b/docs/language/SPEC-v1.md @@ -1032,6 +1032,11 @@ Workspace member paths are normalized under the workspace root before package loading. Duplicate normalized member paths are invalid, even if they were spelled differently in the manifest. +`glagol doc -o ` documents the workspace graph in addition to +module structure. The generated `index.md` includes deterministic lists of +workspace members, packages, and local package dependency edges before the +module sections. + This slice does not add remote registries, lockfiles, semantic-version solving, package publishing, archive formats, optional/dev/target dependencies, feature flags, package build scripts, or stable package