Skip to content

Commit

Permalink
Added generator logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
josephlewis42 committed Aug 10, 2024
1 parent 64a1c39 commit 0e313f7
Show file tree
Hide file tree
Showing 10 changed files with 769 additions and 7 deletions.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies = [
"requests==2.32.3",
"pydantic==2.8.2",
"zimscraperlib==3.4.0",
"Jinja2==3.1.3",
]
dynamic = ["authors", "classifiers", "keywords", "license", "version", "urls"]

Expand All @@ -23,7 +24,7 @@ lint = [
"ruff==0.5.1",
]
check = [
"pyright==1.1.370",
"pyright==1.1.374",
]
test = [
"pytest==8.2.2",
Expand Down
13 changes: 13 additions & 0 deletions src/devdocs2zim/assets/COPYRIGHT
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2013-2024 Thibaut Courouble and other contributors

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

Please do not use the name DevDocs to endorse or promote products
derived from this software without the maintainers' permission, except
as may be necessary to comply with the notice/attribution requirements.

We also wish that any documentation file generated using this software
be attributed to DevDocs. Let's be fair to all contributors by giving
credit where credit's due. Thanks.
373 changes: 373 additions & 0 deletions src/devdocs2zim/assets/LICENSE

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/devdocs2zim/assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
These files are copied from DevDocs:

https://github.com/freeCodeCamp/devdocs

devdocs_48.png is adapted from:

https://github.com/freeCodeCamp/devdocs/blob/0dd0ad813f81d3c8e3d040095992e61b7398be96/public/images/icon-64.png
Binary file added src/devdocs2zim/assets/devdocs_48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 83 additions & 3 deletions src/devdocs2zim/client.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import re
from collections import defaultdict
from enum import Enum

import requests
from pydantic import BaseModel, TypeAdapter

from devdocs2zim.constants import logger

HTTP_TIMEOUT_SECONDS = 15

# These regular expressions are extracted from the DevDocs frontend.
# The expression definitions haven't changed in ~8 years as of 2024-07-28:
# https://github.com/freeCodeCamp/devdocs/blob/e28f81d3218bdbad7eac0540c58c11c7fe1d33d3/assets/javascripts/collections/types.js#L3
BEFORE_CONTENT_PATTERN = re.compile(
r"(^|\()(guides?|tutorials?|reference|book|getting\ started|manual|examples)($|[\):])", # noqa: E501
re.IGNORECASE,
)
AFTER_CONTENT_PATTERN = re.compile(r"appendix", re.IGNORECASE)


class DevdocsMetadataLinks(BaseModel):
"""Project links for a specific documentation set."""
Expand Down Expand Up @@ -74,14 +87,24 @@ class DevdocsIndexEntry(BaseModel):
path: str

# Name of the type (section) the entry is located under.
type: str
type: str | None

@property
def path_without_fragment(self) -> str:
"""Key in db.json for the file's contents."""
return self.path.split("#")[0]


class SortPrecedence(Enum):
"""Represents where to place section in the navbar."""

# NOTE: Definition order must match display order.

BEFORE_CONTENT = 0
CONTENT = 1
AFTER_CONTENT = 2


class DevdocsIndexType(BaseModel):
"""A section header for documentation."""

Expand All @@ -94,6 +117,37 @@ class DevdocsIndexType(BaseModel):
# Section slug. This appears to be unused.
slug: str

def sort_precedence(self) -> SortPrecedence:
"""Determines where this section should be displayed in the navigation."""
if BEFORE_CONTENT_PATTERN.match(self.name):
return SortPrecedence.BEFORE_CONTENT

Check warning on line 123 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L123

Added line #L123 was not covered by tests

if AFTER_CONTENT_PATTERN.match(self.name):
return SortPrecedence.AFTER_CONTENT

Check warning on line 126 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L126

Added line #L126 was not covered by tests

return SortPrecedence.CONTENT

Check warning on line 128 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L128

Added line #L128 was not covered by tests


class NavigationSection:
"""Represents a single section of a devdocs navigation tree."""

def __init__(self, section: DevdocsIndexType, links: list[DevdocsIndexEntry]):
"""Initializes NavigationSection.
Parameters:
section: Heading information for the group of links.
links: Links to display in the section.
"""
self.name = section.name
self.count = section.count
self.links = links

Check warning on line 143 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L141-L143

Added lines #L141 - L143 were not covered by tests

self._contained_pages = {link.path_without_fragment for link in links}

Check warning on line 145 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L145

Added line #L145 was not covered by tests

def contains_page(self, page_path: str) -> bool:
"""Returns whether this section contains the given page."""
return page_path in self._contained_pages

Check warning on line 149 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L149

Added line #L149 was not covered by tests


class DevdocsIndex(BaseModel):
"""Represents entries in the /<slug>/index.json file for each resource."""
Expand All @@ -102,10 +156,36 @@ class DevdocsIndex(BaseModel):
entries: list[DevdocsIndexEntry]

# List of "types" or section headings.
# These are displayed mostly in order, except regular expressions are used to sort:
# https://github.com/freeCodeCamp/devdocs/blob/e28f81d3218bdbad7eac0540c58c11c7fe1d33d3/assets/javascripts/collections/types.js#L3
# These are displayed in the order they're found grouped by sort_precedence.
types: list[DevdocsIndexType]

def build_navigation(self) -> list[NavigationSection]:
"""Builds a navigation hierarchy that's soreted correctly for rendering."""

sections_by_precedence: dict[SortPrecedence, list[DevdocsIndexType]] = (

Check warning on line 165 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L165

Added line #L165 was not covered by tests
defaultdict(list)
)
for section in self.types:
sections_by_precedence[section.sort_precedence()].append(section)

Check warning on line 169 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L169

Added line #L169 was not covered by tests

links_by_section_name: dict[str, list[DevdocsIndexEntry]] = defaultdict(list)

Check warning on line 171 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L171

Added line #L171 was not covered by tests
for entry in self.entries:
if entry.type is None:
continue
links_by_section_name[entry.type].append(entry)

Check warning on line 175 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L174-L175

Added lines #L174 - L175 were not covered by tests

output: list[NavigationSection] = []

Check warning on line 177 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L177

Added line #L177 was not covered by tests
for precedence in SortPrecedence:
for section in sections_by_precedence[precedence]:
output.append(

Check warning on line 180 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L180

Added line #L180 was not covered by tests
NavigationSection(
section=section,
links=links_by_section_name[section.name],
)
)

return output

Check warning on line 187 in src/devdocs2zim/client.py

View check run for this annotation

Codecov / codecov/patch

src/devdocs2zim/client.py#L187

Added line #L187 was not covered by tests


class DevdocsClient:
"""Utility functions to read data from devdocs."""
Expand Down
Loading

0 comments on commit 0e313f7

Please sign in to comment.