|
| 1 | +from typing import Dict, List, Optional, Tuple |
1 | 2 | from mkdocs.plugins import BasePlugin
|
2 |
| -from mkdocs.config import config_options |
3 | 3 | import os
|
4 | 4 |
|
| 5 | + |
5 | 6 | class DefaultMetaPlugin(BasePlugin):
|
6 |
| - # A mapping for special case language names |
7 |
| - SPECIAL_CASES = { |
8 |
| - 'typescript': 'TypeScript', |
9 |
| - 'javascript': 'JavaScript', |
10 |
| - 'csharp': 'C#', |
11 |
| - 'objective-c': 'Objective-C', |
| 7 | + """ |
| 8 | + An MkDocs plugin that automatically generates and updates meta tags |
| 9 | + for pages with enhanced descriptions, keywords, and Open Graph properties. |
| 10 | + """ |
| 11 | + |
| 12 | + LANGUAGES: Dict[str, str] = { |
| 13 | + 'cpp': 'C++', 'c': 'C', 'csharp': 'C#', 'css': 'CSS', 'dart': 'Dart', 'go': 'Go', |
| 14 | + 'html': 'HTML', 'java': 'Java', 'javascript': 'JavaScript', 'json': 'JSON', |
| 15 | + 'kotlin': 'Kotlin', 'markdown': 'Markdown', 'objective-c': 'Objective-C', |
| 16 | + 'php': 'PHP', 'python': 'Python', 'ruby': 'Ruby', 'rust': 'Rust', 'scala': 'Scala', |
| 17 | + 'shell': 'Shell', 'sql': 'SQL', 'swift': 'Swift', 'typescript': 'TypeScript', |
| 18 | + } |
| 19 | + |
| 20 | + PAGE_TITLES: Dict[str, str] = { |
| 21 | + 'index': 'Home', 'about': 'About', 'contributing': 'Contributing', |
| 22 | + 'foundation': 'Foundational Code Standards', |
12 | 23 | }
|
13 | 24 |
|
14 |
| - def format_language_name(self, filename): |
| 25 | + DEFAULT_KEYWORDS: List[str] = [ |
| 26 | + 'Coding Standards', 'Programming Best Practices', 'Coding Guidelines', |
| 27 | + 'Software Development', 'Code Quality', 'Software Engineering Principles', |
| 28 | + 'Code Review Standards', 'Code Style', 'Source Code formatting', |
| 29 | + 'Programming Language Style', 'Clean Code Principles', 'Development Guidelines', |
| 30 | + 'Best Coding Practices', 'Coding Style Guides', 'Software Craftsmanship', |
| 31 | + 'Code Consistency', 'GoatBytes.IO', 'GoatStyles', 'GoatBytes', |
| 32 | + ] |
| 33 | + |
| 34 | + SITE_DESC: str = ("GoatStyles is an authoritative resource dedicated to promoting " |
| 35 | + "best practices and consistency in coding across various programming " |
| 36 | + "languages. As a comprehensive style guide repository created by " |
| 37 | + "GoatBytes.IO, it aims to elevate code quality and readability for " |
| 38 | + "developers worldwide.") |
| 39 | + |
| 40 | + def __init__(self): |
| 41 | + self.site_url: Optional[str] = None |
| 42 | + self.keywords: List[str] = [] |
| 43 | + |
| 44 | + def on_config(self, config): |
| 45 | + """Handles configuration to set site-wide settings.""" |
| 46 | + self.site_url = config.get('site_url', 'https://styles.goatbytes.io') |
| 47 | + # Reset keywords to default at the start of each build to avoid accumulation |
| 48 | + self.keywords = self.DEFAULT_KEYWORDS.copy() |
| 49 | + |
| 50 | + def format_language_name(self, filename: str) -> str: |
15 | 51 | """Format language name correctly based on filename."""
|
16 |
| - language = os.path.splitext(filename)[0] |
17 |
| - return self.SPECIAL_CASES.get(language, language.capitalize()) |
18 |
| - |
19 |
| - def on_page_markdown(self, markdown, page, config, files): |
20 |
| - # Basic site info |
21 |
| - site_url = config.get('site_url', 'https://styles.goatbytes.io') |
22 |
| - default_image = f"{site_url}assets/img/social.jpg" |
23 |
| - |
24 |
| - # Extract and format the language name from the file name |
25 |
| - language = self.format_language_name(os.path.basename(page.file.src_path)) |
26 |
| - custom_title = f"{language} Code Style Guide | GoatStyles" |
27 |
| - custom_description = f"The official {language} code style guide used by GoatBytes.IO." |
28 |
| - |
29 |
| - # Default meta tags with dynamic title and description |
30 |
| - defaults = [ |
31 |
| - {'name': 'description', 'content': custom_description}, |
32 |
| - {'property': 'og:type', 'content': 'website'}, |
33 |
| - {'property': 'og:title', 'content': custom_title}, |
34 |
| - {'property': 'og:description', 'content': custom_description}, |
35 |
| - {'property': 'og:image', 'content': default_image}, |
36 |
| - {'property': 'og:url', 'content': site_url}, |
37 |
| - {'name': 'twitter:card', 'content': 'summary_large_image'}, |
38 |
| - {'name': 'twitter:title', 'content': custom_title}, |
39 |
| - {'name': 'twitter:description', 'content': custom_description}, |
40 |
| - {'name': 'twitter:image', 'content': default_image}, |
| 52 | + base = os.path.splitext(filename)[0] |
| 53 | + return self.LANGUAGES.get(base, base.capitalize()) |
| 54 | + |
| 55 | + def get_language_keywords(self, language: str) -> List[str]: |
| 56 | + """Generate keywords specific to a programming language.""" |
| 57 | + return [ |
| 58 | + f"{language} Style Guide", |
| 59 | + f"{language} Syntax Rules", |
| 60 | + f"{language} Coding Conventions" |
41 | 61 | ]
|
42 | 62 |
|
43 |
| - # Initialize or update page meta |
44 |
| - if 'meta' not in page.meta: |
45 |
| - page.meta['meta'] = defaults |
| 63 | + def format_page_title_and_description(self, filename: str) -> Tuple[str, str]: |
| 64 | + """Generate title and description based on filename.""" |
| 65 | + base, _ = os.path.splitext(filename) |
| 66 | + if base in self.PAGE_TITLES: |
| 67 | + title = self.PAGE_TITLES[base] |
| 68 | + description = self.SITE_DESC |
| 69 | + elif base in self.LANGUAGES: |
| 70 | + lang = self.LANGUAGES[base] |
| 71 | + # Extend keywords list with language-specific keywords |
| 72 | + self.keywords.extend(self.get_language_keywords(lang)) |
| 73 | + title = f"{lang} Code Style Guide" |
| 74 | + description = (f"Explore the official {lang} coding conventions " |
| 75 | + "and best practices used by GoatBytes.IO.") |
46 | 76 | else:
|
47 |
| - # Update existing tags or add defaults if missing |
48 |
| - existing_tags = {tag.get('name') or tag.get('property'): tag for tag in page.meta['meta']} |
49 |
| - for default in defaults: |
50 |
| - key = default.get('name') or default.get('property') |
51 |
| - if key not in existing_tags: |
52 |
| - page.meta['meta'].append(default) |
53 |
| - elif key in ['description', 'og:title', 'og:description', 'twitter:title', 'twitter:description']: |
54 |
| - # Update content for specific tags if they already exist |
55 |
| - existing_tags[key]['content'] = default['content'] |
| 77 | + title = 'GoatStyles Documentation' |
| 78 | + description = self.SITE_DESC |
| 79 | + return title, description |
| 80 | + |
| 81 | + def on_page_markdown(self, markdown: str, page, config, files) -> str: |
| 82 | + """Add meta tags to page based on content.""" |
| 83 | + default_image = f"{self.site_url}/assets/img/goatstyles.png" |
| 84 | + page_title, custom_description = self.format_page_title_and_description( |
| 85 | + os.path.basename(page.file.src_path) |
| 86 | + ) |
| 87 | + |
| 88 | + # Ensure proper formatting and prevent duplication of meta tags |
| 89 | + defaults = self.generate_default_meta(page_title, custom_description, default_image) |
| 90 | + |
| 91 | + # Initialize or update page meta |
| 92 | + page.meta.setdefault('meta', []).extend( |
| 93 | + [tag for tag in defaults if tag not in page.meta['meta']] |
| 94 | + ) |
56 | 95 |
|
57 | 96 | return markdown
|
| 97 | + |
| 98 | + def generate_default_meta(self, title: str, description: str, image: str) -> List[Dict]: |
| 99 | + """Generates a list of default meta tags.""" |
| 100 | + |
| 101 | + # Ensure the image URL does not have double slashes (except after "http:") |
| 102 | + image = image.replace("//assets", "/assets") |
| 103 | + return [ |
| 104 | + {'name': 'description', 'content': description}, |
| 105 | + {'name': 'keywords', 'content': ', '.join(self.keywords)}, |
| 106 | + {'property': 'og:type', 'content': 'website'}, |
| 107 | + {'property': 'og:url', 'content': self.site_url}, |
| 108 | + {'property': 'og:site_name', 'content': 'GoatStyles'}, |
| 109 | + {'property': 'og:title', 'content': title}, |
| 110 | + {'property': 'og:description', 'content': description}, |
| 111 | + {'property': 'og:image', 'content': image}, |
| 112 | + {'property': 'og:image:type', 'content': 'image/png'}, |
| 113 | + {'property': 'og:image:width', 'content': '1200'}, |
| 114 | + {'property': 'og:image:height', 'content': '620'}, |
| 115 | + {'name': 'twitter:card', 'content': 'summary_large_image'}, |
| 116 | + {'name': 'twitter:title', 'content': title}, |
| 117 | + {'name': 'twitter:description', 'content': description}, |
| 118 | + {'name': 'twitter:image', 'content': image}, |
| 119 | + ] |
0 commit comments