@lamentis/naome 1.3.13 → 1.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +2 -2
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/architecture_commands.rs +1 -1
- package/crates/naome-cli/src/quality_commands.rs +4 -4
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/architecture/config/parser/sections.rs +1 -1
- package/crates/naome-core/src/architecture/config.rs +1 -1
- package/crates/naome-core/src/architecture/model.rs +19 -0
- package/crates/naome-core/src/architecture/output.rs +27 -24
- package/crates/naome-core/src/architecture/rules/budgets.rs +2 -1
- package/crates/naome-core/src/architecture/rules.rs +3 -1
- package/crates/naome-core/src/architecture/scan/cache.rs +145 -0
- package/crates/naome-core/src/architecture/scan/graph_builder.rs +31 -10
- package/crates/naome-core/src/architecture/scan.rs +232 -14
- package/crates/naome-core/src/architecture.rs +3 -3
- package/crates/naome-core/src/intent/legacy.rs +1 -1
- package/crates/naome-core/src/intent/model.rs +27 -0
- package/crates/naome-core/src/intent/resolver.rs +3 -28
- package/crates/naome-core/src/intent/resolver_baseline.rs +1 -2
- package/crates/naome-core/src/intent/resolver_policy.rs +1 -2
- package/crates/naome-core/src/intent.rs +2 -1
- package/crates/naome-core/src/quality/adapter_ios.rs +3 -1
- package/crates/naome-core/src/quality/adapter_support.rs +32 -0
- package/crates/naome-core/src/quality/adapters.rs +8 -25
- package/crates/naome-core/src/quality/analysis_model.rs +33 -0
- package/crates/naome-core/src/quality/cache.rs +1 -1
- package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +2 -1
- package/crates/naome-core/src/quality/checks/near_duplicates.rs +2 -1
- package/crates/naome-core/src/quality/mod.rs +1 -0
- package/crates/naome-core/src/quality/scanner/analysis.rs +1 -1
- package/crates/naome-core/src/quality/scanner.rs +1 -32
- package/crates/naome-core/src/quality/semantic/extract.rs +2 -1
- package/crates/naome-core/src/quality/structure/adapter_ios.rs +1 -1
- package/crates/naome-core/src/quality/structure/adapter_model.rs +23 -0
- package/crates/naome-core/src/quality/structure/adapters.rs +2 -23
- package/crates/naome-core/src/quality/structure/config.rs +2 -1
- package/crates/naome-core/src/quality/structure/defaults.rs +2 -2
- package/crates/naome-core/src/quality/structure/mod.rs +1 -0
- package/crates/naome-core/src/quality/structure/model.rs +6 -6
- package/crates/naome-core/src/repository_model.rs +6 -1
- package/crates/naome-core/src/route/builtin_checks.rs +1 -1
- package/crates/naome-core/src/route/builtin_require.rs +1 -1
- package/crates/naome-core/src/route/execution.rs +2 -34
- package/crates/naome-core/src/route/execution_baselines.rs +1 -1
- package/crates/naome-core/src/route/execution_model.rs +37 -0
- package/crates/naome-core/src/route/execution_support.rs +1 -1
- package/crates/naome-core/src/route/execution_tasks.rs +1 -1
- package/crates/naome-core/src/route/quality_gate.rs +0 -1
- package/crates/naome-core/src/route.rs +3 -1
- package/crates/naome-core/src/task_state/api.rs +5 -4
- package/crates/naome-core/src/task_state/commit_gate.rs +1 -1
- package/crates/naome-core/src/task_state/compact_proof.rs +2 -2
- package/crates/naome-core/src/task_state/completed_refresh.rs +0 -13
- package/crates/naome-core/src/task_state/completion.rs +13 -4
- package/crates/naome-core/src/task_state/mod.rs +1 -1
- package/crates/naome-core/src/task_state/progress.rs +1 -1
- package/crates/naome-core/src/task_state/proof.rs +1 -4
- package/crates/naome-core/src/task_state/proof_entry.rs +1 -1
- package/crates/naome-core/src/task_state/proof_model.rs +2 -18
- package/crates/naome-core/src/task_state/proof_sources.rs +2 -2
- package/crates/naome-core/src/task_state/proof_types.rs +17 -0
- package/crates/naome-core/src/task_state/shape.rs +1 -1
- package/crates/naome-core/src/task_state/task_diff_api.rs +1 -1
- package/crates/naome-core/src/verification_contract_policy.rs +2 -6
- package/crates/naome-core/src/workflow/agent/proof.rs +1 -1
- package/crates/naome-core/src/workflow/agent.rs +1 -1
- package/crates/naome-core/src/workflow/mod.rs +3 -1
- package/crates/naome-core/src/workflow/phase_inference.rs +1 -1
- package/crates/naome-core/src/workflow/phase_model.rs +22 -0
- package/crates/naome-core/src/workflow/phases.rs +1 -21
- package/crates/naome-core/tests/architecture_cache.rs +212 -0
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/templates/naome-root/.naome/manifest.json +1 -1
- package/templates/naome-root/docs/naome/architecture-fitness.md +29 -8
- package/crates/naome-core/src/task_state/reconcile.rs +0 -7
package/Cargo.lock
CHANGED
|
@@ -76,7 +76,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
|
76
76
|
|
|
77
77
|
[[package]]
|
|
78
78
|
name = "naome-cli"
|
|
79
|
-
version = "1.3.
|
|
79
|
+
version = "1.3.15"
|
|
80
80
|
dependencies = [
|
|
81
81
|
"naome-core",
|
|
82
82
|
"serde_json",
|
|
@@ -84,7 +84,7 @@ dependencies = [
|
|
|
84
84
|
|
|
85
85
|
[[package]]
|
|
86
86
|
name = "naome-core"
|
|
87
|
-
version = "1.3.
|
|
87
|
+
version = "1.3.15"
|
|
88
88
|
dependencies = [
|
|
89
89
|
"serde",
|
|
90
90
|
"serde_json",
|
|
@@ -53,7 +53,7 @@ fn run_arch_explain(root: &Path, args: &[String]) -> Result<(), Box<dyn std::err
|
|
|
53
53
|
"layers": scan.config.layers.keys().collect::<Vec<_>>(),
|
|
54
54
|
"contexts": scan.config.contexts.keys().collect::<Vec<_>>(),
|
|
55
55
|
"rules": ARCHITECTURE_RULE_IDS,
|
|
56
|
-
"extractors": ["path", "typescript", "javascript", "rust", "python", "go"]
|
|
56
|
+
"extractors": ["path", "typescript", "javascript", "rust", "python", "go", "swift"]
|
|
57
57
|
}))?
|
|
58
58
|
);
|
|
59
59
|
} else {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
3
|
use naome_core::{
|
|
4
|
-
check_repository_quality, check_repository_quality_paths, check_semantic_legacy,
|
|
5
|
-
clear_quality_cache, explain_repository_structure,
|
|
6
|
-
plan_quality_cleanup, quality_cache_status,
|
|
7
|
-
QualityInitMode, QualityMode,
|
|
4
|
+
check_repository_quality, check_repository_quality_paths, check_semantic_legacy,
|
|
5
|
+
check_semantic_legacy_paths, clear_quality_cache, explain_repository_structure,
|
|
6
|
+
init_repository_quality_with_mode, plan_quality_cleanup, quality_cache_status,
|
|
7
|
+
route_quality_cleanup, semantic_route_for_finding, QualityInitMode, QualityMode,
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
use crate::cli_args::option_value;
|
|
@@ -5,7 +5,7 @@ use super::ConfigParser;
|
|
|
5
5
|
use crate::architecture::config::{
|
|
6
6
|
ContextConfig, ExternalDependencyPolicy, IgnoreRule, LayerConfig, RuleConfig,
|
|
7
7
|
};
|
|
8
|
-
use crate::architecture::
|
|
8
|
+
use crate::architecture::model::Severity;
|
|
9
9
|
|
|
10
10
|
pub(super) fn parse_layers(parser: &mut ConfigParser<'_>) -> Result<(), NaomeError> {
|
|
11
11
|
while let Some((_, line)) = parser.peek_line() {
|
|
@@ -38,6 +38,25 @@ pub struct SourceRange {
|
|
|
38
38
|
pub end_column: usize,
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
|
42
|
+
#[serde(rename_all = "snake_case")]
|
|
43
|
+
pub enum Severity {
|
|
44
|
+
Error,
|
|
45
|
+
Warning,
|
|
46
|
+
Info,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
impl Severity {
|
|
50
|
+
pub fn parse(value: &str) -> Option<Self> {
|
|
51
|
+
match value {
|
|
52
|
+
"error" => Some(Self::Error),
|
|
53
|
+
"warning" | "warn" => Some(Self::Warning),
|
|
54
|
+
"info" => Some(Self::Info),
|
|
55
|
+
_ => None,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
41
60
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
42
61
|
pub struct ArchitectureMetadata {
|
|
43
62
|
pub path: Option<String>,
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
use serde::{Deserialize, Serialize};
|
|
2
2
|
|
|
3
|
-
use super::model::SourceRange;
|
|
3
|
+
use super::model::{Severity, SourceRange};
|
|
4
4
|
use super::scan::ArchitectureScanReport;
|
|
5
5
|
|
|
6
|
-
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
|
7
|
-
#[serde(rename_all = "snake_case")]
|
|
8
|
-
pub enum Severity {
|
|
9
|
-
Error,
|
|
10
|
-
Warning,
|
|
11
|
-
Info,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
6
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
15
7
|
#[serde(rename_all = "camelCase")]
|
|
16
8
|
pub struct ViolationSummary {
|
|
@@ -54,6 +46,8 @@ pub struct ArchitectureValidation {
|
|
|
54
46
|
pub rules_executed: Vec<String>,
|
|
55
47
|
pub changed_only_requested: bool,
|
|
56
48
|
pub changed_only_degraded_to_full_scan: bool,
|
|
49
|
+
pub changed_only_mode: String,
|
|
50
|
+
pub changed_only_degradation_reason: Option<String>,
|
|
57
51
|
pub violations: Vec<ArchitectureViolation>,
|
|
58
52
|
#[serde(rename = "agent_feedback")]
|
|
59
53
|
pub agent_feedback: Vec<ArchitectureAgentFeedback>,
|
|
@@ -72,17 +66,6 @@ pub const ARCHITECTURE_RULE_IDS: &[&str] = &[
|
|
|
72
66
|
"arch.external_dependency_policy",
|
|
73
67
|
];
|
|
74
68
|
|
|
75
|
-
impl Severity {
|
|
76
|
-
pub fn parse(value: &str) -> Option<Self> {
|
|
77
|
-
match value {
|
|
78
|
-
"error" => Some(Self::Error),
|
|
79
|
-
"warning" | "warn" => Some(Self::Warning),
|
|
80
|
-
"info" => Some(Self::Info),
|
|
81
|
-
_ => None,
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
69
|
pub fn architecture_agent_feedback(
|
|
87
70
|
violations: &[ArchitectureViolation],
|
|
88
71
|
) -> Vec<ArchitectureAgentFeedback> {
|
|
@@ -134,7 +117,15 @@ pub fn format_architecture_validation(report: &ArchitectureValidation) -> String
|
|
|
134
117
|
];
|
|
135
118
|
|
|
136
119
|
if report.changed_only_degraded_to_full_scan {
|
|
137
|
-
|
|
120
|
+
let reason = report
|
|
121
|
+
.changed_only_degradation_reason
|
|
122
|
+
.as_deref()
|
|
123
|
+
.unwrap_or("soundness");
|
|
124
|
+
lines.push(format!(
|
|
125
|
+
"changed-only requested: degraded to full scan for soundness ({reason})"
|
|
126
|
+
));
|
|
127
|
+
} else if report.changed_only_requested {
|
|
128
|
+
lines.push("changed-only requested: using incremental architecture cache".to_string());
|
|
138
129
|
}
|
|
139
130
|
|
|
140
131
|
for violation in report.violations.iter().take(10) {
|
|
@@ -152,12 +143,24 @@ pub fn format_architecture_validation(report: &ArchitectureValidation) -> String
|
|
|
152
143
|
}
|
|
153
144
|
|
|
154
145
|
pub fn format_architecture_scan(report: &ArchitectureScanReport) -> String {
|
|
155
|
-
format!(
|
|
146
|
+
let mut output = format!(
|
|
156
147
|
"NAOME architecture scan\nfiles scanned: {}\ngraph nodes: {}\ngraph edges: {}\n",
|
|
157
148
|
report.files_scanned,
|
|
158
149
|
report.graph.nodes.len(),
|
|
159
150
|
report.graph.edges.len()
|
|
160
|
-
)
|
|
151
|
+
);
|
|
152
|
+
if report.changed_only_degraded_to_full_scan {
|
|
153
|
+
let reason = report
|
|
154
|
+
.changed_only_degradation_reason
|
|
155
|
+
.as_deref()
|
|
156
|
+
.unwrap_or("soundness");
|
|
157
|
+
output.push_str(&format!(
|
|
158
|
+
"changed-only requested: degraded to full scan for soundness ({reason})\n"
|
|
159
|
+
));
|
|
160
|
+
} else if report.changed_only_requested {
|
|
161
|
+
output.push_str("changed-only requested: using incremental architecture cache\n");
|
|
162
|
+
}
|
|
163
|
+
output
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
pub fn format_architecture_explain(scan: &ArchitectureScanReport) -> String {
|
|
@@ -176,7 +179,7 @@ pub fn format_architecture_explain(scan: &ArchitectureScanReport) -> String {
|
|
|
176
179
|
.collect::<Vec<_>>()
|
|
177
180
|
.join(", ");
|
|
178
181
|
format!(
|
|
179
|
-
"NAOME Architecture Fitness\nrules: {}\nlayers: {}\ncontexts: {}\npath extractor: enabled for every repository\nimport extractors: typescript, javascript, rust, python, go\n",
|
|
182
|
+
"NAOME Architecture Fitness\nrules: {}\nlayers: {}\ncontexts: {}\npath extractor: enabled for every repository\nimport extractors: typescript, javascript, rust, python, go, swift\n",
|
|
180
183
|
ARCHITECTURE_RULE_IDS.join(", "),
|
|
181
184
|
empty_label(&layers),
|
|
182
185
|
empty_label(&contexts)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
use crate::architecture::
|
|
1
|
+
use crate::architecture::model::Severity;
|
|
2
|
+
use crate::architecture::output::ArchitectureViolation;
|
|
2
3
|
use crate::architecture::scan::{ArchitectureScanReport, FileFact, ImportTarget};
|
|
3
4
|
|
|
4
5
|
pub(super) fn validate_file_size_budget(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
use crate::paths;
|
|
2
2
|
|
|
3
|
+
use super::model::Severity;
|
|
3
4
|
use super::output::{
|
|
4
5
|
architecture_agent_feedback, summary_for, ArchitectureValidation, ArchitectureViolation,
|
|
5
|
-
Severity,
|
|
6
6
|
};
|
|
7
7
|
use super::scan::ArchitectureScanReport;
|
|
8
8
|
use crate::architecture::model::ArchitectureEdgeKind;
|
|
@@ -55,6 +55,8 @@ pub fn validate_scan(scan: ArchitectureScanReport) -> ArchitectureValidation {
|
|
|
55
55
|
rules_executed,
|
|
56
56
|
changed_only_requested: scan.changed_only_requested,
|
|
57
57
|
changed_only_degraded_to_full_scan: scan.changed_only_degraded_to_full_scan,
|
|
58
|
+
changed_only_mode: scan.changed_only_mode,
|
|
59
|
+
changed_only_degradation_reason: scan.changed_only_degradation_reason,
|
|
58
60
|
violations,
|
|
59
61
|
agent_feedback,
|
|
60
62
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
use std::collections::{BTreeMap, BTreeSet};
|
|
2
|
+
use std::fs;
|
|
3
|
+
use std::path::Path;
|
|
4
|
+
|
|
5
|
+
use serde::{Deserialize, Serialize};
|
|
6
|
+
use sha2::{Digest, Sha256};
|
|
7
|
+
|
|
8
|
+
use super::FileFact;
|
|
9
|
+
use crate::models::NaomeError;
|
|
10
|
+
|
|
11
|
+
const CACHE_SCHEMA: &str = "naome.architecture-cache.v1";
|
|
12
|
+
const EXTRACTOR_VERSION: &str = "architecture-cache-v1.3.14";
|
|
13
|
+
const CACHE_PATH: &str = ".naome/cache/architecture/cache.json";
|
|
14
|
+
|
|
15
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
16
|
+
#[serde(rename_all = "camelCase")]
|
|
17
|
+
pub(super) struct ArchitectureCache {
|
|
18
|
+
pub schema: String,
|
|
19
|
+
pub extractor_version: String,
|
|
20
|
+
pub config_hash: String,
|
|
21
|
+
pub file_list_hash: String,
|
|
22
|
+
pub files: BTreeMap<String, CachedFileFact>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
26
|
+
#[serde(rename_all = "camelCase")]
|
|
27
|
+
pub(super) struct CachedFileFact {
|
|
28
|
+
pub content_hash: String,
|
|
29
|
+
pub fact: FileFact,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
impl ArchitectureCache {
|
|
33
|
+
pub(super) fn is_compatible(&self, config_hash: &str, file_list_hash: &str) -> CacheStatus {
|
|
34
|
+
if self.schema != CACHE_SCHEMA || self.extractor_version != EXTRACTOR_VERSION {
|
|
35
|
+
return CacheStatus::Miss("cache_miss");
|
|
36
|
+
}
|
|
37
|
+
if self.config_hash != config_hash {
|
|
38
|
+
return CacheStatus::Miss("config_changed");
|
|
39
|
+
}
|
|
40
|
+
if self.file_list_hash != file_list_hash {
|
|
41
|
+
return CacheStatus::Miss("file_set_changed");
|
|
42
|
+
}
|
|
43
|
+
CacheStatus::Hit
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
48
|
+
pub(super) enum CacheStatus {
|
|
49
|
+
Hit,
|
|
50
|
+
Miss(&'static str),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pub(super) fn read(root: &Path) -> Option<ArchitectureCache> {
|
|
54
|
+
let content = fs::read_to_string(root.join(CACHE_PATH)).ok()?;
|
|
55
|
+
serde_json::from_str(&content).ok()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
pub(super) fn write(
|
|
59
|
+
root: &Path,
|
|
60
|
+
config_hash: String,
|
|
61
|
+
file_list_hash: String,
|
|
62
|
+
file_facts: &BTreeMap<String, FileFact>,
|
|
63
|
+
) -> Result<(), NaomeError> {
|
|
64
|
+
let cache = ArchitectureCache {
|
|
65
|
+
schema: CACHE_SCHEMA.to_string(),
|
|
66
|
+
extractor_version: EXTRACTOR_VERSION.to_string(),
|
|
67
|
+
config_hash,
|
|
68
|
+
file_list_hash,
|
|
69
|
+
files: file_facts
|
|
70
|
+
.iter()
|
|
71
|
+
.filter_map(|(path, fact)| {
|
|
72
|
+
let content_hash = content_hash(root, path).ok()?;
|
|
73
|
+
Some((
|
|
74
|
+
path.clone(),
|
|
75
|
+
CachedFileFact {
|
|
76
|
+
content_hash,
|
|
77
|
+
fact: fact.clone(),
|
|
78
|
+
},
|
|
79
|
+
))
|
|
80
|
+
})
|
|
81
|
+
.collect(),
|
|
82
|
+
};
|
|
83
|
+
let path = root.join(CACHE_PATH);
|
|
84
|
+
if let Some(parent) = path.parent() {
|
|
85
|
+
fs::create_dir_all(parent)?;
|
|
86
|
+
}
|
|
87
|
+
fs::write(path, serde_json::to_string_pretty(&cache)?)?;
|
|
88
|
+
Ok(())
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pub(super) fn config_hash(
|
|
92
|
+
root: &Path,
|
|
93
|
+
explicit_path: Option<&Path>,
|
|
94
|
+
default_content: &str,
|
|
95
|
+
) -> Result<String, NaomeError> {
|
|
96
|
+
let path = explicit_path
|
|
97
|
+
.map(Path::to_path_buf)
|
|
98
|
+
.unwrap_or_else(|| root.join("naome.arch.yaml"));
|
|
99
|
+
let source = if path.exists() {
|
|
100
|
+
fs::read_to_string(&path)?
|
|
101
|
+
} else {
|
|
102
|
+
default_content.to_string()
|
|
103
|
+
};
|
|
104
|
+
let label = display_path(root, &path);
|
|
105
|
+
Ok(stable_hash([
|
|
106
|
+
b"architecture-config-v1".as_slice(),
|
|
107
|
+
label.as_bytes(),
|
|
108
|
+
source.as_bytes(),
|
|
109
|
+
]))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pub(super) fn file_list_hash(files: &[String]) -> String {
|
|
113
|
+
let mut hasher = Sha256::new();
|
|
114
|
+
hasher.update(b"architecture-file-list-v1");
|
|
115
|
+
for path in files {
|
|
116
|
+
hasher.update([0]);
|
|
117
|
+
hasher.update(path.as_bytes());
|
|
118
|
+
}
|
|
119
|
+
format!("sha256:{:x}", hasher.finalize())
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
pub(super) fn content_hash(root: &Path, path: &str) -> Result<String, NaomeError> {
|
|
123
|
+
let bytes = fs::read(root.join(path))?;
|
|
124
|
+
Ok(stable_hash([b"architecture-file-v1".as_slice(), &bytes]))
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
pub(super) fn changed_set(changed_paths: &[String]) -> BTreeSet<String> {
|
|
128
|
+
changed_paths.iter().cloned().collect()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fn stable_hash<'a>(parts: impl IntoIterator<Item = &'a [u8]>) -> String {
|
|
132
|
+
let mut hasher = Sha256::new();
|
|
133
|
+
for part in parts {
|
|
134
|
+
hasher.update(part);
|
|
135
|
+
hasher.update([0]);
|
|
136
|
+
}
|
|
137
|
+
format!("sha256:{:x}", hasher.finalize())
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fn display_path(root: &Path, path: &Path) -> String {
|
|
141
|
+
path.strip_prefix(root)
|
|
142
|
+
.unwrap_or(path)
|
|
143
|
+
.to_string_lossy()
|
|
144
|
+
.replace('\\', "/")
|
|
145
|
+
}
|
|
@@ -18,25 +18,46 @@ pub(super) fn build_path_graph(
|
|
|
18
18
|
config: &ArchitectureConfig,
|
|
19
19
|
manifests: &[ManifestFact],
|
|
20
20
|
) -> (ArchitectureGraph, BTreeMap<String, FileFact>) {
|
|
21
|
-
let mut graph = ArchitectureGraph::default();
|
|
22
21
|
let mut file_facts = BTreeMap::new();
|
|
23
|
-
let mut emitted_external_nodes = BTreeSet::new();
|
|
24
22
|
let file_set = files.iter().cloned().collect::<BTreeSet<_>>();
|
|
23
|
+
for path in &files {
|
|
24
|
+
file_facts.insert(path.clone(), scan_file_fact(root, path, config, &file_set));
|
|
25
|
+
}
|
|
26
|
+
let graph = build_graph_from_facts(&files, &file_facts, config, manifests);
|
|
27
|
+
(graph, file_facts)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub(super) fn scan_file_fact(
|
|
31
|
+
root: &Path,
|
|
32
|
+
path: &str,
|
|
33
|
+
config: &ArchitectureConfig,
|
|
34
|
+
file_set: &BTreeSet<String>,
|
|
35
|
+
) -> FileFact {
|
|
36
|
+
let content = fs::read_to_string(root.join(path)).unwrap_or_default();
|
|
37
|
+
let mut fact = facts::file_fact(path, &content, config);
|
|
38
|
+
fact.imports = imports::extract_imports(root, path, &content, file_set);
|
|
39
|
+
fact
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pub(super) fn build_graph_from_facts(
|
|
43
|
+
files: &[String],
|
|
44
|
+
file_facts: &BTreeMap<String, FileFact>,
|
|
45
|
+
config: &ArchitectureConfig,
|
|
46
|
+
manifests: &[ManifestFact],
|
|
47
|
+
) -> ArchitectureGraph {
|
|
48
|
+
let mut graph = ArchitectureGraph::default();
|
|
49
|
+
let mut emitted_external_nodes = BTreeSet::new();
|
|
25
50
|
|
|
26
51
|
push_repository_and_policy_nodes(&mut graph, config);
|
|
27
|
-
push_directories(&mut graph,
|
|
52
|
+
push_directories(&mut graph, files);
|
|
28
53
|
push_manifests(&mut graph, manifests, &mut emitted_external_nodes);
|
|
29
54
|
|
|
30
|
-
for
|
|
31
|
-
let content = fs::read_to_string(root.join(&path)).unwrap_or_default();
|
|
32
|
-
let mut fact = facts::file_fact(&path, &content, config);
|
|
33
|
-
fact.imports = imports::extract_imports(root, &path, &content, &file_set);
|
|
55
|
+
for fact in file_facts.values() {
|
|
34
56
|
push_file(&mut graph, &fact);
|
|
35
|
-
file_facts.insert(path, fact);
|
|
36
57
|
}
|
|
37
58
|
|
|
38
|
-
push_imports(&mut graph,
|
|
39
|
-
|
|
59
|
+
push_imports(&mut graph, file_facts, &mut emitted_external_nodes);
|
|
60
|
+
graph
|
|
40
61
|
}
|
|
41
62
|
|
|
42
63
|
fn push_repository_and_policy_nodes(graph: &mut ArchitectureGraph, config: &ArchitectureConfig) {
|