aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2021-10-24 17:46:05 +0300
committerGitHub <noreply@github.com>2021-10-24 17:46:05 +0300
commit475b8b1ad8cdc5d33ff7bfb0bc91aad53056b81e (patch)
treeb5ab384990078cd33b6ffbf90b34aed2212c975b /docs
parent012ec7d5b3379b035f1dd1369d74cafd26ff6ab0 (diff)
parent0eec5480fb2cff1549f7f593a8da29ee7deed01b (diff)
downloadmeson-475b8b1ad8cdc5d33ff7bfb0bc91aad53056b81e.zip
meson-475b8b1ad8cdc5d33ff7bfb0bc91aad53056b81e.tar.gz
meson-475b8b1ad8cdc5d33ff7bfb0bc91aad53056b81e.tar.bz2
Merge pull request #9377 from mensinda/jsonDocs
docs: Add a JSON documentation backend
Diffstat (limited to 'docs')
-rwxr-xr-xdocs/jsonvalidator.py195
-rw-r--r--docs/markdown/IDE-integration.md11
-rw-r--r--docs/meson.build49
-rw-r--r--docs/refman/generatorjson.py120
-rw-r--r--docs/refman/jsonschema.py87
-rw-r--r--docs/refman/loaderpickle.py22
-rw-r--r--docs/refman/main.py11
-rw-r--r--docs/refman/model.py8
-rw-r--r--docs/refman/templates/root.mustache10
9 files changed, 496 insertions, 17 deletions
diff --git a/docs/jsonvalidator.py b/docs/jsonvalidator.py
new file mode 100755
index 0000000..6a55ddb
--- /dev/null
+++ b/docs/jsonvalidator.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python3
+
+# SPDX-License-Identifer: Apache-2.0
+# Copyright 2021 The Meson development team
+
+import argparse
+import json
+from pathlib import Path
+from copy import deepcopy
+
+import typing as T
+
+T_None = type(None)
+
+# Global root object
+root: dict
+
+def assert_has_typed_keys(path: str, data: dict, keys: T.Dict[str, T.Any]) -> dict:
+ assert set(data.keys()).issuperset(keys.keys()), f'{path}: DIFF: {set(data.keys()).difference(keys.keys())}'
+ res = dict()
+ for key, val in keys.items():
+ cur = data.pop(key)
+ assert isinstance(cur, val), f'{path}: type({key}: {cur}) != {val}'
+ res[key] = cur
+ return res
+
+def validate_base_obj(path: str, name: str, obj: dict) -> None:
+ expected: T.Dict[str, T.Any] = {
+ 'name': str,
+ 'description': str,
+ 'since': (str, T_None),
+ 'deprecated': (str, T_None),
+ 'notes': list,
+ 'warnings': list,
+ }
+ cur = assert_has_typed_keys(f'{path}.{name}', obj, expected)
+ assert cur['name'], f'{path}.{name}'
+ assert cur['description'], f'{path}.{name}'
+ assert cur['name'] == name, f'{path}.{name}'
+ assert all(isinstance(x, str) and x for x in cur['notes']), f'{path}.{name}'
+ assert all(isinstance(x, str) and x for x in cur['warnings']), f'{path}.{name}'
+
+def validate_type(path: str, typ: dict) -> None:
+ expected: T.Dict[str, T.Any] = {
+ 'obj': str,
+ 'holds': list,
+ }
+ cur = assert_has_typed_keys(path, typ, expected)
+ assert not typ, f'{path} has extra keys: {typ.keys()}'
+ assert cur['obj'] in root['objects'], path
+ for i in cur['holds']:
+ validate_type(path, i)
+
+def validate_arg(path: str, name: str, arg: dict) -> None:
+ validate_base_obj(path, name, arg)
+ expected: T.Dict[str, T.Any] = {
+ 'type': list,
+ 'type_str': str,
+ 'required': bool,
+ 'default': (str, T_None),
+ 'min_varargs': (int, T_None),
+ 'max_varargs': (int, T_None),
+ }
+ cur = assert_has_typed_keys(f'{path}.{name}', arg, expected)
+ assert not arg, f'{path}.{name} has extra keys: {arg.keys()}'
+ assert cur['type'], f'{path}.{name}'
+ assert cur['type_str'], f'{path}.{name}'
+ for i in cur['type']:
+ validate_type(f'{path}.{name}', i)
+ if cur['min_varargs'] is not None:
+ assert cur['min_varargs'] > 0, f'{path}.{name}'
+ if cur['max_varargs'] is not None:
+ assert cur['max_varargs'] > 0, f'{path}.{name}'
+
+def validate_function(path: str, name: str, func: dict) -> None:
+ validate_base_obj(path, name, func)
+ expected: T.Dict[str, T.Any] = {
+ 'returns': list,
+ 'returns_str': str,
+ 'example': (str, T_None),
+ 'posargs': dict,
+ 'optargs': dict,
+ 'kwargs': dict,
+ 'varargs': (dict, T_None),
+ }
+ cur = assert_has_typed_keys(f'{path}.{name}', func, expected)
+ assert not func, f'{path}.{name} has extra keys: {func.keys()}'
+ assert cur['returns'], f'{path}.{name}'
+ assert cur['returns_str'], f'{path}.{name}'
+ for i in cur['returns']:
+ validate_type(f'{path}.{name}', i)
+ for k, v in cur['posargs'].items():
+ validate_arg(f'{path}.{name}', k, v)
+ for k, v in cur['optargs'].items():
+ validate_arg(f'{path}.{name}', k, v)
+ for k, v in cur['kwargs'].items():
+ validate_arg(f'{path}.{name}', k, v)
+ if cur['varargs']:
+ validate_arg(f'{path}.{name}', cur['varargs']['name'], cur['varargs'])
+
+def validate_object(path: str, name: str, obj: dict) -> None:
+ validate_base_obj(path, name, obj)
+ expected: T.Dict[str, T.Any] = {
+ 'example': (str, T_None),
+ 'object_type': str,
+ 'methods': dict,
+ 'is_container': bool,
+ 'extends': (str, T_None),
+ 'returned_by': list,
+ 'extended_by': list,
+ 'defined_by_module': (str, T_None),
+ }
+ cur = assert_has_typed_keys(f'{path}.{name}', obj, expected)
+ assert not obj, f'{path}.{name} has extra keys: {obj.keys()}'
+ for key, val in cur['methods'].items():
+ validate_function(f'{path}.{name}', key, val)
+ if cur['extends'] is not None:
+ assert cur['extends'] in root['objects'], f'{path}.{name}'
+ assert all(isinstance(x, str) for x in cur['returned_by']), f'{path}.{name}'
+ assert all(isinstance(x, str) for x in cur['extended_by']), f'{path}.{name}'
+ assert all(x in root['objects'] for x in cur['extended_by']), f'{path}.{name}'
+ if cur['defined_by_module'] is not None:
+ assert cur['defined_by_module'] in root['objects'], f'{path}.{name}'
+ assert cur['object_type'] == 'RETURNED', f'{path}.{name}'
+ assert root['objects'][cur['defined_by_module']]['object_type'] == 'MODULE', f'{path}.{name}'
+ assert name in root['objects_by_type']['modules'][cur['defined_by_module']], f'{path}.{name}'
+ return
+ assert cur['object_type'] in {'ELEMENTARY', 'BUILTIN', 'MODULE', 'RETURNED'}, f'{path}.{name}'
+ if cur['object_type'] == 'ELEMENTARY':
+ assert name in root['objects_by_type']['elementary'], f'{path}.{name}'
+ if cur['object_type'] == 'BUILTIN':
+ assert name in root['objects_by_type']['builtins'], f'{path}.{name}'
+ if cur['object_type'] == 'RETURNED':
+ assert name in root['objects_by_type']['returned'], f'{path}.{name}'
+ if cur['object_type'] == 'MODULE':
+ assert name in root['objects_by_type']['modules'], f'{path}.{name}'
+
+def main() -> int:
+ global root
+
+ parser = argparse.ArgumentParser(description='Meson JSON docs validator')
+ parser.add_argument('doc_file', type=Path, help='The JSON docs to validate')
+ args = parser.parse_args()
+
+ root_tmp = json.loads(args.doc_file.read_text(encoding='utf-8'))
+ root = deepcopy(root_tmp)
+ assert isinstance(root, dict)
+
+ expected: T.Dict[str, T.Any] = {
+ 'version_major': int,
+ 'version_minor': int,
+ 'meson_version': str,
+ 'functions': dict,
+ 'objects': dict,
+ 'objects_by_type': dict,
+ }
+ cur = assert_has_typed_keys('root', root_tmp, expected)
+ assert not root_tmp, f'root has extra keys: {root_tmp.keys()}'
+
+ refs = cur['objects_by_type']
+ expected = {
+ 'elementary': list,
+ 'builtins': list,
+ 'returned': list,
+ 'modules': dict,
+ }
+ assert_has_typed_keys(f'root.objects_by_type', refs, expected)
+ assert not refs, f'root.objects_by_type has extra keys: {refs.keys()}'
+ assert all(isinstance(x, str) for x in root['objects_by_type']['elementary'])
+ assert all(isinstance(x, str) for x in root['objects_by_type']['builtins'])
+ assert all(isinstance(x, str) for x in root['objects_by_type']['returned'])
+ assert all(isinstance(x, str) for x in root['objects_by_type']['modules'])
+ assert all(x in root['objects'] for x in root['objects_by_type']['elementary'])
+ assert all(x in root['objects'] for x in root['objects_by_type']['builtins'])
+ assert all(x in root['objects'] for x in root['objects_by_type']['returned'])
+ assert all(x in root['objects'] for x in root['objects_by_type']['modules'])
+ assert all(root['objects'][x]['object_type'] == 'ELEMENTARY' for x in root['objects_by_type']['elementary'])
+ assert all(root['objects'][x]['object_type'] == 'BUILTIN' for x in root['objects_by_type']['builtins'])
+ assert all(root['objects'][x]['object_type'] == 'RETURNED' for x in root['objects_by_type']['returned'])
+ assert all(root['objects'][x]['object_type'] == 'MODULE' for x in root['objects_by_type']['modules'])
+
+ # Check that module references are correct
+ assert all(all(isinstance(x, str) for x in v) for k, v in root['objects_by_type']['modules'].items())
+ assert all(all(x in root['objects'] for x in v) for k, v in root['objects_by_type']['modules'].items())
+ assert all(all(root['objects'][x]['defined_by_module'] == k for x in v) for k, v in root['objects_by_type']['modules'].items())
+
+ for key, val in cur['functions'].items():
+ validate_function('root', key, val)
+ for key, val in cur['objects'].items():
+ validate_object('root', key, val)
+
+ return 0
+
+if __name__ == '__main__':
+ raise SystemExit(main())
diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md
index cf1c5c1..e64eccf 100644
--- a/docs/markdown/IDE-integration.md
+++ b/docs/markdown/IDE-integration.md
@@ -405,6 +405,17 @@ of a node type or the removal of a key) are unlikely and will be
announced in the release notes.
+# JSON Reference manual
+
+In additional to the online [Reference manual](Reference-manual.md), Meson also
+offers the manual as JSON file. The content of this file is generated from the
+same source as the online documentation. The two versions are thus identical
+in content.
+
+This JSON document is attached to every Meson release since *0.60.0*. The JSON
+schema is defined by the class structure given in
+[`jsonschema.py`](https://github.com/mesonbuild/meson/blob/master/docs/refman/jsonschema.py)
+
# Existing integrations
- [Gnome Builder](https://wiki.gnome.org/Apps/Builder)
diff --git a/docs/meson.build b/docs/meson.build
index c53abcb..a752965 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -15,27 +15,60 @@ docs_gen = custom_target(
build_by_default: true,
install: false)
-refman_gen = custom_target(
- 'gen_refman',
+genrefman = find_program('./genrefman.py')
+refman_binary = custom_target(
+ 'gen_refman_bin',
input: files('sitemap.txt'),
- output: ['configured_sitemap.txt', 'refman_links.json'],
+ output: 'reference_manual.bin',
depfile: 'reman_dep.d',
command: [
- find_program('./genrefman.py'),
+ genrefman,
+ '-l', 'yaml',
+ '-g', 'pickle',
+ '-o', '@OUTPUT@',
+ '--depfile', '@DEPFILE@',
+ '--force-color',
+ ]
+)
+
+refman_md = custom_target(
+ 'gen_refman_md',
+ input: refman_binary,
+ output: ['configured_sitemap.txt', 'refman_links.json'],
+ command: [
+ genrefman,
+ '-l', 'pickle',
'-g', 'md',
- '-s', '@INPUT@',
+ '-s', files('sitemap.txt'),
+ '-i', '@INPUT@',
'-o', '@OUTPUT0@',
'--link-defs', '@OUTPUT1@',
- '--depfile', '@DEPFILE@',
'--force-color',
'--no-modules',
],
)
+refman_json = custom_target(
+ 'gen_refman_json',
+ build_by_default: true,
+ input: refman_binary,
+ output: 'reference_manual.json',
+ command: [
+ genrefman,
+ '-l', 'pickle',
+ '-g', 'json',
+ '-i', '@INPUT@',
+ '-o', '@OUTPUT@',
+ '--force-color',
+ ],
+)
+
+test('validate_docs', find_program('./jsonvalidator.py'), args: [refman_json])
+
hotdoc = import('hotdoc')
documentation = hotdoc.generate_doc(meson.project_name(),
project_version: meson.project_version(),
- sitemap: refman_gen[0],
+ sitemap: refman_md[0],
build_by_default: true,
depends: docs_gen,
index: 'markdown/index.md',
@@ -49,7 +82,7 @@ documentation = hotdoc.generate_doc(meson.project_name(),
syntax_highlighting_activate: true,
keep_markup_in_code_blocks: true,
extra_extension: meson.current_source_dir() / 'extensions' / 'refman_links.py',
- refman_data_file: refman_gen[1],
+ refman_data_file: refman_md[1],
)
run_target('upload',
diff --git a/docs/refman/generatorjson.py b/docs/refman/generatorjson.py
new file mode 100644
index 0000000..f5164d4
--- /dev/null
+++ b/docs/refman/generatorjson.py
@@ -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')
diff --git a/docs/refman/jsonschema.py b/docs/refman/jsonschema.py
new file mode 100644
index 0000000..6d6f98a
--- /dev/null
+++ b/docs/refman/jsonschema.py
@@ -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
diff --git a/docs/refman/loaderpickle.py b/docs/refman/loaderpickle.py
new file mode 100644
index 0000000..722fedf
--- /dev/null
+++ b/docs/refman/loaderpickle.py
@@ -0,0 +1,22 @@
+# SPDX-License-Identifer: Apache-2.0
+# Copyright 2021 The Meson development team
+
+from pathlib import Path
+import pickle
+
+from .loaderbase import LoaderBase
+from .model import ReferenceManual
+
+class LoaderPickle(LoaderBase):
+ def __init__(self, in_file: Path) -> None:
+ super().__init__()
+ self.in_file = in_file
+
+ def load_impl(self) -> ReferenceManual:
+ res = pickle.loads(self.in_file.read_bytes())
+ assert isinstance(res, ReferenceManual)
+ return res
+
+ # Assume that the pickled data is OK and skip validation
+ def load(self) -> ReferenceManual:
+ return self.load_impl()
diff --git a/docs/refman/main.py b/docs/refman/main.py
index 913a0f3..5bc40f7 100644
--- a/docs/refman/main.py
+++ b/docs/refman/main.py
@@ -19,9 +19,11 @@ import typing as T
from mesonbuild import mlog
from .loaderbase import LoaderBase
+from .loaderpickle import LoaderPickle
from .loaderyaml import LoaderYAML
from .generatorbase import GeneratorBase
+from .generatorjson import GeneratorJSON
from .generatorprint import GeneratorPrint
from .generatorpickle import GeneratorPickle
from .generatormd import GeneratorMD
@@ -30,10 +32,11 @@ meson_root = Path(__file__).absolute().parents[2]
def main() -> int:
parser = argparse.ArgumentParser(description='Meson reference manual generator')
- parser.add_argument('-l', '--loader', type=str, default='yaml', choices=['yaml'], help='Information loader backend')
- parser.add_argument('-g', '--generator', type=str, choices=['print', 'pickle', 'md'], required=True, help='Generator backend')
+ parser.add_argument('-l', '--loader', type=str, default='yaml', choices=['yaml', 'pickle'], help='Information loader backend')
+ parser.add_argument('-g', '--generator', type=str, choices=['print', 'pickle', 'md', 'json'], required=True, help='Generator backend')
parser.add_argument('-s', '--sitemap', type=Path, default=meson_root / 'docs' / 'sitemap.txt', help='Path to the input sitemap.txt')
parser.add_argument('-o', '--out', type=Path, required=True, help='Output directory for generated files')
+ parser.add_argument('-i', '--input', type=Path, default=meson_root / 'docs' / 'yaml', help='Input path for the selected loader')
parser.add_argument('--link-defs', type=Path, help='Output file for the MD generator link definition file')
parser.add_argument('--depfile', type=Path, default=None, help='Set to generate a depfile')
parser.add_argument('--force-color', action='store_true', help='Force enable colors')
@@ -44,7 +47,8 @@ def main() -> int:
mlog.colorize_console = lambda: True
loaders: T.Dict[str, T.Callable[[], LoaderBase]] = {
- 'yaml': lambda: LoaderYAML(meson_root / 'docs' / 'yaml'),
+ 'yaml': lambda: LoaderYAML(args.input),
+ 'pickle': lambda: LoaderPickle(args.input),
}
loader = loaders[args.loader]()
@@ -54,6 +58,7 @@ def main() -> int:
'print': lambda: GeneratorPrint(refMan),
'pickle': lambda: GeneratorPickle(refMan, args.out),
'md': lambda: GeneratorMD(refMan, args.out, args.sitemap, args.link_defs, not args.no_modules),
+ 'json': lambda: GeneratorJSON(refMan, args.out, not args.no_modules),
}
generator = generators[args.generator]()
diff --git a/docs/refman/model.py b/docs/refman/model.py
index 23515a2..8a051c9 100644
--- a/docs/refman/model.py
+++ b/docs/refman/model.py
@@ -44,20 +44,20 @@ class Type:
# Arguments
@dataclass
-class ArgBase(NamedObject):
+class ArgBase(NamedObject, FetureCheck):
type: Type
@dataclass
-class PosArg(ArgBase, FetureCheck):
+class PosArg(ArgBase):
default: str
@dataclass
-class VarArgs(ArgBase, FetureCheck):
+class VarArgs(ArgBase):
min_varargs: int
max_varargs: int
@dataclass
-class Kwarg(ArgBase, FetureCheck):
+class Kwarg(ArgBase):
required: bool
default: str
diff --git a/docs/refman/templates/root.mustache b/docs/refman/templates/root.mustache
index 3752a22..c793b04 100644
--- a/docs/refman/templates/root.mustache
+++ b/docs/refman/templates/root.mustache
@@ -5,8 +5,14 @@ render-subpages: false
# Reference manual
-This is the root page of the Meson reference manual. All functions
-and methods are documented in detail in the following subpages:
+This is the root page of the online Meson reference manual. This
+manual is also available in a more machine readable format as a
+JSON documented attached to every release since *0.60.0*. See our
+[IDE integration](IDE-integration.md) documentation for more
+information.
+
+All functions and methods are documented in detail in the
+following subpages:
## Elementary types