Skip to content
4 changes: 4 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@
## 2024-07-13 - 빈 디렉토리 μƒνƒœμ˜ μ ‘κ·Όμ„±(Accessibility) κ°œμ„ 
**Learning:** 정적 파일 μ„œλ²„μ˜ 빈 디렉토리 μƒνƒœλŠ” 슀크린 리더 μ‚¬μš©μžμ—κ²Œ 컨텐츠 λˆ„λ½μœΌλ‘œ μ˜€ν•΄λ°›μ„ 수 있으며, μ‹œκ°μ μœΌλ‘œλ„ 일반 리슀트 μ•„μ΄ν…œκ³Ό 정렬이 λ§žμ§€ μ•ŠλŠ” λ¬Έμ œκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.
**Action:** 빈 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” μš”μ†Œμ— `role="status"`λ₯Ό μΆ”κ°€ν•˜μ—¬ 슀크린 리더가 λͺ…ν™•ν•˜κ²Œ 인지할 수 μžˆλ„λ‘ ν•˜κ³ , μ•„μ΄μ½˜κ³Ό flex λ ˆμ΄μ•„μ›ƒμ„ 톡해 λ‹€λ₯Έ 리슀트 μ•„μ΄ν…œκ³Ό μΌκ΄€λœ μ‹œκ°μ  흐름을 μ œκ³΅ν•˜λ„λ‘ ν•©λ‹ˆλ‹€.

## 2026-08-06 - 파일 경둜 기반 제λͺ© ν‘œμ‹œμ€„μ˜ μ ‘κ·Όμ„± κ°œμ„ 
**ν•™μŠ΅:** 디렉토리 이름이 λΉ„μ–΄μžˆλŠ” 경우(예: 루트 λ””λ ‰ν† λ¦¬λ‚˜ μ»€μŠ€ν…€ 마운트 포인트), <h1> 및 <title> νƒœκ·Έκ°€ λΉ„μ–΄ 있게 λ˜μ–΄ ν™”λ©΄ νŒλ…κΈ° μ‚¬μš©μžκ°€ ν˜„μž¬ νŽ˜μ΄μ§€μ˜ μ»¨ν…μŠ€νŠΈλ₯Ό 이해할 수 μ—†κ²Œ 되며, μ‹œκ°μ μœΌλ‘œλ„ νŽ˜μ΄μ§€ 제λͺ©μ΄ λˆ„λ½λ˜μ–΄ ν˜Όλž€μ„ μ΄ˆλž˜ν•©λ‹ˆλ‹€.
**쑰치:** UI μš”μ†Œ(.name)에 ν‘œμ‹œν•  디렉토리 이름이 λΉ„μ–΄μžˆλŠ” 경우, 항상 μ ˆλŒ€ 경둜(.absolutePath)와 같은 의미 μžˆλŠ” 폴백(fallback) 값을 μ œκ³΅ν•˜μ—¬ ν™”λ©΄ νŒλ…κΈ°μ™€ 일반 μ‚¬μš©μž λͺ¨λ‘ νŽ˜μ΄μ§€μ˜ μœ„μΉ˜λ₯Ό λͺ…ν™•νžˆ μ•Œ 수 μžˆλ„λ‘ 보μž₯ν•˜μ‹­μ‹œμ˜€.
5 changes: 3 additions & 2 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array

val exclude: Set<String> = excludeSet ?: process_ignore_file(curr_dir)

val displayDirName = curr_dir.name.ifBlank { curr_dir.absolutePath }
val index_top = """<!doctype html>
<html lang="ko">
<head>
Expand All @@ -345,12 +346,12 @@ fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src '${STYLE_HASH}'; base-uri 'none'; form-action 'none';">
<!-- λ³΄μ•ˆ ν–₯상: 리퍼러λ₯Ό ν†΅ν•œ 디렉토리 경둜 λ…ΈμΆœ λ°©μ§€ -->
<meta name="referrer" content="no-referrer">
<title>${curr_dir.getName().escapeHtml()}</title>
<title>${displayDirName.escapeHtml()}</title>
<style>${CSS_CONTENT}</style>
</head>
<body>
<main>
<h1>${curr_dir.getName().escapeHtml()}</h1>
<h1>${displayDirName.escapeHtml()}</h1>
<nav aria-label="디렉토리 λͺ©λ‘">
<ul role="list">
<li><a class="dir-link" href="./.." aria-label="μƒμœ„ λ””λ ‰ν† λ¦¬λ‘œ 이동" title="μƒμœ„ λ””λ ‰ν† λ¦¬λ‘œ 이동"><span class="icon" aria-hidden="true">&#x21B0;</span> <span>..</span></a></li>
Expand Down
14 changes: 14 additions & 0 deletions src/test/kotlin/html4tree/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,20 @@ class MainTest {
assertFalse(hiddenDirIndexFile.exists(), "Hidden directories should not be traversed to generate index.html")
}

@Test
fun testProcessDirWithEmptyName() {
val fakeRoot = object : File(tempDir, "fakeRoot") {
override fun getName() = ""
}
fakeRoot.mkdir()
process_dir(fakeRoot)
val indexFile = File(fakeRoot, "index.html")
assertTrue(indexFile.exists())
val htmlContent = indexFile.readText()
assertTrue(htmlContent.contains("<title>${fakeRoot.absolutePath.escapeHtml()}</title>"))
assertTrue(htmlContent.contains("<h1>${fakeRoot.absolutePath.escapeHtml()}</h1>"))
}
Comment on lines +151 to +163

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ”’ Security & Privacy | 🟑 Minor | ⚑ Quick win

HTML μ΄μŠ€μΌ€μ΄ν”„ 검증을 κ΅¬ν˜„κ³Ό λΆ„λ¦¬ν•˜μ‹­μ‹œμ˜€.

ν˜„μž¬ κΈ°λŒ€κ°’μ΄ fakeRoot.absolutePath.escapeHtml()λ₯Ό λ‹€μ‹œ ν˜ΈμΆœν•©λ‹ˆλ‹€. process_dirκ°€ μ΄μŠ€μΌ€μ΄ν”„λ₯Ό μƒλž΅ν•΄λ„ μž„μ‹œ κ²½λ‘œμ— 특수 λ¬Έμžκ°€ μ—†μœΌλ©΄ ν…ŒμŠ€νŠΈκ°€ 톡과할 수 μžˆμŠ΅λ‹ˆλ‹€. 특수 λ¬Έμžκ°€ ν¬ν•¨λœ 디렉토리 경둜λ₯Ό μ‚¬μš©ν•˜κ³  μ˜ˆμƒ HTML에 κ³ μ •λœ μ΄μŠ€μΌ€μ΄ν”„ κ²°κ³Όλ₯Ό κ²€μ¦ν•˜μ‹­μ‹œμ˜€.

μˆ˜μ • μ˜ˆμ‹œ
-        val fakeRoot = object : File(tempDir, "fakeRoot") {
+        val fakeRoot = object : File(tempDir, "fake&root") {
             override fun getName() = ""
         }
...
-        assertTrue(htmlContent.contains("<title>${fakeRoot.absolutePath.escapeHtml()}</title>"))
-        assertTrue(htmlContent.contains("<h1>${fakeRoot.absolutePath.escapeHtml()}</h1>"))
+        val expectedPath = fakeRoot.absolutePath.replace("&", "&amp;")
+        assertTrue(htmlContent.contains("<title>$expectedPath</title>"))
+        assertTrue(htmlContent.contains("<h1>$expectedPath</h1>"))
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
fun testProcessDirWithEmptyName() {
val fakeRoot = object : File(tempDir, "fakeRoot") {
override fun getName() = ""
}
fakeRoot.mkdir()
process_dir(fakeRoot)
val indexFile = File(fakeRoot, "index.html")
assertTrue(indexFile.exists())
val htmlContent = indexFile.readText()
assertTrue(htmlContent.contains("<title>${fakeRoot.absolutePath.escapeHtml()}</title>"))
assertTrue(htmlContent.contains("<h1>${fakeRoot.absolutePath.escapeHtml()}</h1>"))
}
`@Test`
fun testProcessDirWithEmptyName() {
val fakeRoot = object : File(tempDir, "fake&root") {
override fun getName() = ""
}
fakeRoot.mkdir()
process_dir(fakeRoot)
val indexFile = File(fakeRoot, "index.html")
assertTrue(indexFile.exists())
val htmlContent = indexFile.readText()
val expectedPath = fakeRoot.absolutePath.replace("&", "&amp;")
assertTrue(htmlContent.contains("<title>$expectedPath</title>"))
assertTrue(htmlContent.contains("<h1>$expectedPath</h1>"))
}
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/kotlin/html4tree/MainTest.kt` around lines 151 - 163, Update
testProcessDirWithEmptyName to create the temporary directory under a path
containing HTML-special characters, ensuring escaping is exercised. Replace
expected values that call escapeHtml() with fixed strings representing the
correctly escaped absolute path, and keep asserting both the title and h1
output.


@Test
fun testReadFileIdentityMissingPathIsUnreadable() {
val identity = read_file_identity(File(tempDir, "missing"))
Expand Down
Loading