Compare commits

...

12 Commits

Author SHA1 Message Date
6736f84d54 Fixed jsdoc md generation 2024-08-02 21:26:44 +07:00
0983e67f21 [jsdoc] Fixed api docs generation 2024-08-02 20:31:11 +07:00
8e7db87554 Refactoring linux packages deploy (#853)
* Fix deploy desktop editors linux packages (#842)

* Small fix

* Fix make targets

* Small fix

* Refactoring linux packages deploy
2024-07-31 14:18:27 +03:00
9d000b2284 Merge pull request #852 from ONLYOFFICE/fix/generation-path
Added branch name to dist path for jddoc json generation
2024-07-29 04:07:03 -07:00
e29fd0ca09 Added branch name to dist path for jsdoc json generation 2024-07-29 18:06:17 +07:00
dcfde5b5e7 Refactoring 2024-07-29 13:57:17 +03:00
871750d6ae Merge pull request #851 from ONLYOFFICE/fix/jsdoc
Fixed comments
2024-07-29 01:40:16 -07:00
d6b5dc0830 Fixed comments 2024-07-29 15:35:26 +07:00
e99a3e8978 Merge pull request #850 from ONLYOFFICE/fix/jsdoc
Fixed path in jsdoc generation script
2024-07-29 00:17:11 -07:00
13db6d3155 Fixed path in jsdoc generation script 2024-07-29 14:15:46 +07:00
f8845d4fc5 Merge pull request #849 from ONLYOFFICE/fix/jsdoc
Fixed docs generation scripts
2024-07-28 23:28:44 -07:00
efcfb00239 Fixed docs generation scripts 2024-07-29 13:27:41 +07:00
12 changed files with 249 additions and 199 deletions

2
.gitignore vendored
View File

@ -12,3 +12,5 @@ tests/puppeteer/node_modules
tests/puppeteer/work_directory
tests/puppeteer/package.json
tests/puppeteer/package-lock.json
scripts/sdkjs_common/jsdoc/node_modules
scripts/sdkjs_common/jsdoc/package-lock.json

View File

@ -384,7 +384,7 @@ def cmd2(prog, args=[], is_no_errors=False):
sys.exit("Error (" + prog + "): " + str(ret))
return ret
def cmd_exe(prog, args):
def cmd_exe(prog, args, is_no_errors=False):
prog_dir = os.path.dirname(prog)
env_dir = os.environ
if ("linux" == host_platform()):
@ -406,7 +406,7 @@ def cmd_exe(prog, args):
command += (" \"" + arg + "\"")
process = subprocess.Popen(command, stderr=subprocess.STDOUT, shell=True, env=env_dir)
ret = process.wait()
if ret != 0:
if ret != 0 and True != is_no_errors:
sys.exit("Error (" + prog + "): " + str(ret))
return ret
@ -1046,15 +1046,15 @@ def web_apps_addons_param():
def download(url, dst):
return cmd_exe("curl", ["-L", "-o", dst, url])
def extract(src, dst):
def extract(src, dst, is_no_errors=False):
app = "7za" if ("mac" == host_platform()) else "7z"
return cmd_exe(app, ["x", "-y", src, "-o" + dst])
return cmd_exe(app, ["x", "-y", src, "-o" + dst], is_no_errors)
def extract_unicode(src, dst):
def extract_unicode(src, dst, is_no_errors=False):
if "windows" == host_platform():
run_as_bat_win_isolate([u"chcp 65001", u"call 7z.exe x -y \"" + src + u"\" \"-o" + dst + u"\"", u"exit"])
return
return extract(src, dst)
return extract(src, dst, is_no_errors)
def archive_folder(src, dst):
app = "7za" if ("mac" == host_platform()) else "7z"

View File

@ -30,6 +30,59 @@ if utils.is_macos():
builder_product_name = "Document Builder"
if utils.is_linux():
desktop_make_targets = ["deb", "rpm", "suse-rpm", "tar"]
builder_make_targets = ["deb", "rpm"] # tar
server_make_targets = ["deb", "rpm", "tar"]
builder_make_targets = [
{
"make": "tar",
"src": "tar/*.tar*",
"dst": "builder/linux/generic/"
},
{
"make": "deb",
"src": "deb/*.deb",
"dst": "builder/linux/debian/"
},
{
"make": "rpm",
"src": "rpm/builddir/RPMS/*/*.rpm",
"dst": "builder/linux/rhel/"
}
]
desktop_make_targets = [
{
"make": "tar",
"src": "tar/*.tar*",
"dst": "desktop/linux/generic/"
},
{
"make": "deb",
"src": "deb/*.deb",
"dst": "desktop/linux/debian/"
},
{
"make": "rpm",
"src": "rpm/build/RPMS/*/*.rpm",
"dst": "desktop/linux/rhel/"
},
{
"make": "rpm-suse",
"src": "rpm-suse/build/RPMS/*/*.rpm",
"dst": "desktop/linux/suse/"
}
]
server_make_targets = [
{
"make": "deb",
"src": "deb/*.deb",
"dst": "server/linux/debian/"
},
{
"make": "rpm",
"src": "rpm/builddir/RPMS/*/*.rpm",
"dst": "server/linux/rhel/"
},
{
"make": "tar",
"src": "*.tar*",
"dst": "server/linux/snap/"
}
]

View File

@ -137,7 +137,7 @@ def make_linux():
utils.set_cwd("document-builder-package")
utils.log_h2("builder build")
make_args = branding.builder_make_targets
make_args = [t["make"] for t in branding.builder_make_targets]
if common.platform == "linux_aarch64":
make_args += ["-e", "UNAME_M=aarch64"]
if not branding.onlyoffice:
@ -146,32 +146,10 @@ def make_linux():
utils.set_summary("builder build", ret)
if common.deploy:
if ret:
if "tar" in branding.builder_make_targets:
utils.log_h2("builder tar deploy")
ret = s3_upload(
utils.glob_path("tar/*.tar.gz"),
"builder/linux/generic/")
utils.set_summary("builder tar deploy", ret)
if "deb" in branding.builder_make_targets:
utils.log_h2("builder deb deploy")
ret = s3_upload(
utils.glob_path("deb/*.deb"),
"builder/linux/debian/")
utils.set_summary("builder deb deploy", ret)
if "rpm" in branding.builder_make_targets:
utils.log_h2("builder rpm deploy")
ret = s3_upload(
utils.glob_path("rpm/builddir/RPMS/*/*.rpm"),
"builder/linux/rhel/")
utils.set_summary("builder rpm deploy", ret)
else:
if "tar" in branding.builder_make_targets:
utils.set_summary("builder tar deploy", False)
if "deb" in branding.builder_make_targets:
utils.set_summary("builder deb deploy", False)
if "rpm" in branding.builder_make_targets:
utils.set_summary("builder rpm deploy", False)
for t in branding.builder_make_targets:
utils.log_h2("builder " + t["make"] + " deploy")
ret = s3_upload(utils.glob_path(t["src"]), t["dst"])
utils.set_summary("builder " + t["make"] + " deploy", ret)
utils.set_cwd(common.workspace_dir)
return

View File

@ -329,7 +329,7 @@ def make_linux():
utils.set_cwd("desktop-apps/win-linux/package/linux")
utils.log_h2("desktop build")
make_args = branding.desktop_make_targets
make_args = [t["make"] for t in branding.desktop_make_targets]
if common.platform == "linux_aarch64":
make_args += ["-e", "UNAME_M=aarch64"]
if not branding.onlyoffice:
@ -337,68 +337,11 @@ def make_linux():
ret = utils.sh("make clean && make " + " ".join(make_args), verbose=True)
utils.set_summary("desktop build", ret)
rpm_arch = "*"
if common.platform == "linux_aarch64": rpm_arch = "aarch64"
if common.deploy:
if ret:
utils.log_h2("desktop tar deploy")
if "tar" in branding.desktop_make_targets:
ret = s3_upload(
utils.glob_path("tar/*.tar*"),
"desktop/linux/generic/")
utils.set_summary("desktop tar deploy", ret)
if "deb" in branding.desktop_make_targets:
utils.log_h2("desktop deb deploy")
ret = s3_upload(
utils.glob_path("deb/*.deb"),
"desktop/linux/debian/")
utils.set_summary("desktop deb deploy", ret)
if "deb-astra" in branding.desktop_make_targets:
utils.log_h2("desktop deb-astra deploy")
ret = s3_upload(
utils.glob_path("deb-astra/*.deb"),
"desktop/linux/astra/")
utils.set_summary("desktop deb-astra deploy", ret)
if "rpm" in branding.desktop_make_targets:
utils.log_h2("desktop rpm deploy")
ret = s3_upload(
utils.glob_path("rpm/builddir/RPMS/" + rpm_arch + "/*.rpm"),
"desktop/linux/rhel/")
utils.set_summary("desktop rpm deploy", ret)
if "suse-rpm" in branding.desktop_make_targets:
utils.log_h2("desktop suse-rpm deploy")
ret = s3_upload(
utils.glob_path("suse-rpm/builddir/RPMS/" + rpm_arch + "/*.rpm"),
"desktop/linux/suse/")
utils.set_summary("desktop suse-rpm deploy", ret)
if "apt-rpm" in branding.desktop_make_targets:
utils.log_h2("desktop apt-rpm deploy")
ret = s3_upload(
utils.glob_path("apt-rpm/builddir/RPMS/" + rpm_arch + "/*.rpm"),
"desktop/linux/altlinux/")
utils.set_summary("desktop apt-rpm deploy", ret)
if "urpmi" in branding.desktop_make_targets:
utils.log_h2("desktop urpmi deploy")
ret = s3_upload(
utils.glob_path("urpmi/builddir/RPMS/" + rpm_arch + "/*.rpm"),
"desktop/linux/rosa/")
utils.set_summary("desktop urpmi deploy", ret)
else:
if "tar" in branding.desktop_make_targets:
utils.set_summary("desktop tar deploy", False)
if "deb" in branding.desktop_make_targets:
utils.set_summary("desktop deb deploy", False)
if "deb-astra" in branding.desktop_make_targets:
utils.set_summary("desktop deb-astra deploy", False)
if "rpm" in branding.desktop_make_targets:
utils.set_summary("desktop rpm deploy", False)
if "suse-rpm" in branding.desktop_make_targets:
utils.set_summary("desktop suse-rpm deploy", False)
if "apt-rpm" in branding.desktop_make_targets:
utils.set_summary("desktop apt-rpm deploy", False)
if "urpmi" in branding.desktop_make_targets:
utils.set_summary("desktop urpmi deploy", False)
for t in branding.desktop_make_targets:
utils.log_h2("desktop " + t["make"] + " deploy")
ret = s3_upload(utils.glob_path(t["src"]), t["dst"])
utils.set_summary("desktop " + t["make"] + " deploy", ret)
utils.set_cwd(common.workspace_dir)
return

View File

@ -61,7 +61,8 @@ def make_linux(edition):
utils.set_cwd("document-server-package")
utils.log_h2("server " + edition + " build")
make_args = branding.server_make_targets + ["-e", "PRODUCT_NAME=" + product_name]
make_args = [t["make"] for t in branding.server_make_targets]
make_args += ["-e", "PRODUCT_NAME=" + product_name]
if common.platform == "linux_aarch64":
make_args += ["-e", "UNAME_M=aarch64"]
if not branding.onlyoffice:
@ -70,40 +71,10 @@ def make_linux(edition):
utils.set_summary("server " + edition + " build", ret)
if common.deploy:
if ret:
if "deb" in branding.server_make_targets:
utils.log_h2("server " + edition + " deb deploy")
ret = s3_upload(
utils.glob_path("deb/*.deb"),
"server/linux/debian/")
utils.set_summary("server " + edition + " deb deploy", ret)
if "rpm" in branding.server_make_targets:
utils.log_h2("server " + edition + " rpm deploy")
ret = s3_upload(
utils.glob_path("rpm/builddir/RPMS/*/*.rpm"),
"server/linux/rhel/")
utils.set_summary("server " + edition + " rpm deploy", ret)
if "apt-rpm" in branding.server_make_targets:
utils.log_h2("server " + edition + " apt-rpm deploy")
ret = s3_upload(
utils.glob_path("apt-rpm/builddir/RPMS/*/*.rpm"),
"server/linux/altlinux/")
utils.set_summary("server " + edition + " apt-rpm deploy", ret)
if "tar" in branding.server_make_targets:
utils.log_h2("server " + edition + " snap deploy")
ret = s3_upload(
utils.glob_path("*.tar.gz"),
"server/linux/snap/")
utils.set_summary("server " + edition + " snap deploy", ret)
else:
if "deb" in branding.server_make_targets:
utils.set_summary("server " + edition + " deb deploy", False)
if "rpm" in branding.server_make_targets:
utils.set_summary("server " + edition + " rpm deploy", False)
if "apt-rpm" in branding.server_make_targets:
utils.set_summary("server " + edition + " apt-rpm deploy", False)
if "tar" in branding.server_make_targets:
utils.set_summary("server " + edition + " snap deploy", False)
for t in branding.server_make_targets:
utils.log_h2("server " + edition + " " + t["make"] + " deploy")
ret = s3_upload(utils.glob_path(t["src"]), t["dst"])
utils.set_summary("server " + edition + " " + t["make"] + " deploy", ret)
utils.set_cwd(common.workspace_dir)
return

View File

@ -5,7 +5,8 @@
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {

View File

@ -1,14 +1,31 @@
exports.handlers = {
processingComplete: function(e) {
// Инициализация массива для сохранения отфильтрованных doclets
// array for filtered doclets
let filteredDoclets = [];
const cleanName = name => name ? name.replace('<anonymous>~', '').replaceAll('"', '') : name;
const classesDocletsMap = {}; // доклеты классов пишем в конце
let passedClasses = []; // те которые проходят для редактора
const classesDocletsMap = {}; // doclets for classes write at the end
let passedClasses = []; // passed classes for current editor
// набивка доступных классов текущего редактора
// Remove dublicates doclets
const latestDoclets = {};
e.doclets.forEach(doclet => {
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 shouldAddMethod =
doclet.kind !== 'member' &&
(!doclet.longname || doclet.longname.search('private') === -1) &&
doclet.scope !== 'inner' && hasTypeofEditorsTag;
if (shouldAddMethod || doclet.kind == 'typedef' || doclet.kind == 'class') {
latestDoclets[doclet.longname] = doclet;
}
});
e.doclets.splice(0, e.doclets.length, ...Object.values(latestDoclets));
// check available classess for current editor
for (let i = 0; i < e.doclets.length; i++) {
const doclet = e.doclets[i];
const isMethod = doclet.kind === 'function' || doclet.kind === 'method';
@ -30,7 +47,7 @@ exports.handlers = {
}
}
// проходимся по классам и удаляем из мапы те, что недоступны в редакторе
// remove unavailave classes in current editor
passedClasses = passedClasses.filter(className => {
const doclet = classesDocletsMap[className];
if (!doclet) {
@ -39,30 +56,28 @@ exports.handlers = {
const hasTypeofEditorsTag = !!(doclet.tags && doclet.tags.some(tag => tag.title === 'typeofeditors'));
// класс пропускаем если нет тега редактора или текущий редактор есть среди тегов
// class is passes if there is no editor tag or the current editor is among the tags
const isPassed = false == hasTypeofEditorsTag || doclet.tags.some(tag => tag.title === 'typeofeditors' && tag.value && tag.value.includes(process.env.EDITOR));
return isPassed;
});
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 shouldAdd =
const shouldAddMethod =
doclet.kind !== 'member' &&
(!doclet.longname || doclet.longname.search('private') === -1) &&
doclet.scope !== 'inner' &&
(!isMethod || hasTypeofEditorsTag);
doclet.scope !== 'inner' && hasTypeofEditorsTag;
if (shouldAdd) {
// если класса нет в нашей мапе, значит мы его удалили сами -> недоступен в редакторе
if (shouldAddMethod) {
// if the class is not in our map, then we deleted it ourselves -> not available in the editor
if (false == passedClasses.includes(cleanName(doclet.memberof))) {
continue;
}
// Оставляем только нужные поля
// We leave only the necessary fields
doclet.memberof = cleanName(doclet.memberof);
doclet.longname = cleanName(doclet.longname);
doclet.name = cleanName(doclet.name);
@ -121,15 +136,11 @@ exports.handlers = {
see: doclet.see
};
if (!filteredDoclet.see) {
delete filteredDoclet.see;
}
// Добавляем отфильтрованный doclet в массив
// Add the filtered doclet to the array
filteredDoclets.push(filteredDoclet);
}
else if (doclet.kind == 'class') {
// если класса нет в нашей мапе, значит мы его удалили сами -> недоступен в редакторе
// if the class is not in our map, then we deleted it ourselves -> not available in the editor
if (false == passedClasses.includes(cleanName(doclet.name))) {
continue;
}
@ -146,14 +157,60 @@ exports.handlers = {
lineno: doclet.meta.lineno,
columnno: doclet.meta.columnno
} : doclet.meta,
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,
see: doclet.see || undefined
};
filteredDoclets.push(filteredDoclet);
}
else if (doclet.kind == 'typedef') {
const filteredDoclet = {
comment: doclet.comment,
description: doclet.description,
name: cleanName(doclet.name),
longname: cleanName(doclet.longname),
kind: doclet.kind,
scope: "global",
meta: doclet.meta ? {
lineno: doclet.meta.lineno,
columnno: doclet.meta.columnno
} : doclet.meta,
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,
see: doclet.see,
type: doclet.type ? {
names: doclet.type.names,
parsedType: doclet.type.parsedType
} : doclet.type
};
filteredDoclets.push(filteredDoclet);
}
}
// Заменяем doclets на отфильтрованный массив
// Replace doclets with a filtered array
e.doclets.splice(0, e.doclets.length, ...filteredDoclets);
}
};

View File

@ -1,6 +1,6 @@
{
"source": {
"include": ["../../../../sdkjs-forms/apiBuilder.js"]
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs-forms/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {

View File

@ -5,7 +5,8 @@
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {

View File

@ -4,7 +4,7 @@ import json
import argparse
import re
# Конфигурационные файлы
# Configuration files
configs = [
"./config/word.json",
"./config/cell.json",
@ -19,17 +19,17 @@ editors_maps = {
"forms": "CFE"
}
def generate(output_dir):
def generate(output_dir, md=False):
missing_examples_file = f'{output_dir}/missing_examples.txt'
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Пересоздание файла missing_examples.txt
# Recreate missing_examples.txt file
with open(missing_examples_file, 'w', encoding='utf-8') as f:
f.write('')
# Генерация json документации
# Generate JSON documentation
for config in configs:
editor_name = config.split('/')[-1].replace('.json', '')
output_file = os.path.join(output_dir, editor_name + ".json")
@ -37,25 +37,31 @@ def generate(output_dir):
print(f"Generating {editor_name}.json: {command}")
subprocess.run(command, shell=True)
# дозапись примеров в json документацию
# Append examples to JSON documentation
for config in configs:
editor_name = config.split('/')[-1].replace('.json', '')
output_file = os.path.join(output_dir, editor_name + ".json")
# Чтение JSON файла
# Read the JSON file
with open(output_file, 'r', encoding='utf-8') as f:
data = json.load(f)
# Модификация JSON данных
# Modify JSON data
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 editor_name == 'forms':
doclet['see'][0] = doclet['see'][0].replace('{Editor}', 'Word')
else:
doclet['see'][0] = doclet['see'][0].replace('{Editor}', editor_name.title())
file_path = '../../../../' + 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()
# Извлечение первой строки как комментария, если она существует
# Extract the first line as a comment if it exists
lines = example_content.split('\n')
if lines[0].startswith('//'):
comment = lines[0] + '\n'
@ -64,32 +70,54 @@ def generate(output_dir):
comment = ''
code_content = example_content
# Форматирование содержимого для doclet['example']
doclet['example'] = remove_js_comments(comment) + "```js\n" + remove_builder_lines(code_content) + "\n```"
del doclet['see']
# Format content for doclet['example']
doclet['example'] = remove_js_comments(comment) + "```js\n" + code_content + "\n```"
if md == False:
doclet['description'] = doclet['description'] + f'\n\n## Try it\n\n ```js document-builder={{"documentType": "{editor_name.title()}"}}\n{code_content}\n```'
else:
# Запись пропущенного примера в файл missing_examples.txt
# Record missing examples in missing_examples.txt
with open(missing_examples_file, 'a', encoding='utf-8') as missing_file:
missing_file.write(f"{file_path}\n")
# Запись измененного JSON файла обратно
# Write the modified JSON file back
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
print("Documentation generation completed.")
def remove_builder_lines(text):
lines = text.splitlines() # Разделить текст на строки
lines = text.splitlines() # Split text into lines
filtered_lines = [line for line in lines if not line.strip().startswith("builder.")]
return "\n".join(filtered_lines)
def remove_js_comments(text):
# Удаляем однострочные комментарии, оставляя текст после //
# Remove single-line comments, leaving text after //
text = re.sub(r'^\s*//\s?', '', text, flags=re.MULTILINE)
# Удаляем многострочные комментарии, оставляя текст после /*
# Remove multi-line comments, leaving text after /*
text = re.sub(r'/\*\s*|\s*\*/', '', text, flags=re.DOTALL)
return text.strip()
def get_current_branch(path):
try:
# Navigate to the specified directory and get the current branch name
result = subprocess.run(
["git", "rev-parse", "--abbrev-ref", "HEAD"],
cwd=path,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if result.returncode == 0:
return result.stdout.strip()
else:
print(f"Error: {result.stderr}")
return None
except Exception as e:
print(f"Exception: {e}")
return None
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate documentation")
parser.add_argument(
@ -101,4 +129,8 @@ if __name__ == "__main__":
)
args = parser.parse_args()
generate(args.destination)
branch_name = get_current_branch("../../../../sdkjs")
if branch_name:
args.destination = f"{args.destination}/{branch_name}"
generate(args.destination)

View File

@ -5,7 +5,7 @@ import shutil
import argparse
import generate_docs_json
# Конфигурационные файлы
# Configuration files
editors = [
"word",
"cell",
@ -22,9 +22,9 @@ def write_markdown_file(file_path, content):
md_file.write(content)
def remove_js_comments(text):
# Удаляем однострочные комментарии, оставляя текст после //
# Remove single-line comments, leaving text after //
text = re.sub(r'^\s*//\s?', '', text, flags=re.MULTILINE)
# Удаляем многострочные комментарии, оставляя текст после /*
# Remove multi-line comments, leaving text after /*
text = re.sub(r'/\*\s*|\s*\*/', '', text, flags=re.DOTALL)
return text.strip()
@ -32,14 +32,13 @@ def correct_description(string):
if string is None:
return 'No description provided.'
# Заменяем открывающий тег <b> на **
# Replace opening <b> tag with **
string = re.sub(r'<b>', '**', string)
# Заменяем закрывающий тег </b> на **
# Replace closing </b> tag with **
string = re.sub(r'</b>', '**', string)
# Заметка
# Note
return re.sub(r'<note>(.*?)</note>', r'💡 \1', string, flags=re.DOTALL)
def correct_default_value(value, enumerations, classes):
if value is None:
return ''
@ -56,19 +55,19 @@ def correct_default_value(value, enumerations, classes):
def remove_line_breaks(string):
return re.sub(r'[\r\n]', '', string)
def generate_data_types_markdown(types, enumerations, classes):
def generate_data_types_markdown(types, enumerations, classes, root='../../'):
param_types_md = ' &#124;'.join(types)
for enum in enumerations:
if enum['name'] in types:
param_types_md = param_types_md.replace(enum['name'], f"[{enum['name']}](../../Enumeration/{enum['name']}.md)")
param_types_md = param_types_md.replace(enum['name'], f"[{enum['name']}]({root}Enumeration/{enum['name']}.md)")
for cls in classes:
if cls in types:
param_types_md = param_types_md.replace(cls, f"[{cls}](../../{cls}/{cls}.md)")
param_types_md = param_types_md.replace(cls, f"[{cls}]({root}{cls}/{cls}.md)")
def replace_with_links(match):
element = match.group(1).strip()
base_type = element.split('.')[0] # Берем только первую часть до точки, если она есть
base_type = element.split('.')[0] # Take only the first part before the dot, if any
if any(enum['name'] == base_type for enum in enumerations):
return f"<[{element}](../../Enumeration/{base_type}.md)>"
elif base_type in classes:
@ -77,8 +76,11 @@ def generate_data_types_markdown(types, enumerations, classes):
return re.sub(r'<([^<>]+)>', replace_with_links, param_types_md)
def generate_class_markdown(class_name, methods):
def generate_class_markdown(class_name, methods, properties, enumerations, classes):
content = f"# {class_name}\n\nRepresents the {class_name} class.\n\n"
content += generate_properties_markdown(properties, enumerations, classes, '../')
content += "## Methods\n\n"
for method in methods:
method_name = method['name']
@ -137,6 +139,24 @@ def generate_method_markdown(method, enumerations, classes):
return content
def generate_properties_markdown(properties, enumerations, classes, root='../../'):
if (properties is None):
return ''
content = "## Properties\n\n"
content += "| Name | Type | Description |\n"
content += "| ---- | ---- | ----------- |\n"
for prop in properties:
prop_name = prop['name']
prop_description = prop.get('description', 'No description provided.')
prop_description = remove_line_breaks(correct_description(prop_description))
param_types_md = generate_data_types_markdown(prop['type']['names'], enumerations, classes, root)
content += f"| {prop_name} | {param_types_md} | {prop_description} |\n"
content += "\n"
return content
def generate_enumeration_markdown(enumeration, enumerations, classes):
enum_name = enumeration['name']
description = enumeration.get('description', 'No description provided.')
@ -160,16 +180,7 @@ def generate_enumeration_markdown(enumeration, enumerations, classes):
content += f"- {element_name}\n"
elif enumeration['properties'] is not None:
content += "## Type\n\nObject\n\n"
content += "## Properties\n\n"
content += "| Name | Type | Description |\n"
content += "| ---- | ---- | ----------- |\n"
properties = enumeration['properties']
for prop in properties:
prop_name = prop['name']
prop_description = prop.get('description', 'No description provided.')
prop_description = remove_line_breaks(correct_description(prop_description))
param_types_md = generate_data_types_markdown(prop['type']['names'], enumerations, classes)
content += f"| {prop_name} | {param_types_md} | {prop_description} |\n"
content += generate_properties_markdown(enumeration['properties'], enumerations, classes)
else:
content += "## Type\n\n"
types = enumeration['type']['names']
@ -187,12 +198,14 @@ def generate_enumeration_markdown(enumeration, enumerations, classes):
def process_doclets(data, output_dir):
classes = {}
classes_props = {}
enumerations = []
for doclet in data:
if doclet['kind'] == 'class':
class_name = doclet['name']
classes[class_name] = []
classes_props[class_name] = doclet.get('properties', None)
elif doclet['kind'] == 'function':
class_name = doclet.get('memberof')
if class_name:
@ -209,7 +222,7 @@ def process_doclets(data, output_dir):
os.makedirs(methods_dir, exist_ok=True)
# Write class file
class_content = generate_class_markdown(class_name, methods)
class_content = generate_class_markdown(class_name, methods, classes_props[class_name], enumerations, classes)
write_markdown_file(os.path.join(class_dir, f"{class_name}.md"), class_content)
# Write method files
@ -225,11 +238,10 @@ def process_doclets(data, output_dir):
enum_content = generate_enumeration_markdown(enum, enumerations, classes)
write_markdown_file(os.path.join(enum_dir, f"{enum['name']}.md"), enum_content)
def generate(output_dir):
print('Generating Markdown documentation...')
generate_docs_json.generate(output_dir + 'tmp_json')
generate_docs_json.generate(output_dir + 'tmp_json', md=True)
for editor_name in editors:
input_file = os.path.join(output_dir + 'tmp_json', editor_name + ".json")
os.makedirs(output_dir + f'/{editor_name.title()}', exist_ok=True)