mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-06 04:21:33 +00:00
feat(scripts): add check_layer_contract.jl
scripts/check_layer_contract.jl | 127 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+)
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env julia
|
||||
#
|
||||
# Static audit for docs/src/developer/architecture_layers.md (layers A–C).
|
||||
# Run from anywhere:
|
||||
# julia scripts/check_layer_contract.jl [REPO_ROOT]
|
||||
#
|
||||
# Uses only Base — no --project required.
|
||||
|
||||
const REPO_ROOT = isempty(ARGS) ? dirname(dirname(@__FILE__)) : abspath(ARGS[1])
|
||||
|
||||
const INCLUDE_IO_REGEX = r"include\s*\(\s*\"[^\"]*\bio/"
|
||||
|
||||
function jl_files(dir::AbstractString)
|
||||
list = String[]
|
||||
isdir(dir) || return list
|
||||
for (root, _, files) in walkdir(dir)
|
||||
for f in files
|
||||
endswith(f, ".jl") || continue
|
||||
push!(list, joinpath(root, f))
|
||||
end
|
||||
end
|
||||
sort!(list)
|
||||
end
|
||||
|
||||
function code_fragment(line::AbstractString)::SubString{String}
|
||||
# Ignore trailing `# …` so notes do not false-positive the auditors.
|
||||
parts = split(line, '#'; limit = 2)
|
||||
return rstrip(parts[1])
|
||||
end
|
||||
|
||||
function skip_line(line::AbstractString)::Bool
|
||||
s = strip(line)
|
||||
isempty(s) && return true
|
||||
startswith(s, '#') && return true
|
||||
return false
|
||||
end
|
||||
|
||||
const DOMAIN_FORBIDDEN_SUBSTRINGS = [
|
||||
"GmshReader",
|
||||
"read_gmsh_mesh",
|
||||
"GmshMesh",
|
||||
"JuliaFEM.Legacy",
|
||||
"KernelAbstractions",
|
||||
"CUDABackend",
|
||||
"MetalBackend",
|
||||
"AMDGPUBackend",
|
||||
"oneAPIBackend",
|
||||
]
|
||||
|
||||
const FOUNDATION_EXTRA_SUBSTRINGS = [
|
||||
"DOFHandler",
|
||||
"create_structured_box_mesh",
|
||||
]
|
||||
|
||||
function violations_for_line(line::AbstractString, extra_substrings)::Vector{String}
|
||||
hits = String[]
|
||||
if occursin(INCLUDE_IO_REGEX, line)
|
||||
push!(hits, "include(\"…io/…\")")
|
||||
end
|
||||
for tok in DOMAIN_FORBIDDEN_SUBSTRINGS
|
||||
if occursin(tok, line)
|
||||
push!(hits, tok)
|
||||
end
|
||||
end
|
||||
for tok in extra_substrings
|
||||
if occursin(tok, line)
|
||||
push!(hits, tok)
|
||||
end
|
||||
end
|
||||
return hits
|
||||
end
|
||||
|
||||
function audit_tree(label::AbstractString, dir::AbstractString, extra_substrings)::Bool
|
||||
ok = true
|
||||
rel = relpath(dir, REPO_ROOT)
|
||||
for path in jl_files(dir)
|
||||
lineno = 0
|
||||
for line in eachline(path)
|
||||
lineno += 1
|
||||
skip_line(line) && continue
|
||||
frag = code_fragment(line)
|
||||
isempty(strip(frag)) && continue
|
||||
hits = violations_for_line(frag, extra_substrings)
|
||||
isempty(hits) && continue
|
||||
ok = false
|
||||
relfile = relpath(path, REPO_ROOT)
|
||||
println(stderr, "$relfile:$lineno: [layer contract] $(join(sort!(unique(hits)), ", "))")
|
||||
end
|
||||
end
|
||||
ok || println(stderr, "($label) violations under $rel")
|
||||
return ok
|
||||
end
|
||||
|
||||
function main()::Int
|
||||
src = joinpath(REPO_ROOT, "src")
|
||||
isdir(src) || error("expected src/ under $REPO_ROOT")
|
||||
|
||||
println("Layer contract audit (see docs/src/developer/architecture_layers.md)")
|
||||
println("Repository: ", REPO_ROOT)
|
||||
|
||||
all_ok = true
|
||||
|
||||
domains = joinpath(src, "domains")
|
||||
all_ok &= audit_tree("Layer C (domains)", domains, String[])
|
||||
|
||||
foundation_dirs = [
|
||||
joinpath(src, "topology"),
|
||||
joinpath(src, "quadrature"),
|
||||
joinpath(src, "geometry"),
|
||||
joinpath(src, "basis"),
|
||||
joinpath(src, "sparse"),
|
||||
]
|
||||
for d in foundation_dirs
|
||||
all_ok &= audit_tree("Layer A (foundation)", d, FOUNDATION_EXTRA_SUBSTRINGS)
|
||||
end
|
||||
|
||||
if all_ok
|
||||
println("OK — no forbidden coupling patterns found.")
|
||||
return 0
|
||||
else
|
||||
println(stderr, "")
|
||||
println(stderr, "FAILED — fix imports/includes or move code to an outer layer.")
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
exit(main())
|
||||
Reference in New Issue
Block a user