mirror of
https://github.com/ONLYOFFICE/build_tools.git
synced 2026-04-07 14:06:31 +08:00
Compare commits
30 Commits
v8.2.0.7
...
fix/docs-g
| Author | SHA1 | Date | |
|---|---|---|---|
| 6736f84d54 | |||
| 0983e67f21 | |||
| 8e7db87554 | |||
| 9d000b2284 | |||
| e29fd0ca09 | |||
| dcfde5b5e7 | |||
| 871750d6ae | |||
| d6b5dc0830 | |||
| e99a3e8978 | |||
| 13db6d3155 | |||
| f8845d4fc5 | |||
| efcfb00239 | |||
| 1727313e54 | |||
| f6d55d07c1 | |||
| 331bbadaad | |||
| f012c604b8 | |||
| a8f6b0c599 | |||
| e46d73869c | |||
| 6bf413a008 | |||
| 4e5eadbf82 | |||
| 3af65bf276 | |||
| 0a51c3bdea | |||
| ba6c3a8f38 | |||
| 66e196b5ec | |||
| d4a49d7137 | |||
| edccac17f6 | |||
| 1d36cad17e | |||
| 08e6d5ba53 | |||
| 6505ee1b35 | |||
| e719ae24f0 |
13
.github/workflows/check.yml
vendored
13
.github/workflows/check.yml
vendored
@ -1,25 +1,24 @@
|
||||
name: Markdown check
|
||||
name: Markdown Lint
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- '**'
|
||||
paths:
|
||||
- '*.md'
|
||||
- 'develop/*.md'
|
||||
- 'scripts/**.md'
|
||||
- '.markdownlint.jsonc'
|
||||
|
||||
jobs:
|
||||
markdownlint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v9
|
||||
- uses: actions/checkout@v4
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v16
|
||||
with:
|
||||
command: config
|
||||
globs: |
|
||||
.markdownlint.jsonc
|
||||
*.md
|
||||
develop/*.md
|
||||
scripts/**.md
|
||||
scripts/**.md
|
||||
|
||||
9
.github/workflows/update-version.yml
vendored
9
.github/workflows/update-version.yml
vendored
@ -3,16 +3,13 @@ name: Update hard-coded version
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
|
||||
update-version:
|
||||
if: >-
|
||||
${{ contains(github.ref, 'refs/heads/hotfix/v') ||
|
||||
contains(github.ref, 'refs/heads/release/v') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.PUSH_TOKEN }}
|
||||
|
||||
@ -25,9 +22,9 @@ jobs:
|
||||
run: echo "${{ env.version }}" > version
|
||||
|
||||
- name: Commit & push changes
|
||||
uses: EndBug/add-and-commit@v8
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
author_name: github-actions[bot]
|
||||
author_email: github-actions[bot]@users.noreply.github.com
|
||||
message: Update hard-coded version to v${{ env.version }}
|
||||
message: Update hard-coded version to ${{ env.version }}
|
||||
add: version
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
||||
@ -196,9 +196,8 @@ LD_LIBRARY_PATH=./ ./DesktopEditors
|
||||
**Note**: The created database must have **onlyoffice** both for user and password.
|
||||
|
||||
```bash
|
||||
sudo -i -u postgres psql -c "CREATE DATABASE onlyoffice;"
|
||||
sudo -i -u postgres psql -c "CREATE USER onlyoffice WITH password 'onlyoffice';"
|
||||
sudo -i -u postgres psql -c "GRANT ALL privileges ON DATABASE onlyoffice TO onlyoffice;"
|
||||
sudo -i -u postgres psql -c "CREATE USER onlyoffice WITH PASSWORD 'onlyoffice';"
|
||||
sudo -i -u postgres psql -c "CREATE DATABASE onlyoffice OWNER onlyoffice;"
|
||||
```
|
||||
|
||||
3. Configure the database:
|
||||
|
||||
@ -61,7 +61,6 @@ Clone development modules to the work dir
|
||||
* `server` repo is located [here](https://github.com/ONLYOFFICE/server/)
|
||||
|
||||
```bash
|
||||
cd ../..
|
||||
git clone https://github.com/ONLYOFFICE/sdkjs.git
|
||||
git clone https://github.com/ONLYOFFICE/web-apps.git
|
||||
git clone https://github.com/ONLYOFFICE/server.git
|
||||
@ -75,14 +74,15 @@ along with the relative paths to the required folders.
|
||||
The folders `sdkjs` and `web-apps` are required for proper development workflow.
|
||||
The folders `server` is optional
|
||||
|
||||
**Note**: Run command with the current working directory
|
||||
containing `sdkjs`, `web-apps`...
|
||||
|
||||
**Note**: ONLYOFFICE server uses port 80.
|
||||
Look for another application using port 80 and stop it
|
||||
|
||||
**Note**: Server start with `sdkjs` and `web-apps` takes 15 minutes
|
||||
and takes 20 minutes with `server`
|
||||
|
||||
**Note**: Run command from work dir with development modules
|
||||
|
||||
### docker run on Windows (PowerShell)
|
||||
|
||||
**Note**: Run PowerShell as administrator to fix EACCES error when installing
|
||||
|
||||
@ -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"
|
||||
@ -1354,7 +1354,7 @@ def copy_sdkjs_plugins(dst_dir, is_name_as_guid=False, is_desktop_local=False, i
|
||||
plugins_dir = __file__script__path__ + "/../../onlyoffice.github.io/sdkjs-plugins/content"
|
||||
plugins_list_config = config.option("sdkjs-plugin")
|
||||
if isXp:
|
||||
plugins_list_config="photoeditor, macros, drawio, highlightcode, doc2md"
|
||||
plugins_list_config="photoeditor, macros, highlightcode, doc2md"
|
||||
if ("" == plugins_list_config):
|
||||
return
|
||||
plugins_list = plugins_list_config.rsplit(", ")
|
||||
@ -1743,3 +1743,14 @@ def check_tools():
|
||||
create_dir(directory + "/qt")
|
||||
cmd("python", [directory + "/arm/build_qt.py", "--arch", "arm64", directory + "/qt/arm64"])
|
||||
return
|
||||
|
||||
def apply_patch(file, patch):
|
||||
patch_content = readFile(patch)
|
||||
index1 = patch_content.find("<<<<<<<")
|
||||
index2 = patch_content.find("=======")
|
||||
index3 = patch_content.find(">>>>>>>")
|
||||
file_content_old = patch_content[index1 + 7:index2].strip()
|
||||
file_content_new = patch_content[index2 + 7:index3].strip()
|
||||
#file_content_new = "\n#if 0" + file_content_old + "#else" + file_content_new + "#endif\n"
|
||||
replaceInFile(file, file_content_old, file_content_new)
|
||||
return
|
||||
|
||||
@ -49,7 +49,6 @@ cpp_flags = [
|
||||
|
||||
"-DUCONFIG_NO_COLLATION=0",
|
||||
"-DUCONFIG_NO_FORMATTING=0",
|
||||
"-DUCONFIG_NO_LEGACY_CONVERSION=1",
|
||||
"-DUCONFIG_NO_REGULAR_EXPRESSIONS=0",
|
||||
"-DUCONFIG_NO_TRANSLITERATION=0",
|
||||
|
||||
|
||||
@ -27,8 +27,16 @@ def make():
|
||||
base_dir = base.get_script_dir() + "/../../core/Common/3dParty/socketio"
|
||||
if not base.is_dir(base_dir + "/socket.io-client-cpp"):
|
||||
base.cmd_in_dir(base_dir, "git", ["clone", "https://github.com/socketio/socket.io-client-cpp.git"])
|
||||
base.cmd_in_dir(base_dir + "/socket.io-client-cpp", "git", ["checkout", "da779141a7379cc30c870d48295033bc16a23c66"])
|
||||
base.cmd_in_dir(base_dir + "/socket.io-client-cpp", "git", ["submodule", "init"])
|
||||
base.cmd_in_dir(base_dir + "/socket.io-client-cpp", "git", ["submodule", "update"])
|
||||
base.cmd_in_dir(base_dir + "/socket.io-client-cpp/lib/asio", "git", ["checkout", "230c0d2ae035c5ce1292233fcab03cea0d341264"])
|
||||
base.cmd_in_dir(base_dir + "/socket.io-client-cpp/lib/websocketpp", "git", ["checkout", "56123c87598f8b1dd471be83ca841ceae07f95ba"])
|
||||
# patches
|
||||
base.apply_patch(base_dir + "/socket.io-client-cpp/lib/websocketpp/websocketpp/impl/connection_impl.hpp", base_dir + "/patches/websocketpp.patch")
|
||||
base.apply_patch(base_dir + "/socket.io-client-cpp/src/internal/sio_client_impl.cpp", base_dir + "/patches/sio_client_impl_fail.patch")
|
||||
base.apply_patch(base_dir + "/socket.io-client-cpp/src/internal/sio_client_impl.cpp", base_dir + "/patches/sio_client_impl_open.patch")
|
||||
base.apply_patch(base_dir + "/socket.io-client-cpp/src/internal/sio_client_impl.cpp", base_dir + "/patches/sio_client_impl_close_timeout.patch")
|
||||
|
||||
# no tls realization (remove if socket.io fix this)
|
||||
dst_dir = base_dir + "/socket.io-client-cpp/src_no_tls"
|
||||
|
||||
@ -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/"
|
||||
}
|
||||
]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
import os
|
||||
import shutil
|
||||
import re
|
||||
import argparse
|
||||
|
||||
def readFile(path):
|
||||
with open(path, "r", errors='replace') as file:
|
||||
filedata = file.read()
|
||||
@ -179,7 +181,7 @@ class EditorApi(object):
|
||||
|
||||
def generate(self):
|
||||
for file in self.files:
|
||||
file_content = readFile(file)
|
||||
file_content = readFile(f'{sdkjs_dir}/{file}')
|
||||
arrRecords = file_content.split("/**")
|
||||
arrRecords = arrRecords[1:-1]
|
||||
for record in arrRecords:
|
||||
@ -187,8 +189,8 @@ class EditorApi(object):
|
||||
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(args.destination + self.folder)
|
||||
writeFile(args.destination + self.folder + "/api.js", correctContent)
|
||||
return
|
||||
|
||||
def convert_to_interface(arrFiles, sEditorType):
|
||||
@ -197,12 +199,27 @@ def convert_to_interface(arrFiles, sEditorType):
|
||||
editor.generate()
|
||||
return
|
||||
|
||||
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')
|
||||
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")
|
||||
os.chdir(old_cur)
|
||||
sdkjs_dir = "../../../sdkjs"
|
||||
|
||||
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="../../../onlyoffice.github.io\sdkjs-plugins\content\macros\libs/" # Default value
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
old_cur = os.getcwd()
|
||||
|
||||
if True == os.path.isdir(args.destination):
|
||||
shutil.rmtree(args.destination, ignore_errors=True)
|
||||
os.mkdir(args.destination)
|
||||
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")
|
||||
os.chdir(old_cur)
|
||||
|
||||
|
||||
|
||||
57
scripts/sdkjs_common/jsdoc/README.md
Normal file
57
scripts/sdkjs_common/jsdoc/README.md
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
# Documentation Generation Guide
|
||||
|
||||
This guide explains how to generate documentation for Onlyoffice API 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.
|
||||
|
||||
16
scripts/sdkjs_common/jsdoc/config/cell.json
Normal file
16
scripts/sdkjs_common/jsdoc/config/cell.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"source": {
|
||||
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs/slide/apiBuilder.js", "../../../../sdkjs/cell/apiBuilder.js"]
|
||||
},
|
||||
"plugins": ["./correct_doclets.js"],
|
||||
"opts": {
|
||||
"destination": "./out",
|
||||
"recurse": true,
|
||||
"encoding": "utf8"
|
||||
},
|
||||
"templates": {
|
||||
"json": {
|
||||
"pretty": true
|
||||
}
|
||||
}
|
||||
}
|
||||
216
scripts/sdkjs_common/jsdoc/config/correct_doclets.js
Normal file
216
scripts/sdkjs_common/jsdoc/config/correct_doclets.js
Normal file
@ -0,0 +1,216 @@
|
||||
exports.handlers = {
|
||||
processingComplete: function(e) {
|
||||
// array for filtered doclets
|
||||
let filteredDoclets = [];
|
||||
|
||||
const cleanName = name => name ? name.replace('<anonymous>~', '').replaceAll('"', '') : name;
|
||||
|
||||
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';
|
||||
const hasTypeofEditorsTag = isMethod && doclet.tags && doclet.tags.some(tag => tag.title === 'typeofeditors' && tag.value.includes(process.env.EDITOR));
|
||||
|
||||
const shouldAdd =
|
||||
doclet.kind !== 'member' &&
|
||||
(!doclet.longname || doclet.longname.search('private') === -1) &&
|
||||
doclet.scope !== 'inner' &&
|
||||
(!isMethod || hasTypeofEditorsTag);
|
||||
|
||||
if (shouldAdd) {
|
||||
if (doclet.memberof && false == passedClasses.includes(cleanName(doclet.memberof))) {
|
||||
passedClasses.push(cleanName(doclet.memberof));
|
||||
}
|
||||
}
|
||||
else if (doclet.kind == 'class') {
|
||||
classesDocletsMap[cleanName(doclet.name)] = doclet;
|
||||
}
|
||||
}
|
||||
|
||||
// remove unavailave classes in current editor
|
||||
passedClasses = passedClasses.filter(className => {
|
||||
const doclet = classesDocletsMap[className];
|
||||
if (!doclet) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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 shouldAddMethod =
|
||||
doclet.kind !== 'member' &&
|
||||
(!doclet.longname || doclet.longname.search('private') === -1) &&
|
||||
doclet.scope !== 'inner' && hasTypeofEditorsTag;
|
||||
|
||||
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);
|
||||
|
||||
const filteredDoclet = {
|
||||
comment: doclet.comment,
|
||||
description: doclet.description,
|
||||
memberof: cleanName(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: cleanName(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
|
||||
} : doclet.meta,
|
||||
|
||||
see: doclet.see
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
const filteredDoclet = {
|
||||
comment: doclet.comment,
|
||||
description: doclet.description,
|
||||
name: cleanName(doclet.name),
|
||||
longname: cleanName(doclet.longname),
|
||||
kind: doclet.kind,
|
||||
scope: "global",
|
||||
augments: doclet.augments || undefined,
|
||||
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 || 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace doclets with a filtered array
|
||||
e.doclets.splice(0, e.doclets.length, ...filteredDoclets);
|
||||
}
|
||||
};
|
||||
16
scripts/sdkjs_common/jsdoc/config/forms.json
Normal file
16
scripts/sdkjs_common/jsdoc/config/forms.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"source": {
|
||||
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs-forms/apiBuilder.js"]
|
||||
},
|
||||
"plugins": ["./correct_doclets.js"],
|
||||
"opts": {
|
||||
"destination": "./out",
|
||||
"recurse": true,
|
||||
"encoding": "utf8"
|
||||
},
|
||||
"templates": {
|
||||
"json": {
|
||||
"pretty": true
|
||||
}
|
||||
}
|
||||
}
|
||||
16
scripts/sdkjs_common/jsdoc/config/slide.json
Normal file
16
scripts/sdkjs_common/jsdoc/config/slide.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"source": {
|
||||
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs/slide/apiBuilder.js"]
|
||||
},
|
||||
"plugins": ["./correct_doclets.js"],
|
||||
"opts": {
|
||||
"destination": "./out",
|
||||
"recurse": true,
|
||||
"encoding": "utf8"
|
||||
},
|
||||
"templates": {
|
||||
"json": {
|
||||
"pretty": true
|
||||
}
|
||||
}
|
||||
}
|
||||
16
scripts/sdkjs_common/jsdoc/config/word.json
Normal file
16
scripts/sdkjs_common/jsdoc/config/word.json
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
136
scripts/sdkjs_common/jsdoc/generate_docs_json.py
Normal file
136
scripts/sdkjs_common/jsdoc/generate_docs_json.py
Normal file
@ -0,0 +1,136 @@
|
||||
import os
|
||||
import subprocess
|
||||
import json
|
||||
import argparse
|
||||
import re
|
||||
|
||||
# Configuration files
|
||||
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, md=False):
|
||||
missing_examples_file = f'{output_dir}/missing_examples.txt'
|
||||
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
# Recreate missing_examples.txt file
|
||||
with open(missing_examples_file, 'w', encoding='utf-8') as f:
|
||||
f.write('')
|
||||
|
||||
# Generate JSON documentation
|
||||
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)
|
||||
|
||||
# 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")
|
||||
|
||||
# Read the JSON file
|
||||
with open(output_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Modify JSON data
|
||||
for doclet in data:
|
||||
if 'see' in doclet:
|
||||
if doclet['see'] is not None:
|
||||
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'
|
||||
code_content = '\n'.join(lines[1:])
|
||||
else:
|
||||
comment = ''
|
||||
code_content = example_content
|
||||
|
||||
# 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:
|
||||
# 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")
|
||||
|
||||
# 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() # 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(
|
||||
"destination",
|
||||
type=str,
|
||||
help="Destination directory for the generated documentation",
|
||||
nargs='?', # Indicates the argument is optional
|
||||
default="../../../../document-builder-declarations/document-builder" # Default value
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
branch_name = get_current_branch("../../../../sdkjs")
|
||||
if branch_name:
|
||||
args.destination = f"{args.destination}/{branch_name}"
|
||||
|
||||
generate(args.destination)
|
||||
266
scripts/sdkjs_common/jsdoc/generate_docs_md.py
Normal file
266
scripts/sdkjs_common/jsdoc/generate_docs_md.py
Normal file
@ -0,0 +1,266 @@
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
import argparse
|
||||
import generate_docs_json
|
||||
|
||||
# Configuration files
|
||||
editors = [
|
||||
"word",
|
||||
"cell",
|
||||
"slide",
|
||||
"forms"
|
||||
]
|
||||
|
||||
def load_json(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
def write_markdown_file(file_path, content):
|
||||
with open(file_path, 'w', encoding='utf-8') as md_file:
|
||||
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()
|
||||
|
||||
def correct_description(string):
|
||||
if string is None:
|
||||
return 'No description provided.'
|
||||
|
||||
# Replace opening <b> tag with **
|
||||
string = re.sub(r'<b>', '**', string)
|
||||
# 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 ''
|
||||
|
||||
if value == True:
|
||||
value = "true"
|
||||
elif value == False:
|
||||
value = "false"
|
||||
else:
|
||||
value = str(value)
|
||||
|
||||
return generate_data_types_markdown([value], enumerations, classes)
|
||||
|
||||
def remove_line_breaks(string):
|
||||
return re.sub(r'[\r\n]', '', string)
|
||||
|
||||
def generate_data_types_markdown(types, enumerations, classes, root='../../'):
|
||||
param_types_md = ' |'.join(types)
|
||||
|
||||
for enum in enumerations:
|
||||
if enum['name'] in types:
|
||||
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}]({root}{cls}/{cls}.md)")
|
||||
|
||||
def replace_with_links(match):
|
||||
element = match.group(1).strip()
|
||||
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:
|
||||
return f"<[{element}](../../{base_type}/{base_type}.md)>"
|
||||
return f"<{element}>"
|
||||
|
||||
return re.sub(r'<([^<>]+)>', replace_with_links, param_types_md)
|
||||
|
||||
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']
|
||||
content += f"- [{method_name}](./Methods/{method_name}.md)\n"
|
||||
return content
|
||||
|
||||
def generate_method_markdown(method, enumerations, classes):
|
||||
method_name = method['name']
|
||||
description = method.get('description', 'No description provided.')
|
||||
description = correct_description(description)
|
||||
params = method.get('params', [])
|
||||
returns = method.get('returns', [])
|
||||
example = method.get('example', '')
|
||||
memberof = method.get('memberof', '')
|
||||
|
||||
content = f"# {method_name}\n\n{description}\n\n"
|
||||
|
||||
# Syntax section
|
||||
param_list = ', '.join([param['name'] for param in params]) if params else ''
|
||||
content += f"## Syntax\n\nexpression.{method_name}({param_list});\n\n"
|
||||
if memberof:
|
||||
content += f"`expression` - A variable that represents a [{memberof}](../{memberof}.md) class.\n\n"
|
||||
|
||||
content += "## Parameters\n\n"
|
||||
|
||||
if params:
|
||||
content += "| **Name** | **Required/Optional** | **Data type** | **Default** | **Description** |\n"
|
||||
content += "| ------------- | ------------- | ------------- | ------------- | ------------- |\n"
|
||||
for param in params:
|
||||
param_name = param.get('name', 'Unnamed')
|
||||
param_types = param.get('type', {}).get('names', []) if param.get('type') else []
|
||||
param_types_md = generate_data_types_markdown(param_types, enumerations, classes)
|
||||
param_desc = remove_line_breaks(correct_description(param.get('description', 'No description provided.')))
|
||||
param_required = "Required" if not param.get('optional') else "Optional"
|
||||
param_default = correct_default_value(param.get('defaultvalue', ''), enumerations, classes)
|
||||
|
||||
content += f"| {param_name} | {param_required} | {param_types_md} | {param_default} | {param_desc} |\n"
|
||||
else:
|
||||
content += "This method doesn't have any parameters.\n"
|
||||
|
||||
content += "\n## Returns\n\n"
|
||||
if returns:
|
||||
return_type = ', '.join(returns[0].get('type', {}).get('names', [])) if returns[0].get('type') else 'Unknown'
|
||||
|
||||
# Check for enumerations and classes in return type and add links if they exist
|
||||
return_type_md = generate_data_types_markdown([return_type], enumerations, classes)
|
||||
content += return_type_md
|
||||
else:
|
||||
content += "This method doesn't return any data."
|
||||
|
||||
if example:
|
||||
# Separate comment and code, and remove comment symbols
|
||||
comment, code = example.split('```js', 1)
|
||||
comment = remove_js_comments(comment)
|
||||
content += f"\n\n## Example\n\n{comment}\n\n```javascript\n{code.strip()}\n"
|
||||
|
||||
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.')
|
||||
description = correct_description(description)
|
||||
example = enumeration.get('example', '')
|
||||
|
||||
content = f"# {enum_name}\n\n{description}\n\n"
|
||||
|
||||
if 'TypeUnion' == enumeration['type']['parsedType']['type']:
|
||||
content += "## Type\n\nEnumeration\n\n"
|
||||
content += "## Values\n\n"
|
||||
elements = enumeration['type']['parsedType']['elements']
|
||||
for element in elements:
|
||||
element_name = element['name'] if element['type'] != 'NullLiteral' else 'null'
|
||||
# Check if element is in enumerations or classes before adding link
|
||||
if any(enum['name'] == element_name for enum in enumerations):
|
||||
content += f"- [{element_name}](../../Enumeration/{element_name}.md)\n"
|
||||
elif element_name in classes:
|
||||
content += f"- [{element_name}](../../{element_name}/{element_name}.md)\n"
|
||||
else:
|
||||
content += f"- {element_name}\n"
|
||||
elif enumeration['properties'] is not None:
|
||||
content += "## Type\n\nObject\n\n"
|
||||
content += generate_properties_markdown(enumeration['properties'], enumerations, classes)
|
||||
else:
|
||||
content += "## Type\n\n"
|
||||
types = enumeration['type']['names']
|
||||
for t in types:
|
||||
t = generate_data_types_markdown([t], enumerations, classes)
|
||||
content += t + "\n\n"
|
||||
|
||||
if example:
|
||||
# Separate comment and code, and remove comment symbols
|
||||
comment, code = example.split('```js', 1)
|
||||
comment = remove_js_comments(comment)
|
||||
content += f"\n\n## Example\n\n{comment}\n\n```javascript\n{code.strip()}\n"
|
||||
|
||||
return content
|
||||
|
||||
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:
|
||||
if class_name not in classes:
|
||||
classes[class_name] = []
|
||||
classes[class_name].append(doclet)
|
||||
elif doclet['kind'] == 'typedef':
|
||||
enumerations.append(doclet)
|
||||
|
||||
# Process classes
|
||||
for class_name, methods in classes.items():
|
||||
class_dir = os.path.join(output_dir, class_name)
|
||||
methods_dir = os.path.join(class_dir, 'Methods')
|
||||
os.makedirs(methods_dir, exist_ok=True)
|
||||
|
||||
# Write class file
|
||||
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
|
||||
for method in methods:
|
||||
method_content = generate_method_markdown(method, enumerations, classes)
|
||||
write_markdown_file(os.path.join(methods_dir, f"{method['name']}.md"), method_content)
|
||||
|
||||
# Process enumerations
|
||||
enum_dir = os.path.join(output_dir, 'Enumeration')
|
||||
os.makedirs(enum_dir, exist_ok=True)
|
||||
|
||||
for enum in enumerations:
|
||||
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', 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)
|
||||
|
||||
data = load_json(input_file)
|
||||
process_doclets(data, output_dir + f'/{editor_name}')
|
||||
|
||||
shutil.rmtree(output_dir + 'tmp_json')
|
||||
print('Done')
|
||||
|
||||
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="../../../../office-js-api/" # Default value
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
generate(args.destination)
|
||||
7
scripts/sdkjs_common/jsdoc/package.json
Normal file
7
scripts/sdkjs_common/jsdoc/package.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"jsdoc-to-markdown": "7.1.1",
|
||||
"dmd": "6.1.0",
|
||||
"handlebars": "4.7.7"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user