@silverbulletmd/silverbullet 2.4.2 → 2.5.3
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 +20 -4
- package/client/markdown_parser/constants.ts +2 -2
- package/client/plugos/hooks/code_widget.ts +0 -3
- package/client/plugos/hooks/document_editor.ts +0 -3
- package/client/plugos/hooks/event.ts +1 -1
- package/client/plugos/hooks/mq.ts +1 -1
- package/client/plugos/hooks/plug_namespace.ts +0 -3
- package/client/plugos/hooks/slash_command.ts +2 -2
- package/client/plugos/plug.ts +0 -1
- package/client/plugos/plug_compile.ts +28 -29
- package/client/plugos/proxy_fetch.ts +1 -1
- package/client/plugos/sandboxes/web_worker_sandbox.ts +1 -1
- package/client/plugos/sandboxes/worker_sandbox.ts +2 -3
- package/client/plugos/syscalls/editor.ts +12 -12
- package/client/plugos/syscalls/fetch.ts +1 -1
- package/client/plugos/syscalls/jsonschema.ts +1 -1
- package/client/plugos/syscalls/mq.ts +1 -1
- package/client/plugos/syscalls/space.ts +1 -1
- package/client/plugos/system.ts +2 -2
- package/client/plugos/worker_runtime.ts +8 -30
- package/client/space_lua/aggregates.ts +209 -0
- package/client/space_lua/ast.ts +24 -2
- package/client/space_lua/eval.ts +58 -53
- package/client/space_lua/labels.ts +1 -1
- package/client/space_lua/parse.ts +117 -12
- package/client/space_lua/query_collection.ts +850 -70
- package/client/space_lua/query_env.ts +26 -0
- package/client/space_lua/runtime.ts +47 -17
- package/client/space_lua/stdlib/format.ts +19 -19
- package/client/space_lua/stdlib/math.ts +73 -48
- package/client/space_lua/stdlib/net.ts +2 -2
- package/client/space_lua/stdlib/os.ts +5 -0
- package/client/space_lua/stdlib/pattern.ts +702 -0
- package/client/space_lua/stdlib/prng.ts +145 -0
- package/client/space_lua/stdlib/space_lua.ts +3 -8
- package/client/space_lua/stdlib/string.ts +103 -181
- package/client/space_lua/stdlib/string_pack.ts +486 -0
- package/client/space_lua/stdlib/table.ts +73 -9
- package/client/space_lua/stdlib.ts +38 -14
- package/client/space_lua/tonumber.ts +3 -2
- package/client/space_lua/util.ts +43 -9
- package/dist/plug-compile.js +23 -69
- package/dist/worker_runtime_bundle.js +233 -0
- package/package.json +10 -5
- package/plug-api/constants.ts +0 -32
- package/plug-api/lib/async.ts +2 -2
- package/plug-api/lib/crypto.ts +11 -11
- package/plug-api/lib/json.ts +1 -1
- package/plug-api/lib/limited_map.ts +1 -1
- package/plug-api/lib/native_fetch.ts +2 -0
- package/plug-api/lib/ref.ts +5 -5
- package/plug-api/lib/transclusion.ts +5 -5
- package/plug-api/lib/tree.ts +50 -2
- package/plug-api/lib/yaml.ts +10 -10
- package/plug-api/syscalls/editor.ts +1 -1
- package/plug-api/system_mock.ts +0 -1
- package/client/plugos/sandboxes/deno_worker_sandbox.ts +0 -6
package/plug-api/constants.ts
CHANGED
|
@@ -8,35 +8,3 @@ export const wrongSpacePathError: Error = new Error(
|
|
|
8
8
|
);
|
|
9
9
|
export const pingTimeout: number = 2000;
|
|
10
10
|
export const pingInterval: number = 5000;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* HTTP status codes that should be treated as "offline" conditions.
|
|
14
|
-
*
|
|
15
|
-
* This is particularly useful for cases where a proxy (such as Cloudflare or other reverse proxies)
|
|
16
|
-
* indicates that the backend server is down, but there is still network connectivity between
|
|
17
|
-
* the user and the proxy. In these scenarios, we want to allow the user to continue working
|
|
18
|
-
* with their cached data rather than showing an error, even though technically there is network
|
|
19
|
-
* connectivity to the proxy.
|
|
20
|
-
*
|
|
21
|
-
* This enables SilverBullet to work in a true "offline-first" manner, falling back to cached
|
|
22
|
-
* content when the backend is unavailable through no fault of the user's network connection.
|
|
23
|
-
*
|
|
24
|
-
* All 5xx server errors are included to prevent the client from caching error HTML pages
|
|
25
|
-
* (e.g., Nginx 500 error pages) which would prevent the client from booting in offline mode.
|
|
26
|
-
*/
|
|
27
|
-
export const offlineStatusCodes = {
|
|
28
|
-
500: "Internal Server Error", // Server encountered an unexpected condition
|
|
29
|
-
501: "Not Implemented", // Server does not support the functionality required
|
|
30
|
-
502: "Bad Gateway", // Proxy server received invalid response from upstream server
|
|
31
|
-
503: "Service Unavailable", // Server is temporarily unable to handle the request
|
|
32
|
-
504: "Gateway Timeout", // Proxy server did not receive a timely response from upstream server
|
|
33
|
-
505: "HTTP Version Not Supported", // Server does not support the HTTP version
|
|
34
|
-
506: "Variant Also Negotiates", // Server has an internal configuration error
|
|
35
|
-
507: "Insufficient Storage", // Server is unable to store the representation
|
|
36
|
-
508: "Loop Detected", // Server detected an infinite loop while processing
|
|
37
|
-
509: "Bandwidth Limit Exceeded", // Server bandwidth limit has been exceeded
|
|
38
|
-
510: "Not Extended", // Further extensions to the request are required
|
|
39
|
-
511: "Network Authentication Required", // Client needs to authenticate to gain network access
|
|
40
|
-
|
|
41
|
-
530: "Unable to resolve origin hostname", // Served when cloudflared is down on the host
|
|
42
|
-
} as const;
|
package/plug-api/lib/async.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function throttle(func: () => void, limit: number): () => void {
|
|
2
2
|
let timer: any = null;
|
|
3
|
-
return
|
|
3
|
+
return () => {
|
|
4
4
|
if (!timer) {
|
|
5
5
|
timer = setTimeout(() => {
|
|
6
6
|
func();
|
|
@@ -15,7 +15,7 @@ export function throttleImmediately(
|
|
|
15
15
|
limit: number,
|
|
16
16
|
): () => void {
|
|
17
17
|
let timer: any = null;
|
|
18
|
-
return
|
|
18
|
+
return () => {
|
|
19
19
|
if (!timer) {
|
|
20
20
|
func();
|
|
21
21
|
timer = setTimeout(() => {
|
package/plug-api/lib/crypto.ts
CHANGED
|
@@ -85,7 +85,7 @@ export async function encryptStringDeterministic(
|
|
|
85
85
|
key: CryptoKey,
|
|
86
86
|
clearText: string,
|
|
87
87
|
): Promise<string> {
|
|
88
|
-
const encrypted = await crypto.subtle.encrypt(
|
|
88
|
+
const encrypted = await globalThis.crypto.subtle.encrypt(
|
|
89
89
|
{ name: "AES-CTR", counter: fixedCounter, length: fixedCounter.length * 8 },
|
|
90
90
|
key,
|
|
91
91
|
new TextEncoder().encode(clearText),
|
|
@@ -97,7 +97,7 @@ export async function decryptStringDeterministic(
|
|
|
97
97
|
key: CryptoKey,
|
|
98
98
|
cipherText: string,
|
|
99
99
|
): Promise<string> {
|
|
100
|
-
const decrypted = await crypto.subtle.decrypt(
|
|
100
|
+
const decrypted = await globalThis.crypto.subtle.decrypt(
|
|
101
101
|
{ name: "AES-CTR", counter: fixedCounter, length: fixedCounter.length * 8 },
|
|
102
102
|
key,
|
|
103
103
|
base64Decode(cipherText) as BufferSource,
|
|
@@ -110,8 +110,8 @@ export async function encryptAesGcm(
|
|
|
110
110
|
key: CryptoKey,
|
|
111
111
|
data: Uint8Array,
|
|
112
112
|
): Promise<Uint8Array> {
|
|
113
|
-
const iv = crypto.getRandomValues(new Uint8Array(12)); // 96-bit IV recommended for GCM
|
|
114
|
-
const encryptedBuffer = await crypto.subtle.encrypt(
|
|
113
|
+
const iv = globalThis.crypto.getRandomValues(new Uint8Array(12)); // 96-bit IV recommended for GCM
|
|
114
|
+
const encryptedBuffer = await globalThis.crypto.subtle.encrypt(
|
|
115
115
|
{ name: "AES-GCM", iv },
|
|
116
116
|
key,
|
|
117
117
|
data as BufferSource,
|
|
@@ -132,7 +132,7 @@ export async function decryptAesGcm(
|
|
|
132
132
|
): Promise<Uint8Array> {
|
|
133
133
|
const iv = encryptedData.slice(0, 12); // extract IV (first 12 bytes)
|
|
134
134
|
const ciphertext = encryptedData.slice(12);
|
|
135
|
-
const decryptedBuffer = await crypto.subtle.decrypt(
|
|
135
|
+
const decryptedBuffer = await globalThis.crypto.subtle.decrypt(
|
|
136
136
|
{ name: "AES-GCM", iv },
|
|
137
137
|
key,
|
|
138
138
|
ciphertext,
|
|
@@ -148,7 +148,7 @@ export async function deriveCTRKeyFromPassword(
|
|
|
148
148
|
const passwordBytes = new TextEncoder().encode(password);
|
|
149
149
|
|
|
150
150
|
// Import password as a CryptoKey
|
|
151
|
-
const baseKey = await crypto.subtle.importKey(
|
|
151
|
+
const baseKey = await globalThis.crypto.subtle.importKey(
|
|
152
152
|
"raw",
|
|
153
153
|
passwordBytes,
|
|
154
154
|
{ name: "PBKDF2" },
|
|
@@ -156,7 +156,7 @@ export async function deriveCTRKeyFromPassword(
|
|
|
156
156
|
["deriveBits", "deriveKey"],
|
|
157
157
|
);
|
|
158
158
|
|
|
159
|
-
return crypto.subtle.deriveKey(
|
|
159
|
+
return globalThis.crypto.subtle.deriveKey(
|
|
160
160
|
{
|
|
161
161
|
name: "PBKDF2",
|
|
162
162
|
salt: salt as BufferSource,
|
|
@@ -174,7 +174,7 @@ export async function deriveCTRKeyFromPassword(
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
export function importKey(b64EncodedKey: string): Promise<CryptoKey> {
|
|
177
|
-
return crypto.subtle.importKey(
|
|
177
|
+
return globalThis.crypto.subtle.importKey(
|
|
178
178
|
"raw",
|
|
179
179
|
base64Decode(b64EncodedKey) as BufferSource,
|
|
180
180
|
{ name: "AES-CTR" },
|
|
@@ -184,15 +184,15 @@ export function importKey(b64EncodedKey: string): Promise<CryptoKey> {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
export async function exportKey(ctrKey: CryptoKey): Promise<string> {
|
|
187
|
-
const key = await crypto.subtle.exportKey("raw", ctrKey);
|
|
187
|
+
const key = await globalThis.crypto.subtle.exportKey("raw", ctrKey);
|
|
188
188
|
return base64Encode(new Uint8Array(key));
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
export async function deriveGCMKeyFromCTR(
|
|
192
192
|
ctrKey: CryptoKey,
|
|
193
193
|
): Promise<CryptoKey> {
|
|
194
|
-
const rawKey = await crypto.subtle.exportKey("raw", ctrKey);
|
|
195
|
-
return crypto.subtle.importKey(
|
|
194
|
+
const rawKey = await globalThis.crypto.subtle.exportKey("raw", ctrKey);
|
|
195
|
+
return globalThis.crypto.subtle.importKey(
|
|
196
196
|
"raw",
|
|
197
197
|
rawKey,
|
|
198
198
|
{ name: "AES-GCM" },
|
package/plug-api/lib/json.ts
CHANGED
|
@@ -125,7 +125,7 @@ export function deepClone<T>(obj: T, ignoreKeys: string[] = []): T {
|
|
|
125
125
|
for (const key in obj) {
|
|
126
126
|
if (ignoreKeys.includes(key)) {
|
|
127
127
|
objClone[key] = obj[key];
|
|
128
|
-
} else if (Object.
|
|
128
|
+
} else if (Object.hasOwn(obj, key)) {
|
|
129
129
|
objClone[key] = deepClone(obj[key], ignoreKeys);
|
|
130
130
|
}
|
|
131
131
|
}
|
package/plug-api/lib/ref.ts
CHANGED
|
@@ -87,7 +87,7 @@ export function isValidName(name: string): boolean {
|
|
|
87
87
|
export function isValidPath(path: string): path is Path {
|
|
88
88
|
const ref = parseToRef(path);
|
|
89
89
|
|
|
90
|
-
return !!ref && ref.path === path;
|
|
90
|
+
return !!ref && ref.path === path && path !== "";
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
@@ -95,7 +95,7 @@ export function isValidPath(path: string): path is Path {
|
|
|
95
95
|
* TO THE INNER WORKINGS OF SILVERBULLET AND CHANGES COULD INTRODUCE MAJOR BUGS
|
|
96
96
|
*/
|
|
97
97
|
const refRegex =
|
|
98
|
-
/^(?<meta>\^)?(?<path>(?!.*\.[a-zA-Z0-9]+\.md$)(?!\/?(\.|\^))(?!.*(?:\/|^)\.{1,2}(?:\/|$)|.*\/{2})(?!.*(?:\]\]|\[\[))[
|
|
98
|
+
/^(?<meta>\^)?(?<path>(?!.*\.[a-zA-Z0-9]+\.md$)(?!\/?(\.|\^))(?!.*(?:\/|^)\.{1,2}(?:\/|$)|.*\/{2})(?!.*(?:\]\]|\[\[))[^@#|<>]*)(@(?<pos>\d+)|@[Ll](?<line>\d+)(?:[Cc](?<col>\d+))?|#\s*(?<header>.*))?$/;
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
101
|
* Parses a reference string into a ref object.
|
|
@@ -118,13 +118,13 @@ export function parseToRef(stringRef: string): Ref | null {
|
|
|
118
118
|
if (groups.pos !== undefined) {
|
|
119
119
|
ref.details = {
|
|
120
120
|
type: "position",
|
|
121
|
-
pos: parseInt(groups.pos),
|
|
121
|
+
pos: parseInt(groups.pos, 10),
|
|
122
122
|
};
|
|
123
123
|
} else if (groups.line !== undefined) {
|
|
124
124
|
ref.details = {
|
|
125
125
|
type: "linecolumn",
|
|
126
|
-
line: parseInt(groups.line),
|
|
127
|
-
column: groups.col !== undefined ? parseInt(groups.col) : 1,
|
|
126
|
+
line: parseInt(groups.line, 10),
|
|
127
|
+
column: groups.col !== undefined ? parseInt(groups.col, 10) : 1,
|
|
128
128
|
};
|
|
129
129
|
} else if (groups.header !== undefined) {
|
|
130
130
|
ref.details = {
|
|
@@ -45,19 +45,19 @@ export function parseDimensionFromAlias(
|
|
|
45
45
|
const [width, height] = dimPart.split("x");
|
|
46
46
|
dim = {};
|
|
47
47
|
if (width) {
|
|
48
|
-
dim.width = parseInt(width);
|
|
48
|
+
dim.width = parseInt(width, 10);
|
|
49
49
|
}
|
|
50
50
|
if (height) {
|
|
51
|
-
dim.height = parseInt(height);
|
|
51
|
+
dim.height = parseInt(height, 10);
|
|
52
52
|
}
|
|
53
53
|
} else if (/^[x\d]/.test(text)) {
|
|
54
54
|
const [width, height] = text.split("x");
|
|
55
55
|
dim = {};
|
|
56
56
|
if (width) {
|
|
57
|
-
dim.width = parseInt(width);
|
|
57
|
+
dim.width = parseInt(width, 10);
|
|
58
58
|
}
|
|
59
59
|
if (height) {
|
|
60
|
-
dim.height = parseInt(height);
|
|
60
|
+
dim.height = parseInt(height, 10);
|
|
61
61
|
}
|
|
62
62
|
alias = "";
|
|
63
63
|
} else {
|
|
@@ -74,7 +74,7 @@ export function parseDimensionFromAlias(
|
|
|
74
74
|
export function parseTransclusion(
|
|
75
75
|
text: string,
|
|
76
76
|
): Transclusion | null {
|
|
77
|
-
let url, alias
|
|
77
|
+
let url, alias ;
|
|
78
78
|
let linktype: LinkType = "markdownlink";
|
|
79
79
|
// TODO: Take in the tree and use tree nodes to get url and alias (Applies to all regex uses)
|
|
80
80
|
mdLinkRegex.lastIndex = 0;
|
package/plug-api/lib/tree.ts
CHANGED
|
@@ -91,7 +91,7 @@ export function replaceNodesMatching(
|
|
|
91
91
|
tree: ParseTree,
|
|
92
92
|
substituteFn: (tree: ParseTree) => ParseTree | null | undefined,
|
|
93
93
|
) {
|
|
94
|
-
if (tree
|
|
94
|
+
if (tree?.children) {
|
|
95
95
|
const children = tree.children.slice();
|
|
96
96
|
for (const child of children) {
|
|
97
97
|
const subst = substituteFn(child);
|
|
@@ -182,7 +182,8 @@ export function nodeAtPos(tree: ParseTree, pos: number): ParseTree | null {
|
|
|
182
182
|
if (n && n.text !== undefined) {
|
|
183
183
|
// Got a text node, let's return its parent
|
|
184
184
|
return tree;
|
|
185
|
-
}
|
|
185
|
+
}
|
|
186
|
+
if (n) {
|
|
186
187
|
// Got it
|
|
187
188
|
return n;
|
|
188
189
|
}
|
|
@@ -190,6 +191,53 @@ export function nodeAtPos(tree: ParseTree, pos: number): ParseTree | null {
|
|
|
190
191
|
return null;
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
// Ensure a TableRow/TableHeader has a TableCell between every pair of
|
|
195
|
+
// TableDelimiters, and optionally pad to match columnCount.
|
|
196
|
+
// headerHasLeadingDelim indicates whether the header starts with a delimiter.
|
|
197
|
+
export function normalizeTableRow(
|
|
198
|
+
row: ParseTree,
|
|
199
|
+
columnCount?: number,
|
|
200
|
+
headerHasLeadingDelim?: boolean,
|
|
201
|
+
): void {
|
|
202
|
+
const children = row.children;
|
|
203
|
+
if (!children) return;
|
|
204
|
+
const normalized: ParseTree[] = [];
|
|
205
|
+
let lookingForCell = false;
|
|
206
|
+
for (const child of children) {
|
|
207
|
+
if (child.type === "TableDelimiter" && lookingForCell) {
|
|
208
|
+
normalized.push({ type: "TableCell", children: [] });
|
|
209
|
+
}
|
|
210
|
+
if (child.type === "TableDelimiter") {
|
|
211
|
+
lookingForCell = true;
|
|
212
|
+
}
|
|
213
|
+
if (child.type === "TableCell") {
|
|
214
|
+
lookingForCell = false;
|
|
215
|
+
}
|
|
216
|
+
normalized.push(child);
|
|
217
|
+
}
|
|
218
|
+
row.children = normalized;
|
|
219
|
+
|
|
220
|
+
// Fix leading-pipe mismatch: row has leading delimiter but header doesn't
|
|
221
|
+
if (headerHasLeadingDelim === false) {
|
|
222
|
+
if (row.children.length > 0 && row.children[0].type === "TableDelimiter") {
|
|
223
|
+
// Insert empty cell after the leading delimiter
|
|
224
|
+
row.children.splice(1, 0, { type: "TableCell", children: [] });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Pad trailing empty cells to match header column count
|
|
229
|
+
if (columnCount !== undefined) {
|
|
230
|
+
let cellCount = 0;
|
|
231
|
+
for (const child of row.children) {
|
|
232
|
+
if (child.type === "TableCell") cellCount++;
|
|
233
|
+
}
|
|
234
|
+
while (cellCount < columnCount) {
|
|
235
|
+
row.children.push({ type: "TableCell", children: [] });
|
|
236
|
+
cellCount++;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
193
241
|
// Turn ParseTree back into text
|
|
194
242
|
export function renderToText(tree?: ParseTree): string {
|
|
195
243
|
if (!tree) {
|
package/plug-api/lib/yaml.ts
CHANGED
|
@@ -44,7 +44,7 @@ function serializeToYamlValue(
|
|
|
44
44
|
return "[]"; // Use flow style for empty arrays for simplicity
|
|
45
45
|
}
|
|
46
46
|
// Determine indentation for list items (base + 2 spaces)
|
|
47
|
-
const itemIndentation = baseIndentation
|
|
47
|
+
const itemIndentation = `${baseIndentation} `;
|
|
48
48
|
// Format each item recursively, preceded by '- ' marker
|
|
49
49
|
return "\n" +
|
|
50
50
|
value.map((item) =>
|
|
@@ -55,7 +55,7 @@ function serializeToYamlValue(
|
|
|
55
55
|
} else if (typeof value === "object" && value !== null) {
|
|
56
56
|
// Basic object serialization (not requested, but good to consider)
|
|
57
57
|
// This is highly simplified and doesn't handle nesting well without more context
|
|
58
|
-
const itemIndentation = baseIndentation
|
|
58
|
+
const itemIndentation = `${baseIndentation} `;
|
|
59
59
|
const entries = Object.entries(value);
|
|
60
60
|
if (entries.length === 0) return "{}"; // Flow style empty objects
|
|
61
61
|
return "\n" +
|
|
@@ -89,7 +89,7 @@ export function applyPatches(
|
|
|
89
89
|
for (let i = 0; i < lines.length; i++) {
|
|
90
90
|
const line = lines[i];
|
|
91
91
|
const trimmedLine = line.trim();
|
|
92
|
-
if (trimmedLine.startsWith(key
|
|
92
|
+
if (trimmedLine.startsWith(`${key}:`)) {
|
|
93
93
|
keyLineIndex = i;
|
|
94
94
|
startDeleteIndex = i;
|
|
95
95
|
endDeleteIndex = i;
|
|
@@ -203,7 +203,7 @@ export function applyPatches(
|
|
|
203
203
|
for (let i = 0; i < lines.length; i++) {
|
|
204
204
|
const line = lines[i];
|
|
205
205
|
const trimmedLine = line.trim();
|
|
206
|
-
if (trimmedLine.startsWith(key
|
|
206
|
+
if (trimmedLine.startsWith(`${key}:`)) {
|
|
207
207
|
keyLineIndex = i;
|
|
208
208
|
// Extract inline comment if present
|
|
209
209
|
const commentMatch = line.match(/#.*$/);
|
|
@@ -214,7 +214,7 @@ export function applyPatches(
|
|
|
214
214
|
for (let j = i - 1; j >= 0; j--) {
|
|
215
215
|
const prevLine = lines[j].trim();
|
|
216
216
|
if (prevLine.startsWith("#")) {
|
|
217
|
-
commentBlock = lines[j]
|
|
217
|
+
commentBlock = `${lines[j]}\n${commentBlock}`;
|
|
218
218
|
} else if (prevLine !== "") {
|
|
219
219
|
break;
|
|
220
220
|
}
|
|
@@ -223,7 +223,7 @@ export function applyPatches(
|
|
|
223
223
|
for (let j = i + 1; j < lines.length; j++) {
|
|
224
224
|
const nextLine = lines[j].trim();
|
|
225
225
|
if (nextLine.startsWith("#")) {
|
|
226
|
-
trailingComments += lines[j]
|
|
226
|
+
trailingComments += `${lines[j]}\n`;
|
|
227
227
|
} else if (nextLine !== "") {
|
|
228
228
|
break;
|
|
229
229
|
}
|
|
@@ -243,7 +243,7 @@ export function applyPatches(
|
|
|
243
243
|
} else {
|
|
244
244
|
// For scalars, format as key: value
|
|
245
245
|
replacementLine = `${key}: ${serializedNewValue}${
|
|
246
|
-
inlineComment ?
|
|
246
|
+
inlineComment ? ` ${inlineComment}` : ""
|
|
247
247
|
}`;
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -267,14 +267,14 @@ export function applyPatches(
|
|
|
267
267
|
];
|
|
268
268
|
|
|
269
269
|
// Join lines and ensure proper newlines
|
|
270
|
-
currentYaml = newContent.join("\n").replace(/\n*$/, "\n")
|
|
270
|
+
currentYaml = `${newContent.join("\n").replace(/\n*$/, "\n")}\n`;
|
|
271
271
|
} else {
|
|
272
272
|
// Key not found: Add the new key-value pair to the end
|
|
273
273
|
const newLineBlock = replacementLine;
|
|
274
274
|
if (currentYaml.trim() === "") {
|
|
275
|
-
currentYaml = newLineBlock
|
|
275
|
+
currentYaml = `${newLineBlock}\n`;
|
|
276
276
|
} else {
|
|
277
|
-
currentYaml = currentYaml.replace(/\n*$/, "\n") + newLineBlock
|
|
277
|
+
currentYaml = `${currentYaml.replace(/\n*$/, "\n") + newLineBlock}\n`;
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
280
|
}
|
|
@@ -249,7 +249,7 @@ export function filterBox(
|
|
|
249
249
|
export function showPanel(
|
|
250
250
|
id: "lhs" | "rhs" | "bhs" | "modal",
|
|
251
251
|
mode: number,
|
|
252
|
-
html: string,
|
|
252
|
+
html: HTMLElement | HTMLElement[] | string,
|
|
253
253
|
script = "",
|
|
254
254
|
): Promise<void> {
|
|
255
255
|
return syscall("editor.showPanel", id, mode, html, script);
|
package/plug-api/system_mock.ts
CHANGED