@pipemd-core/pipemd 1.0.0
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/AI_SETUP_PIPEMD.md +184 -0
- package/CHANGELOG.md +47 -0
- package/LICENSE +15 -0
- package/README.md +535 -0
- package/dist/index.js +6647 -0
- package/dist/plugins/opencode-server.js +235 -0
- package/dist/plugins/opencode-tui.js +914 -0
- package/dist/templates/agent-decision-tree.md +113 -0
- package/dist/templates/static-rules.md +7 -0
- package/package.json +68 -0
- package/scripts/C-CPP/architecture/arch.sh +229 -0
- package/scripts/C-CPP/lib/limit.sh +146 -0
- package/scripts/C-CPP/project/class-diagram.sh +96 -0
- package/scripts/C-CPP/project/cmake-targets.sh +68 -0
- package/scripts/C-CPP/project/deps.sh +44 -0
- package/scripts/C-CPP/project/find-todos.sh +6 -0
- package/scripts/C-CPP/project/include-graph.sh +110 -0
- package/scripts/C-CPP/project/interfaces.sh +108 -0
- package/scripts/C-CPP/project/tree.sh +5 -0
- package/scripts/C-CPP/quality/lint.sh +14 -0
- package/scripts/C-CPP/quality/test-summary.sh +22 -0
- package/scripts/C-CPP/quality/type-check.sh +26 -0
- package/scripts/DevOps/architecture/arch.sh +186 -0
- package/scripts/DevOps/devops/aws-context.sh +34 -0
- package/scripts/DevOps/devops/docker-stats.sh +42 -0
- package/scripts/DevOps/devops/k8s-unhealthy.sh +41 -0
- package/scripts/DevOps/devops/tf-state.sh +65 -0
- package/scripts/DevOps/lib/limit.sh +143 -0
- package/scripts/Generic/architecture/arch.sh +570 -0
- package/scripts/Generic/lib/limit.sh +140 -0
- package/scripts/Go/architecture/arch.sh +79 -0
- package/scripts/Go/lib/limit.sh +142 -0
- package/scripts/Go/project/deps.sh +35 -0
- package/scripts/Go/project/find-todos.sh +6 -0
- package/scripts/Go/project/go-interfaces.sh +18 -0
- package/scripts/Go/project/go-packages.sh +28 -0
- package/scripts/Go/project/tree.sh +5 -0
- package/scripts/Go/quality/lint.sh +16 -0
- package/scripts/Go/quality/test-summary.sh +16 -0
- package/scripts/Go/quality/type-check.sh +16 -0
- package/scripts/Node-TypeScript/api/express-routes.sh +14 -0
- package/scripts/Node-TypeScript/api/nest-controllers.sh +18 -0
- package/scripts/Node-TypeScript/architecture/arch.sh +174 -0
- package/scripts/Node-TypeScript/frontend/angular-routes.sh +15 -0
- package/scripts/Node-TypeScript/frontend/nextjs-app-router.sh +13 -0
- package/scripts/Node-TypeScript/frontend/react-components.sh +20 -0
- package/scripts/Node-TypeScript/lib/limit.sh +146 -0
- package/scripts/Node-TypeScript/project/deps.sh +15 -0
- package/scripts/Node-TypeScript/project/find-todos.sh +6 -0
- package/scripts/Node-TypeScript/quality/lint.sh +10 -0
- package/scripts/Node-TypeScript/quality/test-summary.sh +39 -0
- package/scripts/Node-TypeScript/quality/type-check.sh +10 -0
- package/scripts/Python/api/fastapi-routes.sh +12 -0
- package/scripts/Python/architecture/arch.sh +220 -0
- package/scripts/Python/db/django-models.sh +12 -0
- package/scripts/Python/db/sqlalchemy.sh +17 -0
- package/scripts/Python/lib/limit.sh +144 -0
- package/scripts/Python/project/deps.sh +28 -0
- package/scripts/Python/project/find-todos.sh +6 -0
- package/scripts/Python/quality/lint.sh +13 -0
- package/scripts/Python/quality/test-summary.sh +11 -0
- package/scripts/Python/quality/type-check.sh +10 -0
- package/scripts/Rust/architecture/arch.sh +176 -0
- package/scripts/Rust/lib/limit.sh +142 -0
- package/scripts/Rust/project/cargo-deps.sh +42 -0
- package/scripts/Rust/project/cargo-features.sh +26 -0
- package/scripts/Rust/project/find-todos.sh +6 -0
- package/scripts/Rust/project/tree.sh +5 -0
- package/scripts/Rust/quality/lint.sh +16 -0
- package/scripts/Rust/quality/test-summary.sh +16 -0
- package/scripts/Rust/quality/type-check.sh +16 -0
- package/scripts/Shared/api/express-routes.sh +11 -0
- package/scripts/Shared/api/fastapi-routes.sh +10 -0
- package/scripts/Shared/api/nest-controllers.sh +22 -0
- package/scripts/Shared/architecture/normalize.sh +178 -0
- package/scripts/Shared/crew/crew.sh +15 -0
- package/scripts/Shared/db/django-models.sh +11 -0
- package/scripts/Shared/db/prisma.sh +33 -0
- package/scripts/Shared/db/sqlalchemy.sh +12 -0
- package/scripts/Shared/frontend/angular-routes.sh +11 -0
- package/scripts/Shared/frontend/nextjs-app-router.sh +13 -0
- package/scripts/Shared/frontend/react-components.sh +11 -0
- package/scripts/Shared/git/diff-stat.sh +6 -0
- package/scripts/Shared/git/git-branch.sh +16 -0
- package/scripts/Shared/git/git-log.sh +6 -0
- package/scripts/Shared/git/git-status.sh +6 -0
- package/scripts/Shared/lib/limit.sh +144 -0
- package/scripts/Shared/project/compose-md.sh +182 -0
- package/scripts/Shared/project/deps.sh +69 -0
- package/scripts/Shared/project/find-todos.sh +6 -0
- package/scripts/Shared/project/tree.sh +5 -0
- package/scripts/Shared/quality/lint.sh +81 -0
- package/scripts/Shared/quality/test-summary.sh +103 -0
- package/scripts/Shared/quality/type-check.sh +114 -0
- package/scripts/copy-plugins.mjs +4 -0
- package/scripts/copy-templates.mjs +5 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Architecture map — Generic module dependencies (ecosystem-agnostic fallback)
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
: "${MAX_ARCH:=100}"
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
NORMALIZE="$SCRIPT_DIR/normalize.sh"
|
|
10
|
+
[ -f "$NORMALIZE" ] || NORMALIZE="$SCRIPT_DIR/../../Shared/architecture/normalize.sh"
|
|
11
|
+
|
|
12
|
+
EXCLUDE_DIRS='node_modules|\.git|\.pipemd|dist|build|coverage|venv|\.venv|__pycache__|target|\.next|\.nuxt|out|bin|obj|\.cache|vendor|bower_components'
|
|
13
|
+
|
|
14
|
+
SOURCE_EXTS='\.js$|\.ts$|\.jsx$|\.tsx$|\.py$|\.go$|\.rs$|\.c$|\.cpp$|\.cc$|\.cxx$|\.h$|\.hpp$|\.java$|\.rb$|\.php$|\.cs$|\.swift$|\.kt$|\.scala$|\.sh$|\.mjs$|\.cjs$'
|
|
15
|
+
|
|
16
|
+
PROJECT_ROOT="$(pwd)"
|
|
17
|
+
|
|
18
|
+
top_modules() {
|
|
19
|
+
local modules=""
|
|
20
|
+
for entry in "$PROJECT_ROOT"/*; do
|
|
21
|
+
[ -e "$entry" ] || continue
|
|
22
|
+
local name
|
|
23
|
+
name=$(basename "$entry")
|
|
24
|
+
echo "$name" | grep -qE "^($EXCLUDE_DIRS)$" && continue
|
|
25
|
+
echo "$name" | grep -qE '^\.' && continue
|
|
26
|
+
if [ -d "$entry" ]; then
|
|
27
|
+
modules="$modules $name"
|
|
28
|
+
fi
|
|
29
|
+
done
|
|
30
|
+
echo "$modules"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
MODULE_LIST=$(top_modules)
|
|
34
|
+
|
|
35
|
+
is_internal_dir() {
|
|
36
|
+
local name="$1"
|
|
37
|
+
echo "$MODULE_LIST" | grep -qw "$name"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
find_source_files() {
|
|
41
|
+
find . -maxdepth 3 -type f -print 2>/dev/null | while IFS= read -r f; do
|
|
42
|
+
echo "$f" | grep -qE "/($EXCLUDE_DIRS)(/|$)" && continue
|
|
43
|
+
echo "$f" | grep -qE "$SOURCE_EXTS" && echo "$f"
|
|
44
|
+
done
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
file_to_module() {
|
|
48
|
+
local filepath="$1"
|
|
49
|
+
local relpath="${filepath#./}"
|
|
50
|
+
local dirpart
|
|
51
|
+
dirpart=$(dirname "$relpath")
|
|
52
|
+
|
|
53
|
+
if [ "$dirpart" = "." ]; then
|
|
54
|
+
basename "$relpath" | sed 's/\.[^.]*$//'
|
|
55
|
+
return
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
local topdir
|
|
59
|
+
topdir=$(echo "$dirpart" | cut -d/ -f1)
|
|
60
|
+
if is_internal_dir "$topdir"; then
|
|
61
|
+
echo "$topdir"
|
|
62
|
+
else
|
|
63
|
+
echo "$dirpart" | awk -F/ '{print $NF}'
|
|
64
|
+
fi
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
EXTERNAL_DEPS=""
|
|
68
|
+
collect_external_deps() {
|
|
69
|
+
local deps=""
|
|
70
|
+
|
|
71
|
+
if [ -f package.json ]; then
|
|
72
|
+
local js_deps
|
|
73
|
+
js_deps=$(python3 -c "
|
|
74
|
+
import json, sys
|
|
75
|
+
try:
|
|
76
|
+
with open('package.json') as f: pkg = json.load(f)
|
|
77
|
+
except: sys.exit(0)
|
|
78
|
+
for section in ('dependencies', 'devDependencies', 'peerDependencies'):
|
|
79
|
+
for k in pkg.get(section, {}):
|
|
80
|
+
print(k)
|
|
81
|
+
" 2>/dev/null)
|
|
82
|
+
if [ -z "$js_deps" ]; then
|
|
83
|
+
js_deps=$(awk '
|
|
84
|
+
/"dependencies"/{in_deps=1;next}
|
|
85
|
+
/"devDependencies"/{in_deps=1;next}
|
|
86
|
+
/^\s*"[a-zA-Z@]/{
|
|
87
|
+
if(in_deps){
|
|
88
|
+
gsub(/"/,"")
|
|
89
|
+
sub(/:.*/,"")
|
|
90
|
+
if(length>0 && $0 !~ /^dependencies$/ && $0 !~ /^devDependencies$/) print
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/^\s*}/{if(in_deps && depth==0){in_deps=0} else if(in_deps){depth--}}
|
|
94
|
+
/^\s*{/{if(in_deps)depth++}
|
|
95
|
+
' package.json 2>/dev/null)
|
|
96
|
+
fi
|
|
97
|
+
deps="$deps
|
|
98
|
+
$js_deps"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
if [ -f requirements.txt ]; then
|
|
102
|
+
local py_deps
|
|
103
|
+
py_deps=$(grep -vE '^\s*(#|-r|--index-url|--extra-index-url|--find-links)' requirements.txt 2>/dev/null | sed 's/[<>=!].*//' | sed 's/\[.*//')
|
|
104
|
+
deps="$deps
|
|
105
|
+
$py_deps"
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
if [ -f pyproject.toml ]; then
|
|
109
|
+
local pyproj_deps
|
|
110
|
+
pyproj_deps=$(awk '
|
|
111
|
+
/^\[project\.dependencies\]/{in_deps=1;next}
|
|
112
|
+
/^\[/{in_deps=0}
|
|
113
|
+
in_deps && /^[a-zA-Z]/{
|
|
114
|
+
gsub(/#.*/,"")
|
|
115
|
+
gsub(/;.*$/,"")
|
|
116
|
+
gsub(/"/,"")
|
|
117
|
+
sub(/[<=>!].*/,"")
|
|
118
|
+
sub(/\[.*$/,"")
|
|
119
|
+
if(length>0) print tolower($0)
|
|
120
|
+
}
|
|
121
|
+
' pyproject.toml 2>/dev/null)
|
|
122
|
+
deps="$deps
|
|
123
|
+
$pyproj_deps"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if [ -f Cargo.toml ]; then
|
|
127
|
+
local cargo_deps
|
|
128
|
+
cargo_deps=$(awk '
|
|
129
|
+
/^\[dependencies\]/{in_deps=1;next}
|
|
130
|
+
/^\[/{in_deps=0}
|
|
131
|
+
in_deps && /^[a-zA-Z0-9_-]/{
|
|
132
|
+
gsub(/#.*/,"")
|
|
133
|
+
sub(/=.*$/,"")
|
|
134
|
+
sub(/\{.*$/,"")
|
|
135
|
+
sub(/".*$/,"")
|
|
136
|
+
if(length>0) print
|
|
137
|
+
}
|
|
138
|
+
' Cargo.toml 2>/dev/null)
|
|
139
|
+
deps="$deps
|
|
140
|
+
$cargo_deps"
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
if [ -f go.mod ]; then
|
|
144
|
+
local go_deps
|
|
145
|
+
go_deps=$(awk '
|
|
146
|
+
/^require \(/{in_deps=1;next}
|
|
147
|
+
/^\)/{in_deps=0}
|
|
148
|
+
in_deps && /^\s+\S+/{
|
|
149
|
+
gsub(/#.*/,"")
|
|
150
|
+
sub(/\/\/.*/,"")
|
|
151
|
+
n=split($0,a,"/")
|
|
152
|
+
print tolower(a[n])
|
|
153
|
+
}
|
|
154
|
+
/^require [^(]/{
|
|
155
|
+
gsub(/#.*/,"")
|
|
156
|
+
sub(/^require /,"")
|
|
157
|
+
sub(/\/\/.*/,"")
|
|
158
|
+
n=split($0,a,"/")
|
|
159
|
+
print tolower(a[n])
|
|
160
|
+
}
|
|
161
|
+
' go.mod 2>/dev/null)
|
|
162
|
+
deps="$deps
|
|
163
|
+
$go_deps"
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
EXTERNAL_DEPS=$(echo "$deps" | sed '/^\s*$/d' | tr '\n' '|' | sed 's/|$//')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
is_external() {
|
|
170
|
+
local pkg="$1"
|
|
171
|
+
[ -z "$EXTERNAL_DEPS" ] && return 1
|
|
172
|
+
echo "$EXTERNAL_DEPS" | grep -qiE "(^|\|)${pkg}(\||$)"
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
GO_STDLIB='archive,tar,zip,bufio,builtin,bytes,compress,bzip2,flate,gzip,lzo,zlib,container,heap,list,ring,context,crypto,aes,cipher,des,dsa,ecdsa,ed25519,elliptic,hmac,md5,rand,rc4,rsa,sha256,sha512,subtle,tls,x509,pkix,database,sql,driver,debug,dwarf,elf,macho,pe,plan9obj,buildinfo,dwarf,runtime,encoding,ascii85,asn1,binary,csv,hex,json,jose,gob,base32,base64,pem,xml,errors,expvar,flag,fmt,go,ast,build,constant,doc,format,importer,parser,printer,scanner,token,typecheck,hash,adler32,crc32,crc64,fnv,maphash,html,template,image,color,draw,gif,jpeg,png,font,ccitt,dxt5,gaussian,riff,index,suffixarray,io,ioutil,log,syslog,maps,math,big,cmplx,rand,mime,multipart,quotedprintable,net,http,cgi,cookiejar,fcgi,httputil,pprof,trace,mail,rpc,jsonrpc,smtp,url,text,scanner,tabwriter,template,time,unicode,utf16,utf8,unsafe,os,exec,signal,user,filepath,syscall,unattended,path,reflect,regexp,syntax,runtime,cgo,debug,msan,pprof,race,trace,search,slices,sort,strconv,strings,sync,atomic,map,testing,fstest,iotest,mock,quick,internal'
|
|
176
|
+
|
|
177
|
+
go_is_stdlib() {
|
|
178
|
+
local pkg="$1"
|
|
179
|
+
echo "$GO_STDLIB" | grep -qE "(^|,)"$pkg"(,|$)"
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
extract_and_resolve() {
|
|
183
|
+
local src_module="$1"
|
|
184
|
+
local filepath="$2"
|
|
185
|
+
local ext="${filepath##*.}"
|
|
186
|
+
|
|
187
|
+
case "$ext" in
|
|
188
|
+
js|ts|jsx|tsx|mjs|cjs)
|
|
189
|
+
grep -nE '^\s*(import\s+.*\s+from|import\s+"|import\s+'"'"'|require\s*\()' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
190
|
+
imp=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//')
|
|
191
|
+
local raw_target=""
|
|
192
|
+
if echo "$imp" | grep -qE 'from\s+["'"'"']'; then
|
|
193
|
+
raw_target=$(echo "$imp" | sed -n "s/.*from\s*[\"']//p" | sed "s/[\"'].*//")
|
|
194
|
+
elif echo "$imp" | grep -qE 'import\s+["'"'"']'; then
|
|
195
|
+
raw_target=$(echo "$imp" | sed -n "s/.*import\s*[\"']//p" | sed "s/[\"'].*//")
|
|
196
|
+
elif echo "$imp" | grep -qE 'require\s*\('; then
|
|
197
|
+
raw_target=$(echo "$imp" | sed -n "s/.*require\s*(\s*[\"']//p" | sed "s/[\"'].*//")
|
|
198
|
+
fi
|
|
199
|
+
[ -z "$raw_target" ] && continue
|
|
200
|
+
if echo "$raw_target" | grep -qE '^\.{1,2}/'; then
|
|
201
|
+
local resolved
|
|
202
|
+
resolved=$(echo "$raw_target" | sed 's|^\./||;s|^\.\./||;s|/index$||;s|\.[^.]*$||')
|
|
203
|
+
local topdir
|
|
204
|
+
topdir=$(echo "$resolved" | cut -d/ -f1)
|
|
205
|
+
if is_internal_dir "$topdir"; then
|
|
206
|
+
printf '%s\t%s\n' "$src_module" "$topdir"
|
|
207
|
+
elif [ -n "$resolved" ]; then
|
|
208
|
+
printf '%s\t%s\n' "$src_module" "$(echo "$resolved" | cut -d/ -f1)"
|
|
209
|
+
fi
|
|
210
|
+
else
|
|
211
|
+
local top_pkg
|
|
212
|
+
top_pkg=$(echo "$raw_target" | sed 's|/.*||;s|@.*/||' | sed 's/@$//')
|
|
213
|
+
if [ -n "$top_pkg" ]; then
|
|
214
|
+
if is_internal_dir "$top_pkg"; then
|
|
215
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
216
|
+
elif is_external "$top_pkg"; then
|
|
217
|
+
printf '%s\t%s\n' "$src_module" "ext:$top_pkg"
|
|
218
|
+
fi
|
|
219
|
+
fi
|
|
220
|
+
fi
|
|
221
|
+
done
|
|
222
|
+
;;
|
|
223
|
+
|
|
224
|
+
py)
|
|
225
|
+
grep -nE '^\s*(import\s+[a-zA-Z_]|from\s+[\.a-zA-Z_])' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
226
|
+
imp=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//')
|
|
227
|
+
if echo "$imp" | grep -qE '^\s*import\s+'; then
|
|
228
|
+
targets=$(echo "$imp" | sed 's/^\s*import\s*//' | sed 's/\s*as\s.*//' | sed 's/,/,/g')
|
|
229
|
+
IFS=',' read -ra parts <<< "$targets"
|
|
230
|
+
for part in "${parts[@]}"; do
|
|
231
|
+
pkg=$(echo "$part" | sed 's/^\s*//;s/\s*$//' | cut -d'.' -f1)
|
|
232
|
+
[ -z "$pkg" ] && continue
|
|
233
|
+
if is_internal_dir "$pkg"; then
|
|
234
|
+
printf '%s\t%s\n' "$src_module" "$pkg"
|
|
235
|
+
elif is_external "$pkg"; then
|
|
236
|
+
printf '%s\t%s\n' "$src_module" "ext:$(echo "$pkg" | tr '[:upper:]' '[:lower:]')"
|
|
237
|
+
fi
|
|
238
|
+
done
|
|
239
|
+
unset IFS
|
|
240
|
+
elif echo "$imp" | grep -qE '^\s*from\s+\.'; then
|
|
241
|
+
dots=$(echo "$imp" | sed 's/^\s*from\s*//' | sed 's/[^.].*//' | tr -d '\n' | wc -c)
|
|
242
|
+
afterdots=$(echo "$imp" | sed 's/^\s*from\s*//' | sed 's/^\.*/ /' | sed 's/^\s*//' | awk '{print $1}')
|
|
243
|
+
if [ -z "$afterdots" ] || [ "$afterdots" = "import" ]; then
|
|
244
|
+
:
|
|
245
|
+
else
|
|
246
|
+
local top_pkg
|
|
247
|
+
top_pkg=$(echo "$afterdots" | cut -d'.' -f1)
|
|
248
|
+
if is_internal_dir "$top_pkg"; then
|
|
249
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
250
|
+
fi
|
|
251
|
+
fi
|
|
252
|
+
elif echo "$imp" | grep -qE '^\s*from\s+[a-zA-Z_]'; then
|
|
253
|
+
from_pkg=$(echo "$imp" | sed 's/^\s*from\s*//' | awk '{print $1}')
|
|
254
|
+
top_pkg=$(echo "$from_pkg" | cut -d'.' -f1)
|
|
255
|
+
[ -z "$top_pkg" ] && continue
|
|
256
|
+
if is_internal_dir "$top_pkg"; then
|
|
257
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
258
|
+
elif is_external "$top_pkg"; then
|
|
259
|
+
printf '%s\t%s\n' "$src_module" "ext:$(echo "$top_pkg" | tr '[:upper:]' '[:lower:]')"
|
|
260
|
+
fi
|
|
261
|
+
fi
|
|
262
|
+
done
|
|
263
|
+
;;
|
|
264
|
+
|
|
265
|
+
go)
|
|
266
|
+
local in_block=0
|
|
267
|
+
grep -nE '^\s*(import\s+"|import\s+\(|use\s+|mod\s+)' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
268
|
+
imp=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//')
|
|
269
|
+
if echo "$imp" | grep -qE '^\s*import\s+\('; then
|
|
270
|
+
in_block=1
|
|
271
|
+
continue
|
|
272
|
+
fi
|
|
273
|
+
if [ "$in_block" -eq 1 ] && echo "$imp" | grep -qE '^\s*\)'; then
|
|
274
|
+
in_block=0
|
|
275
|
+
continue
|
|
276
|
+
fi
|
|
277
|
+
if [ "$in_block" -eq 1 ]; then
|
|
278
|
+
raw_target=$(echo "$imp" | sed -n 's/.*"\([^"]*\)".*/\1/p')
|
|
279
|
+
elif echo "$imp" | grep -qE '^\s*import\s+"'; then
|
|
280
|
+
raw_target=$(echo "$imp" | sed -n 's/.*import\s*"\([^"]*\)".*/\1/p')
|
|
281
|
+
else
|
|
282
|
+
continue
|
|
283
|
+
fi
|
|
284
|
+
[ -z "$raw_target" ] && continue
|
|
285
|
+
local pkg_base
|
|
286
|
+
pkg_base=$(echo "$raw_target" | awk -F/ '{print $NF}')
|
|
287
|
+
if echo "$raw_target" | grep -qE '^(\.|\.\.|./)'; then
|
|
288
|
+
printf '%s\t%s\n' "$src_module" "$pkg_base"
|
|
289
|
+
elif go_is_stdlib "$pkg_base"; then
|
|
290
|
+
continue
|
|
291
|
+
elif is_external "$pkg_base"; then
|
|
292
|
+
printf '%s\text:%s\n' "$src_module" "$pkg_base"
|
|
293
|
+
elif is_internal_dir "$pkg_base"; then
|
|
294
|
+
printf '%s\t%s\n' "$src_module" "$pkg_base"
|
|
295
|
+
fi
|
|
296
|
+
done
|
|
297
|
+
# Also catch multi-line import blocks that span across grep lines
|
|
298
|
+
awk -v src="$src_module" -v stdlib="$GO_STDLIB" '
|
|
299
|
+
BEGIN { in_block=0 }
|
|
300
|
+
/import[[:space:]]*\(/ { in_block=1; next }
|
|
301
|
+
in_block && /\)/ { in_block=0; next }
|
|
302
|
+
in_block && /"/ {
|
|
303
|
+
match($0, /"[^"]*"/)
|
|
304
|
+
imp = substr($0, RSTART+1, RLENGTH-2)
|
|
305
|
+
if (imp != "") {
|
|
306
|
+
n = split(imp, parts, "/")
|
|
307
|
+
pkg = parts[n]
|
|
308
|
+
is_std = 0
|
|
309
|
+
n2 = split(stdlib, a, ",")
|
|
310
|
+
for (i=1; i<=n2; i++) if (a[i] == pkg) { is_std=1; break }
|
|
311
|
+
if (!is_std) print src "\text:" pkg
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/^import[[:space:]]+"[^"]*"/ {
|
|
315
|
+
match($0, /"[^"]*"/)
|
|
316
|
+
imp = substr($0, RSTART+1, RLENGTH-2)
|
|
317
|
+
if (imp != "") {
|
|
318
|
+
n = split(imp, parts, "/")
|
|
319
|
+
pkg = parts[n]
|
|
320
|
+
is_std = 0
|
|
321
|
+
n2 = split(stdlib, a, ",")
|
|
322
|
+
for (i=1; i<=n2; i++) if (a[i] == pkg) { is_std=1; break }
|
|
323
|
+
if (!is_std) print src "\text:" pkg
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
' "$filepath" 2>/dev/null
|
|
327
|
+
;;
|
|
328
|
+
|
|
329
|
+
rs)
|
|
330
|
+
grep -nE '^\s*(use\s+|mod\s+)' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
331
|
+
imp=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//')
|
|
332
|
+
if echo "$imp" | grep -qE '^\s*use\s+crate::'; then
|
|
333
|
+
path=$(echo "$imp" | sed 's/^\s*use\s*crate:://' | sed 's/[{;].*//' | sed 's/\s*$//' | sed 's/::.*//')
|
|
334
|
+
[ -z "$path" ] && continue
|
|
335
|
+
if is_internal_dir "$path"; then
|
|
336
|
+
printf '%s\t%s\n' "$src_module" "$path"
|
|
337
|
+
fi
|
|
338
|
+
elif echo "$imp" | grep -qE '^\s*use\s+super::'; then
|
|
339
|
+
: # skip super references in generic mode
|
|
340
|
+
elif echo "$imp" | grep -qE '^\s*use\s+[a-z]'; then
|
|
341
|
+
crate_name=$(echo "$imp" | sed 's/^\s*use\s*//' | sed 's/[{;].*//' | sed 's/\s*$//' | sed 's/::.*//')
|
|
342
|
+
[ -z "$crate_name" ] && continue
|
|
343
|
+
[ "$crate_name" = "crate" ] || [ "$crate_name" = "super" ] || [ "$crate_name" = "self" ] && continue
|
|
344
|
+
if is_external "$crate_name"; then
|
|
345
|
+
printf '%s\text:%s\n' "$src_module" "$crate_name"
|
|
346
|
+
fi
|
|
347
|
+
elif echo "$imp" | grep -qE '^\s*mod\s+'; then
|
|
348
|
+
mod_name=$(echo "$imp" | sed 's/^\s*mod\s*//' | sed 's/[{;].*//' | sed 's/\s*$//')
|
|
349
|
+
[ -z "$mod_name" ] && continue
|
|
350
|
+
if is_internal_dir "$mod_name"; then
|
|
351
|
+
printf '%s\t%s\n' "$src_module" "$mod_name"
|
|
352
|
+
fi
|
|
353
|
+
fi
|
|
354
|
+
done
|
|
355
|
+
;;
|
|
356
|
+
|
|
357
|
+
c|h|cpp|cc|cxx|hpp)
|
|
358
|
+
grep -nE '^\s*#\s*include\s*"' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
359
|
+
raw_target=$(echo "$line" | sed -n 's/.*#include\s*"\([^"]*\)".*/\1/p')
|
|
360
|
+
[ -z "$raw_target" ] && continue
|
|
361
|
+
local topdir
|
|
362
|
+
topdir=$(echo "$raw_target" | cut -d/ -f1)
|
|
363
|
+
if [ "$topdir" != "$raw_target" ] && is_internal_dir "$topdir"; then
|
|
364
|
+
printf '%s\t%s\n' "$src_module" "$topdir"
|
|
365
|
+
else
|
|
366
|
+
local base
|
|
367
|
+
base=$(echo "$raw_target" | sed 's/\.[^.]*$//')
|
|
368
|
+
if is_internal_dir "$base"; then
|
|
369
|
+
printf '%s\t%s\n' "$src_module" "$base"
|
|
370
|
+
fi
|
|
371
|
+
fi
|
|
372
|
+
done
|
|
373
|
+
;;
|
|
374
|
+
|
|
375
|
+
java)
|
|
376
|
+
grep -nE '^\s*import\s+' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
377
|
+
raw_target=$(echo "$line" | sed 's/.*import\s*//' | sed 's/;.*//' | sed 's/static\s*//')
|
|
378
|
+
[ -z "$raw_target" ] && continue
|
|
379
|
+
local top_pkg
|
|
380
|
+
top_pkg=$(echo "$raw_target" | cut -d'.' -f1)
|
|
381
|
+
if is_internal_dir "$top_pkg"; then
|
|
382
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
383
|
+
elif is_external "$top_pkg"; then
|
|
384
|
+
printf '%s\text:%s\n' "$src_module" "$(echo "$top_pkg" | tr '[:upper:]' '[:lower:]')"
|
|
385
|
+
fi
|
|
386
|
+
done
|
|
387
|
+
;;
|
|
388
|
+
|
|
389
|
+
rb)
|
|
390
|
+
grep -nE '^\s*(require|require_relative|gem)\s' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
391
|
+
imp=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//')
|
|
392
|
+
if echo "$imp" | grep -qE 'require_relative'; then
|
|
393
|
+
raw_target=$(echo "$imp" | sed "s/.*require_relative\s*//" | sed "s/['\"].*//" | sed 's/^\s*//;s/\s*$//')
|
|
394
|
+
[ -z "$raw_target" ] && continue
|
|
395
|
+
local topdir
|
|
396
|
+
topdir=$(echo "$raw_target" | cut -d/ -f1)
|
|
397
|
+
if is_internal_dir "$topdir"; then
|
|
398
|
+
printf '%s\t%s\n' "$src_module" "$topdir"
|
|
399
|
+
fi
|
|
400
|
+
elif echo "$imp" | grep -qE '^(\s*)require'; then
|
|
401
|
+
raw_target=$(echo "$imp" | sed "s/.*require\s*//" | sed "s/['\"].*//" | sed 's/^\s*//;s/\s*$//')
|
|
402
|
+
[ -z "$raw_target" ] && continue
|
|
403
|
+
local top_pkg
|
|
404
|
+
top_pkg=$(echo "$raw_target" | cut -d'/' -f1 | tr '[:upper:]' '[:lower:]')
|
|
405
|
+
if is_internal_dir "$top_pkg"; then
|
|
406
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
407
|
+
elif is_external "$top_pkg"; then
|
|
408
|
+
printf '%s\text:%s\n' "$src_module" "$top_pkg"
|
|
409
|
+
fi
|
|
410
|
+
fi
|
|
411
|
+
done
|
|
412
|
+
;;
|
|
413
|
+
|
|
414
|
+
php)
|
|
415
|
+
grep -nE '^\s*(use\s+|require_once|include_once|require|include)\s' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
416
|
+
imp=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//')
|
|
417
|
+
if echo "$imp" | grep -qE '^\s*use\s+'; then
|
|
418
|
+
raw_target=$(echo "$imp" | sed 's/.*use\s*//' | sed 's/;.*//' | sed 's/\s*as\s.*//' | cut -d'\\' -f1)
|
|
419
|
+
[ -z "$raw_target" ] && continue
|
|
420
|
+
local top_pkg
|
|
421
|
+
top_pkg=$(echo "$raw_target" | cut -d'\\' -f1 | tr '[:upper:]' '[:lower:]')
|
|
422
|
+
if is_internal_dir "$top_pkg"; then
|
|
423
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
424
|
+
elif is_external "$top_pkg"; then
|
|
425
|
+
printf '%s\text:%s\n' "$src_module" "$top_pkg"
|
|
426
|
+
fi
|
|
427
|
+
fi
|
|
428
|
+
done
|
|
429
|
+
;;
|
|
430
|
+
|
|
431
|
+
cs)
|
|
432
|
+
grep -nE '^\s*using\s+' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
433
|
+
raw_target=$(echo "$line" | sed 's/.*using\s*//' | sed 's/;.*//' | sed 's/\s*=.*//')
|
|
434
|
+
[ -z "$raw_target" ] && continue
|
|
435
|
+
local top_pkg
|
|
436
|
+
top_pkg=$(echo "$raw_target" | cut -d'.' -f1)
|
|
437
|
+
if is_internal_dir "$top_pkg"; then
|
|
438
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
439
|
+
elif is_external "$top_pkg"; then
|
|
440
|
+
printf '%s\text:%s\n' "$src_module" "$(echo "$top_pkg" | tr '[:upper:]' '[:lower:]')"
|
|
441
|
+
fi
|
|
442
|
+
done
|
|
443
|
+
;;
|
|
444
|
+
|
|
445
|
+
swift|kt)
|
|
446
|
+
grep -nE '^\s*import\s+' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
447
|
+
raw_target=$(echo "$line" | sed 's/.*import\s*//' | awk '{print $1}')
|
|
448
|
+
[ -z "$raw_target" ] && continue
|
|
449
|
+
if is_internal_dir "$raw_target"; then
|
|
450
|
+
printf '%s\t%s\n' "$src_module" "$raw_target"
|
|
451
|
+
elif is_external "$raw_target"; then
|
|
452
|
+
printf '%s\text:%s\n' "$src_module" "$(echo "$raw_target" | tr '[:upper:]' '[:lower:]')"
|
|
453
|
+
fi
|
|
454
|
+
done
|
|
455
|
+
;;
|
|
456
|
+
|
|
457
|
+
scala)
|
|
458
|
+
grep -nE '^\s*import\s+' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
459
|
+
raw_target=$(echo "$line" | sed 's/.*import\s*//' | sed 's/\{.*//')
|
|
460
|
+
[ -z "$raw_target" ] && continue
|
|
461
|
+
local top_pkg
|
|
462
|
+
top_pkg=$(echo "$raw_target" | cut -d'.' -f1)
|
|
463
|
+
if is_internal_dir "$top_pkg"; then
|
|
464
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
465
|
+
elif is_external "$top_pkg"; then
|
|
466
|
+
printf '%s\text:%s\n' "$src_module" "$(echo "$top_pkg" | tr '[:upper:]' '[:lower:]')"
|
|
467
|
+
fi
|
|
468
|
+
done
|
|
469
|
+
;;
|
|
470
|
+
|
|
471
|
+
sh)
|
|
472
|
+
grep -nE '^\s*(source\s+|\.\s+)' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
473
|
+
raw_target=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//' | sed -e 's/^source\s*//' -e 's/^\.\s*//')
|
|
474
|
+
raw_target=$(echo "$raw_target" | sed 's/^\s*//;s/\s*$//' | sed 's/ .*//')
|
|
475
|
+
[ -z "$raw_target" ] && continue
|
|
476
|
+
local topdir
|
|
477
|
+
topdir=$(echo "$raw_target" | cut -d/ -f1)
|
|
478
|
+
if is_internal_dir "$topdir"; then
|
|
479
|
+
printf '%s\t%s\n' "$src_module" "$topdir"
|
|
480
|
+
fi
|
|
481
|
+
done
|
|
482
|
+
;;
|
|
483
|
+
|
|
484
|
+
*)
|
|
485
|
+
grep -nE '^\s*(import\s+|require\s*\(|#include\s*"|use\s+|from\s+.*import)' "$filepath" 2>/dev/null | while IFS= read -r line; do
|
|
486
|
+
imp=$(echo "$line" | sed 's/^[0-9]*://' | sed 's/^\s*//')
|
|
487
|
+
local raw_target=""
|
|
488
|
+
if echo "$imp" | grep -qE 'from\s+["'"'"']'; then
|
|
489
|
+
raw_target=$(echo "$imp" | sed -n "s/.*from\s*[\"']//p" | sed "s/[\"'].*//")
|
|
490
|
+
elif echo "$imp" | grep -qE 'import\s+["'"'"']'; then
|
|
491
|
+
raw_target=$(echo "$imp" | sed -n "s/.*import\s*[\"']//p" | sed "s/[\"'].*//")
|
|
492
|
+
elif echo "$imp" | grep -qE 'require\s*\('; then
|
|
493
|
+
raw_target=$(echo "$imp" | sed -n "s/.*require\s*(\s*[\"']//p" | sed "s/[\"'].*//")
|
|
494
|
+
elif echo "$imp" | grep -qE '^\s*import\s+[a-zA-Z_]'; then
|
|
495
|
+
raw_target=$(echo "$imp" | sed 's/.*import\s*//' | awk '{print $1}' | cut -d'.' -f1)
|
|
496
|
+
fi
|
|
497
|
+
[ -z "$raw_target" ] && continue
|
|
498
|
+
if echo "$raw_target" | grep -qE '^\.{1,2}/'; then
|
|
499
|
+
local resolved
|
|
500
|
+
resolved=$(echo "$raw_target" | sed 's|^\./||;s|^\.\./||')
|
|
501
|
+
local topdir
|
|
502
|
+
topdir=$(echo "$resolved" | cut -d/ -f1)
|
|
503
|
+
if is_internal_dir "$topdir"; then
|
|
504
|
+
printf '%s\t%s\n' "$src_module" "$topdir"
|
|
505
|
+
fi
|
|
506
|
+
else
|
|
507
|
+
local top_pkg
|
|
508
|
+
top_pkg=$(echo "$raw_target" | sed 's|/.*||;s|@.*/||' | sed 's/@$//')
|
|
509
|
+
if [ -n "$top_pkg" ]; then
|
|
510
|
+
if is_internal_dir "$top_pkg"; then
|
|
511
|
+
printf '%s\t%s\n' "$src_module" "$top_pkg"
|
|
512
|
+
elif is_external "$top_pkg"; then
|
|
513
|
+
printf '%s\text:%s\n' "$src_module" "$top_pkg"
|
|
514
|
+
fi
|
|
515
|
+
fi
|
|
516
|
+
fi
|
|
517
|
+
done
|
|
518
|
+
;;
|
|
519
|
+
esac
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
directory_heuristic_edges() {
|
|
523
|
+
local dirs=()
|
|
524
|
+
for entry in "$PROJECT_ROOT"/*; do
|
|
525
|
+
[ -d "$entry" ] || continue
|
|
526
|
+
local dname
|
|
527
|
+
dname=$(basename "$entry")
|
|
528
|
+
echo "$dname" | grep -qE "^($EXCLUDE_DIRS)$" && continue
|
|
529
|
+
echo "$dname" | grep -qE '^\.' && continue
|
|
530
|
+
local has_src
|
|
531
|
+
has_src=$(find "$entry" -maxdepth 2 -type f \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.c" -o -name "*.cpp" -o -name "*.java" -o -name "*.rb" -o -name "*.php" -o -name "*.cs" -o -name "*.swift" -o -name "*.kt" \) -print -quit 2>/dev/null)
|
|
532
|
+
[ -z "$has_src" ] && continue
|
|
533
|
+
dirs+=("$dname")
|
|
534
|
+
done
|
|
535
|
+
|
|
536
|
+
local n=${#dirs[@]}
|
|
537
|
+
if [ "$n" -lt 2 ]; then
|
|
538
|
+
return
|
|
539
|
+
fi
|
|
540
|
+
|
|
541
|
+
for ((i = 0; i < n; i++)); do
|
|
542
|
+
for ((j = i + 1; j < n; j++)); do
|
|
543
|
+
printf '%s\t%s\n' "${dirs[$i]}" "${dirs[$j]}"
|
|
544
|
+
done
|
|
545
|
+
done
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
collect_external_deps
|
|
549
|
+
|
|
550
|
+
(
|
|
551
|
+
has_edges=0
|
|
552
|
+
|
|
553
|
+
while IFS= read -r srcfile; do
|
|
554
|
+
[ -z "$srcfile" ] && continue
|
|
555
|
+
|
|
556
|
+
src_module=$(file_to_module "$srcfile")
|
|
557
|
+
[ -z "$src_module" ] && continue
|
|
558
|
+
|
|
559
|
+
edges=$(extract_and_resolve "$src_module" "$srcfile")
|
|
560
|
+
[ -z "$edges" ] && continue
|
|
561
|
+
|
|
562
|
+
echo "$edges"
|
|
563
|
+
has_edges=1
|
|
564
|
+
done < <(find_source_files)
|
|
565
|
+
|
|
566
|
+
if [ "$has_edges" -eq 0 ]; then
|
|
567
|
+
directory_heuristic_edges
|
|
568
|
+
fi
|
|
569
|
+
|
|
570
|
+
) 2>/dev/null | sort -u | head -"$((MAX_ARCH * 2))" | MAX_ARCH="$MAX_ARCH" bash "$NORMALIZE"
|