@silverbulletmd/silverbullet 2.8.1 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -25
- package/client/plugos/hooks/syscall.ts +24 -10
- package/client/plugos/syscalls/asset.ts +61 -23
- package/client/plugos/syscalls/clientStore.ts +32 -6
- package/client/plugos/syscalls/client_code_widget.ts +9 -4
- package/client/plugos/syscalls/code_widget.ts +26 -11
- package/client/plugos/syscalls/config.ts +146 -30
- package/client/plugos/syscalls/datastore.ts +146 -40
- package/client/plugos/syscalls/editor.ts +1432 -700
- package/client/plugos/syscalls/event.ts +46 -13
- package/client/plugos/syscalls/fetch.ts +123 -82
- package/client/plugos/syscalls/index.ts +243 -114
- package/client/plugos/syscalls/jsonschema.ts +107 -8
- package/client/plugos/syscalls/language.ts +38 -12
- package/client/plugos/syscalls/markdown.ts +166 -50
- package/client/plugos/syscalls/mq.ts +93 -20
- package/client/plugos/syscalls/schema_introspection.ts +33 -0
- package/client/plugos/syscalls/service_registry.ts +74 -20
- package/client/plugos/syscalls/shell.ts +51 -20
- package/client/plugos/syscalls/space.ts +169 -113
- package/client/plugos/syscalls/sync.ts +50 -19
- package/client/plugos/syscalls/system.ts +236 -139
- package/client/plugos/system.ts +21 -5
- package/client/space_lua/api_documentation.ts +107 -0
- package/client/space_lua/ast.ts +13 -0
- package/client/space_lua/eval.ts +12 -4
- package/client/space_lua/parse.ts +254 -119
- package/client/space_lua/pretty_print.ts +465 -0
- package/client/space_lua/query_collection.ts +3 -3
- package/client/space_lua/render_widget.ts +156 -0
- package/client/space_lua/runtime.ts +83 -22
- package/client/space_lua/stdlib/crypto.ts +8 -3
- package/client/space_lua/stdlib/encoding.ts +27 -9
- package/client/space_lua/stdlib/js.ts +137 -22
- package/client/space_lua/stdlib/load.ts +26 -17
- package/client/space_lua/stdlib/math.ts +323 -118
- package/client/space_lua/stdlib/net.ts +57 -9
- package/client/space_lua/stdlib/os.ts +111 -44
- package/client/space_lua/stdlib/space_lua.ts +397 -13
- package/client/space_lua/stdlib/string.ts +282 -104
- package/client/space_lua/stdlib/string_pack.ts +58 -19
- package/client/space_lua/stdlib/table.ts +195 -40
- package/client/space_lua/stdlib.ts +336 -94
- package/client/space_lua/syscalls.ts +270 -0
- package/dist/plug-compile.js +1 -1
- package/package.json +12 -4
- package/plug-api/lib/ref.ts +96 -0
- package/plug-api/lib/shortcut.ts +2 -1
- package/plug-api/syscalls/config.ts +5 -3
- package/plug-api/syscalls/editor.ts +23 -2
- package/plug-api/syscalls/index.ts +24 -1
- package/plug-api/syscalls/jsonschema.ts +9 -0
- package/plug-api/syscalls/lua.ts +28 -1
- package/plug-api/syscalls/shell.ts +0 -1
- package/plug-api/syscalls/system.ts +7 -0
- package/plug-api/system_mock.ts +2 -2
- package/plug-api/types/config.ts +1 -1
- package/plug-api/types/index.ts +52 -1
- package/plug-api/types/manifest.ts +22 -4
- package/plug-api/ui/cx.ts +4 -0
- package/plug-api/ui/index.ts +22 -0
- package/plug-api/ui/panel_styles.ts +33 -0
- package/plug-api/ui/slugify.ts +44 -0
- package/plugs/builtin_plugs.ts +1 -0
- package/client/plugos/syscalls/lua.ts +0 -58
package/README.md
CHANGED
|
@@ -5,45 +5,52 @@
|
|
|
5
5
|
[](https://deepwiki.com/silverbulletmd/silverbullet)
|
|
6
6
|
|
|
7
7
|
# SilverBullet
|
|
8
|
-
SilverBullet is a Programmable, Private, Browser-based, Open Source, Self Hosted, Personal Knowledge
|
|
8
|
+
SilverBullet is a Programmable, Private, Browser-based, Open Source, Self Hosted, Personal Knowledge Database — a fancy term for a "notes app on steroids".
|
|
9
9
|
|
|
10
10
|
_Yowza!_ That surely is a lot of adjectives to describe a browser-based Markdown editor programmable with Lua.
|
|
11
11
|
|
|
12
12
|
Let’s get more specific.
|
|
13
13
|
|
|
14
|
+
SilverBullet combines a clean live-preview editor with wiki-style linking, a built-in database and query language, and a fully integrated Space Lua scripting environment, turning your notes into a programmable system that grows with you.
|
|
15
|
+
|
|
14
16
|
In SilverBullet you keep your content as a collection of Markdown Pages (called a Space). You navigate your space using the Page Picker like a traditional notes app, or through Links like a wiki (except they are bi-directional).
|
|
15
17
|
|
|
16
|
-
If you are the **writer** type, you’ll appreciate SilverBullet as a clean Markdown editor with Live Preview. If you have more of an **outliner** personality, SilverBullet has Outlining tools for you. Productivity freak? Have a look at Tasks. More of a **database** person? You will appreciate Objects and Queries.
|
|
18
|
+
If you are the **writer** type, you’ll appreciate SilverBullet as a clean Markdown editor with Live Preview. If you have more of an **outliner** personality, SilverBullet has Outlining tools for you. Productivity freak? Have a look at Tasks. More of a **database** person? You will appreciate Objects and Queries (SLIQ).
|
|
17
19
|
|
|
18
20
|
And if you are comfortable **programming** a little bit — now we’re really talking. You will love _dynamically generating content_ with Space Lua (SilverBullet’s Lua dialect), or to use it to create custom Commands, Page Templates or Widgets.
|
|
19
21
|
|
|
22
|
+
You were told there’s no such thing as a silver bullet. You were told wrong.
|
|
23
|
+
|
|
20
24
|
[Much more detail can be found on silverbullet.md](https://silverbullet.md)
|
|
21
25
|
|
|
22
26
|
## Installing SilverBullet
|
|
23
27
|
Check out the [instructions](https://silverbullet.md/Install).
|
|
24
28
|
|
|
25
29
|
## Developing SilverBullet
|
|
26
|
-
SilverBullet's frontend is written in [TypeScript](https://www.typescriptlang.org/) and built on top of the excellent [CodeMirror 6](https://codemirror.net/) editor component. Additional UI is built using [Preact](https://preactjs.com). [ESBuild](https://esbuild.github.io) is used to build the frontend.
|
|
30
|
+
SilverBullet's frontend ("client") is written in [TypeScript](https://www.typescriptlang.org/) and built on top of the excellent [CodeMirror 6](https://codemirror.net/) editor component. Additional UI is built using [Preact](https://preactjs.com). [ESBuild](https://esbuild.github.io) is used to build the frontend.
|
|
27
31
|
|
|
28
|
-
The server backend is written in
|
|
32
|
+
The server backend is written in [Rust](https://www.rust-lang.org/) (a Cargo workspace). It serves the pre-built client bundle, the file/space HTTP API, authentication, and a headless-Chrome runtime for server-side Lua.
|
|
29
33
|
|
|
30
34
|
## Code structure
|
|
31
|
-
* `
|
|
32
|
-
* `
|
|
33
|
-
* `
|
|
34
|
-
* `
|
|
35
|
-
* `
|
|
35
|
+
* `bin/silverbullet/`: The standalone `silverbullet` server binary (Rust) (this is the one you generally run)
|
|
36
|
+
* `bin/sb/`: The `sb` CLI client (Rust)
|
|
37
|
+
* `bin/plug-compile.ts`: the plug compiler
|
|
38
|
+
* `client/`: The SilverBullet client (browser, TypeScript)
|
|
39
|
+
* `server/`: The SilverBullet server library (Rust): HTTP router, handlers, auth, runtime seam
|
|
40
|
+
* `server-common/`: Shared Rust crate (space primitives, shared types)
|
|
41
|
+
* `server-runtime-chrome/`: Headless-Chrome runtime backend (Rust)
|
|
42
|
+
* `plugs`: Set of built-in plugs (TypeScript) that are distributed with SilverBullet
|
|
43
|
+
* `libraries`: A set of libraries (space scripts, page templates, slash templates) distributed with SilverBullet (Space Lua)
|
|
44
|
+
* `plug-api/`: Useful APIs for use in plugs and published to NPM
|
|
36
45
|
* `lib/`: Useful libraries to be used in plugs
|
|
37
46
|
* `syscalls/`: TypeScript wrappers around syscalls
|
|
38
47
|
* `types/`: Various (client) types that can be references from plugs
|
|
39
|
-
* `bin`
|
|
40
|
-
* `plug_compile.ts` the plug compiler
|
|
41
48
|
* `scripts/`: Useful scripts
|
|
42
|
-
* `
|
|
49
|
+
* `docs/`: documentation (also serves a silverbullet.md website content)
|
|
43
50
|
|
|
44
51
|
### Requirements
|
|
45
|
-
* [Node.js](https://nodejs.org/) 24+ and npm 10+: Used to build the frontend and plugs
|
|
46
|
-
* [
|
|
52
|
+
* [Node.js](https://nodejs.org/) 24+ and npm 10+: Used to build the frontend (client) and plugs
|
|
53
|
+
* [Rust](https://www.rust-lang.org/tools/install) (stable, via `rustup`): Used to build the server
|
|
47
54
|
|
|
48
55
|
The project includes `.nvmrc` and `.node-version` files. If you use [nvm](https://github.com/nvm-sh/nvm) or another Node version manager, it will automatically use the correct Node.js version:
|
|
49
56
|
|
|
@@ -51,35 +58,45 @@ The project includes `.nvmrc` and `.node-version` files. If you use [nvm](https:
|
|
|
51
58
|
nvm use # If using nvm
|
|
52
59
|
```
|
|
53
60
|
|
|
54
|
-
|
|
61
|
+
First, install dependencies:
|
|
55
62
|
|
|
56
63
|
```shell
|
|
57
|
-
|
|
64
|
+
make setup
|
|
58
65
|
```
|
|
59
|
-
Make sure your `$GOPATH/bin` is in your $PATH.
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
To create a (release) build:
|
|
62
68
|
|
|
63
69
|
```shell
|
|
64
|
-
make
|
|
70
|
+
make
|
|
65
71
|
```
|
|
66
72
|
|
|
67
|
-
|
|
73
|
+
This will produce `silverbullet` and `cli` binaries in `./target/release/`, run `./target/release/silverbullet` to run the server.
|
|
74
|
+
|
|
75
|
+
### Development workflow
|
|
76
|
+
|
|
77
|
+
SilverBullet has two halves you rebuild **independently**:
|
|
78
|
+
|
|
79
|
+
* The **client** (TypeScript: `client/`) is built by ESBuild into `client_bundle/`, which the server then serves.
|
|
80
|
+
* The **server** (Rust: `server/`, `server-common/`, `server-runtime-chrome/`, `bin/silverbullet/`) is a compiled binary.
|
|
81
|
+
|
|
82
|
+
Run the server in development with `cargo run`. A **debug** build serves the client bundle **live from `client_bundle/` on disk** (a release build embeds it instead):
|
|
68
83
|
|
|
69
84
|
```shell
|
|
70
|
-
|
|
85
|
+
npm run build
|
|
86
|
+
cargo run <PATH-TO-YOUR-SPACE>
|
|
71
87
|
```
|
|
72
88
|
|
|
73
|
-
|
|
89
|
+
**When you change only the client** (TypeScript in `client/`): you do **not** need to restart the server. Rebuild just the client bundle and reload the page in your browser — the debug server serves the freshly-built bundle straight from disk:
|
|
74
90
|
|
|
75
91
|
```shell
|
|
76
|
-
|
|
92
|
+
npm run build
|
|
77
93
|
```
|
|
78
94
|
|
|
79
|
-
To
|
|
95
|
+
To build a self-contained **release** binary (with the client bundle embedded), and run it:
|
|
80
96
|
|
|
81
97
|
```shell
|
|
82
|
-
|
|
98
|
+
make
|
|
99
|
+
./target/release/silverbullet <PATH-TO-YOUR-SPACE>
|
|
83
100
|
```
|
|
84
101
|
|
|
85
102
|
### Useful development tasks
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Hook, Manifest } from "../types.ts";
|
|
2
|
-
import type { SysCallMapping, System } from "../system.ts";
|
|
2
|
+
import type { SysCallMapping, SyscallContext, System } from "../system.ts";
|
|
3
3
|
import type { SyscallHookT } from "@silverbulletmd/silverbullet/type/manifest";
|
|
4
4
|
|
|
5
5
|
export class SyscallHook implements Hook<SyscallHookT> {
|
|
@@ -24,16 +24,27 @@ export class SyscallHook implements Hook<SyscallHookT> {
|
|
|
24
24
|
continue;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const syscallDefinition = functionDef.syscall;
|
|
28
|
+
const syscallName =
|
|
29
|
+
typeof syscallDefinition === "string"
|
|
30
|
+
? syscallDefinition
|
|
31
|
+
: syscallDefinition.name;
|
|
28
32
|
|
|
29
33
|
// Add the syscall to our mapping
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return system.syscall(ctx, "system.invokeFunction", [
|
|
34
|
+
const callback = (ctx: SyscallContext, ...args: any[]) =>
|
|
35
|
+
system.syscall(ctx, "system.invokeFunction", [
|
|
33
36
|
`${plug.manifest!.name}.${name}`,
|
|
34
37
|
...args,
|
|
35
38
|
]);
|
|
36
|
-
|
|
39
|
+
if (typeof syscallDefinition === "string") {
|
|
40
|
+
syscalls[syscallName] = callback;
|
|
41
|
+
} else {
|
|
42
|
+
const { name: _name, ...metadata } = syscallDefinition;
|
|
43
|
+
syscalls[syscallName] = {
|
|
44
|
+
callback,
|
|
45
|
+
...metadata,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
37
48
|
|
|
38
49
|
// Register the syscalls with no required permissions
|
|
39
50
|
system.registerSyscalls([], syscalls);
|
|
@@ -48,16 +59,19 @@ export class SyscallHook implements Hook<SyscallHookT> {
|
|
|
48
59
|
continue;
|
|
49
60
|
}
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
const syscallName =
|
|
63
|
+
typeof functionDef.syscall === "string"
|
|
64
|
+
? functionDef.syscall
|
|
65
|
+
: functionDef.syscall.name;
|
|
66
|
+
if (!syscallName) {
|
|
53
67
|
errors.push(`Function ${name} has a syscall but no name`);
|
|
54
68
|
continue;
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
// Validate syscall name format (should be namespaced)
|
|
58
|
-
if (!
|
|
72
|
+
if (!syscallName.includes(".")) {
|
|
59
73
|
errors.push(
|
|
60
|
-
`Function ${name} has invalid syscall name "${
|
|
74
|
+
`Function ${name} has invalid syscall name "${syscallName}" - must be in format "namespace.name"`,
|
|
61
75
|
);
|
|
62
76
|
}
|
|
63
77
|
}
|
|
@@ -3,31 +3,69 @@ import type { FileMeta } from "../../../plug-api/types/index.ts";
|
|
|
3
3
|
|
|
4
4
|
export default function assetSyscalls(system: System<any>): SysCallMapping {
|
|
5
5
|
return {
|
|
6
|
-
"asset.readAsset":
|
|
7
|
-
|
|
6
|
+
"asset.readAsset": {
|
|
7
|
+
callback: (_ctx, plugName: string, name: string): string => {
|
|
8
|
+
return system.loadedPlugs
|
|
9
|
+
.get(plugName)!
|
|
10
|
+
.assets!.readFileAsDataUrl(name);
|
|
11
|
+
},
|
|
12
|
+
description: "Reads an asset embedded in a plug as a data URL.",
|
|
13
|
+
parameters: [
|
|
14
|
+
{ name: "plugName", type: "string", description: "Plug name." },
|
|
15
|
+
{ name: "name", type: "string", description: "Asset path." },
|
|
16
|
+
],
|
|
17
|
+
returns: [{ type: "string", description: "Asset data URL." }],
|
|
18
|
+
examples: [
|
|
19
|
+
{ code: 'local image = asset.readAsset("myplug", "image.png")' },
|
|
20
|
+
],
|
|
8
21
|
},
|
|
9
|
-
"asset.listFiles":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
name
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
"asset.listFiles": {
|
|
23
|
+
callback: (_ctx, plugName: string): FileMeta[] => {
|
|
24
|
+
const assets = system.loadedPlugs.get(plugName)!.assets!;
|
|
25
|
+
const fileNames = assets.listFiles();
|
|
26
|
+
return fileNames.map((name) => ({
|
|
27
|
+
name,
|
|
28
|
+
contentType: assets.getMimeType(name),
|
|
29
|
+
created: assets.getMtime(name),
|
|
30
|
+
lastModified: assets.getMtime(name),
|
|
31
|
+
size: -1,
|
|
32
|
+
perm: "ro",
|
|
33
|
+
}));
|
|
34
|
+
},
|
|
35
|
+
description: "Lists the assets embedded in a plug.",
|
|
36
|
+
parameters: [
|
|
37
|
+
{ name: "plugName", type: "string", description: "Plug name." },
|
|
38
|
+
],
|
|
39
|
+
returns: [{ type: "table", description: "List of file metadata." }],
|
|
40
|
+
examples: [
|
|
41
|
+
{
|
|
42
|
+
code: 'for _, file in ipairs(asset.listFiles("myplug")) do\n print(file.name)\nend',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
20
45
|
},
|
|
21
|
-
"asset.getFileMeta":
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
"asset.getFileMeta": {
|
|
47
|
+
callback: (_ctx, plugName: string, name: string): FileMeta => {
|
|
48
|
+
const assets = system.loadedPlugs.get(plugName)!.assets!;
|
|
49
|
+
return {
|
|
50
|
+
name,
|
|
51
|
+
contentType: assets.getMimeType(name),
|
|
52
|
+
created: assets.getMtime(name),
|
|
53
|
+
lastModified: assets.getMtime(name),
|
|
54
|
+
size: -1,
|
|
55
|
+
perm: "ro",
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
description: "Gets metadata for an asset embedded in a plug.",
|
|
59
|
+
parameters: [
|
|
60
|
+
{ name: "plugName", type: "string", description: "Plug name." },
|
|
61
|
+
{ name: "name", type: "string", description: "Asset path." },
|
|
62
|
+
],
|
|
63
|
+
returns: [{ type: "table", description: "File metadata." }],
|
|
64
|
+
examples: [
|
|
65
|
+
{
|
|
66
|
+
code: 'local meta = asset.getFileMeta("myplug", "data.txt")\nprint(meta.lastModified)',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
31
69
|
},
|
|
32
70
|
};
|
|
33
71
|
}
|
|
@@ -8,14 +8,40 @@ export function clientStoreSyscalls(
|
|
|
8
8
|
prefix: KvKey = ["client"],
|
|
9
9
|
): SysCallMapping {
|
|
10
10
|
return {
|
|
11
|
-
"clientStore.get":
|
|
12
|
-
|
|
11
|
+
"clientStore.get": {
|
|
12
|
+
callback: (_ctx, key: string): Promise<any> => {
|
|
13
|
+
return ds.get([...prefix, key]);
|
|
14
|
+
},
|
|
15
|
+
description:
|
|
16
|
+
"Gets a client-specific value from the local key-value store.",
|
|
17
|
+
parameters: [
|
|
18
|
+
{ name: "key", type: "string", description: "Key to read." },
|
|
19
|
+
],
|
|
20
|
+
returns: [{ description: "Stored value, or nil when absent." }],
|
|
21
|
+
examples: [{ code: 'local theme = clientStore.get("theme")' }],
|
|
13
22
|
},
|
|
14
|
-
"clientStore.set":
|
|
15
|
-
|
|
23
|
+
"clientStore.set": {
|
|
24
|
+
callback: (_ctx, key: string, val: any): Promise<void> => {
|
|
25
|
+
return ds.set([...prefix, key], val);
|
|
26
|
+
},
|
|
27
|
+
description:
|
|
28
|
+
"Stores a client-specific value in the local key-value store.",
|
|
29
|
+
parameters: [
|
|
30
|
+
{ name: "key", type: "string", description: "Key to set." },
|
|
31
|
+
{ name: "value", description: "Value to store." },
|
|
32
|
+
],
|
|
33
|
+
examples: [{ code: 'clientStore.set("theme", "dark")' }],
|
|
16
34
|
},
|
|
17
|
-
"clientStore.delete":
|
|
18
|
-
|
|
35
|
+
"clientStore.delete": {
|
|
36
|
+
callback: (_ctx, key: string): Promise<void> => {
|
|
37
|
+
return ds.delete([...prefix, key]);
|
|
38
|
+
},
|
|
39
|
+
description:
|
|
40
|
+
"Deletes a client-specific value from the local key-value store.",
|
|
41
|
+
parameters: [
|
|
42
|
+
{ name: "key", type: "string", description: "Key to delete." },
|
|
43
|
+
],
|
|
44
|
+
examples: [{ code: 'clientStore.delete("theme")' }],
|
|
19
45
|
},
|
|
20
46
|
};
|
|
21
47
|
}
|
|
@@ -5,10 +5,15 @@ import { broadcastReload } from "../../components/widget_sandbox_iframe.ts";
|
|
|
5
5
|
|
|
6
6
|
export function clientCodeWidgetSyscalls(client: Client): SysCallMapping {
|
|
7
7
|
return {
|
|
8
|
-
"codeWidget.refreshAll":
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
"codeWidget.refreshAll": {
|
|
9
|
+
callback: () => {
|
|
10
|
+
client.widgetCache.clearPrewarm();
|
|
11
|
+
broadcastReload();
|
|
12
|
+
return reloadAllWidgets();
|
|
13
|
+
},
|
|
14
|
+
description:
|
|
15
|
+
"Refreshes all code widgets on the current page that support refreshing.",
|
|
16
|
+
examples: [{ code: "codeWidget.refreshAll()" }],
|
|
12
17
|
},
|
|
13
18
|
};
|
|
14
19
|
}
|
|
@@ -6,17 +6,32 @@ export function codeWidgetSyscalls(
|
|
|
6
6
|
codeWidgetHook: CodeWidgetHook,
|
|
7
7
|
): SysCallMapping {
|
|
8
8
|
return {
|
|
9
|
-
"codeWidget.render":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
"codeWidget.render": {
|
|
10
|
+
callback: (
|
|
11
|
+
_ctx,
|
|
12
|
+
lang: string,
|
|
13
|
+
body: string,
|
|
14
|
+
pageName: string,
|
|
15
|
+
): Promise<CodeWidgetContent | null> => {
|
|
16
|
+
const langCallback = codeWidgetHook.codeWidgetCallbacks.get(lang);
|
|
17
|
+
if (!langCallback) {
|
|
18
|
+
throw new Error(`Code widget ${lang} not found`);
|
|
19
|
+
}
|
|
20
|
+
return langCallback(body, pageName);
|
|
21
|
+
},
|
|
22
|
+
description: "Renders code through the widget registered for a language.",
|
|
23
|
+
parameters: [
|
|
24
|
+
{ name: "language", type: "string", description: "Widget language." },
|
|
25
|
+
{ name: "body", type: "string", description: "Code block body." },
|
|
26
|
+
{
|
|
27
|
+
name: "pageName",
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "Containing page name.",
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
returns: [
|
|
33
|
+
{ type: "table", description: "Rendered widget content, or nil." },
|
|
34
|
+
],
|
|
20
35
|
},
|
|
21
36
|
};
|
|
22
37
|
}
|
|
@@ -5,45 +5,161 @@ import { stripFunctions } from "../util.ts";
|
|
|
5
5
|
|
|
6
6
|
export function configSyscalls(config: Config): SysCallMapping {
|
|
7
7
|
return {
|
|
8
|
-
"config.get":
|
|
9
|
-
|
|
8
|
+
"config.get": {
|
|
9
|
+
callback: (_ctx, path: string, defaultValue: any) => {
|
|
10
|
+
return config.get(path, defaultValue);
|
|
11
|
+
},
|
|
12
|
+
description:
|
|
13
|
+
"Gets a configuration value by path, with dot notation support.",
|
|
14
|
+
parameters: [
|
|
15
|
+
{ name: "path", type: "string", description: "Configuration path." },
|
|
16
|
+
{
|
|
17
|
+
name: "defaultValue",
|
|
18
|
+
description: "Value returned when the path is absent.",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
returns: [{ description: "Configured value or the supplied default." }],
|
|
22
|
+
examples: [{ code: 'local theme = config.get("theme", "light")' }],
|
|
10
23
|
},
|
|
11
|
-
"config.set":
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
"config.set": {
|
|
25
|
+
callback: (
|
|
26
|
+
_ctx,
|
|
27
|
+
keyOrValues: string | string[] | Record<string, any>,
|
|
28
|
+
value?: any,
|
|
29
|
+
) => {
|
|
30
|
+
config.set(keyOrValues as any, value);
|
|
31
|
+
},
|
|
32
|
+
description: "Sets one configuration value or multiple values at once.",
|
|
33
|
+
signatures: ["config.set(path, value)", "config.set(values)"],
|
|
34
|
+
parameters: [
|
|
35
|
+
{
|
|
36
|
+
name: "pathOrValues",
|
|
37
|
+
description: "Configuration path or table of values.",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "value",
|
|
41
|
+
description: "Value to set when a path is supplied.",
|
|
42
|
+
optional: true,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
examples: [
|
|
46
|
+
{ code: 'config.set("theme", "dark")' },
|
|
47
|
+
{ code: 'config.set({theme = "dark", fontSize = 14})' },
|
|
48
|
+
],
|
|
17
49
|
},
|
|
18
|
-
"lua:config.setLuaValue":
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
50
|
+
"lua:config.setLuaValue": {
|
|
51
|
+
callback: async (
|
|
52
|
+
_ctx,
|
|
53
|
+
keyOrValues: string | string[] | Record<string, any>,
|
|
54
|
+
value?: any,
|
|
55
|
+
) => {
|
|
56
|
+
// This is for special cases where we explicitly want to NOT convert a value to a JS value, but maintain its Lua version (mostly for LuaTables) — main use case: metatable
|
|
57
|
+
keyOrValues = await luaValueToJS(keyOrValues, LuaStackFrame.lostFrame);
|
|
58
|
+
config.set(keyOrValues as any, value);
|
|
59
|
+
},
|
|
60
|
+
description:
|
|
61
|
+
"Sets configuration while preserving the supplied Lua value representation.",
|
|
62
|
+
signatures: [
|
|
63
|
+
"config.setLuaValue(path, value)",
|
|
64
|
+
"config.setLuaValue(values)",
|
|
65
|
+
],
|
|
66
|
+
parameters: [
|
|
67
|
+
{
|
|
68
|
+
name: "pathOrValues",
|
|
69
|
+
description: "Configuration path or table of values.",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "value",
|
|
73
|
+
description: "Lua value to preserve.",
|
|
74
|
+
optional: true,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
26
77
|
},
|
|
27
|
-
"config.insert":
|
|
28
|
-
|
|
78
|
+
"config.insert": {
|
|
79
|
+
callback: (_ctx, key: string | string[], value: any) => {
|
|
80
|
+
config.insert(key, value);
|
|
81
|
+
},
|
|
82
|
+
description: "Appends a value to the configuration array at a path.",
|
|
83
|
+
parameters: [
|
|
84
|
+
{ name: "path", description: "Configuration path." },
|
|
85
|
+
{ name: "value", description: "Value to append." },
|
|
86
|
+
],
|
|
29
87
|
},
|
|
30
|
-
"config.has":
|
|
31
|
-
|
|
88
|
+
"config.has": {
|
|
89
|
+
callback: (_ctx, path: string) => {
|
|
90
|
+
return config.has(path);
|
|
91
|
+
},
|
|
92
|
+
description: "Checks whether a configuration path exists.",
|
|
93
|
+
parameters: [
|
|
94
|
+
{ name: "path", type: "string", description: "Configuration path." },
|
|
95
|
+
],
|
|
96
|
+
returns: [{ type: "boolean", description: "Whether the path exists." }],
|
|
32
97
|
},
|
|
33
|
-
"config.define":
|
|
34
|
-
|
|
98
|
+
"config.define": {
|
|
99
|
+
callback: (_ctx, key: string, schema: any) => {
|
|
100
|
+
config.define(key, schema);
|
|
101
|
+
},
|
|
102
|
+
description: "Defines a JSON schema for a configuration key.",
|
|
103
|
+
parameters: [
|
|
104
|
+
{ name: "key", type: "string", description: "Configuration key." },
|
|
105
|
+
{
|
|
106
|
+
name: "schema",
|
|
107
|
+
type: "table",
|
|
108
|
+
description:
|
|
109
|
+
"JSON Schema definition; default applies a missing value and ui annotations expose it in the Configuration Manager.",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
examples: [
|
|
113
|
+
{
|
|
114
|
+
code: 'config.define("shortWikiLinks", {\n description = "Render short wiki link labels",\n type = "boolean",\n default = true,\n ui = {category = "Editor", label = "Short wiki links", priority = 1},\n})',
|
|
115
|
+
},
|
|
116
|
+
],
|
|
35
117
|
},
|
|
36
|
-
"config.defineCategory":
|
|
37
|
-
|
|
118
|
+
"config.defineCategory": {
|
|
119
|
+
callback: (_ctx, definition: any) => {
|
|
120
|
+
config.defineCategory(definition);
|
|
121
|
+
},
|
|
122
|
+
description: "Defines or updates a Configuration Manager UI category.",
|
|
123
|
+
parameters: [
|
|
124
|
+
{
|
|
125
|
+
name: "definition",
|
|
126
|
+
type: "table",
|
|
127
|
+
description: "Category name, description, and priority.",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
examples: [
|
|
131
|
+
{
|
|
132
|
+
code: 'config.defineCategory {\n name = "Editor",\n description = "Page editor behavior.",\n priority = 50,\n}',
|
|
133
|
+
},
|
|
134
|
+
],
|
|
38
135
|
},
|
|
39
|
-
"config.getValues":
|
|
40
|
-
|
|
136
|
+
"config.getValues": {
|
|
137
|
+
callback: () => {
|
|
138
|
+
return stripFunctions(config.values);
|
|
139
|
+
},
|
|
140
|
+
description: "Gets all configuration values as a single table.",
|
|
141
|
+
returns: [{ type: "table", description: "All configuration values." }],
|
|
41
142
|
},
|
|
42
|
-
"config.getSchemas":
|
|
43
|
-
|
|
143
|
+
"config.getSchemas": {
|
|
144
|
+
callback: () => {
|
|
145
|
+
return stripFunctions(config.schemas);
|
|
146
|
+
},
|
|
147
|
+
description: "Gets all defined configuration schemas.",
|
|
148
|
+
returns: [
|
|
149
|
+
{
|
|
150
|
+
type: "table",
|
|
151
|
+
description: "Schemas keyed by configuration path.",
|
|
152
|
+
},
|
|
153
|
+
],
|
|
44
154
|
},
|
|
45
|
-
"config.getCategories":
|
|
46
|
-
|
|
155
|
+
"config.getCategories": {
|
|
156
|
+
callback: () => {
|
|
157
|
+
return { ...config.categories };
|
|
158
|
+
},
|
|
159
|
+
description: "Gets all Configuration Manager UI categories.",
|
|
160
|
+
returns: [
|
|
161
|
+
{ type: "table", description: "Category definitions keyed by name." },
|
|
162
|
+
],
|
|
47
163
|
},
|
|
48
164
|
};
|
|
49
165
|
}
|