moosey-cms 0.4.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
moosey_cms/filters.py CHANGED
@@ -472,6 +472,43 @@ def read_time(text: str) -> str:
472
472
  return "1 min read"
473
473
  return f"{minutes} min read"
474
474
 
475
+
476
+ # ============================================================================
477
+ # HTML UTILITIES
478
+ # ============================================================================
479
+
480
+ def strip_comments(text, enabled=True):
481
+ """
482
+ Removes HTML comments from the output.
483
+ Usage: {% filter strip_comments(enabled=True) %} ... {% endfilter %}
484
+ """
485
+ if not enabled or not text:
486
+ return text
487
+
488
+ # Regex: Matches <!-- followed by anything (including newlines) until -->
489
+ # The *? ensures it is non-greedy (stops at the first closing tag)
490
+ return re.sub(r'<!--[\s\S]*?-->', '', str(text))
491
+
492
+ def minify_html(text, enabled=True):
493
+ """
494
+ Minifies HTML by removing unnecessary whitespace and newlines.
495
+ WARNING: This is a regex-based minifier. It does not respect <pre> tags.
496
+ """
497
+ if not enabled or not text:
498
+ return text
499
+
500
+ text = str(text)
501
+
502
+ # 1. Normalize whitespace:
503
+ # Replace sequences of whitespace (tabs, newlines) with a single space
504
+ text = re.sub(r'\s+', ' ', text)
505
+
506
+ # 2. Remove space between tags:
507
+ # Turns "</div> <div..." into "</div><div..."
508
+ text = re.sub(r'>\s+<', '><', text)
509
+
510
+ return text.strip()
511
+
475
512
  # ============================================================================
476
513
  # REGISTRATION FUNCTION
477
514
  # ============================================================================
@@ -511,7 +548,9 @@ def register_filters(jinja_env):
511
548
  'filesize': filesize,
512
549
  'default_if_none': default_if_none,
513
550
  'yesno': yesno,
514
- 'read_time':read_time
551
+ 'read_time':read_time,
552
+ 'strip_comments': strip_comments,
553
+ 'minify_html': minify_html
515
554
  }
516
555
 
517
556
  for name, func in filters_dict.items():
@@ -17,11 +17,13 @@ class ScriptInjectorMiddleware(BaseHTTPMiddleware):
17
17
  self.script = script
18
18
 
19
19
  async def dispatch(self, request: Request, call_next):
20
+
20
21
  # Process the request and get the response
21
22
  response = await call_next(request)
22
23
 
23
24
  # We only want to touch HTML pages, not JSON APIs or Images
24
25
  content_type = response.headers.get("content-type", "")
26
+
25
27
  # get content length
26
28
  content_length = response.headers.get("content-length")
27
29
 
@@ -29,11 +31,10 @@ class ScriptInjectorMiddleware(BaseHTTPMiddleware):
29
31
  if "text/html" not in content_type:
30
32
  return response
31
33
 
32
- # Skip if too big (e.g. > 20KB) to prevent Memory DoS
33
- if content_length and int(content_length) > 20 * 1024 :
34
+ # Skip if too big (e.g. > 10mb) to prevent Memory DoS
35
+ if content_length and int(content_length) > 10 * 1024 * 1024 :
34
36
  return response
35
37
 
36
-
37
38
  # Read the response body
38
39
  # Note: Response body is a stream, we must consume it to modify it
39
40
  response_body = [section async for section in response.body_iterator]
@@ -51,6 +52,7 @@ class ScriptInjectorMiddleware(BaseHTTPMiddleware):
51
52
  # Fallback: Just append if no body tag found
52
53
  full_body += injection
53
54
 
55
+
54
56
  # Create a NEW Response object
55
57
  # We cannot modify the existing response easily because Content-Length
56
58
  # would be wrong. Creating a new one recalculates headers.
@@ -69,6 +71,7 @@ class ScriptInjectorMiddleware(BaseHTTPMiddleware):
69
71
 
70
72
 
71
73
  def inject_script_middleware(app, host, port):
74
+ # print('>>>>>>IIIIII')
72
75
  # Your custom script to inject
73
76
  package_root = Path(__file__).resolve().parent
74
77
  javascript_file = package_root / "static" / "js" / "reload-script.js"
@@ -85,6 +88,8 @@ def inject_script_middleware(app, host, port):
85
88
  f"{host}:{port}",
86
89
  )
87
90
 
91
+ # print('RELOAD ', script_data)
92
+
88
93
  # Add the middleware
89
94
  app.add_middleware(
90
95
  ScriptInjectorMiddleware, script=f"<script>{script_data}</script>"
moosey_cms/main.py CHANGED
@@ -24,6 +24,30 @@ from .hot_reload_script import inject_script_middleware
24
24
 
25
25
  from fastapi import WebSocket, WebSocketDisconnect
26
26
 
27
+ from jinja2 import Environment, FileSystemLoader
28
+ from jinja2.ext import Extension
29
+ import re
30
+
31
+ class AutoRemoveCommentsExtension(Extension):
32
+ """Automatically removes HTML comments from all included files"""
33
+
34
+ def __init__(self, environment):
35
+ super().__init__(environment)
36
+
37
+ # Store original include function
38
+ original_include = environment.globals['include']
39
+
40
+ # Create wrapper that removes comments
41
+ def include_no_comments(template_name, **kwargs):
42
+ # Get the included template
43
+ included = environment.get_template(template_name)
44
+ rendered = included.render(**kwargs)
45
+ # Remove comments
46
+ return re.sub(r'<!--.*?-->', '', rendered, flags=re.DOTALL)
47
+
48
+ # Replace include function
49
+ environment.globals['include_no_comments'] = include_no_comments
50
+
27
51
 
28
52
  class ConnectionManager:
29
53
  def __init__(self):
@@ -81,6 +105,7 @@ def init_cms(
81
105
  # This ensures site_data is available in 404.html and base.html automatically
82
106
  templates.env.globals["site_data"] = site_data
83
107
  templates.env.globals["mode"] = mode
108
+
84
109
 
85
110
  # Register all custom filters once
86
111
  filters.register_filters(templates.env)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moosey-cms
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.9
6
6
  Requires-Dist: cachetools>=6.2.4
@@ -259,6 +259,8 @@ Moosey CMS comes packed with a comprehensive library of Jinja2 filters to help y
259
259
 
260
260
  ---
261
261
 
262
+ [Read More On Filters](docs/filters.md) and how to use some interesting ones such as stripping comments.
263
+
262
264
  ## ⚙️ Configuration Reference
263
265
 
264
266
  The `init_cms` function accepts the following parameters:
@@ -0,0 +1,14 @@
1
+ moosey_cms/__init__.py,sha256=y7gzxC1LB7qRmjqJHJpN4kEqBNAbuIwNc4xeEI2clMY,184
2
+ moosey_cms/cache.py,sha256=YI6rRb4OVi-Mb1CmMW-jRz0CC9U6YZyszqLmjqLOsq8,2067
3
+ moosey_cms/file_watcher.py,sha256=0miTFpKZuT8aZPTByC0OVRr8A0mIG-fgPGrz2QfMG1k,915
4
+ moosey_cms/filters.py,sha256=8bMVixNbjlnOMfxXATpj4K1xRIxLrIZf8W-c6ecFpHg,17255
5
+ moosey_cms/helpers.py,sha256=m94mDAaDKiH6wvzqoICQuavJ53EVTJ5VmJiRsfLT38o,10277
6
+ moosey_cms/hot_reload_script.py,sha256=394R-AtjCWEMjLp1ONdvzfg6ETp8TXMF8psoklW_z5c,3074
7
+ moosey_cms/main.py,sha256=oj_tePjiZXeOT4ujv8dMqodgZ7n5OCUYr5wROFboYwg,9815
8
+ moosey_cms/md.py,sha256=m857SKApJkK62wNrMVsypuJAqumbBt5GuPvcnuN1O6w,4970
9
+ moosey_cms/models.py,sha256=kYNIf7utTq94PUdqqZXfil5vpp0wciI5UgqRHJ56A0E,3070
10
+ moosey_cms/seo.py,sha256=jQ2FVuELNoytJkbp0ILK_IF7sZSaz9fkl59HM7xlg70,5246
11
+ moosey_cms/static/js/reload-script.js,sha256=hnrVXEWeTK-Y2vLeADmtlZ7fOXpDJMF-0zK09o3mrOA,2247
12
+ moosey_cms-0.6.0.dist-info/METADATA,sha256=ghuwQT1ZZXLEtG_zLQT9-AzWdpDuLx5PcR7KAAM0iB4,11005
13
+ moosey_cms-0.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
14
+ moosey_cms-0.6.0.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- 3.12
moosey_cms/py.typed DELETED
File without changes
moosey_cms/pyproject.toml DELETED
@@ -1,28 +0,0 @@
1
- [project]
2
- name = "moosey-cms"
3
- version = "0.1.0"
4
- description = "A drop-in Markdown CMS for FastAPI with Hot Reloading"
5
- readme = "README.md"
6
- requires-python = ">=3.12"
7
- dependencies = [
8
- "cachetools>=6.2.4",
9
- "inflection>=0.5.1",
10
- "jinja2>=3.1.6",
11
- "markdown>=3.10",
12
- "pymdown-extensions>=10.20",
13
- "python-frontmatter>=1.1.0",
14
- "python-slugify>=8.0.4",
15
- "slugify>=0.0.1",
16
- ]
17
-
18
- [build-system]
19
- requires = ["hatchling"]
20
- build-backend = "hatchling.build"
21
-
22
- # --- CRITICAL: INCLUDE STATIC FILES ---
23
- [tool.hatch.build.targets.wheel]
24
- packages = ["src/moosey_cms"]
25
-
26
- # This forces the inclusion of non-python files inside the package
27
- [tool.hatch.build.targets.wheel.force-include]
28
- "src/simple_cms/static" = "moosey_cms/static"
@@ -1,17 +0,0 @@
1
- moosey_cms/.python-version,sha256=e1X45ntWI8S-8_ppEojalDfXnTq6FW3kjUgdsyrH0W0,5
2
- moosey_cms/__init__.py,sha256=y7gzxC1LB7qRmjqJHJpN4kEqBNAbuIwNc4xeEI2clMY,184
3
- moosey_cms/cache.py,sha256=YI6rRb4OVi-Mb1CmMW-jRz0CC9U6YZyszqLmjqLOsq8,2067
4
- moosey_cms/file_watcher.py,sha256=0miTFpKZuT8aZPTByC0OVRr8A0mIG-fgPGrz2QfMG1k,915
5
- moosey_cms/filters.py,sha256=QIHeffZAxn4KqQE4zwR4D7njE96L-oeqHc5DYrYgCpw,15983
6
- moosey_cms/helpers.py,sha256=m94mDAaDKiH6wvzqoICQuavJ53EVTJ5VmJiRsfLT38o,10277
7
- moosey_cms/hot_reload_script.py,sha256=Dflj5hgHVkVOfjeU7wzEUeVTt684nj22et8jKzVFEGw,2987
8
- moosey_cms/main.py,sha256=VDRbhmGUpyar8ZY4Dv33YQ1_bQX-vkgQFNgN_ckXqY4,8926
9
- moosey_cms/md.py,sha256=m857SKApJkK62wNrMVsypuJAqumbBt5GuPvcnuN1O6w,4970
10
- moosey_cms/models.py,sha256=kYNIf7utTq94PUdqqZXfil5vpp0wciI5UgqRHJ56A0E,3070
11
- moosey_cms/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- moosey_cms/pyproject.toml,sha256=lFRsY2yJOKtDWJc-Mfq9s0teGrhmB3ALDJyMltjBOGg,735
13
- moosey_cms/seo.py,sha256=jQ2FVuELNoytJkbp0ILK_IF7sZSaz9fkl59HM7xlg70,5246
14
- moosey_cms/static/js/reload-script.js,sha256=hnrVXEWeTK-Y2vLeADmtlZ7fOXpDJMF-0zK09o3mrOA,2247
15
- moosey_cms-0.4.0.dist-info/METADATA,sha256=LrcBDpkWXF8ya0GC6cc_zCxvmADK6JaVFpo51hWLBhM,10899
16
- moosey_cms-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
17
- moosey_cms-0.4.0.dist-info/RECORD,,