Skip to content

Commit

Permalink
make jdoc extractor on js
Browse files Browse the repository at this point in the history
  • Loading branch information
igorkorsukov committed Sep 13, 2024
1 parent eb02119 commit 052b2bc
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 380 deletions.
2 changes: 0 additions & 2 deletions src/framework/global/api/apiobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
//! If we move it to the `api` module, we will have to link it to all other modules.
//! That’s why it’s located here, because the `global` module links to everything.

#define API_DOC(name, str) Q_INVOKABLE QString name##_doc() const { return str; }

namespace muse::api {
class ApiObject : public QObject, public Injectable
{
Expand Down
4 changes: 2 additions & 2 deletions src/framework/global/api/interactiveapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ InteractiveApi::InteractiveApi(IApiEngine* e)
{
}

/** APIDOC method: info(title, text)
/** APIDOC method
* Show information message
* @param {String} title Title
* @param {String} text Message
Expand All @@ -46,7 +46,7 @@ void InteractiveApi::info(const QString& title, const QString& text)
interactive()->info(title.toStdString(), text.toStdString());
}

/** APIDOC method: openUrl(url)
/** APIDOC method
* Open URL in external browser
* @param {String} url URL
*/
Expand Down
2 changes: 0 additions & 2 deletions src/framework/global/api/interactiveapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ class InteractiveApi : public ApiObject
explicit InteractiveApi(IApiEngine* e);

Q_INVOKABLE void info(const QString& title, const QString& text);

API_DOC(openUrl, "Open URL in external browser")
Q_INVOKABLE void openUrl(const QString& url);
};
}
Expand Down
4 changes: 0 additions & 4 deletions src/framework/global/api/logapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,15 @@ class LogApi : public api::ApiObject
public:
explicit LogApi(api::IApiEngine* e);

API_DOC(error, "Write error to console and log")
Q_INVOKABLE void error(const QString& message);
Q_INVOKABLE void error(const QString& tag, const QString& message);

API_DOC(warn, "Write warning to console and log")
Q_INVOKABLE void warn(const QString& message);
Q_INVOKABLE void warn(const QString& tag, const QString& message);

API_DOC(info, "Write info to console and log")
Q_INVOKABLE void info(const QString& message);
Q_INVOKABLE void info(const QString& tag, const QString& message);

API_DOC(debug, "Write debug to console and log")
Q_INVOKABLE void debug(const QString& message);
Q_INVOKABLE void debug(const QString& tag, const QString& message);
};
Expand Down
255 changes: 255 additions & 0 deletions tools/jsdoc/jsdoc_extractor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
const fs = require('node:fs');
const path = require('node:path');
const readline = require('node:readline');

const VERSION = "0.1"

var filter = {
ignoreFile: "",
exts: []
};

function scan(files, rootPath, filter)
{
if (filter.ignoreFile !== "" && fs.existsSync(rootPath + "/" + filter.ignoreFile)) {
// ignore
return [];
}

const items = fs.readdirSync(rootPath, {withFileTypes: true, recursive: false})
for (var i in items) {
const item = items[i]

const itemPath = rootPath + "/" + item.name
if (item.isDirectory()) {
// recursion
scan(files, itemPath, filter)
} else if (item.isFile()) {
if ((filter.exts.length === 0) || filter.exts.includes(path.extname(itemPath))) {
files.push(itemPath)
}
}
}
}

async function extractDoc(file)
{
const fileStream = fs.createReadStream(file)
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
})

const APIDOC_BEGIN = "/** APIDOC"
const APIDOC_END = "*/"
const APIDOC_NSPACE = "namespace:"
const APIDOC_METHOD = "method"

var state = {
namespaceStared: false,
namespaceName: "",

methodDocContent: false,
methodParams: [],
methodLookName: false,
};

var doc = ""

for await (var line of rl) {
line = line.trim()

if (line.startsWith(APIDOC_BEGIN)) {

// remove /** APIDOC
line = line.substring(APIDOC_BEGIN.length);
line = line.trim()

// check namespace
// `namespace: interactive`
if (line.startsWith(APIDOC_NSPACE)) {
state.namespaceName = line.substring(APIDOC_NSPACE.length).trim()
state.namespaceStared = true;
doc += "/**\n"
}
// check method
// `method`
else if (line.startsWith(APIDOC_METHOD)) {
doc += "\t/**\n"
state.methodDocContent = true
}

continue;
}

if (line.startsWith(APIDOC_END)) {
// write ns
if (state.namespaceName !== "") {
doc += "*/\n"
doc += "const " + state.namespaceName + " = {\n\n"
state.namespaceName = ""
}
// end method
else if (state.methodDocContent) {
state.methodDocContent = false
state.methodLookName = true
}

continue;
}

if (state.namespaceName !== "") {
doc += line + "\n"
continue;
}

if (state.methodDocContent) {
doc += "\t" + line + "\n"

if (line.includes("@param")) {
var words = line.split(' ');
state.methodParams.push(words[3])
}

continue;
}

if (state.methodLookName) {
// Result Class::method(...)
var colonIdx = line.lastIndexOf("::")
if (colonIdx !== -1) {
colonIdx += 2 // skip ::
var braceIdx = line.indexOf("(", colonIdx)
var name = line.substr(colonIdx, (braceIdx - colonIdx))

// write method
doc += "\t*/\n"
doc += "\t" + name + "(" + state.methodParams.join(', ') + ") {},\n\n"

// cleanup state
state.methodLookName = ""
state.methodParams = []
}
}
}

if (state.namespaceStared) {
doc += "};";
}

return doc
}

function saveDoc(doc, dir, name)
{
const outPath = dir + "/" + name + ".js"
fs.writeFileSync(outPath, doc);

console.log("[saved] ", outPath)
}

function printVersion()
{
console.log("version: ", VERSION)
}

function printHelp()
{
var h = "Hello World! I am jsdoc extractor!\n"
h += "This is a utility for scanning files, extracting documentation from them and creating JS files. \n"
h += "use:\n"
h += "-d --dir /path root dir for scan\n"
h += "-o --out /path output path\n"
h += "-i --ignore filename if present this file, dir (and subdirs) will be ignored\n"
h += "-e --extensions .ext1,.extn allowed extensions\n"
h += "-h, --help this help\n"
h += "-v, --version print version\n"

console.log(h)
}

async function main()
{
// default
var dir = ".";
var out = "./out";


// parse args
var args = process.argv.slice(2);
{
var i = -1;
while (true) {
++i
if (i >= args.length) {
break;
}

const arg = args[i]

if (arg == "-v" || arg == "--version") {
printVersion()
return 0
}
else if (arg == "-h" || arg == "--help") {
printHelp()
return 0
}
else if (arg == "-d" || arg == "--dir") {
dir = args[++i]
}
else if (arg == "-o" || arg == "--out") {
out = args[++i]
}
else if (arg == "-i" || arg == "--ignore") {
filter.ignoreFile = args[++i]
}
else if (arg == "-e" || arg == "--extensions") {
var extsStr = args[++i];
exts = extsStr.split(',')
for (const e of exts) {
if (e === "") {
continue;
}

if (e[0] !== '.') {
filter.exts.push('.' + e);
} else {
filter.exts.push(e);
}
}
}
else {
console.log("invalid option -- '", arg, "', try '--help' for more information.\n")
}
}
}

// scan
var files = []
scan(files, dir, filter)

if (filter.length === 0) {
console.log("not found files")
return 0;
}

if (!fs.existsSync(out)) {
fs.mkdirSync(out)
}

// extrac
for (var i in files) {
const file = files[i]
const name = path.parse(file).name

const doc = await extractDoc(file);
if (doc !== "") {
saveDoc(doc, out, name);
}
}

return 0;
}

main()
74 changes: 0 additions & 74 deletions tools/jsdoc/jsdoc_extractor/.gitignore

This file was deleted.

Loading

0 comments on commit 052b2bc

Please sign in to comment.