Skip to content

Commit

Permalink
Added documentation generation scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
KhromovNikita committed Jul 26, 2024
1 parent 6bf413a commit 89c9d36
Show file tree
Hide file tree
Showing 10 changed files with 563 additions and 4 deletions.
8 changes: 4 additions & 4 deletions scripts/sdkjs_common/generate_builder_intarface.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ def generate(self):
self.numfile += 1
correctContent = ''.join(self.records)
correctContent += "\n"
os.mkdir('deploy/api_builder/' + self.folder)
writeFile("deploy/api_builder/" + self.folder + "/api.js", correctContent)
os.mkdir('deploy/api_builder/interface/' + self.folder)
writeFile("deploy/api_builder/interface/" + self.folder + "/api.js", correctContent)
return

def convert_to_interface(arrFiles, sEditorType):
Expand All @@ -200,8 +200,8 @@ def convert_to_interface(arrFiles, sEditorType):
old_cur = os.getcwd()
os.chdir("../../../sdkjs")
if True == os.path.isdir('deploy/api_builder'):
shutil.rmtree('deploy/api_builder', ignore_errors=True)
os.mkdir('deploy/api_builder')
shutil.rmtree('deploy/api_builder/interface', ignore_errors=True)
os.mkdir('deploy/api_builder/interface')
convert_to_interface(["word/apiBuilder.js"], "word")
convert_to_interface(["word/apiBuilder.js", "slide/apiBuilder.js"], "slide")
convert_to_interface(["word/apiBuilder.js", "slide/apiBuilder.js", "cell/apiBuilder.js"], "cell")
Expand Down
57 changes: 57 additions & 0 deletions scripts/sdkjs_common/jsdoc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

# Documentation Generation Guide

This guide explains how to generate documentation for Onlyoffice API project using the provided Python scripts, `generate_docs_json.py` and `generate_docs_md.py`. These scripts are used to create JSON and Markdown documentation for the `apiBuilder.js` files from the word, cell, and slide editors.

## Prerequisites

1. **Node.js and npm**: Ensure you have Node.js and npm installed on your machine. You can download them from [Node.js official website](https://nodejs.org/).

2. **jsdoc**: The scripts use `jsdoc` to generate documentation. Install it using npm:
```bash
npm install
```

## Scripts Overview

### `generate_docs_json.py`

This script generates JSON documentation based on the `apiBuilder.js` files.

- **Usage**:
```bash
python generate_docs_json.py output_path
```

- **Parameters**:
- `output_path` (optional): The directory where the JSON documentation will be saved. If not specified, the default path is `Onlyoffice/sdkjs/deploy/api_builder/json`.

### `generate_docs_md.py`

This script generates Markdown documentation from the `apiBuilder.js` files.

- **Usage**:
```bash
python generate_docs_md.py output_path
```

- **Parameters**:
- `output_path` (optional): The directory where the Markdown documentation will be saved. If not specified, the default path is `Onlyoffice/office-js-api`.

## Example

To generate JSON documentation with the default output path:
```bash
python generate_docs_json.py /path/to/save/json
```

To generate Markdown documentation and specify a custom output path:
```bash
python generate_docs_md.py /path/to/save/markdown
```

## Notes

- Make sure to have all necessary permissions to run these scripts and write to the specified directories.
- The output directories will be created if they do not exist.

15 changes: 15 additions & 0 deletions scripts/sdkjs_common/jsdoc/config/cell.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"source": {
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs/slide/apiBuilder.js", "../../../../sdkjs/cell/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true
},
"templates": {
"json": {
"pretty": true
}
}
}
88 changes: 88 additions & 0 deletions scripts/sdkjs_common/jsdoc/config/correct_doclets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
exports.handlers = {
processingComplete: function(e) {
// Инициализация массива для сохранения отфильтрованных doclets
const filteredDoclets = [];

// Итерация по doclets и фильтрация
for (let i = 0; i < e.doclets.length; i++) {
const doclet = e.doclets[i];
const isMethod = doclet.kind === 'function' || doclet.kind === 'method';
const hasTypeofEditorsTag = isMethod && doclet.tags && doclet.tags.some(tag => tag.title === 'typeofeditors' && tag.value.includes(process.env.EDITOR));

const bAdd = doclet.kind != 'member' && (!doclet.longname || doclet.longname.search('private') == -1) && doclet.scope != "inner";
const bSkipMethod = isMethod && !hasTypeofEditorsTag;

if (!bSkipMethod && bAdd) {
// Оставляем только нужные поля
doclet.memberof = doclet.memberof ? doclet.memberof.replace('<anonymous>~', '') : doclet.memberof;
doclet.longname = doclet.longname ? doclet.longname.replace('<anonymous>~', '').replaceAll('"', '') : doclet.longname;
doclet.name = doclet.name ? doclet.name.replace('<anonymous>~', '').replaceAll('"', '') : doclet.name;

const filteredDoclet = {
comment: doclet.comment,
description: doclet.description,
memberof: doclet.memberof ? doclet.memberof.replace('<anonymous>~', '') : doclet.memberof,

params: doclet.params ? doclet.params.map(param => ({
type: param.type ? {
names: param.type.names,
parsedType: param.type.parsedType
} : param.type,

name: param.name,
description: param.description,
optional: param.optional,
defaultvalue: param.defaultvalue
})) : doclet.params,

returns: doclet.returns ? doclet.returns.map(returnObj => ({
type: {
names: returnObj.type.names,
parsedType: returnObj.type.parsedType
}
})) : doclet.returns,

name: doclet.name,
longname: doclet.longname ? doclet.longname.replace('<anonymous>~', '') : doclet.longname,
kind: doclet.kind,
scope: doclet.scope,

type: doclet.type ? {
names: doclet.type.names,
parsedType: doclet.type.parsedType
} : doclet.type,

properties: doclet.properties ? doclet.properties.map(property => ({
type: property.type ? {
names: property.type.names,
parsedType: property.type.parsedType
} : property.type,

name: property.name,
description: property.description,
optional: property.optional,
defaultvalue: property.defaultvalue
})) : doclet.properties,

meta: doclet.meta ? {
lineno: doclet.meta.lineno,
columnno: doclet.meta.columnno,
file: doclet.meta.file
} : doclet.meta,

see: doclet.see
};

if (!doclet.see) {
delete doclet.see;
}

// Добавляем отфильтрованный doclet в массив
filteredDoclets.push(filteredDoclet);
}
}

// Заменяем doclets на отфильтрованный массив
e.doclets.splice(0, e.doclets.length, ...filteredDoclets);
}
};
16 changes: 16 additions & 0 deletions scripts/sdkjs_common/jsdoc/config/forms.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"source": {
"include": ["../../../../sdkjs-forms/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}
15 changes: 15 additions & 0 deletions scripts/sdkjs_common/jsdoc/config/slide.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"source": {
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs/slide/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true
},
"templates": {
"json": {
"pretty": true
}
}
}
16 changes: 16 additions & 0 deletions scripts/sdkjs_common/jsdoc/config/word.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"source": {
"include": ["../../../../sdkjs/word/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}
91 changes: 91 additions & 0 deletions scripts/sdkjs_common/jsdoc/generate_docs_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import os
import subprocess
import json
import argparse

# Конфигурационные файлы
configs = [
"./config/word.json",
"./config/cell.json",
"./config/slide.json",
"./config/forms.json"
]

editors_maps = {
"word": "CDE",
"cell": "CSE",
"slide": "CPE",
"forms": "CFE"
}

def generate(output_dir):
missing_examples_file = f'{output_dir}/missing_examples.txt'

if not os.path.exists(output_dir):
os.makedirs(output_dir)

# Пересоздание файла missing_examples.txt
with open(missing_examples_file, 'w', encoding='utf-8') as f:
f.write('')

# Генерация json документации
for config in configs:
editor_name = config.split('/')[-1].replace('.json', '')
output_file = os.path.join(output_dir, editor_name + ".json")
command = f"set EDITOR={editors_maps[editor_name]} && npx jsdoc -c {config} -X > {output_file}"
print(f"Generating {editor_name}.json: {command}")
subprocess.run(command, shell=True)

# дозапись примеров в json документацию
for config in configs:
editor_name = config.split('/')[-1].replace('.json', '')
output_file = os.path.join(output_dir, editor_name + ".json")

# Чтение JSON файла
with open(output_file, 'r', encoding='utf-8') as f:
data = json.load(f)

# Модификация JSON данных
for doclet in data:
if 'see' in doclet:
if doclet['see'] is not None:
file_path = 'C:\\Users\\khrom\\Desktop\\Onlyoffice\\' + doclet['see'][0]
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as see_file:
example_content = see_file.read()

# Извлечение первой строки как комментария, если она существует
lines = example_content.split('\n')
if lines[0].startswith('//'):
comment = lines[0] + '\n'
code_content = '\n'.join(lines[1:])
else:
comment = ''
code_content = example_content

# Форматирование содержимого для doclet['example']
doclet['example'] = comment + "```js\n" + code_content + "\n```"
del doclet['see']
else:
# Запись пропущенного примера в файл missing_examples.txt
with open(missing_examples_file, 'a', encoding='utf-8') as missing_file:
missing_file.write(f"{file_path}\n")

# Запись измененного JSON файла обратно
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)

print("Documentation generation completed.")

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate documentation")
parser.add_argument(
"destination",
type=str,
help="Destination directory for the generated documentation",
nargs='?', # Indicates the argument is optional
default="../../../../sdkjs/deploy/api_builder/json" # Default value
)
args = parser.parse_args()

generate(args.destination)
Loading

0 comments on commit 89c9d36

Please sign in to comment.