Skip to main content
refactoring-detection リファクタリング候補検出のast-grepパターン、推定工数算出、言語別設定を定義
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/takemo101/compose-workflow --skill refactoring-detectionThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository Related occupations SOC
Based on SOC occupation classification
name refactoring-detection description リファクタリング候補検出のast-grepパターン、推定工数算出、言語別設定を定義
リファクタリング検出スキル
/find-refactoringコマンドで使用する検出ロジック・パターンを定義。
前提ツール
ツール 必須/任意 用途 インストール ast-grep (sg)必須 AST解析 cargo install ast-grep / brew install ast-grepjscpd任意 重複検出 npm install -g jscpdjq必須 JSON処理 brew install jqwc, grep必須 基本検出 標準コマンド
ツール確認
check_required_tools () {
local missing=()
command -v sg &>/dev/null || missing+=("ast-grep (sg): cargo install ast-grep" )
command -v jq &>/dev/null || missing+=("jq: brew install jq" )
if [[ ${#missing[@]} -gt 0 ]]; then
echo "Error: Missing required tools:"
printf
1
0
}
() {
-v jscpd &>/dev/null || -v npx &>/dev/null;
}
' - %s\n'
"${missing[@]} "
return
fi
return
check_optional_tools
if
command
command
then
echo
"jscpd: available"
else
echo
"jscpd: not available (duplicate detection skipped)"
fi
言語検出 detect_language () {
if [[ -f "package.json" ]]; then
echo "typescript"
elif [[ -f "Cargo.toml" ]]; then
echo "rust"
elif [[ -f "go.mod" ]]; then
echo "go"
elif [[ -f "pyproject.toml" ]] || [[ -f "requirements.txt" ]]; then
echo "python"
else
echo "typescript"
fi
}
言語別設定 言語 拡張子 ast-grep lang ファイル上限 関数上限 TypeScript *.ts,*.tsxtypescript/tsx500行 80行 Rust *.rsrust500行 80行 Go *.gogo400行 60行 Python *.pypython400行 60行
検出パターン(TypeScript)
注意 : ast-grep出力は0-indexed。表示時に+1する。
サイズ系
find_large_files () {
local target="$1 "
find "$target " -type f \( -name "*.ts" -o -name "*.tsx" \) \
! -path "*/node_modules/*" ! -path "*/.git/*" \
-exec wc -l {} + 2>/dev/null | \
awk '$1 > 500 && !/total$/ {printf "%s:%d:file_split\n", $2, $1}'
}
find_large_functions_ts () {
local target="$1 "
sg run --pattern 'function $NAME($$$) { $$$ }' --lang typescript "$target " --json 2>/dev/null | \
jq -r '.[] | select(.range.end.line - .range.start.line > 80) |
"\(.file):\(.range.start.line + 1):\(.range.end.line - .range.start.line):func_split:\(.metaVariables.single.NAME.text // "anonymous")"'
}
find_large_arrow_functions () {
local target="$1 "
sg run --pattern 'const $NAME = ($$$) => { $$$ }' --lang typescript "$target " --json 2>/dev/null | \
jq -r '.[] | select(.range.end.line - .range.start.line > 80) |
"\(.file):\(.range.start.line + 1):\(.range.end.line - .range.start.line):func_split:\(.metaVariables.single.NAME.text)"'
}
find_many_params () {
local target="$1 "
sg run --pattern 'function $NAME($A, $B, $C, $D, $E, $F, $G, $$$) { $$$ }' \
--lang typescript "$target " --json 2>/dev/null | \
jq -r '.[] | "\(.file):\(.range.start.line + 1):7:many_params"'
}
型安全系
find_any_types () {
local target="$1 "
grep -rn --include="*.ts" --include="*.tsx" -E ':\s*any\b' "$target " 2>/dev/null | \
grep -v node_modules | \
while IFS=: read -r file line _; do
echo "$file :$line :1:any_type"
done
}
find_ts_ignore () {
local target="$1 "
grep -rn --include="*.ts" --include="*.tsx" -E '@ts-ignore|@ts-expect-error' "$target " 2>/dev/null | \
grep -v node_modules | \
while IFS=: read -r file line _; do
echo "$file :$line :1:ts_ignore"
done
}
エラー処理系
find_empty_catch () {
local target="$1 "
sg run --pattern 'try { $$$ } catch ($E) { }' --lang typescript "$target " --json 2>/dev/null | \
jq -r '.[] | "\(.file):\(.range.start.line + 1):1:empty_catch"'
}
品質系
find_console_log () {
local target="$1 "
sg run --pattern 'console.log($$$)' --lang typescript "$target " --json 2>/dev/null | \
jq -r '.[] | select(
(.file | test("\\.(spec|test)\\.(ts|tsx)$") | not) and
(.file | test("(jest|vitest|eslint|prettier)\\.config") | not)
) | "\(.file):\(.range.start.line + 1):1:console_log"'
}
検出パターン(Rust)
find_large_functions_rust () {
local target="$1 "
sg run --pattern 'fn $NAME($$$) { $$$ }' --lang rust "$target " --json 2>/dev/null | \
jq -r '.[] | select(.range.end.line - .range.start.line > 80) |
"\(.file):\(.range.start.line + 1):\(.range.end.line - .range.start.line):func_split:\(.metaVariables.single.NAME.text)"'
}
find_unwrap_abuse () {
local target="$1 "
sg run --pattern '$_.unwrap()' --lang rust "$target " --json 2>/dev/null | \
jq -r 'group_by(.file) | .[] | select(length > 5) |
"\(.[0].file):1:\(length):unwrap_abuse"'
}
find_rust_todo () {
local target="$1 "
grep -rn --include="*.rs" -E 'todo!|unimplemented!' "$target " 2>/dev/null | \
while IFS=: read -r file line _; do
echo "$file :$line :1:rust_todo"
done
}
検出パターン(Go)
find_large_functions_go () {
local target="$1 "
sg run --pattern 'func $NAME($$$) { $$$ }' --lang go "$target " --json 2>/dev/null | \
jq -r '.[] | select(.range.end.line - .range.start.line > 60) |
"\(.file):\(.range.start.line + 1):\(.range.end.line - .range.start.line):func_split:\(.metaVariables.single.NAME.text)"'
}
find_go_panic () {
local target="$1 "
grep -rn --include="*.go" 'panic(' "$target " 2>/dev/null | \
grep -v '_test.go' | \
while IFS=: read -r file line _; do
echo "$file :$line :1:go_panic"
done
}
検出パターン(Python)
find_large_functions_python () {
local target="$1 "
sg run --pattern 'def $NAME($$$): $$$' --lang python "$target " --json 2>/dev/null | \
jq -r '.[] | select(.range.end.line - .range.start.line > 60) |
"\(.file):\(.range.start.line + 1):\(.range.end.line - .range.start.line):func_split:\(.metaVariables.single.NAME.text)"'
}
find_python_print () {
local target="$1 "
grep -rn --include="*.py" 'print(' "$target " 2>/dev/null | \
grep -v test_ | grep -v _test.py | \
while IFS=: read -r file line _; do
echo "$file :$line :1:python_print"
done
}
重複コード検出 find_duplicates () {
local target="$1 "
local cmd=""
if command -v jscpd &>/dev/null; then
cmd="jscpd"
elif command -v npx &>/dev/null; then
cmd="npx jscpd"
else
return 0
fi
$cmd "$target " --min-lines 10 --reporters json --silent 2>/dev/null | \
jq -r '.duplicates[]? |
"\(.firstFile.name):\(.firstFile.start):\(.firstFile.end - .firstFile.start):duplicate:\(.secondFile.name)"' 2>/dev/null || true
}
統合検出関数 run_all_detections () {
local target="$1 "
local lang="$2 "
find_large_files "$target "
case "$lang " in
typescript)
find_large_functions_ts "$target "
find_large_arrow_functions "$target "
find_many_params "$target "
find_any_types "$target "
find_ts_ignore "$target "
find_empty_catch "$target "
find_console_log "$target "
;;
rust)
find_large_functions_rust "$target "
find_unwrap_abuse "$target "
find_rust_todo "$target "
;;
go)
find_large_functions_go "$target "
find_go_panic "$target "
;;
python)
find_large_functions_python "$target "
find_python_print "$target "
;;
esac
find_duplicates "$target "
}
推定工数算出 問題タイプ 変数 計算式 例 file_split 超過行数 (行数-500)*0.3分723行→67分 func_split 超過行数 (行数-80)*0.5分150行→35分 any_type 箇所数 箇所数*5分5箇所→25分 empty_catch 箇所数 箇所数*10分3箇所→30分 ts_ignore 箇所数 箇所数*15分2箇所→30分 console_log 箇所数 箇所数*2分10箇所→20分 duplicate 重複行数 行数*0.5分40行→20分 many_params 固定 20分 - unwrap_abuse 箇所数 箇所数*3分10箇所→30分 rust_todo 箇所数 箇所数*10分3箇所→30分
estimate_effort () {
local type ="$1 "
local value="$2 "
local minutes=0
case "$type " in
file_split) minutes=$(( (value - 500 ) * 3 / 10 )) ;;
func_split) minutes=$(( (value - 80 ) / 2 )) ;;
any_type) minutes=$(( value * 5 )) ;;
empty_catch) minutes=$(( value * 10 )) ;;
ts_ignore) minutes=$(( value * 15 )) ;;
console_log) minutes=$(( value * 2 )) ;;
duplicate) minutes=$(( value / 2 )) ;;
many_params) minutes=20 ;;
unwrap_abuse) minutes=$(( value * 3 )) ;;
rust_todo|go_panic|python_print) minutes=$(( value * 10 )) ;;
*) minutes=30 ;;
esac
if [[ $minutes -lt 1 ]]; then minutes=5; fi
if [[ $minutes -ge 60 ]]; then
echo "$(( minutes / 60 ) )h$(( minutes % 60 ) )m"
else
echo "${minutes} m"
fi
}
Issue粒度チェック estimate_work_lines () {
local type ="$1 "
local value="$2 "
case "$type " in
file_split) echo $(( (value - 500 ) / 3 )) ;;
func_split) echo $(( (value - 80 ) / 2 )) ;;
any_type) echo $(( value * 5 )) ;;
empty_catch) echo $(( value * 10 )) ;;
ts_ignore) echo $(( value * 15 )) ;;
duplicate) echo $(( value / 2 )) ;;
*) echo 50 ;;
esac
}
needs_decompose () {
local lines="$1 "
[[ "$lines " -gt 200 ]]
}
既存Issue重複チェック get_existing_refactoring_issues () {
gh issue list --label refactoring --state open \
--json number,title,body --limit 100 2>/dev/null || echo "[]"
}
check_duplicate_issue () {
local file_path="$1 "
local existing_issues="$2 "
echo "$existing_issues " | jq -r --arg fp "$file_path " \
'.[] | select(.body | contains($fp)) | "#\(.number)"' | head -1
}
優先度判定 優先度 ルール Critical ts_ignoreHigh file_split, func_split, any_type, empty_catch, rust_todo, go_panicMedium duplicate, many_params, console_log, unwrap_abuse, python_printLow その他
get_priority () {
local type ="$1 "
case "$type " in
ts_ignore) echo "critical" ;;
file_split|func_split|any_type|empty_catch|rust_todo|go_panic)
echo "high" ;;
duplicate|many_params|console_log|unwrap_abuse|python_print)
echo "medium" ;;
*) echo "low" ;;
esac
}