@lamentis/naome 1.3.12 → 1.3.13
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-core/Cargo.toml +1 -1
- package/crates/naome-core/src/architecture/rules/external.rs +59 -0
- package/crates/naome-core/src/architecture/scan/graph_builder.rs +130 -30
- package/crates/naome-core/src/architecture/scan/imports/extractors/swift.rs +48 -0
- package/crates/naome-core/src/architecture/scan/imports/extractors.rs +3 -0
- package/crates/naome-core/src/architecture/scan/imports/resolver.rs +41 -1
- package/crates/naome-core/src/architecture/scan/imports.rs +1 -0
- package/crates/naome-core/src/architecture/scan/manifest/common.rs +102 -0
- package/crates/naome-core/src/architecture/scan/manifest/parsers/json.rs +46 -0
- package/crates/naome-core/src/architecture/scan/manifest/parsers/other.rs +280 -0
- package/crates/naome-core/src/architecture/scan/manifest/parsers/toml.rs +184 -0
- package/crates/naome-core/src/architecture/scan/manifest/parsers.rs +3 -0
- package/crates/naome-core/src/architecture/scan/manifest.rs +33 -0
- package/crates/naome-core/src/architecture/scan.rs +27 -1
- package/crates/naome-core/tests/architecture_manifests.rs +289 -0
- package/crates/naome-core/tests/architecture_support/mod.rs +2 -0
- package/crates/naome-core/tests/architecture_swift.rs +111 -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 +2 -2
- package/templates/naome-root/docs/naome/architecture-fitness.md +17 -7
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
use naome_core::{scan_architecture, ArchitectureEdgeKind, ArchitectureScanOptions};
|
|
2
|
+
|
|
3
|
+
mod architecture_support;
|
|
4
|
+
|
|
5
|
+
use architecture_support::FixtureRepo;
|
|
6
|
+
|
|
7
|
+
#[test]
|
|
8
|
+
fn manifest_extractors_add_package_dependency_graph_nodes() {
|
|
9
|
+
let repo = FixtureRepo::new();
|
|
10
|
+
repo.write(
|
|
11
|
+
"package.json",
|
|
12
|
+
r#"{
|
|
13
|
+
"name": "@acme/web",
|
|
14
|
+
"dependencies": { "react": "^18.0.0" },
|
|
15
|
+
"devDependencies": { "vite": "^5.0.0" }
|
|
16
|
+
}
|
|
17
|
+
"#,
|
|
18
|
+
);
|
|
19
|
+
repo.write(
|
|
20
|
+
"crates/app/Cargo.toml",
|
|
21
|
+
"[package]\nname = \"app\"\nversion = \"0.1.0\"\n[dependencies]\nserde = \"1\"\n",
|
|
22
|
+
);
|
|
23
|
+
repo.write(
|
|
24
|
+
"pyproject.toml",
|
|
25
|
+
"[project]\nname = \"acme-python\"\ndependencies = [\"requests>=2\", \"fastapi\"]\n",
|
|
26
|
+
);
|
|
27
|
+
repo.write(
|
|
28
|
+
"go.mod",
|
|
29
|
+
"module github.com/acme/app\nrequire github.com/gin-gonic/gin v1.9.0\n",
|
|
30
|
+
);
|
|
31
|
+
repo.write(
|
|
32
|
+
"pom.xml",
|
|
33
|
+
"<project><groupId>com.acme</groupId><artifactId>service</artifactId><dependencies><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></dependency></dependencies></project>",
|
|
34
|
+
);
|
|
35
|
+
repo.write(
|
|
36
|
+
"build.gradle",
|
|
37
|
+
"plugins { id 'java' }\ndependencies { implementation 'com.google.guava:guava:33.0.0-jre' }\n",
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
41
|
+
|
|
42
|
+
for node_id in [
|
|
43
|
+
"package:npm:package.json",
|
|
44
|
+
"package:cargo:crates/app/Cargo.toml",
|
|
45
|
+
"package:python:pyproject.toml",
|
|
46
|
+
"package:go:go.mod",
|
|
47
|
+
"package:maven:pom.xml",
|
|
48
|
+
"package:gradle:build.gradle",
|
|
49
|
+
"external:react",
|
|
50
|
+
"external:vite",
|
|
51
|
+
"external:serde",
|
|
52
|
+
"external:requests",
|
|
53
|
+
"external:fastapi",
|
|
54
|
+
"external:github.com/gin-gonic/gin",
|
|
55
|
+
"external:org.slf4j:slf4j-api",
|
|
56
|
+
"external:com.google.guava:guava",
|
|
57
|
+
] {
|
|
58
|
+
assert!(
|
|
59
|
+
scan.graph.nodes.iter().any(|node| node.id == node_id),
|
|
60
|
+
"missing {node_id}"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
assert!(scan.graph.edges.iter().any(|edge| {
|
|
64
|
+
edge.kind == ArchitectureEdgeKind::DependsOn
|
|
65
|
+
&& edge.from == "package:npm:package.json"
|
|
66
|
+
&& edge.to == "external:react"
|
|
67
|
+
&& edge.metadata.extractor == "manifest:package.json"
|
|
68
|
+
}));
|
|
69
|
+
assert!(scan.graph.edges.iter().any(|edge| {
|
|
70
|
+
edge.kind == ArchitectureEdgeKind::DependsOn
|
|
71
|
+
&& edge.from == "package:go:go.mod"
|
|
72
|
+
&& edge.to == "external:github.com/gin-gonic/gin"
|
|
73
|
+
}));
|
|
74
|
+
assert!(scan
|
|
75
|
+
.graph
|
|
76
|
+
.nodes
|
|
77
|
+
.iter()
|
|
78
|
+
.any(|node| { node.id == "package:npm:package.json" && node.label == "@acme/web" }));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#[test]
|
|
82
|
+
fn manifest_package_ids_are_namespaced_and_parse_common_multiline_forms() {
|
|
83
|
+
let repo = FixtureRepo::new();
|
|
84
|
+
repo.write(
|
|
85
|
+
"package.json",
|
|
86
|
+
r#"{
|
|
87
|
+
"name": "core",
|
|
88
|
+
"dependencies": { "react": "^18.0.0" }
|
|
89
|
+
}
|
|
90
|
+
"#,
|
|
91
|
+
);
|
|
92
|
+
repo.write(
|
|
93
|
+
"crates/core/Cargo.toml",
|
|
94
|
+
"[package]\nname = \"core\"\nversion = \"0.1.0\"\n[dependencies.serde]\nversion = \"1\"\n",
|
|
95
|
+
);
|
|
96
|
+
repo.write(
|
|
97
|
+
"pyproject.toml",
|
|
98
|
+
"[project]\nname = \"core\"\ndependencies = [\n \"requests>=2\",\n \"fastapi\",\n]\n",
|
|
99
|
+
);
|
|
100
|
+
repo.write(
|
|
101
|
+
"build.gradle.kts",
|
|
102
|
+
"dependencies {\n // implementation(\"com.acme:old-lib:1.0\")\n implementation(\"com.google.guava:guava:33.0.0-jre\")\n implementation group: 'com.squareup.okio', name: 'okio', version: '3.9.0'\n}\n",
|
|
103
|
+
);
|
|
104
|
+
repo.write(
|
|
105
|
+
"child/pom.xml",
|
|
106
|
+
r#"<project>
|
|
107
|
+
<parent>
|
|
108
|
+
<groupId>com.acme.parent</groupId>
|
|
109
|
+
<artifactId>parent</artifactId>
|
|
110
|
+
</parent>
|
|
111
|
+
<groupId>com.acme.child</groupId>
|
|
112
|
+
<artifactId>service</artifactId>
|
|
113
|
+
<dependencyManagement>
|
|
114
|
+
<dependencies>
|
|
115
|
+
<dependency>
|
|
116
|
+
<groupId>com.acme</groupId>
|
|
117
|
+
<artifactId>managed-only</artifactId>
|
|
118
|
+
</dependency>
|
|
119
|
+
</dependencies>
|
|
120
|
+
</dependencyManagement>
|
|
121
|
+
<dependencies>
|
|
122
|
+
<dependency>
|
|
123
|
+
<groupId>org.slf4j</groupId>
|
|
124
|
+
<artifactId>slf4j-api</artifactId>
|
|
125
|
+
</dependency>
|
|
126
|
+
</dependencies>
|
|
127
|
+
<build>
|
|
128
|
+
<plugins>
|
|
129
|
+
<plugin>
|
|
130
|
+
<dependencies>
|
|
131
|
+
<dependency>
|
|
132
|
+
<groupId>com.acme</groupId>
|
|
133
|
+
<artifactId>plugin-only</artifactId>
|
|
134
|
+
</dependency>
|
|
135
|
+
</dependencies>
|
|
136
|
+
</plugin>
|
|
137
|
+
</plugins>
|
|
138
|
+
</build>
|
|
139
|
+
</project>"#,
|
|
140
|
+
);
|
|
141
|
+
let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
142
|
+
|
|
143
|
+
for (node_id, label) in [
|
|
144
|
+
("package:npm:package.json", "core"),
|
|
145
|
+
("package:cargo:crates/core/Cargo.toml", "core"),
|
|
146
|
+
("package:python:pyproject.toml", "core"),
|
|
147
|
+
("package:gradle:build.gradle.kts", "gradle:build.gradle.kts"),
|
|
148
|
+
("package:maven:child/pom.xml", "com.acme.child:service"),
|
|
149
|
+
] {
|
|
150
|
+
assert!(
|
|
151
|
+
scan.graph
|
|
152
|
+
.nodes
|
|
153
|
+
.iter()
|
|
154
|
+
.any(|node| node.id == node_id && node.label == label),
|
|
155
|
+
"missing {node_id} with label {label}"
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
for (package_id, dependency_id) in [
|
|
159
|
+
("package:npm:package.json", "external:react"),
|
|
160
|
+
("package:cargo:crates/core/Cargo.toml", "external:serde"),
|
|
161
|
+
("package:python:pyproject.toml", "external:requests"),
|
|
162
|
+
("package:python:pyproject.toml", "external:fastapi"),
|
|
163
|
+
(
|
|
164
|
+
"package:gradle:build.gradle.kts",
|
|
165
|
+
"external:com.google.guava:guava",
|
|
166
|
+
),
|
|
167
|
+
(
|
|
168
|
+
"package:gradle:build.gradle.kts",
|
|
169
|
+
"external:com.squareup.okio:okio",
|
|
170
|
+
),
|
|
171
|
+
(
|
|
172
|
+
"package:maven:child/pom.xml",
|
|
173
|
+
"external:org.slf4j:slf4j-api",
|
|
174
|
+
),
|
|
175
|
+
] {
|
|
176
|
+
assert!(
|
|
177
|
+
scan.graph.edges.iter().any(|edge| {
|
|
178
|
+
edge.kind == ArchitectureEdgeKind::DependsOn
|
|
179
|
+
&& edge.from == package_id
|
|
180
|
+
&& edge.to == dependency_id
|
|
181
|
+
}),
|
|
182
|
+
"missing edge {package_id} -> {dependency_id}"
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
assert!(!scan
|
|
186
|
+
.graph
|
|
187
|
+
.nodes
|
|
188
|
+
.iter()
|
|
189
|
+
.any(|node| node.id == "external:com.acme:old-lib"));
|
|
190
|
+
assert!(!scan
|
|
191
|
+
.graph
|
|
192
|
+
.nodes
|
|
193
|
+
.iter()
|
|
194
|
+
.any(|node| node.id == "external:com.acme:managed-only"));
|
|
195
|
+
assert!(!scan
|
|
196
|
+
.graph
|
|
197
|
+
.nodes
|
|
198
|
+
.iter()
|
|
199
|
+
.any(|node| node.id == "external:com.acme:plugin-only"));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
#[test]
|
|
203
|
+
fn swift_manifests_emit_package_and_dependency_nodes() {
|
|
204
|
+
let repo = FixtureRepo::new();
|
|
205
|
+
repo.write(
|
|
206
|
+
"Package.swift",
|
|
207
|
+
r#"// swift-tools-version: 5.9
|
|
208
|
+
import PackageDescription
|
|
209
|
+
|
|
210
|
+
let package = Package(
|
|
211
|
+
name: "Tickets",
|
|
212
|
+
dependencies: [
|
|
213
|
+
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0"),
|
|
214
|
+
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", exact: "1.8.0")
|
|
215
|
+
]
|
|
216
|
+
)
|
|
217
|
+
"#,
|
|
218
|
+
);
|
|
219
|
+
repo.write(
|
|
220
|
+
"Tickets.xcodeproj/project.pbxproj",
|
|
221
|
+
r#"
|
|
222
|
+
/* Begin XCRemoteSwiftPackageReference section */
|
|
223
|
+
repositoryURL = "https://github.com/onevcat/Kingfisher.git";
|
|
224
|
+
/* End XCRemoteSwiftPackageReference section */
|
|
225
|
+
"#,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
229
|
+
|
|
230
|
+
for node_id in [
|
|
231
|
+
"package:swift:Package.swift",
|
|
232
|
+
"package:xcode:Tickets.xcodeproj/project.pbxproj",
|
|
233
|
+
"external:Alamofire",
|
|
234
|
+
"external:swift-composable-architecture",
|
|
235
|
+
"external:Kingfisher",
|
|
236
|
+
] {
|
|
237
|
+
assert!(
|
|
238
|
+
scan.graph.nodes.iter().any(|node| node.id == node_id),
|
|
239
|
+
"missing {node_id}"
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
assert!(scan.graph.edges.iter().any(|edge| {
|
|
243
|
+
edge.kind == ArchitectureEdgeKind::DependsOn
|
|
244
|
+
&& edge.from == "package:swift:Package.swift"
|
|
245
|
+
&& edge.to == "external:Alamofire"
|
|
246
|
+
}));
|
|
247
|
+
assert!(scan.graph.edges.iter().any(|edge| {
|
|
248
|
+
edge.kind == ArchitectureEdgeKind::DependsOn
|
|
249
|
+
&& edge.from == "package:xcode:Tickets.xcodeproj/project.pbxproj"
|
|
250
|
+
&& edge.to == "external:Kingfisher"
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
#[test]
|
|
255
|
+
fn swift_manifests_ignore_commented_package_declarations() {
|
|
256
|
+
let repo = FixtureRepo::new();
|
|
257
|
+
repo.write(
|
|
258
|
+
"Package.swift",
|
|
259
|
+
r#"// swift-tools-version: 5.9
|
|
260
|
+
import PackageDescription
|
|
261
|
+
|
|
262
|
+
let package = Package(
|
|
263
|
+
name: "CoreSwift",
|
|
264
|
+
dependencies: [
|
|
265
|
+
// .package(url: "https://github.com/Old/Old.git", from: "1.0.0"),
|
|
266
|
+
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0")
|
|
267
|
+
]
|
|
268
|
+
)
|
|
269
|
+
"#,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
273
|
+
|
|
274
|
+
assert!(scan
|
|
275
|
+
.graph
|
|
276
|
+
.nodes
|
|
277
|
+
.iter()
|
|
278
|
+
.any(|node| node.id == "package:swift:Package.swift" && node.label == "CoreSwift"));
|
|
279
|
+
assert!(scan.graph.edges.iter().any(|edge| {
|
|
280
|
+
edge.kind == ArchitectureEdgeKind::DependsOn
|
|
281
|
+
&& edge.from == "package:swift:Package.swift"
|
|
282
|
+
&& edge.to == "external:Alamofire"
|
|
283
|
+
}));
|
|
284
|
+
assert!(!scan
|
|
285
|
+
.graph
|
|
286
|
+
.nodes
|
|
287
|
+
.iter()
|
|
288
|
+
.any(|node| node.id == "external:Old"));
|
|
289
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
use naome_core::{scan_architecture, validate_architecture, ArchitectureScanOptions};
|
|
2
|
+
|
|
3
|
+
mod architecture_support;
|
|
4
|
+
|
|
5
|
+
use architecture_support::FixtureRepo;
|
|
6
|
+
|
|
7
|
+
#[test]
|
|
8
|
+
fn swift_imports_emit_external_dependency_edges_for_ios_apps() {
|
|
9
|
+
let repo = FixtureRepo::new();
|
|
10
|
+
repo.write(
|
|
11
|
+
"Sources/Tickets/AppView.swift",
|
|
12
|
+
"import SwiftUI\nimport UIKit\n@testable import TicketsCore\n@preconcurrency import Alamofire\n@_implementationOnly import Firebase\n",
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
16
|
+
let fact = scan
|
|
17
|
+
.file_facts
|
|
18
|
+
.get("Sources/Tickets/AppView.swift")
|
|
19
|
+
.unwrap();
|
|
20
|
+
|
|
21
|
+
assert_eq!(fact.language.as_deref(), Some("swift"));
|
|
22
|
+
for package in ["SwiftUI", "UIKit", "TicketsCore", "Alamofire", "Firebase"] {
|
|
23
|
+
assert!(
|
|
24
|
+
scan.graph
|
|
25
|
+
.nodes
|
|
26
|
+
.iter()
|
|
27
|
+
.any(|node| { node.id == format!("external:{package}") && node.label == package }),
|
|
28
|
+
"missing external node for {package}"
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[test]
|
|
34
|
+
fn swift_apple_frameworks_do_not_violate_external_dependency_policy() {
|
|
35
|
+
let repo = FixtureRepo::new();
|
|
36
|
+
repo.write(
|
|
37
|
+
"naome.arch.yaml",
|
|
38
|
+
r#"
|
|
39
|
+
layers:
|
|
40
|
+
domain:
|
|
41
|
+
paths:
|
|
42
|
+
- "Sources/Domain/**"
|
|
43
|
+
rules:
|
|
44
|
+
external_dependency_policy:
|
|
45
|
+
enabled: true
|
|
46
|
+
severity: error
|
|
47
|
+
external_dependencies:
|
|
48
|
+
domain:
|
|
49
|
+
allow: []
|
|
50
|
+
"#,
|
|
51
|
+
);
|
|
52
|
+
repo.write(
|
|
53
|
+
"Sources/Domain/EventView.swift",
|
|
54
|
+
"import Foundation\nimport SwiftUI\nimport UIKit\nimport CoreBluetooth\nimport CoreImage\nimport CoreML\nimport Network\nimport Vision\nimport Alamofire\n",
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
let report = validate_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
58
|
+
|
|
59
|
+
assert_eq!(report.summary.errors, 1);
|
|
60
|
+
assert_eq!(
|
|
61
|
+
report.violations[0].to.as_deref(),
|
|
62
|
+
Some("external:Alamofire")
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#[test]
|
|
67
|
+
fn swiftpm_target_imports_resolve_to_local_target_files() {
|
|
68
|
+
let repo = FixtureRepo::new();
|
|
69
|
+
repo.write(
|
|
70
|
+
"naome.arch.yaml",
|
|
71
|
+
r#"
|
|
72
|
+
layers:
|
|
73
|
+
ui:
|
|
74
|
+
paths:
|
|
75
|
+
- "Sources/App/**"
|
|
76
|
+
- "Tests/**"
|
|
77
|
+
rules:
|
|
78
|
+
external_dependency_policy:
|
|
79
|
+
enabled: true
|
|
80
|
+
severity: error
|
|
81
|
+
external_dependencies:
|
|
82
|
+
ui:
|
|
83
|
+
allow: []
|
|
84
|
+
"#,
|
|
85
|
+
);
|
|
86
|
+
repo.write(
|
|
87
|
+
"Sources/App/AppView.swift",
|
|
88
|
+
"import SwiftUI\nimport Core\nimport Alamofire\n",
|
|
89
|
+
);
|
|
90
|
+
repo.write("Sources/Core/Model.swift", "public struct Model {}\n");
|
|
91
|
+
repo.write(
|
|
92
|
+
"Tests/CoreTests/CoreTests.swift",
|
|
93
|
+
"import XCTest\n@testable import Core\n",
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
let report = validate_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
97
|
+
let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
98
|
+
|
|
99
|
+
assert!(scan.graph.edges.iter().any(|edge| {
|
|
100
|
+
edge.from == "file:Sources/App/AppView.swift" && edge.to == "file:Sources/Core/Model.swift"
|
|
101
|
+
}));
|
|
102
|
+
assert!(scan.graph.edges.iter().any(|edge| {
|
|
103
|
+
edge.from == "file:Tests/CoreTests/CoreTests.swift"
|
|
104
|
+
&& edge.to == "file:Sources/Core/Model.swift"
|
|
105
|
+
}));
|
|
106
|
+
assert_eq!(report.summary.errors, 1);
|
|
107
|
+
assert_eq!(
|
|
108
|
+
report.violations[0].to.as_deref(),
|
|
109
|
+
Some("external:Alamofire")
|
|
110
|
+
);
|
|
111
|
+
}
|
|
Binary file
|
package/native/linux-x64/naome
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"harnessVersion": "1.3.
|
|
2
|
+
"harnessVersion": "1.3.13",
|
|
3
3
|
"installedAt": null,
|
|
4
4
|
"integrity": {
|
|
5
5
|
".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
10
10
|
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
11
11
|
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
12
|
-
"docs/naome/architecture-fitness.md": "sha256:
|
|
12
|
+
"docs/naome/architecture-fitness.md": "sha256:26f04884c3ada083380bee5c3cb1aa3f39d8c8a1cc31ccc84c4ae795c594de5b",
|
|
13
13
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
14
14
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
15
15
|
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
@@ -137,16 +137,26 @@ fails only on configured error rules.
|
|
|
137
137
|
|
|
138
138
|
## Language Support
|
|
139
139
|
|
|
140
|
-
The v1.3.
|
|
140
|
+
The v1.3.13 foundation classifies TypeScript, JavaScript, Rust, Python, Go,
|
|
141
141
|
Java, Kotlin, and Swift files by path extension. It extracts import facts for
|
|
142
|
-
TypeScript, JavaScript, Rust, Python, and
|
|
143
|
-
simple repository-absolute aliases
|
|
144
|
-
explicitly as graph nodes instead of dropping
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
TypeScript, JavaScript, Rust, Python, Go, and Swift, resolves relative imports
|
|
143
|
+
and simple repository-absolute aliases where the language supports them, and
|
|
144
|
+
represents unresolved imports explicitly as graph nodes instead of dropping
|
|
145
|
+
them. Swift and iOS app repositories get Apple framework imports, SwiftPM
|
|
146
|
+
manifests, and Xcode Swift package references represented in the normalized
|
|
147
|
+
graph; Apple SDK frameworks are treated as platform APIs for external policy.
|
|
148
|
+
It also extracts package and dependency facts from `package.json`,
|
|
149
|
+
`Cargo.toml`, `pyproject.toml`, `go.mod`, lightweight `pom.xml` / Gradle
|
|
150
|
+
manifests, `Package.swift`, and `.xcodeproj/project.pbxproj`, then emits
|
|
151
|
+
manifest-identity package nodes and manifest-owned `DependsOn` edges to
|
|
152
|
+
external dependencies.
|
|
153
|
+
Architecture rules now cover layers, bounded contexts, public APIs, cycles,
|
|
154
|
+
transitive layer reach, import/fan-out budgets, and external dependency
|
|
155
|
+
policies.
|
|
147
156
|
|
|
148
157
|
## Limitations
|
|
149
158
|
|
|
150
159
|
This release intentionally keeps validation file-graph based. Manifest
|
|
151
|
-
extractors
|
|
160
|
+
extractors are dependency-owner oriented and do not yet parse every build-tool
|
|
161
|
+
feature. SARIF output, persistent scan caching, and deeper symbol-level call
|
|
152
162
|
analysis remain planned follow-up slices before v1.4.0.
|