Document workspace package graphs
This commit is contained in:
parent
0c612ad7fd
commit
0337974923
@ -20,12 +20,14 @@ ABI promise.
|
|||||||
- Diagnose missing `default_package` references during workspace loading.
|
- Diagnose missing `default_package` references during workspace loading.
|
||||||
- Diagnose duplicate workspace members after path normalization before package
|
- Diagnose duplicate workspace members after path normalization before package
|
||||||
loading.
|
loading.
|
||||||
|
- Add workspace package and dependency summaries to `glagol doc`.
|
||||||
- Keep dependency resolution local-path-only and deterministic.
|
- Keep dependency resolution local-path-only and deterministic.
|
||||||
|
|
||||||
## Acceptance Gates
|
## Acceptance Gates
|
||||||
|
|
||||||
- `cargo test --test project_mode workspace_default_package`
|
- `cargo test --test project_mode workspace_default_package`
|
||||||
- `cargo test --test project_mode workspace_package_boundaries`
|
- `cargo test --test project_mode workspace_package_boundaries`
|
||||||
|
- `cargo test --test dx_v1_7 doc_generates_workspace_package_summary`
|
||||||
- `cargo fmt --check`
|
- `cargo fmt --check`
|
||||||
- `git diff --check`
|
- `git diff --check`
|
||||||
|
|
||||||
|
|||||||
@ -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
|
Local workspaces may declare `[workspace] default_package = "name"` to select
|
||||||
the build/run entry package when multiple packages have entry modules.
|
the build/run entry package when multiple packages have entry modules.
|
||||||
Duplicate normalized workspace members and missing default-package references
|
Duplicate normalized workspace members and missing default-package references
|
||||||
are now dedicated diagnostics. Remote registries, lockfiles, semantic-version
|
are now dedicated diagnostics. `glagol doc <workspace> -o <dir>` includes a
|
||||||
solving, package publishing, and stable package ABI/layout remain deferred.
|
workspace package/dependency summary. Remote registries, lockfiles,
|
||||||
|
semantic-version solving, package publishing, and stable package ABI/layout
|
||||||
|
remain deferred.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|||||||
@ -4,14 +4,14 @@ use crate::{
|
|||||||
ast::Program,
|
ast::Program,
|
||||||
diag::Diagnostic,
|
diag::Diagnostic,
|
||||||
lexer, lower,
|
lexer, lower,
|
||||||
project::{self, SourceFile, ToolFailure},
|
project::{self, ProjectArtifact, SourceFile, ToolFailure, WorkspaceArtifact},
|
||||||
sexpr::{Atom, SExpr, SExprKind},
|
sexpr::{Atom, SExpr, SExprKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn generate(input: &str, output_dir: &str) -> Result<(), ToolFailure> {
|
pub fn generate(input: &str, output_dir: &str) -> Result<(), ToolFailure> {
|
||||||
let docs = if project::is_project_input(input) {
|
let docs = if project::is_project_input(input) {
|
||||||
let loaded = project::load_project_sources_for_tools(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 {
|
} else {
|
||||||
let source = fs::read_to_string(input).map_err(|err| ToolFailure {
|
let source = fs::read_to_string(input).map_err(|err| ToolFailure {
|
||||||
diagnostics: vec![Diagnostic::new(
|
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<String, ToolFailure> {
|
fn render_project(
|
||||||
|
artifact: &ProjectArtifact,
|
||||||
|
sources: &[SourceFile],
|
||||||
|
) -> Result<String, ToolFailure> {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
out.push_str("# Project ");
|
out.push_str("# Project ");
|
||||||
out.push_str(title);
|
out.push_str(&artifact.project_name);
|
||||||
out.push_str("\n\n");
|
out.push_str("\n\n");
|
||||||
|
if let Some(workspace) = &artifact.workspace {
|
||||||
|
render_workspace(&mut out, workspace);
|
||||||
|
}
|
||||||
for source in sources {
|
for source in sources {
|
||||||
let module = document_source(source)?;
|
let module = document_source(source)?;
|
||||||
render_module(&mut out, &module);
|
render_module(&mut out, &module);
|
||||||
@ -64,6 +70,35 @@ fn render_project(title: &str, sources: &[SourceFile]) -> Result<String, ToolFai
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_workspace(out: &mut String, workspace: &WorkspaceArtifact) {
|
||||||
|
out.push_str("## Workspace\n\n");
|
||||||
|
render_list(out, "Members", &workspace.members);
|
||||||
|
|
||||||
|
let packages = workspace
|
||||||
|
.packages
|
||||||
|
.iter()
|
||||||
|
.map(|package| {
|
||||||
|
format!(
|
||||||
|
"{} {} (entry {})",
|
||||||
|
package.name, package.version, package.entry
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
render_list(out, "Packages", &packages);
|
||||||
|
|
||||||
|
let dependencies = workspace
|
||||||
|
.dependencies
|
||||||
|
.iter()
|
||||||
|
.map(|dependency| {
|
||||||
|
format!(
|
||||||
|
"{} -> {} ({}, {})",
|
||||||
|
dependency.from, dependency.to, dependency.kind, dependency.path
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
render_list(out, "Package Dependencies", &dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
fn render_file(title: &str, sources: &[SourceFile]) -> Result<String, ToolFailure> {
|
fn render_file(title: &str, sources: &[SourceFile]) -> Result<String, ToolFailure> {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
out.push_str("# File ");
|
out.push_str("# File ");
|
||||||
|
|||||||
@ -351,6 +351,38 @@ fn doc_generates_markdown_for_file_and_project() {
|
|||||||
assert!(project_index.contains("- `math`"));
|
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)]
|
#[cfg(unix)]
|
||||||
#[test]
|
#[test]
|
||||||
fn project_tooling_rejects_symlinked_module_escape() {
|
fn project_tooling_rejects_symlinked_module_escape() {
|
||||||
|
|||||||
@ -134,7 +134,8 @@ Work:
|
|||||||
In progress after `1.0.0-beta.4`: local workspaces can declare
|
In progress after `1.0.0-beta.4`: local workspaces can declare
|
||||||
`default_package` to select the build/run entry package when multiple packages
|
`default_package` to select the build/run entry package when multiple packages
|
||||||
have entry modules. Duplicate normalized member paths and missing default
|
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
|
semver solving, publishing, optional/dev/target dependencies, and stable
|
||||||
package ABI/layout remain out of scope.
|
package ABI/layout remain out of scope.
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,8 @@ integration/readiness release, not the first real beta.
|
|||||||
- Workspace loading now diagnoses a missing `default_package` reference with
|
- Workspace loading now diagnoses a missing `default_package` reference with
|
||||||
`WorkspaceDefaultPackageMissing`, and build/run diagnose a selected package
|
`WorkspaceDefaultPackageMissing`, and build/run diagnose a selected package
|
||||||
that lacks its entry module with `WorkspaceDefaultPackageEntryMissing`.
|
that lacks its entry module with `WorkspaceDefaultPackageEntryMissing`.
|
||||||
|
- `glagol doc <workspace> -o <dir>` now includes a deterministic workspace
|
||||||
|
summary with members, packages, and local package dependency edges.
|
||||||
|
|
||||||
## 1.0.0-beta.4
|
## 1.0.0-beta.4
|
||||||
|
|
||||||
|
|||||||
@ -33,8 +33,8 @@ diagnostics.
|
|||||||
Current unreleased work is the package/workspace discipline slice. It adds
|
Current unreleased work is the package/workspace discipline slice. It adds
|
||||||
`[workspace] default_package = "name"` for deterministic build/run entry
|
`[workspace] default_package = "name"` for deterministic build/run entry
|
||||||
selection in multi-entry workspaces and tightens workspace-member/default
|
selection in multi-entry workspaces and tightens workspace-member/default
|
||||||
package diagnostics while keeping registries, lockfiles, semver solving, and
|
package diagnostics. Workspace docs now include package/dependency summaries.
|
||||||
publishing deferred.
|
Registries, lockfiles, semver solving, and publishing remain deferred.
|
||||||
|
|
||||||
The final experimental precursor scope is `exp-125`. Its unsigned direct-value
|
The final experimental precursor scope is `exp-125`. Its unsigned direct-value
|
||||||
flow, parse/format runtime lanes, and matching staged stdlib helper breadth
|
flow, parse/format runtime lanes, and matching staged stdlib helper breadth
|
||||||
|
|||||||
@ -26,6 +26,8 @@ diagnostics bundle.
|
|||||||
`WorkspaceDefaultPackageMissing` diagnostic. A selected default package that
|
`WorkspaceDefaultPackageMissing` diagnostic. A selected default package that
|
||||||
lacks its configured entry module is diagnosed as
|
lacks its configured entry module is diagnosed as
|
||||||
`WorkspaceDefaultPackageEntryMissing` during build/run.
|
`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
|
## 1.0.0-beta.4
|
||||||
|
|
||||||
|
|||||||
@ -20,8 +20,8 @@ standard-library stabilization release, entry-specific project/workspace
|
|||||||
Current unreleased work is the package/workspace discipline slice. It adds
|
Current unreleased work is the package/workspace discipline slice. It adds
|
||||||
`[workspace] default_package = "name"` for deterministic build/run entry
|
`[workspace] default_package = "name"` for deterministic build/run entry
|
||||||
selection in multi-entry workspaces and tightens duplicate-member/default
|
selection in multi-entry workspaces and tightens duplicate-member/default
|
||||||
package diagnostics while keeping registries, lockfiles, semver solving, and
|
package diagnostics. Workspace docs now include package/dependency summaries.
|
||||||
publishing deferred.
|
Registries, lockfiles, semver solving, and publishing remain deferred.
|
||||||
|
|
||||||
The final experimental precursor scope is `exp-125`, defined in
|
The final experimental precursor scope is `exp-125`, defined in
|
||||||
`.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its
|
`.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its
|
||||||
|
|||||||
@ -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
|
loading. Duplicate normalized member paths are invalid, even if they were
|
||||||
spelled differently in the manifest.
|
spelled differently in the manifest.
|
||||||
|
|
||||||
|
`glagol doc <workspace> -o <dir>` 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
|
This slice does not add remote registries, lockfiles, semantic-version
|
||||||
solving, package publishing, archive formats, optional/dev/target
|
solving, package publishing, archive formats, optional/dev/target
|
||||||
dependencies, feature flags, package build scripts, or stable package
|
dependencies, feature flags, package build scripts, or stable package
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user