sphinx-autoapi/autoapi/mappers/javascript.py
2023-03-22 22:33:11 -07:00

153 lines
4.2 KiB
Python

import json
import subprocess
import os
from sphinx.util.console import colorize
import sphinx.util.logging
from .base import PythonMapperBase, SphinxMapperBase
LOGGER = sphinx.util.logging.getLogger(__name__)
class JavaScriptSphinxMapper(SphinxMapperBase):
"""Auto API domain handler for Javascript
Parses directly from Javascript files.
:param app: Sphinx application passed in as part of the extension
"""
def read_file(self, path, **kwargs):
"""Read file input into memory, returning deserialized objects
:param path: Path of file to read
"""
# TODO support JSON here
# TODO sphinx way of reporting errors in logs?
subcmd = "jsdoc"
if os.name == "nt":
subcmd = ".".join([subcmd, "cmd"])
try:
parsed_data = json.loads(subprocess.check_output([subcmd, "-X", path]))
return parsed_data
except IOError:
LOGGER.warning(
f"Error reading file: {path}",
type="autoapi",
subtype="not_readable",
)
except TypeError:
LOGGER.warning(
f"Error reading file: {path}",
type="autoapi",
subtype="not_readable",
)
return None
# Subclassed to iterate over items
def map(self, options=None):
"""Trigger find of serialized sources and build objects"""
for _, data in sphinx.util.status_iterator(
self.paths.items(),
colorize("bold", "[AutoAPI] ") + "Mapping Data... ",
length=len(self.paths),
stringify_func=(lambda x: x[0]),
):
for item in data:
for obj in self.create_class(item, options):
obj.jinja_env = self.jinja_env
self.add_object(obj)
def create_class(self, data, options=None, **kwargs):
"""Return instance of class based on Javascript data
Data keys handled here:
type
Set the object class
consts, types, vars, funcs
Recurse into :py:meth:`create_class` to create child object
instances
:param data: dictionary data from godocjson output
"""
obj_map = dict((cls.type, cls) for cls in ALL_CLASSES)
try:
cls = obj_map[data["kind"]]
except (KeyError, TypeError):
# this warning intentionally has no (sub-)type
LOGGER.warning(f"Unknown type: {data}")
else:
# Recurse for children
obj = cls(data, jinja_env=self.jinja_env, app=self.app)
if "children" in data:
for child_data in data["children"]:
for child_obj in self.create_class(child_data, options=options):
obj.children.append(child_obj)
yield obj
class JavaScriptPythonMapper(PythonMapperBase):
language = "javascript"
def __init__(self, obj, **kwargs):
"""
Map JSON data into Python object.
This is the standard object that will be rendered into the templates,
so we try and keep standard naming to keep templates more re-usable.
"""
super().__init__(obj, **kwargs)
self.name = obj.get("name")
self.id = self.name
# Second level
self.docstring = obj.get("description", "")
# self.docstring = obj.get('comment', '')
self.imports = obj.get("imports", [])
self.children = []
self.parameters = map(
lambda n: {"name": n["name"], "type": n["type"][0]}, obj.get("param", [])
)
class JavaScriptClass(JavaScriptPythonMapper):
type = "class"
ref_directive = "class"
top_level_object = True
class JavaScriptFunction(JavaScriptPythonMapper):
type = "function"
ref_type = "func"
class JavaScriptData(JavaScriptPythonMapper):
type = "data"
ref_directive = "data"
class JavaScriptMember(JavaScriptPythonMapper):
type = "member"
ref_directive = "member"
class JavaScriptAttribute(JavaScriptPythonMapper):
type = "attribute"
ref_directive = "attr"
ALL_CLASSES = [
JavaScriptFunction,
JavaScriptClass,
JavaScriptData,
JavaScriptAttribute,
JavaScriptMember,
]