Skip to content
Merged
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
75 changes: 51 additions & 24 deletions generate_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,36 +77,56 @@ def copy_vendor_files(self, output_dir: str) -> None:

def rewrite_html_content(self, content: str) -> str:
"""
Rewrite known CDN asset URLs in an HTML document to their corresponding local vendor paths.

Replaces specific external CDN links (React, Babel, Tailwind, PrismJS, FontAwesome, etc.) with local /vendor/... paths so the returned HTML references vendored assets.

Rewrite CDN asset URLs in HTML to local /vendor/ paths.

Replaces known external CDN links (React, Babel, Tailwind, PrismJS, FontAwesome, etc.) with corresponding /vendor/... paths and removes `integrity` and `crossorigin` attributes from `<link>` and `<script>` tags that reference those local vendor files.

Parameters:
content (str): HTML document content to rewrite.

Returns:
The input HTML string with matched CDN URLs substituted by local vendor URLs.
str: The HTML content with matching CDN URLs substituted by local vendor URLs and SRI/crossorigin attributes stripped for vendored assets.
"""
replacements = [
# React
('https://unpkg.com/react@18/umd/react.development.js', '/vendor/react/react.development.js'),
('https://unpkg.com/react@18/umd/react.production.min.js', '/vendor/react/react.production.min.js'),
('https://unpkg.com/react-dom@18/umd/react-dom.development.js', '/vendor/react-dom/react-dom.development.js'),
('https://unpkg.com/react-dom@18/umd/react-dom.production.min.js', '/vendor/react-dom/react-dom.production.min.js'),
(r'https://unpkg\.com/react@[^/]+/umd/react\.development\.js', '/vendor/react/react.development.js'),
(r'https://unpkg\.com/react@[^/]+/umd/react\.production\.min\.js', '/vendor/react/react.production.min.js'),
(r'https://unpkg\.com/react-dom@[^/]+/umd/react-dom\.development\.js', '/vendor/react-dom/react-dom.development.js'),
(r'https://unpkg\.com/react-dom@[^/]+/umd/react-dom\.production\.min\.js', '/vendor/react-dom/react-dom.production.min.js'),
# Babel
('https://unpkg.com/@babel/standalone/babel.min.js', '/vendor/babel/babel.min.js'),
('https://unpkg.com/@babel/standalone/babel.js', '/vendor/babel/babel.min.js'),
(r'https://unpkg\.com/@babel/standalone(?:@[^/]+)?/babel\.min\.js', '/vendor/babel/babel.min.js'),
(r'https://unpkg\.com/@babel/standalone(?:@[^/]+)?/babel\.js', '/vendor/babel/babel.min.js'),
# Tailwind
('https://cdn.tailwindcss.com', '/vendor/tailwindcss/script.js'),
(r'https://cdn\.tailwindcss\.com(?:@[^/]+)?', '/vendor/tailwindcss/script.js'),
# PrismJS
# Handle minified vs unminified mapping. Node modules usually has unminified.
# We map the CDN .min.css requests to our local .css files (which we copied from node_modules)
('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css', '/vendor/prismjs/themes/prism.css'),
('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css', '/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css'),
('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css', '/vendor/prismjs/plugins/toolbar/prism-toolbar.css'),
(r'https://cdnjs\.cloudflare\.com/ajax/libs/prism/[^/]+/themes/prism\.min\.css', '/vendor/prismjs/themes/prism.css'),
(r'https://cdnjs\.cloudflare\.com/ajax/libs/prism/[^/]+/plugins/line-numbers/prism-line-numbers\.min\.css', '/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css'),
(r'https://cdnjs\.cloudflare\.com/ajax/libs/prism/[^/]+/plugins/toolbar/prism-toolbar\.min\.css', '/vendor/prismjs/plugins/toolbar/prism-toolbar.css'),
# FontAwesome
('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css', '/vendor/fontawesome/css/all.min.css'),
(r'https://cdnjs\.cloudflare\.com/ajax/libs/font-awesome/[^/]+/css/all\.min\.css', '/vendor/fontawesome/css/all.min.css'),
]

for old, new in replacements:
content = content.replace(old, new)
for pattern_str, new in replacements:
content = re.sub(pattern_str, new, content)

# Strip integrity and crossorigin attributes from tags referencing local /vendor/ files
def strip_sri(match):
"""
Remove Subresource Integrity (`integrity`) and `crossorigin` attributes from an HTML <link> or <script> tag if the tag references a `/vendor/` path.

Parameters:
match (re.Match): A regex match object whose matched text is the full HTML tag.

Returns:
str: The original tag text with `integrity` and `crossorigin` attributes removed when the tag contains `/vendor/`; otherwise the original tag text unchanged.
"""
tag_text = match.group(0)
if '/vendor/' in tag_text:
tag_text = re.sub(r'\s*integrity="[^"]+"', '', tag_text)
tag_text = re.sub(r'\s*crossorigin="[^"]+"', '', tag_text)
return tag_text

content = re.sub(r'<(?:link|script)[^>]+>', strip_sri, content)

return content

Expand Down Expand Up @@ -174,6 +194,12 @@ def generate_index(self) -> None:
title = self.get_html_title(filepath)
except Exception:
title = os.path.basename(filepath)

# Append disambiguator if 'detailed' is in the filename
if 'detailed' in filename.lower():
if '(detailed)' not in title.lower():
title += ' (detailed)'

structure[category].append((title, rel_path))

# Sort categories and files
Expand Down Expand Up @@ -891,11 +917,11 @@ def generate_index(self) -> None:
def render_category_files(structure, sorted_categories):
"""
Builds HTML fragments for category tabs, per-category file lists, and an aggregated all-files list.

Parameters:
structure (Dict[str, List[Tuple[str, str]]]): Mapping from category name to a list of (title, relative_path) pairs for files in that category.
sorted_categories (List[str]): Ordered list of category names to render; determines the iteration order and tab order.

Returns:
Tuple[str, str, str]: A 3-tuple with:
- tabs_html: HTML for the category tab buttons (includes icon and item count for each category).
Expand Down Expand Up @@ -925,7 +951,8 @@ def render_category_files(structure, sorted_categories):
safe_title = html.escape(title)
safe_github_path = html.escape(github_path) # Escape path for display

item_html = f'<li class="file-item" data-category="{css_cat}"><a class="file-link" href="{encoded_path}">' \
safe_encoded_path = html.escape(encoded_path, quote=True)
item_html = f'<li class="file-item" data-category="{css_cat}"><a class="file-link" href="{safe_encoded_path}">' \
f'<span class="card-header"><span class="card-icon">{icon}</span>' \
f'<span class="card-title">{safe_title}</span></span><span class="file-path">{safe_github_path}</span></a></li>\n'
category_files.append(item_html)
Expand Down Expand Up @@ -955,4 +982,4 @@ def render_category_files(structure, sorted_categories):
print(f"Successfully updated {output_index_path} with vendored assets at {current_time}")

if __name__ == "__main__":
Solution().generate_index()
Solution().generate_index()
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ <h4 class="font-bold text-blue-900 mb-2">💡 最適化ポイント</h4>
></script>

<!-- Babel Standalone -->
<script src="https://unpkg.com/@babel/standalone@7.24.0/babel.min.js"></script>
<script src="/vendor/babel/babel.min.js"></script>

<!-- Prism.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<!-- Icons -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
href="/vendor/fontawesome/css/all.min.css"
/>

<style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
rel="stylesheet"
/>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
href="/vendor/fontawesome/css/all.min.css"
rel="stylesheet"
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
crossorigin="anonymous"
href="/vendor/fontawesome/css/all.min.css"
referrerpolicy="no-referrer"
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
crossorigin="anonymous"
href="/vendor/fontawesome/css/all.min.css"
referrerpolicy="no-referrer"
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

<!-- Font Awesome (icons) -->
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
href="/vendor/fontawesome/css/all.min.css"
rel="stylesheet"
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<!-- Font Awesome (任意 / SRIなし) -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
href="/vendor/fontawesome/css/all.min.css"
/>

<!-- Prism CSS (SRIなし) -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@
<link
href="/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css"
rel="stylesheet"
integrity="sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv"
crossorigin="anonymous"
/>
<link
href="/vendor/prismjs/plugins/toolbar/prism-toolbar.css"
rel="stylesheet"
integrity="sha384-EUzJ34/1CCeefTGUKLgvA5Z/vYIwi+Jyu8aAaCfFDxfwZ3Xs3OfkkIeegsLRM11e"
crossorigin="anonymous"
/>

<style>
Expand Down Expand Up @@ -1149,18 +1145,14 @@ <h3 class="text-xl font-semibold text-teal-800 mt-8 mb-4">実装方法の比較<

<!-- React & ReactDOM -->
<script
src="https://unpkg.com/react@18.3.1/umd/react.production.min.js"
integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z"
crossorigin="anonymous"
src="/vendor/react/react.production.min.js"
></script>
<script
src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"
integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1"
crossorigin="anonymous"
src="/vendor/react-dom/react-dom.production.min.js"
></script>

<!-- Babel Standalone -->
<script src="https://unpkg.com/@babel/standalone@7.23.5/babel.min.js" integrity="sha384-1qlE7MZPM2pHD/pBZCU/yB8UCP52RYL8bge/qNdfNBCWToySp8/M+JL2waXU4hjJ" crossorigin="anonymous"></script>
<script src="/vendor/babel/babel.min.js"></script>

<!-- Prism.js & Plugins (SRI Protected) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js" integrity="sha384-06z5D//U/xpvxZHuUz92xBvq3DqBBFi7Up53HRrbV7Jlv7Yvh/MZ7oenfUe9iCEt" crossorigin="anonymous"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,23 @@
<link
rel="stylesheet"
href="/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css"
integrity="sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="/vendor/prismjs/plugins/toolbar/prism-toolbar.css"
integrity="sha384-EUzJ34/1CCeefTGUKLgvA5Z/vYIwi+Jyu8aAaCfFDxfwZ3Xs3OfkkIeegsLRM11e"
crossorigin="anonymous"
/>

<!-- React & ReactDOM (Production) -->
<script
crossorigin="anonymous"
src="https://unpkg.com/react@18.3.1/umd/react.production.min.js"
integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z"
src="/vendor/react/react.production.min.js"
></script>
<script
crossorigin="anonymous"
src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"
integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1"
src="/vendor/react-dom/react-dom.production.min.js"
></script>

<!-- Babel Standalone -->
<script
src="https://unpkg.com/@babel/standalone@7.26.9/babel.min.js"
integrity="sha384-pKNXKj7jF9BNMkQyGWg5YLfoPyqBa/gf7wjTSoTGQlwxbZB+sabJuKyOHR6JQvTd"
crossorigin="anonymous"
src="/vendor/babel/babel.min.js"
></script>

<style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,23 @@
<link
rel="stylesheet"
href="/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css"
integrity="sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="/vendor/prismjs/plugins/toolbar/prism-toolbar.css"
integrity="sha384-EUzJ34/1CCeefTGUKLgvA5Z/vYIwi+Jyu8aAaCfFDxfwZ3Xs3OfkkIeegsLRM11e"
crossorigin="anonymous"
/>

<!-- React & ReactDOM -->
<script
crossorigin="anonymous"
src="/vendor/react/react.production.min.js"
integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z"
></script>
<script
crossorigin="anonymous"
src="/vendor/react-dom/react-dom.production.min.js"
integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1"
></script>

<!-- Babel Standalone -->
<script
src="/vendor/babel/babel.min.js"
integrity="sha384-Fo0OdKhdnE7y2WmzjOMW4PYjHkkANeu1501pWTqKrzAPeJMFQb4ZTdAA9dtrVUJV"
crossorigin="anonymous"
></script>
<!-- Note: Runtime transpilation is for demos only. -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,6 @@ <h3 class="text-xl font-bold text-teal-800 mb-3">実装比較</h3>
<!-- Babel Standalone -->
<script
src="/vendor/babel/babel.min.js"
crossorigin="anonymous"
></script>

<!-- Prism.js -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@
<title>LeetCode 2629 - Function Composition</title>
<script
src="/vendor/react/react.production.min.js"
integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z"
crossorigin="anonymous"
></script>
<script
src="/vendor/react-dom/react-dom.production.min.js"
integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1"
crossorigin="anonymous"
></script>
<script
src="/vendor/babel/babel.min.js"
integrity="sha384-Fo0OdKhdnE7y2WmzjOMW4PYjHkkANeu1501pWTqKrzAPeJMFQb4ZTdAA9dtrVUJV"
crossorigin="anonymous"
></script>
<script src="/vendor/tailwindcss/script.js"></script>
<link
Expand All @@ -33,8 +27,6 @@
<link
rel="stylesheet"
href="/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css"
integrity="sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv"
crossorigin="anonymous"
/>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,13 @@
<title>Akash and Akhil — ボール逆順ゲーム O(1) 解法</title>
<script
src="/vendor/react/react.production.min.js"
integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z"
crossorigin="anonymous"
></script>
<script
src="/vendor/react-dom/react-dom.production.min.js"
integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fsDUf5YJj1"
crossorigin="anonymous"
></script>
<!-- Babel standalone is required for in-browser JSX transpilation -->
<script
src="/vendor/babel/babel.min.js"
integrity="sha384-Fo0OdKhdnE7y2WmzjOMW4PYjHkkANeu1501pWTqKrzAPeJMFQb4ZTdAA9dtrVUJV"
crossorigin="anonymous"
></script>
<!-- Tailwind CDN generates CSS dynamically; SRI is not applicable -->
<script src="/vendor/tailwindcss/script.js"></script>
Expand All @@ -35,14 +29,10 @@
/>
<link
href="/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css"
integrity="sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv"
crossorigin="anonymous"
rel="stylesheet"
/>
<link
href="/vendor/prismjs/plugins/toolbar/prism-toolbar.css"
integrity="sha384-EUzJ34/1CCeefTGUKLgvA5Z/vYIwi+Jyu8aAaCfFDxfwZ3Xs3OfkkIeegsLRM11e"
crossorigin="anonymous"
rel="stylesheet"
/>
<style>
Expand Down
Loading