Created
June 25, 2025 18:46
-
-
Save johnnymo87/055680e716f8a822ef318ececa467f40 to your computer and use it in GitHub Desktop.
Concatenates code files output from `madge` into a single output file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
: <<'END' | |
Script Name: madge_concatenator.sh | |
Purpose: | |
This script uses 'madge' to find all dependencies for a given TypeScript/JavaScript | |
entry file, and then concatenates all found files into a single output file. | |
The output file will contain the absolute file paths and contents of each code file, | |
separated by a delimiter (```). This is useful for providing a large codebase | |
context to tools that accept a single file input. | |
Usage: | |
./madge_concatenator.bash <ENTRY_FILE> | |
Arguments: | |
- ENTRY_FILE: The path to the entry file (e.g., a .ts or .js file) for madge to analyze. | |
Features: | |
- Runs madge to build a dependency graph for the specified entry file. | |
- Parses madge's JSON output to get a complete and unique list of all dependent files. | |
- Correctly resolves file paths, which madge outputs relative to the entry file's directory. | |
- Concatenates the absolute file path and full content for each file. | |
- Outputs the final concatenated content to standard output, which can be redirected to a file. | |
Dependencies: | |
- bash: The script is written for Bash shell environments. | |
- madge: Must be available in the environment (e.g., `npm install -g madge` or as a project dependency). | |
- jq: A command-line JSON processor. Must be installed. | |
Note: | |
This script should be run from the root of your project, where `tsconfig.json` is located. | |
END | |
set -euo pipefail | |
# --- Dependency Checks --- | |
if ! command -v npx &> /dev/null; then | |
echo "Error: npx is not installed. Please install Node.js and npm." >&2 | |
exit 1 | |
fi | |
# Check for madge via npx | |
if ! npx madge --version &> /dev/null; then | |
echo "Error: madge could not be found by npx. Please install it in your project ('npm install madge') or globally ('npm install -g madge')." >&2 | |
exit 1 | |
fi | |
if ! command -v jq &> /dev/null; then | |
echo "Error: jq is not installed. Please install it (e.g., 'brew install jq' or 'sudo apt-get install jq')." >&2 | |
exit 1 | |
fi | |
# --- End Dependency Checks --- | |
# --- Argument Parsing --- | |
if [ -z "${1-}" ]; then | |
echo "Usage: $0 <ENTRY_FILE>" >&2 | |
echo "Example: $0 src/index.ts" >&2 | |
exit 1 | |
fi | |
ENTRY_FILE="$1" | |
if [ ! -f "$ENTRY_FILE" ]; then | |
echo "Error: Entry file not found at '$ENTRY_FILE'" >&2 | |
exit 1 | |
fi | |
# The directory of the entry file is used as the base for resolving relative paths from madge. | |
ENTRY_DIR=$(dirname "$ENTRY_FILE") | |
# --- End Argument Parsing --- | |
# --- Main Logic --- | |
# Create a temporary file for the final output | |
output_file=$(mktemp) | |
# Ensure cleanup on exit | |
trap 'rm -f -- "$output_file"' EXIT | |
echo "1. Running madge to analyze dependencies for '$ENTRY_FILE'..." >&2 | |
# These flags are based on your example. You can modify them as needed. | |
madge_output=$(npx madge --ts-config tsconfig.json --extensions ts,tsx "$ENTRY_FILE" --json) | |
echo "2. Parsing madge's JSON output to create a file list..." >&2 | |
# The jq command extracts all unique file paths (both keys and values in the dependency arrays). | |
file_list=$(echo "$madge_output" | jq -r '(keys_unsorted[], .[][]) | select(length > 0)' | sort -u) | |
# If madge failed to produce a list, fall back to just the entry file. | |
if [ -z "$file_list" ]; then | |
echo "Warning: madge found no dependencies. Processing only the entry file." >&2 | |
# The path madge would have returned for the entry file is its basename. | |
file_list=$(basename "$ENTRY_FILE") | |
fi | |
echo "3. Concatenating all dependent files..." >&2 | |
# Loop through the list of files and concatenate them | |
while IFS= read -r file; do | |
# madge paths are relative to the entry file's directory. We construct the full path from CWD. | |
full_path="$ENTRY_DIR/$file" | |
# Normalize the path (e.g., resolve ../) and check for existence. | |
if [ -f "$full_path" ]; then | |
# `realpath` gives the canonical, absolute path. | |
canonical_path=$(realpath "$full_path") | |
printf " - Adding %s\n" "$canonical_path" >&2 | |
# We use a temporary delimiter '###' to avoid conflicts with '```' in source code. | |
{ | |
printf "%s\n" "$canonical_path" | |
printf "###\n" | |
cat "$canonical_path" | |
# Ensure there's a newline at the end of the file content before the delimiter | |
if [ "$(tail -c1 "$canonical_path" | wc -l)" -eq 0 ]; then | |
printf "\n" | |
fi | |
printf "###\n" | |
} >> "$output_file" | |
else | |
echo " - Warning: File not found, skipping: $full_path" >&2 | |
fi | |
done <<< "$file_list" | |
echo "4. Finalizing output..." >&2 | |
# Print the contents of the output file to stdout, replacing the temporary delimiter with the final one. | |
sed 's/^###$/```/g' "$output_file" | |
# The trap will handle removing the temp file. | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to Use
madge_concatenator.bash
in the root of your project.chmod +x madge_concatenator.bash
../madge_concatenator.bash src/templates/Cooking/CookingLayout/PodLayout/shared/TaskSlots/usePersistedTasks.ts > context.txt