@silverbulletmd/silverbullet 2.4.1
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/LICENSE.md +18 -0
- package/README.md +98 -0
- package/client/asset_bundle/bundle.ts +95 -0
- package/client/data/datastore.ts +85 -0
- package/client/data/kv_primitives.ts +25 -0
- package/client/markdown_parser/constants.ts +13 -0
- package/client/plugos/event.ts +36 -0
- package/client/plugos/eventhook.ts +8 -0
- package/client/plugos/hooks/code_widget.ts +59 -0
- package/client/plugos/hooks/command.ts +104 -0
- package/client/plugos/hooks/document_editor.ts +77 -0
- package/client/plugos/hooks/event.ts +187 -0
- package/client/plugos/hooks/mq.ts +154 -0
- package/client/plugos/hooks/plug_namespace.ts +85 -0
- package/client/plugos/hooks/slash_command.ts +192 -0
- package/client/plugos/hooks/syscall.ts +66 -0
- package/client/plugos/manifest_cache.ts +67 -0
- package/client/plugos/plug.ts +99 -0
- package/client/plugos/plug_compile.ts +202 -0
- package/client/plugos/protocol.ts +40 -0
- package/client/plugos/proxy_fetch.ts +53 -0
- package/client/plugos/sandboxes/deno_worker_sandbox.ts +6 -0
- package/client/plugos/sandboxes/sandbox.ts +14 -0
- package/client/plugos/sandboxes/web_worker_sandbox.ts +17 -0
- package/client/plugos/sandboxes/worker_sandbox.ts +132 -0
- package/client/plugos/syscalls/asset.ts +35 -0
- package/client/plugos/syscalls/clientStore.ts +21 -0
- package/client/plugos/syscalls/client_code_widget.ts +12 -0
- package/client/plugos/syscalls/code_widget.ts +24 -0
- package/client/plugos/syscalls/config.ts +46 -0
- package/client/plugos/syscalls/datastore.ts +89 -0
- package/client/plugos/syscalls/editor.ts +673 -0
- package/client/plugos/syscalls/event.ts +36 -0
- package/client/plugos/syscalls/fetch.ts +128 -0
- package/client/plugos/syscalls/index.ts +102 -0
- package/client/plugos/syscalls/jsonschema.ts +69 -0
- package/client/plugos/syscalls/language.ts +23 -0
- package/client/plugos/syscalls/lua.ts +58 -0
- package/client/plugos/syscalls/markdown.ts +84 -0
- package/client/plugos/syscalls/mq.ts +52 -0
- package/client/plugos/syscalls/service_registry.ts +43 -0
- package/client/plugos/syscalls/shell.ts +39 -0
- package/client/plugos/syscalls/space.ts +139 -0
- package/client/plugos/syscalls/sync.ts +77 -0
- package/client/plugos/syscalls/system.ts +150 -0
- package/client/plugos/system.ts +201 -0
- package/client/plugos/types.ts +60 -0
- package/client/plugos/util.ts +14 -0
- package/client/plugos/worker_runtime.ts +195 -0
- package/client/space_lua/ast.ts +328 -0
- package/client/space_lua/ast_narrow.ts +81 -0
- package/client/space_lua/eval.ts +2478 -0
- package/client/space_lua/labels.ts +416 -0
- package/client/space_lua/numeric.ts +240 -0
- package/client/space_lua/parse.ts +1522 -0
- package/client/space_lua/query_collection.ts +232 -0
- package/client/space_lua/rp.ts +27 -0
- package/client/space_lua/runtime.ts +1702 -0
- package/client/space_lua/stdlib/crypto.ts +10 -0
- package/client/space_lua/stdlib/encoding.ts +19 -0
- package/client/space_lua/stdlib/format.ts +770 -0
- package/client/space_lua/stdlib/js.ts +73 -0
- package/client/space_lua/stdlib/load.ts +52 -0
- package/client/space_lua/stdlib/math.ts +193 -0
- package/client/space_lua/stdlib/net.ts +113 -0
- package/client/space_lua/stdlib/os.ts +368 -0
- package/client/space_lua/stdlib/space_lua.ts +153 -0
- package/client/space_lua/stdlib/string.ts +286 -0
- package/client/space_lua/stdlib/table.ts +401 -0
- package/client/space_lua/stdlib.ts +489 -0
- package/client/space_lua/tonumber.ts +501 -0
- package/client/space_lua/util.ts +96 -0
- package/dist/plug-compile.js +1513 -0
- package/package.json +120 -0
- package/plug-api/constants.ts +42 -0
- package/plug-api/lib/async.ts +162 -0
- package/plug-api/lib/crypto.ts +202 -0
- package/plug-api/lib/dates.ts +13 -0
- package/plug-api/lib/json.ts +136 -0
- package/plug-api/lib/limited_map.ts +72 -0
- package/plug-api/lib/memory_cache.ts +21 -0
- package/plug-api/lib/native_fetch.ts +6 -0
- package/plug-api/lib/ref.ts +275 -0
- package/plug-api/lib/resolve.ts +90 -0
- package/plug-api/lib/tags.ts +15 -0
- package/plug-api/lib/transclusion.ts +122 -0
- package/plug-api/lib/tree.ts +232 -0
- package/plug-api/lib/yaml.ts +284 -0
- package/plug-api/syscall.ts +15 -0
- package/plug-api/syscalls/asset.ts +36 -0
- package/plug-api/syscalls/client_store.ts +33 -0
- package/plug-api/syscalls/code_widget.ts +8 -0
- package/plug-api/syscalls/config.ts +58 -0
- package/plug-api/syscalls/datastore.ts +96 -0
- package/plug-api/syscalls/editor.ts +517 -0
- package/plug-api/syscalls/event.ts +47 -0
- package/plug-api/syscalls/index.ts +77 -0
- package/plug-api/syscalls/jsonschema.ts +25 -0
- package/plug-api/syscalls/language.ts +23 -0
- package/plug-api/syscalls/lua.ts +20 -0
- package/plug-api/syscalls/markdown.ts +38 -0
- package/plug-api/syscalls/mq.ts +79 -0
- package/plug-api/syscalls/shell.ts +14 -0
- package/plug-api/syscalls/space.ts +212 -0
- package/plug-api/syscalls/sync.ts +28 -0
- package/plug-api/syscalls/system.ts +102 -0
- package/plug-api/syscalls/yaml.ts +28 -0
- package/plug-api/syscalls.ts +21 -0
- package/plug-api/system_mock.ts +89 -0
- package/plug-api/types/client.ts +116 -0
- package/plug-api/types/config.ts +22 -0
- package/plug-api/types/datastore.ts +28 -0
- package/plug-api/types/event.ts +27 -0
- package/plug-api/types/index.ts +56 -0
- package/plug-api/types/manifest.ts +98 -0
- package/plug-api/types/namespace.ts +6 -0
- package/plugs/builtin_plugs.ts +14 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import type { LuaExpression } from "./ast.ts";
|
|
2
|
+
import { LuaEnv, luaGet, luaKeys, LuaStackFrame, LuaTable } from "./runtime.ts";
|
|
3
|
+
import { evalExpression } from "./eval.ts";
|
|
4
|
+
import { asyncQuickSort } from "./util.ts";
|
|
5
|
+
import type { DataStore } from "../data/datastore.ts";
|
|
6
|
+
import type { KvPrimitives } from "../data/kv_primitives.ts";
|
|
7
|
+
|
|
8
|
+
import type { QueryCollationConfig } from "../../plug-api/types/config.ts";
|
|
9
|
+
|
|
10
|
+
import type { KvKey } from "../../plug-api/types/datastore.ts";
|
|
11
|
+
|
|
12
|
+
export function buildItemEnv(
|
|
13
|
+
objectVariable: string | undefined,
|
|
14
|
+
item: any,
|
|
15
|
+
env: LuaEnv,
|
|
16
|
+
sf: LuaStackFrame,
|
|
17
|
+
): LuaEnv {
|
|
18
|
+
const itemEnv = new LuaEnv(env);
|
|
19
|
+
if (!objectVariable) {
|
|
20
|
+
// Inject all item keys as variables
|
|
21
|
+
for (const key of luaKeys(item)) {
|
|
22
|
+
itemEnv.setLocal(key, luaGet(item, key, sf.astCtx ?? null, sf));
|
|
23
|
+
}
|
|
24
|
+
// As well as _
|
|
25
|
+
itemEnv.setLocal("_", item);
|
|
26
|
+
} else {
|
|
27
|
+
itemEnv.setLocal(objectVariable, item);
|
|
28
|
+
}
|
|
29
|
+
return itemEnv;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type LuaOrderBy = {
|
|
33
|
+
expr: LuaExpression;
|
|
34
|
+
desc: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Represents a query for a collection
|
|
39
|
+
*/
|
|
40
|
+
export type LuaCollectionQuery = {
|
|
41
|
+
objectVariable?: string;
|
|
42
|
+
// The filter expression evaluated with Lua
|
|
43
|
+
where?: LuaExpression;
|
|
44
|
+
// The order by expression evaluated with Lua
|
|
45
|
+
orderBy?: LuaOrderBy[];
|
|
46
|
+
// The select expression evaluated with Lua
|
|
47
|
+
select?: LuaExpression;
|
|
48
|
+
// The limit of the query
|
|
49
|
+
limit?: number;
|
|
50
|
+
// The offset of the query
|
|
51
|
+
offset?: number;
|
|
52
|
+
// Whether to return only distinct values
|
|
53
|
+
distinct?: boolean;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export interface LuaQueryCollection {
|
|
57
|
+
query(
|
|
58
|
+
query: LuaCollectionQuery,
|
|
59
|
+
env: LuaEnv,
|
|
60
|
+
sf: LuaStackFrame,
|
|
61
|
+
): Promise<any[]>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Implements a query collection for a regular JavaScript array
|
|
66
|
+
*/
|
|
67
|
+
export class ArrayQueryCollection<T> implements LuaQueryCollection {
|
|
68
|
+
constructor(private readonly array: T[]) {
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
query(
|
|
72
|
+
query: LuaCollectionQuery,
|
|
73
|
+
env: LuaEnv,
|
|
74
|
+
sf: LuaStackFrame,
|
|
75
|
+
collation?: QueryCollationConfig,
|
|
76
|
+
): Promise<any[]> {
|
|
77
|
+
return applyQuery(this.array, query, env, sf, collation);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Applies a given query (where, order by, limit etc.) to a set of results
|
|
83
|
+
*/
|
|
84
|
+
export async function applyQuery(
|
|
85
|
+
results: any[],
|
|
86
|
+
query: LuaCollectionQuery,
|
|
87
|
+
env: LuaEnv,
|
|
88
|
+
sf: LuaStackFrame,
|
|
89
|
+
collation?: QueryCollationConfig,
|
|
90
|
+
): Promise<any[]> {
|
|
91
|
+
// Shallow copy to avoid updating underlying data structures
|
|
92
|
+
results = results.slice();
|
|
93
|
+
|
|
94
|
+
// Filter results based on `where` clause first
|
|
95
|
+
if (query.where) {
|
|
96
|
+
const filteredResults = [];
|
|
97
|
+
for (const value of results) {
|
|
98
|
+
// Enrich value
|
|
99
|
+
const itemEnv = buildItemEnv(query.objectVariable, value, env, sf);
|
|
100
|
+
if (await evalExpression(query.where, itemEnv, sf)) {
|
|
101
|
+
filteredResults.push(value);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
results = filteredResults;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Apply `order by` next
|
|
108
|
+
if (query.orderBy) {
|
|
109
|
+
// Retrieve from config API if not passed
|
|
110
|
+
if (collation === undefined) {
|
|
111
|
+
// @ts-ignore: Hack to access client via the browser
|
|
112
|
+
const config = globalThis.client.config; // HACK: Shouldn't be using client here directly
|
|
113
|
+
|
|
114
|
+
collation = config.get("queryCollation", {});
|
|
115
|
+
}
|
|
116
|
+
// Both arguments are optional, so passing undefined is fine
|
|
117
|
+
const collator = Intl.Collator(collation?.locale, collation?.options);
|
|
118
|
+
|
|
119
|
+
results = await asyncQuickSort(results, async (a, b) => {
|
|
120
|
+
// Compare each orderBy clause until we find a difference
|
|
121
|
+
for (const { expr, desc } of query.orderBy!) {
|
|
122
|
+
const aEnv = buildItemEnv(query.objectVariable, a, env, sf);
|
|
123
|
+
const bEnv = buildItemEnv(query.objectVariable, b, env, sf);
|
|
124
|
+
|
|
125
|
+
const aVal = await evalExpression(expr, aEnv, sf);
|
|
126
|
+
const bVal = await evalExpression(expr, bEnv, sf);
|
|
127
|
+
|
|
128
|
+
if (
|
|
129
|
+
collation?.enabled &&
|
|
130
|
+
typeof aVal === "string" &&
|
|
131
|
+
typeof bVal === "string"
|
|
132
|
+
) {
|
|
133
|
+
const order = collator.compare(aVal, bVal);
|
|
134
|
+
if (order != 0) {
|
|
135
|
+
return desc ? -order : order;
|
|
136
|
+
}
|
|
137
|
+
} else if (aVal < bVal) {
|
|
138
|
+
return desc ? 1 : -1;
|
|
139
|
+
} else if (aVal > bVal) {
|
|
140
|
+
return desc ? -1 : 1;
|
|
141
|
+
}
|
|
142
|
+
// If equal, continue to next orderBy clause
|
|
143
|
+
}
|
|
144
|
+
return 0; // All orderBy clauses were equal
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Apply the select
|
|
149
|
+
if (query.select) {
|
|
150
|
+
const newResult = [];
|
|
151
|
+
for (const item of results) {
|
|
152
|
+
const itemEnv = buildItemEnv(query.objectVariable, item, env, sf);
|
|
153
|
+
newResult.push(await evalExpression(query.select, itemEnv, sf));
|
|
154
|
+
}
|
|
155
|
+
results = newResult;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Apply distinct filter (after select to filter on selected values)
|
|
159
|
+
if (query.distinct) {
|
|
160
|
+
const seen = new Set();
|
|
161
|
+
const distinctResult = [];
|
|
162
|
+
|
|
163
|
+
for (const item of results) {
|
|
164
|
+
// For non-primitive values, we use a JSON string as the key for comparison
|
|
165
|
+
const key = generateKey(item);
|
|
166
|
+
|
|
167
|
+
if (!seen.has(key)) {
|
|
168
|
+
seen.add(key);
|
|
169
|
+
distinctResult.push(item);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
results = distinctResult;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Apply the limit and offset
|
|
177
|
+
if (query.limit !== undefined && query.offset !== undefined) {
|
|
178
|
+
results = results.slice(query.offset, query.offset + query.limit);
|
|
179
|
+
} else if (query.limit !== undefined) {
|
|
180
|
+
results = results.slice(0, query.limit);
|
|
181
|
+
} else if (query.offset !== undefined) {
|
|
182
|
+
results = results.slice(query.offset);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return results;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function queryLua<T = any>(
|
|
189
|
+
kv: KvPrimitives,
|
|
190
|
+
prefix: KvKey,
|
|
191
|
+
query: LuaCollectionQuery,
|
|
192
|
+
env: LuaEnv,
|
|
193
|
+
sf: LuaStackFrame = LuaStackFrame.lostFrame,
|
|
194
|
+
enricher?: (key: KvKey, item: any) => any,
|
|
195
|
+
): Promise<T[]> {
|
|
196
|
+
const results: T[] = [];
|
|
197
|
+
// Accumulate all results into an array
|
|
198
|
+
for await (
|
|
199
|
+
let { key, value } of kv.query({ prefix })
|
|
200
|
+
) {
|
|
201
|
+
if (enricher) {
|
|
202
|
+
value = enricher(key, value);
|
|
203
|
+
}
|
|
204
|
+
results.push(value);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return applyQuery(results, query, env, sf);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function generateKey(value: any) {
|
|
211
|
+
if (value instanceof LuaTable) {
|
|
212
|
+
return JSON.stringify(value.toJS());
|
|
213
|
+
}
|
|
214
|
+
return typeof value === "object" && value !== null
|
|
215
|
+
? JSON.stringify(value)
|
|
216
|
+
: value;
|
|
217
|
+
}
|
|
218
|
+
export class DataStoreQueryCollection implements LuaQueryCollection {
|
|
219
|
+
constructor(
|
|
220
|
+
private readonly dataStore: DataStore,
|
|
221
|
+
readonly prefix: string[],
|
|
222
|
+
) {
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
query(
|
|
226
|
+
query: LuaCollectionQuery,
|
|
227
|
+
env: LuaEnv,
|
|
228
|
+
sf: LuaStackFrame,
|
|
229
|
+
): Promise<any[]> {
|
|
230
|
+
return queryLua(this.dataStore.kv, this.prefix, query, env, sf);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Result-or-Promise helpers
|
|
2
|
+
|
|
3
|
+
export type RP<T> = T | Promise<T>;
|
|
4
|
+
|
|
5
|
+
// Returns true when v is a Promise or a has a then function.
|
|
6
|
+
export function isPromise<T>(v: RP<T>): v is Promise<T> {
|
|
7
|
+
return v !== null &&
|
|
8
|
+
(typeof v === "object" || typeof v === "function") &&
|
|
9
|
+
typeof (v as any).then === "function";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function rpThen<A, B>(v: RP<A>, f: (a: A) => RP<B>): RP<B> {
|
|
13
|
+
return isPromise(v) ? (v as Promise<A>).then(f) : f(v as A);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Collect an array of Result-or-Promise values into a single array
|
|
18
|
+
* avoiding Promise allocation when all inputs are synchronous.
|
|
19
|
+
*/
|
|
20
|
+
export function rpAll<T>(arr: RP<T>[]): RP<T[]> {
|
|
21
|
+
for (let i = 0; i < arr.length; i++) {
|
|
22
|
+
if (isPromise(arr[i])) {
|
|
23
|
+
return Promise.all(arr as Promise<T>[]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return arr as T[];
|
|
27
|
+
}
|