parent
ba93dd20ca
commit
d427c8fdb6
3 changed files with 210 additions and 1 deletions
@ -0,0 +1,120 @@ |
|||||||
|
# SPDX-License-Identifer: Apache-2.0 |
||||||
|
# Copyright 2021 The Meson development team |
||||||
|
|
||||||
|
from pathlib import Path |
||||||
|
import json |
||||||
|
import re |
||||||
|
|
||||||
|
from .generatorbase import GeneratorBase |
||||||
|
from . import jsonschema as J |
||||||
|
from .model import ( |
||||||
|
ReferenceManual, |
||||||
|
Function, |
||||||
|
Object, |
||||||
|
Type, |
||||||
|
|
||||||
|
PosArg, |
||||||
|
VarArgs, |
||||||
|
Kwarg, |
||||||
|
) |
||||||
|
|
||||||
|
import typing as T |
||||||
|
|
||||||
|
class GeneratorJSON(GeneratorBase): |
||||||
|
def __init__(self, manual: ReferenceManual, out: Path, enable_modules: bool) -> None: |
||||||
|
super().__init__(manual) |
||||||
|
self.out = out |
||||||
|
self.enable_modules = enable_modules |
||||||
|
|
||||||
|
def _generate_type(self, typ: Type) -> T.List[J.Type]: |
||||||
|
return [ |
||||||
|
{ |
||||||
|
'obj': x.data_type.name, |
||||||
|
'holds': self._generate_type(x.holds) if x.holds else [], |
||||||
|
} |
||||||
|
for x in typ.resolved |
||||||
|
] |
||||||
|
|
||||||
|
def _generate_type_str(self, typ: Type) -> str: |
||||||
|
# Remove all whitespaces |
||||||
|
return re.sub(r'[ \n\r\t]', '', typ.raw) |
||||||
|
|
||||||
|
def _generate_arg(self, arg: T.Union[PosArg, VarArgs, Kwarg], isOptarg: bool = False) -> J.Argument: |
||||||
|
return { |
||||||
|
'name': arg.name, |
||||||
|
'description': arg.description, |
||||||
|
'since': arg.since if arg.since else None, |
||||||
|
'deprecated': arg.deprecated if arg.deprecated else None, |
||||||
|
'type': self._generate_type(arg.type), |
||||||
|
'type_str': self._generate_type_str(arg.type), |
||||||
|
'required': arg.required if isinstance(arg, Kwarg) else not isOptarg and not isinstance(arg, VarArgs), |
||||||
|
'default': arg.default if isinstance(arg, (PosArg, Kwarg)) else None, |
||||||
|
'min_varargs': arg.min_varargs if isinstance(arg, VarArgs) and arg.min_varargs > 0 else None, |
||||||
|
'max_varargs': arg.max_varargs if isinstance(arg, VarArgs) and arg.max_varargs > 0 else None, |
||||||
|
|
||||||
|
# Not yet supported |
||||||
|
'notes': [], |
||||||
|
'warnings': [], |
||||||
|
} |
||||||
|
|
||||||
|
def _generate_function(self, func: Function) -> J.Function: |
||||||
|
return { |
||||||
|
'name': func.name, |
||||||
|
'description': func.description, |
||||||
|
'since': func.since if func.since else None, |
||||||
|
'deprecated': func.deprecated if func.deprecated else None, |
||||||
|
'notes': func.notes, |
||||||
|
'warnings': func.warnings, |
||||||
|
'example': func.example if func.example else None, |
||||||
|
'returns': self._generate_type(func.returns), |
||||||
|
'returns_str': self._generate_type_str(func.returns), |
||||||
|
'posargs': {x.name: self._generate_arg(x) for x in func.posargs}, |
||||||
|
'optargs': {x.name: self._generate_arg(x, True) for x in func.optargs}, |
||||||
|
'kwargs': {x.name: self._generate_arg(x) for x in self.sorted_and_filtered(list(func.kwargs.values()))}, |
||||||
|
'varargs': self._generate_arg(func.varargs) if func.varargs else None, |
||||||
|
} |
||||||
|
|
||||||
|
def _generate_objects(self, obj: Object) -> J.Object: |
||||||
|
return { |
||||||
|
'name': obj.name, |
||||||
|
'description': obj.description, |
||||||
|
'since': obj.since if obj.since else None, |
||||||
|
'deprecated': obj.deprecated if obj.deprecated else None, |
||||||
|
'notes': obj.notes, |
||||||
|
'warnings': obj.warnings, |
||||||
|
'defined_by_module': obj.defined_by_module.name if obj.defined_by_module else None, |
||||||
|
'object_type': obj.obj_type.name, |
||||||
|
'is_container': obj.is_container, |
||||||
|
'example': obj.example if obj.example else None, |
||||||
|
'extends': obj.extends if obj.extends else None, |
||||||
|
'returned_by': [x.name for x in self.sorted_and_filtered(obj.returned_by)], |
||||||
|
'extended_by': [x.name for x in self.sorted_and_filtered(obj.extended_by)], |
||||||
|
'methods': {x.name: self._generate_function(x) for x in self.sorted_and_filtered(obj.methods)}, |
||||||
|
} |
||||||
|
|
||||||
|
def _extract_meson_version(self) -> str: |
||||||
|
# Hack around python relative imports to get to the Meson version |
||||||
|
import sys |
||||||
|
sys.path.append(Path(__file__).resolve().parents[2].as_posix()) |
||||||
|
from mesonbuild.coredata import version |
||||||
|
return version |
||||||
|
|
||||||
|
def generate(self) -> None: |
||||||
|
data: J.Root = { |
||||||
|
'version_major': J.VERSION_MAJOR, |
||||||
|
'version_minor': J.VERSION_MINOR, |
||||||
|
'meson_version': self._extract_meson_version(), |
||||||
|
'functions': {x.name: self._generate_function(x) for x in self.sorted_and_filtered(self.functions)}, |
||||||
|
'objects': {x.name: self._generate_objects(x) for x in self.sorted_and_filtered(self.objects)}, |
||||||
|
'objects_by_type': { |
||||||
|
'elementary': [x.name for x in self.elementary], |
||||||
|
'builtins': [x.name for x in self.builtins], |
||||||
|
'returned': [x.name for x in self.returned], |
||||||
|
'modules': { |
||||||
|
x.name: [y.name for y in self.sorted_and_filtered(self.extract_returned_by_module(x))] |
||||||
|
for x in self.modules |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
self.out.write_text(json.dumps(data), encoding='utf-8') |
@ -0,0 +1,87 @@ |
|||||||
|
# SPDX-License-Identifer: Apache-2.0 |
||||||
|
# Copyright 2021 The Meson development team |
||||||
|
|
||||||
|
import typing as T |
||||||
|
|
||||||
|
# The following variables define the current version of |
||||||
|
# the JSON documentation format. This is different from |
||||||
|
# the Meson version |
||||||
|
|
||||||
|
VERSION_MAJOR = 1 # Changes here indicate breaking format changes (changes to existing keys) |
||||||
|
VERSION_MINOR = 0 # Changes here indicate non-breaking changes (only new keys are added to the existing structure) |
||||||
|
|
||||||
|
class BaseObject(T.TypedDict): |
||||||
|
''' |
||||||
|
Base object for most dicts in the JSON doc. |
||||||
|
|
||||||
|
All objects inheriting from BaseObject will support |
||||||
|
the keys specified here: |
||||||
|
''' |
||||||
|
name: str |
||||||
|
description: str |
||||||
|
since: T.Optional[str] |
||||||
|
deprecated: T.Optional[str] |
||||||
|
notes: T.List[str] |
||||||
|
warnings: T.List[str] |
||||||
|
|
||||||
|
class Type(T.TypedDict): |
||||||
|
obj: str # References an object from `root.objects` |
||||||
|
holds: T.Sequence[object] # Mypy does not support recusive dicts, but this should be T.List[Type]... |
||||||
|
|
||||||
|
class Argument(BaseObject): |
||||||
|
''' |
||||||
|
Object that represents any type of a single function or method argumet. |
||||||
|
''' |
||||||
|
type: T.List[Type] # A non-empty list of types that are supported. |
||||||
|
type_str: str # Formated version of `type`. Is guranteed to not contain any whitespaces. |
||||||
|
required: bool |
||||||
|
default: T.Optional[str] |
||||||
|
min_varargs: T.Optional[int] # Only relevant for varargs, must be `null` for all other types of arguments |
||||||
|
max_varargs: T.Optional[int] # Only relevant for varargs, must be `null` for all other types of arguments |
||||||
|
|
||||||
|
class Function(BaseObject): |
||||||
|
''' |
||||||
|
Represents a function or method. |
||||||
|
''' |
||||||
|
returns: T.List[Type] # A non-empty list of types that are supported. |
||||||
|
returns_str: str # Formated version of `returns`. Is guranteed to not contain any whitespaces. |
||||||
|
example: T.Optional[str] |
||||||
|
posargs: T.Dict[str, Argument] |
||||||
|
optargs: T.Dict[str, Argument] |
||||||
|
kwargs: T.Dict[str, Argument] |
||||||
|
varargs: T.Optional[Argument] |
||||||
|
|
||||||
|
class Object(BaseObject): |
||||||
|
''' |
||||||
|
Represents all types of Meson objects. The specific object type is stored in the `object_type` field. |
||||||
|
''' |
||||||
|
example: T.Optional[str] |
||||||
|
object_type: str # Defines the object type: Must be one of: ELEMENTARY, BUILTIN, MODULE, RETURNED |
||||||
|
methods: T.Dict[str, Function] |
||||||
|
is_container: bool |
||||||
|
extends: T.Optional[str] |
||||||
|
returned_by: T.List[str] |
||||||
|
extended_by: T.List[str] |
||||||
|
defined_by_module: T.Optional[str] |
||||||
|
|
||||||
|
class ObjectsByType(T.TypedDict): |
||||||
|
''' |
||||||
|
References to other objects are stored here for ease of navigation / filtering |
||||||
|
''' |
||||||
|
elementary: T.List[str] |
||||||
|
builtins: T.List[str] |
||||||
|
returned: T.List[str] |
||||||
|
modules: T.Dict[str, T.List[str]] |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Root(T.TypedDict): |
||||||
|
''' |
||||||
|
The root object of the JSON reference manual |
||||||
|
''' |
||||||
|
version_major: int # See the description above for |
||||||
|
version_minor: int # VERSION_MAJOR and VERSION_MINOR |
||||||
|
meson_version: str |
||||||
|
functions: T.Dict[str, Function] # A mapping of <name> to a `Function` object for *all* Meson functions |
||||||
|
objects: T.Dict[str, Object] # A mapping of <name> to a `Object` object for *all* Meson objects (including modules, elementary, etc.) |
||||||
|
objects_by_type: ObjectsByType |
Loading…
Reference in new issue