forked from wazuh/wazuh
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add entry point of documentation with the markdown exporter
- Loading branch information
1 parent
0e22fa6
commit d7123a4
Showing
22 changed files
with
720 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
69 changes: 69 additions & 0 deletions
69
src/engine/test/helper_tests/engine_helper_test/src/documentation_generator/__main__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import argparse | ||
import sys | ||
from pathlib import Path | ||
from test_cases_generator.parser import Parser | ||
from .documentation import * | ||
from .exporter import IExporter | ||
from .types import * | ||
import tempfile | ||
|
||
|
||
def parse_arguments() -> argparse.Namespace: | ||
arg_parser = argparse.ArgumentParser(description="Generates files containing test cases for a given helper") | ||
arg_parser.add_argument( | ||
"--input_file_path", | ||
help="Absolute or relative path where the description of the helper function is located", | ||
) | ||
arg_parser.add_argument( | ||
"--folder_path", | ||
help="Absolute or relative path where the directory that contains the descriptions of the auxiliary functions is located", | ||
) | ||
arg_parser.add_argument( | ||
"--exporter", | ||
help="Absolute or relative path of the directory where the generated test files will be located", | ||
) | ||
arg_parser.add_argument( | ||
"-o", | ||
"--output_path", | ||
help="Absolute or relative path of the directory where the generated test files will be located", | ||
) | ||
|
||
args = arg_parser.parse_args() | ||
|
||
if args.input_file_path and args.folder_path: | ||
arg_parser.error("Only one of --input_file_path or --folder_path can be specified.") | ||
|
||
return args | ||
|
||
|
||
def is_temp_path(path_str): | ||
path = Path(path_str).resolve() | ||
temp_dir = Path(tempfile.gettempdir()).resolve() | ||
return str(path).startswith(str(temp_dir)) | ||
|
||
|
||
def generate_documentation(parser: Parser, exporter: IExporter, file: Path, output_dir: Path): | ||
parser.load_yaml_from_file(file) | ||
documentation = parse_yaml_to_documentation(parser) | ||
exporter.create_document(documentation) | ||
exporter.save(output_dir) | ||
|
||
|
||
def main(): | ||
args = parse_arguments() | ||
parser = Parser() | ||
exporter_type = args.exporter if args.exporter else "mark_down" | ||
output_dir = Path(args.output_path if args.output_path else "/tmp/documentation") | ||
exporter = ExporterFactory.get_exporter(exporter_type) | ||
if args.input_file_path: | ||
generate_documentation(parser, exporter, Path(args.input_file_path), output_dir) | ||
elif args.folder_path: | ||
for file in Path(args.folder_path).iterdir(): | ||
if file.is_file() and (file.suffix in ['.yml', '.yaml']): | ||
generate_documentation(parser, exporter, file, output_dir) | ||
else: | ||
sys.exit("It is necessary to indicate a file or directory that contains a configuration yaml") | ||
|
||
print("Success validation") |
49 changes: 49 additions & 0 deletions
49
src/engine/test/helper_tests/engine_helper_test/src/documentation_generator/documentation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from .html_generator import HTMLGenerator | ||
from .pdf_generator import PDFGenerator | ||
from .mark_down_generator import MarkdownGenerator | ||
from .exporter import * | ||
from .types import * | ||
from test_cases_generator.parser import Parser | ||
|
||
|
||
class ExporterFactory(): | ||
@staticmethod | ||
def get_exporter(type_: str) -> IExporter: | ||
if convert_str_to_exporter_type(type_) == ExporterType.PDF: | ||
return PDFGenerator() | ||
elif convert_str_to_exporter_type(type_) == ExporterType.HTML: | ||
return HTMLGenerator() | ||
elif convert_str_to_exporter_type(type_) == ExporterType.MARK_DOWN: | ||
return MarkdownGenerator() | ||
|
||
|
||
def parse_yaml_to_documentation(parser: Parser): | ||
metadata = Metadata( | ||
parser.get_metadata()["description"], | ||
parser.get_metadata()["keywords"]) | ||
|
||
arguments = {name: Argument(parser.get_types()[index], parser.get_sources()[index], parser.get_subset( | ||
)[index], parser.get_restrictions()[index]) for index, (name, arg_info) in enumerate(parser.get_arguments().items())} | ||
|
||
output = Output(parser.get_output()["type"], parser.get_output().get("subset")) | ||
|
||
examples = [ | ||
Example( | ||
test['arguments'], | ||
test['should_pass'], | ||
test['description'], | ||
test.get('skipped', False), | ||
test.get('expected')) for test in parser.get_tests()] | ||
|
||
documentation = Documentation( | ||
name=parser.get_name(), | ||
helper_type=parser.get_helper_type(), | ||
is_variadic=parser.is_variadic(), | ||
metadata=metadata, | ||
arguments=arguments, | ||
output=output, | ||
general_restrictions=parser.get_general_restrictions_details(), | ||
examples=examples | ||
) | ||
|
||
return documentation |
42 changes: 42 additions & 0 deletions
42
src/engine/test/helper_tests/engine_helper_test/src/documentation_generator/exporter.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from abc import ABC, abstractmethod | ||
from enum import Enum | ||
from pathlib import Path | ||
from .types import Documentation | ||
|
||
|
||
class ExporterType(Enum): | ||
PDF = 1, | ||
HTML = 2, | ||
MARK_DOWN = 3 | ||
|
||
|
||
def convert_str_to_exporter_type(type_: str): | ||
if type_ == "pdf": | ||
return ExporterType.PDF | ||
elif type_ == "html": | ||
return ExporterType.HTML | ||
elif type_ == "mark_down": | ||
return ExporterType.MARK_DOWN | ||
else: | ||
raise ValueError(f"Exporter type {type_} does not exist") | ||
|
||
|
||
def convert_exporter_type_to_str(exporter_type: ExporterType): | ||
if exporter_type == convert_str_to_exporter_type("pdf"): | ||
return "pdf" | ||
elif exporter_type == convert_str_to_exporter_type("pdf"): | ||
return "html" | ||
elif exporter_type == convert_str_to_exporter_type("html"): | ||
return "mark_down" | ||
else: | ||
raise ValueError(f"Exporter type does not exist") | ||
|
||
|
||
class IExporter(ABC): | ||
@abstractmethod | ||
def create_document(self, doc: Documentation): | ||
pass | ||
|
||
@abstractmethod | ||
def save(self, output_dir: Path): | ||
pass |
14 changes: 14 additions & 0 deletions
14
...engine/test/helper_tests/engine_helper_test/src/documentation_generator/html_generator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from .types import Documentation | ||
from .exporter import * | ||
|
||
|
||
class HTMLGenerator(IExporter): | ||
def __init__(self): | ||
self.content = [] | ||
self.helper_name = "" | ||
|
||
def create_document(self, doc: Documentation): | ||
pass | ||
|
||
def save(self, output_dir: Path): | ||
pass |
143 changes: 143 additions & 0 deletions
143
...e/test/helper_tests/engine_helper_test/src/documentation_generator/mark_down_generator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
from .types import Documentation | ||
from .exporter import * | ||
|
||
|
||
class MarkdownGenerator(IExporter): | ||
def __init__(self): | ||
self.content = [] | ||
self.helper_name = "" | ||
|
||
def create_signature(self, doc: Documentation): | ||
self.content.append(f"```\n") | ||
if not doc.is_variadic: | ||
self.content.append(f"field: {doc.name}({', '.join(str(v) for v in doc.arguments)})") | ||
else: | ||
self.content.append(f"field: {doc.name}({', '.join(str(v) for v in doc.arguments)}, [...])") | ||
self.content.append(f"```\n") | ||
|
||
def create_table(self, arguments: dict, headers: list): | ||
""" | ||
Create a table in Markdown format. | ||
:param arguments: Dictionary of arguments. | ||
:return: Table string in Markdown format. | ||
""" | ||
# Create the header row | ||
header_row = '| ' + ' | '.join(headers) + ' |' | ||
separator_row = '| ' + ' | '.join(['-' * len(header) for header in headers]) + ' |' | ||
|
||
# Create the data rows | ||
rows = [] | ||
for name, info in arguments.items(): | ||
row = [] # Create a new list for each argument | ||
row.append(name) | ||
|
||
# Handle arg_type being a list or a string | ||
if isinstance(info.arg_type, list): | ||
row.append(', '.join(info.arg_type)) | ||
else: | ||
row.append(info.arg_type) | ||
|
||
if info.source == "both": | ||
row.append("value or reference") | ||
else: | ||
row.append(info.source) | ||
|
||
if info.restrictions: | ||
row.append(', '.join(info.restrictions["allowed"]) if isinstance( | ||
info.restrictions["allowed"], list) else str(info.restrictions["allowed"])) | ||
else: | ||
if info.arg_type == "object": | ||
row.append("Any object") | ||
elif info.arg_type == "array": | ||
row.append("Any array") | ||
elif info.generate == "integer": | ||
row.append("Integers between `-2^63` and `2^63-1`") | ||
elif info.generate == "string": | ||
row.append("Any string") | ||
elif info.generate == "ip": | ||
row.append("Any IP") | ||
|
||
rows.append(row) | ||
data_rows = ['| ' + ' | '.join(row) + ' |' for row in rows] | ||
|
||
# Merge all rows | ||
self.content.append('\n'.join([header_row, separator_row] + data_rows)) | ||
self.content.append("\n") | ||
|
||
def create_output_table(self, output, headers: list): | ||
""" | ||
Create a table in Markdown format. | ||
:param arguments: Dictionary of arguments. | ||
:return: Table string in Markdown format. | ||
""" | ||
# Create the header row | ||
header_row = '| ' + ' | '.join(headers) + ' |' | ||
separator_row = '| ' + ' | '.join(['-' * len(header) for header in headers]) + ' |' | ||
|
||
# Create the data rows | ||
rows = [] | ||
row = [] # Create a new list for each argument | ||
row.append(output.type_) | ||
if output.type_ == "object": | ||
row.append("Any object") | ||
elif output.type_ == "array": | ||
row.append("Any array") | ||
elif output.subset == "integer": | ||
row.append("Integers between `-2^63` and `2^63-1`") | ||
elif output.subset == "string": | ||
row.append("Any string") | ||
elif output.subset == "ip": | ||
row.append("Any IP") | ||
rows.append(row) | ||
data_rows = ['| ' + ' | '.join(row) + ' |' for row in rows] | ||
|
||
# Merge all rows | ||
self.content.append('\n'.join([header_row, separator_row] + data_rows)) | ||
self.content.append("\n") | ||
|
||
def create_document(self, doc: Documentation): | ||
self.content = [] | ||
self.helper_name = doc.name | ||
self.content.append(f"# {doc.name}\n") | ||
|
||
self.content.append(f"## Signature\n") | ||
self.create_signature(doc) | ||
|
||
self.content.append(f"## Arguments\n") | ||
headers = ["parameter", "Type", "Source", "Accepted values"] | ||
self.create_table(doc.arguments, headers) | ||
|
||
self.content.append(f"## Outputs\n") | ||
headers = ["Type", "Posible values"] | ||
self.create_output_table(doc.output, headers) | ||
|
||
self.content.append(f"## Description\n") | ||
self.content.append(f"{doc.description}\n") | ||
self.content.append(f"**Keywords**\n") | ||
for keyword in doc.keywords: | ||
self.content.append(f"- `{keyword}` \n") | ||
|
||
if doc.general_restrictions: | ||
self.content.append(f"## Notes\n") | ||
for general_restriction in doc.general_restrictions: | ||
self.content.append(f"- {general_restriction}\n") | ||
|
||
# self.content.append("\n### Examples\n") | ||
# for idx, example in enumerate(doc.examples, start=1): | ||
# self.content.append(f"**Example {idx}**:") | ||
# self.content.append(" - **Arguments**:") | ||
# for arg, value in example.arguments.items(): | ||
# self.content.append(f" - `{arg}`: `{value}`") | ||
# self.content.append(f" - **Should Pass**: `{example.should_pass}`") | ||
# if example.skipped: | ||
# self.content.append(f" - **Skipped**: `{example.skipped}`") | ||
# if example.expected is not None: | ||
# self.content.append(f" - **Expected**: `{example.expected}`") | ||
# self.content.append(f" - **Description**: {example.description}\n") | ||
|
||
def save(self, output_dir: Path): | ||
output_dir.mkdir(parents=True, exist_ok=True) | ||
with open((output_dir / self.helper_name).as_posix() + ".md", 'w') as file: | ||
file.write('\n'.join(self.content)) |
14 changes: 14 additions & 0 deletions
14
src/engine/test/helper_tests/engine_helper_test/src/documentation_generator/pdf_generator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from .types import Documentation | ||
from .exporter import * | ||
|
||
|
||
class PDFGenerator(IExporter): | ||
def __init__(self): | ||
self.content = [] | ||
self.helper_name = "" | ||
|
||
def create_document(self, doc: Documentation): | ||
pass | ||
|
||
def save(self, output_dir: Path): | ||
pass |
Oops, something went wrong.