Skip to content

Commit 0d9ecfc

Browse files
committed
This PR addresses all validator issues raised in the review thread.
1 parent 25a599f commit 0d9ecfc

File tree

1 file changed

+37
-19
lines changed

1 file changed

+37
-19
lines changed

dist/validate-links.sh

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ EXIT_CODE=0
88
VERBOSE="${VERBOSE:-0}"
99

1010
log_verbose() {
11-
[[ "$VERBOSE" == "1" ]] && echo "Info: $*"
11+
if [[ "$VERBOSE" == "1" ]]; then
12+
echo "Info: $*"
13+
fi
1214
}
1315

14-
ASSET_EXTENSIONS_REGEX='png|jpg|jpeg|svg|gif|webp|avif|ico|xml|yaml|yml|json|css|js|pdf|zip|tar.gz|woff|woff2|ttf|eot|mp4|webm'
16+
ASSET_EXTENSIONS_REGEX='png|jpg|jpeg|svg|gif|webp|avif|ico|xml|yaml|yml|json|css|js|pdf|zip|tar\.gz|woff|woff2|ttf|eot|mp4|webm'
1517
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || exit 1
1618
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" || exit 1
1719
CONTENT_ROOT="$(cd "$REPO_ROOT/$CONTENT_DIR" && pwd)" || exit 1
@@ -47,15 +49,19 @@ canonicalize_path() {
4749
local path="$1"
4850
local result=()
4951
local part
52+
local parts
5053

54+
# Bash 3.2 compatible: use here-string
5155
IFS='/' read -r -a parts <<< "$path"
5256

5357
for part in "${parts[@]}"; do
5458
if [[ -z "$part" || "$part" == "." ]]; then
5559
continue
5660
elif [[ "$part" == ".." ]]; then
61+
# Bash 3.2 compatible: calculate last index instead of using -1
5762
if [[ ${#result[@]} -gt 0 ]]; then
58-
unset 'result[-1]'
63+
local last_idx=$((${#result[@]} - 1))
64+
unset "result[$last_idx]"
5965
fi
6066
else
6167
result+=("$part")
@@ -105,7 +111,6 @@ check_internal_link() {
105111
return 0
106112
fi
107113

108-
# Bash 3.2 compatible lowercase conversion
109114
local clean_lower
110115
clean_lower="$(printf "%s" "$clean_link" | tr '[:upper:]' '[:lower:]')"
111116

@@ -139,9 +144,13 @@ check_internal_link() {
139144
target_path="$REPO_ROOT/static${clean_link}"
140145

141146
elif [[ "$clean_link" == /* ]]; then
142-
echo "Error: Unknown absolute path"
143-
echo " File: $file:$line_no"
147+
location="$file"
148+
[[ -n "$line_no" ]] && location="$file:$line_no"
149+
150+
echo "Error: Unsupported absolute internal path (cannot validate deterministically)"
151+
echo " File: $location"
144152
echo " Link: $link"
153+
145154
EXIT_CODE=1
146155
return
147156

@@ -199,14 +208,21 @@ check_internal_link() {
199208

200209
echo "Starting link validation..."
201210

202-
while read -r FILE; do
211+
while IFS= read -r FILE; do
212+
203213
CODE_LINES=""
204214
in_fence=false
205215
line_no=0
206216

207-
while IFS= read -r line; do
208-
((line_no++))
209-
217+
while IFS= read -r line || [[ -n "$line" ]]; do
218+
((++line_no))
219+
# NOTE:
220+
# Code fence detection is heuristic and does not validate proper pairing.
221+
# The logic simply toggles state when encountering ``` or ~~~ markers.
222+
# If a Markdown file contains an unclosed fence or mismatched fence types,
223+
# all subsequent lines may be treated as code and skipped from validation.
224+
# This behavior is intentional to keep the validator lightweight and
225+
# avoids implementing a full Markdown parser. Such cases require manual review.
210226
if [[ "$line" =~ ^[[:space:]]*(\`\`\`|~~~) ]]; then
211227
# NOTE:
212228
# Code fence detection assumes fences are properly paired.
@@ -229,20 +245,22 @@ while read -r FILE; do
229245
fi
230246

231247
# NOTE:
232-
# Inline code detection is heuristic.
233-
# It assumes backticks are paired on the same line.
234-
# Escaped backticks are ignored, but complex or malformed
235-
# Markdown inline code spans may still be misdetected.
236-
248+
# Inline code detection is heuristic and intentionally simplistic.
249+
# The logic assumes backticks are properly paired within a single line
250+
# after removing escaped backticks. Malformed Markdown, complex inline
251+
# constructs, or unusual escaping patterns may cause false positives
252+
# or false negatives. This validator does not implement a full Markdown
253+
# parser and therefore cannot guarantee perfect inline code detection.
237254
escaped_line="${line//\\\`/}"
238-
inline_count=$(grep -o "\`" <<< "$escaped_line" | wc -l)
255+
inline_count=$(printf "%s\n" "$escaped_line" | grep -o "\`" || true)
256+
inline_count=$(printf "%s\n" "$inline_count" | wc -l)
239257
if (( inline_count % 2 == 1 )); then
240258
CODE_LINES="$CODE_LINES $line_no "
241259
fi
242260

243261
done < "$FILE"
244262

245-
while read -r MATCH; do
263+
while read -r MATCH || [[ -n "$MATCH" ]]; do
246264
[[ -z "$MATCH" ]] && continue
247265

248266
LINE_NO="${MATCH%%:*}"
@@ -254,10 +272,10 @@ while read -r FILE; do
254272
LINK="${LINK%)}"
255273

256274
check_internal_link "$LINK" "$FILE" "$LINE_NO"
257-
done < <(grep -n -oE '\]\([^)]+\)' "$FILE")
275+
done < <(grep -n -oE '\]\([^)]+\)' "$FILE" || true)
258276

259277
unset CODE_LINES
260-
done < <(find "$CONTENT_ROOT" -type f -name "*.md")
278+
done < <(find "$CONTENT_ROOT" -type f -name "*.md" 2>/dev/null || true)
261279

262280
if [[ $EXIT_CODE -eq 0 ]]; then
263281
echo "Link validation passed!"

0 commit comments

Comments
 (0)