diff --git a/admin/pages/DocsBrowser.svelte b/admin/pages/DocsBrowser.svelte
new file mode 100644
index 0000000..9fc1c8c
--- /dev/null
+++ b/admin/pages/DocsBrowser.svelte
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+ {#each Object.keys(index) as item}
+ {item}
+ {/each}
+
+
+
+
+ {#if docs_data}
+ {#each docs_data.exports as exp}
+ { url }
+ {exp.name}
+ {#if exp.comment}
+
+{ exp.comment.value }
+
+ {/if}
+ {#if exp.isa === "class"}
+ {#each exp.methods as method}
+ { method.name }
+ {#if exp.comment}
+
+{ exp.comment.value }
+
+ {/if}
+
+ {/each}
+ {:else}
+
+ {/if}
+ {/each}
+ {/if}
+
+
+
+
+
diff --git a/admin/routes.js b/admin/routes.js
index 55db28c..0d7b6e4 100644
--- a/admin/routes.js
+++ b/admin/routes.js
@@ -8,8 +8,10 @@ import ReadUpdate from "$/admin/pages/ReadUpdate.svelte";
import EmailConfig from "$/admin/pages/EmailConfig.svelte";
import NotFound from "$/client/pages/NotFound.svelte";
import Components from "./bando/Components.svelte";
+import DocsBrowser from "$/admin/pages/DocsBrowser.svelte";
export default {
+ "/docs/*": DocsBrowser,
"/bando/components/:name?": Components,
"/errors/": Errors,
"/routes/": Routes,
diff --git a/commands/codedoc.js b/commands/codedoc.js
index 7d5a869..447bbfe 100644
--- a/commands/codedoc.js
+++ b/commands/codedoc.js
@@ -2,8 +2,7 @@
import fs from "fs";
import assert from "assert";
import logging from '../lib/logging.js';
-import { mkdir, mkdir_to } from "../lib/builderator.js";
-import glob from "fast-glob";
+import { mkdir, mkdir_to, glob } from "../lib/builderator.js";
import path from "path";
import template from "lodash/template.js";
import * as acorn from "acorn";
@@ -18,7 +17,7 @@ export const options = [
]
// example of a positional argument, it's the 1st argument to main
-export const argument = ["source", "source directory"];
+export const argument = ["", "source input globs"];
// put required options in the required variable
export const required = [
@@ -38,9 +37,10 @@ const dump = (obj) => {
}
class ParseWalker {
- constructor(comments) {
+ constructor(comments, code) {
this.comments = comments;
this.exported = [];
+ this.code = code;
}
handle_class(root) {
@@ -56,7 +56,8 @@ class ParseWalker {
acorn_walk.simple(root, {
ClassDeclaration: (cls_node) => {
assert(cls_node.id.name === new_class.name, "Name of class changed!");
- this.exported.push(new_class);
+ new_class.range = [cls_node.start, cls_node.body.start];
+ this.add_export(cls_node.id, new_class);
},
MethodDefinition: (meth_node) => {
@@ -67,9 +68,13 @@ class ParseWalker {
generator: meth_node.value.generator,
name: meth_node.key.name,
line_start: meth_node.loc.start.line,
+ range: [meth_node.start, meth_node.value.body.start],
params: this.handle_params(meth_node.value.params),
- comment: this.find_comment(meth_node.loc.start.line)
+ comment: this.find_comment(meth_node.loc.start.line),
}
+
+ new_method.code = this.slice_code(new_method.range);
+
new_class.methods.push(new_method);
}
});
@@ -106,51 +111,39 @@ class ParseWalker {
exp.name = id.name;
exp.line_start = id.loc.start.line;
exp.comment = this.find_comment(exp.line_start);
+ exp.code = this.slice_code(exp.range);
this.exported.push(exp);
}
+ slice_code(range) {
+ return this.code.slice(range[0], range[1]);
+ }
+
handle_arrow_func(id, arrow) {
this.add_export(id, {
isa: "function",
async: arrow.async,
generator: arrow.generator,
expression: arrow.expression,
+ range: [id.start, arrow.body.start],
params: this.handle_params(arrow.params),
});
}
handle_variable(root) {
const declare = root.declaration.declarations[0];
- // console.log("VARIABLE", declare);
const id = declare.id;
+ const _node = declare.init;
+ const init_is = declare.init.type;
- if(declare.init.type === "ArrowFunctionExpression") {
+ if(init_is === "ArrowFunctionExpression") {
this.handle_arrow_func(id, declare.init);
} else {
- acorn_walk.simple(root, {
- Literal: (_node) => {
- this.add_export(id, {
- isa: _node.type.toLowerCase(),
- value: _node.value,
- raw: _node.raw
- });
- },
- CallExpression: (_node) => {
- this.add_export(id, {
- isa: _node.type.toLowerCase(),
- identifier: _node.callee.name,
- arguments: this.handle_params(_node.arguments)
- });
- },
- MemberExpression: (_node) => {
- this.add_export(id, {
- isa: _node.type.toLowerCase(),
- object: _node.object.name,
- property: _node.property.name,
- computed: _node.computed,
- options: _node.optional,
- });
- }
+ this.add_export(id, {
+ isa: _node.type.toLowerCase(),
+ value: _node.value,
+ range: declare.range,
+ raw: _node.raw
});
}
}
@@ -186,17 +179,16 @@ class ParseWalker {
}
}
-export const main = async (arg, opts) => {
- const code = fs.readFileSync(arg);
+const parse_source = (source) => {
+ const code = fs.readFileSync(source);
- mkdir(opts.output);
let comments = [];
const acorn_opts = {
sourceType: "module",
ecmaVersion: "2023",
locations: true,
- sourceFile: arg,
+ sourceFile: source,
ranges: true,
onComment: comments
}
@@ -213,17 +205,45 @@ export const main = async (arg, opts) => {
}
});
- const walker = new ParseWalker(comments);
+ const walker = new ParseWalker(comments, code.toString());
// acorn is stupid and they grab a reference to the functions so that _removes_
// this from the object, instead of just...calling walker.function() like a normal person
acorn_walk.simple(parsed, {
ExportNamedDeclaration: (_node) => walker.handle_export(_node),
});
- console.log(dump({
+ return {
+ // normalize to / even on windows
+ source: source.replaceAll("\\", "/"),
exports: walker.exported,
orphan_comments: walker.comments.filter(c => !c.found)
- }));
+ };
+}
+
+export const main = async (source_globs, opts) => {
+ const index = {};
+ mkdir_to(opts.output);
+
+ for(let source of source_globs) {
+ const source_list = glob(source);
+
+ for(let fname of source_list) {
+ const result = parse_source(fname);
+
+ const target = `${path.join(opts.output, fname)}.json`;
+ mkdir_to(target);
+ fs.writeFileSync(target, dump(result));
+
+ const name = fname.replaceAll("\\", "/").slice(2);
+
+ index[name] = result.exports.map(e => {
+ return {isa: e.isa, name: e.name};
+ });
+ }
+ }
+ // now write the grand index
+ const index_name = path.join(opts.output, "index.json");
+ fs.writeFileSync(index_name, dump(index));
process.exit(0);
}