Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@
## 2025-01-24 - 단일 readAttributes 호출로 파일 속성 조회 최적화
**학습:** `isDirectory`, `!it.isDirectory()`, `isSymbolicLink` 3개의 개별적인 파일 시스템 I/O 호출을 수행하면 성능 저하가 큽니다. 이를 단일 `Files.readAttributes` 호출로 변경하여 메타데이터를 한 번에 조회함으로써 I/O 오버헤드를 대폭 줄일 수 있음을 확인했습니다.
**조치:** 디렉토리 순회 시 파일의 여러 속성을 확인할 때는 개별적인 stat 호출보다 `Files.readAttributes`를 사용하여 필요한 모든 속성을 한 번에 가져오는 방식을 우선적으로 고려해야 합니다.
## 2026-07-27 - 디렉토리 처리 루프 내 정적 자원 및 해시 계산 추출
**Learning:** 디렉토리를 순회하며 처리하는 루프(`process_dir`) 내부에서 정적 CSS 문자열과 SHA-256 해시를 매번 생성하면 불필요한 객체 할당과 CPU 오버헤드가 발생합니다. 하지만 이를 단순히 외부로 빼면 Kotlin 컴파일러가 암시적 getter를 생성해 JaCoCo 100% 커버리지 유지가 어려울 수 있습니다.
**Action:** 큰 정적 문자열이나 결정론적 계산 결과는 `private object`로 추출하되, `const val`과 `@JvmField`를 적용하여 런타임 성능을 최적화하는 동시에 컴파일러의 암시적 메서드 생성을 막아 100% 테스트 커버리지를 방어해야 합니다.
19 changes: 11 additions & 8 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,8 @@ fun write_index_file(curr_dir: File, content: String) {
}
}

fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array<File>? = null){

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

val cssContent = """
private object HtmlConstants {
const val cssContent = """
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.5;
Expand Down Expand Up @@ -310,12 +307,18 @@ fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array
}
"""

@JvmField
val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8)))

val css = """
const val css = """
<style>
${cssContent} </style>
Comment on lines +310 to 315

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

CSP 해시 입력과 실제 <style> 본문을 동일하게 맞춰야 합니다.

styleHashcssContent만 해시하지만, Line [315]에서는 ${cssContent} 뒤에 공백을 추가한 후 </style>을 붙입니다. CSP 해시는 실제 인라인 스타일 본문과 정확히 일치해야 하므로 브라우저가 이 스타일을 차단하고 생성된 HTML의 CSS가 적용되지 않습니다. (w3.org)

닫는 태그를 보간 결과에 바로 붙이고, MainTest.kt에서도 실제 스타일 본문과 해시가 일치하는지 검증하세요.

수정 예시
               <style>
-${cssContent}              </style>
+${cssContent}</style>
               """
📝 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
@JvmField
val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8)))
val css = """
const val css = """
<style>
${cssContent} </style>
`@JvmField`
val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8)))
const val css = """
<style>
${cssContent}</style>
🤖 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/main/kotlin/html4tree/main.kt` around lines 310 - 315, Align the `css`
template’s inline style body with the input used by `styleHash`: remove the
whitespace inserted between `${cssContent}` and `</style>` so the hashed content
is identical to the rendered style content. Update `MainTest.kt` to verify that
the generated style body and `styleHash` correspond exactly.

"""
Comment on lines +313 to 316
}

fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array<File>? = null){

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

val index_top = """<!doctype html>
<html lang="ko">
Expand All @@ -324,11 +327,11 @@ ${cssContent} </style>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<!-- 보안 향상: 인라인 스크립트 실행 방지 -->
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src '${styleHash}'; base-uri 'none'; form-action 'none';">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src '${HtmlConstants.styleHash}'; base-uri 'none'; form-action 'none';">
<!-- 보안 향상: 리퍼러를 통한 디렉토리 경로 노출 방지 -->
<meta name="referrer" content="no-referrer">
<title>${curr_dir.getName().escapeHtml()}</title>
${css}
${HtmlConstants.css}
</head>
<body>
<main>
Expand Down
Loading