abelworkflow 1.1.3 → 1.2.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/LICENSE +21 -0
- package/README.md +30 -29
- package/extensions/gpt-responses-compat.ts +213 -0
- package/extensions/k2think-compat.ts +40 -0
- package/lib/cli/args.mjs +5 -19
- package/lib/cli/main.mjs +105 -72
- package/lib/cli/prompts.mjs +9 -2
- package/lib/config/dotenv.mjs +1 -1
- package/lib/config/jsonc.mjs +1 -1
- package/lib/config/store.mjs +197 -45
- package/lib/config/toml.mjs +147 -453
- package/lib/installer/assets.mjs +67 -45
- package/lib/installer/install.mjs +202 -45
- package/lib/installer/links.mjs +124 -101
- package/lib/installer/lock.mjs +82 -0
- package/lib/installer/state.mjs +14 -21
- package/lib/paths.mjs +9 -9
- package/lib/providers/claude.mjs +58 -114
- package/lib/providers/codex.mjs +101 -198
- package/lib/providers/pi.mjs +331 -497
- package/lib/providers/skills.mjs +88 -68
- package/lib/providers/url.mjs +35 -0
- package/lib/templates/workflow/commands/abel-design.md +23 -161
- package/lib/templates/workflow/commands/abel-diagnose.md +30 -56
- package/lib/templates/workflow/commands/abel-implement.md +30 -150
- package/lib/templates/workflow/commands/abel-init.md +1 -1
- package/lib/tools/cli-installer.mjs +29 -190
- package/package.json +7 -9
- package/skills/context7-auto-research/context7-api.cjs +75 -17
- package/skills/dev-browser/SKILL.md +15 -1
- package/skills/dev-browser/dist/scripts/start.d.ts +0 -1
- package/skills/dev-browser/dist/scripts/start.js +8 -36
- package/skills/dev-browser/dist/src/client.d.ts +3 -4
- package/skills/dev-browser/dist/src/client.js +117 -117
- package/skills/dev-browser/dist/src/entrypoint.d.ts +1 -1
- package/skills/dev-browser/dist/src/entrypoint.js +38 -31
- package/skills/dev-browser/dist/src/index.d.ts +0 -1
- package/skills/dev-browser/dist/src/index.js +0 -1
- package/skills/dev-browser/dist/src/page-api.d.ts +0 -1
- package/skills/dev-browser/dist/src/page-api.js +0 -1
- package/skills/dev-browser/dist/src/relay.d.ts +0 -1
- package/skills/dev-browser/dist/src/relay.js +53 -7
- package/skills/dev-browser/dist/src/runtime.d.ts +3 -14
- package/skills/dev-browser/dist/src/runtime.js +5 -15
- package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts +0 -1
- package/skills/dev-browser/dist/src/snapshot/browser-script.js +0 -1
- package/skills/dev-browser/dist/src/snapshot/index.d.ts +0 -1
- package/skills/dev-browser/dist/src/snapshot/index.js +0 -1
- package/skills/dev-browser/dist/src/snapshot/inject.d.ts +0 -1
- package/skills/dev-browser/dist/src/snapshot/inject.js +0 -1
- package/skills/dev-browser/dist/src/standalone.d.ts +0 -1
- package/skills/dev-browser/dist/src/standalone.js +2 -3
- package/skills/dev-browser/dist/src/startup.d.ts +3 -12
- package/skills/dev-browser/dist/src/startup.js +6 -10
- package/skills/dev-browser/dist/src/target-registry.d.ts +0 -1
- package/skills/dev-browser/dist/src/target-registry.js +0 -1
- package/skills/dev-browser/dist/src/types.d.ts +0 -1
- package/skills/dev-browser/dist/src/types.js +0 -1
- package/skills/dev-browser/package-lock.json +1 -1
- package/skills/dev-browser/package.json +2 -2
- package/skills/grok-search/.env.example +1 -1
- package/skills/grok-search/SKILL.md +13 -16
- package/skills/grok-search/scripts/_dotenv.py +1 -1
- package/skills/grok-search/scripts/groksearch_cli.py +271 -195
- package/skills/time/SKILL.md +5 -2
- package/skills/time/scripts/time_cli.py +61 -22
- package/extensions/pi-gpt-responses-compat/index.ts +0 -25
- package/lib/templates/codex/config-base.toml +0 -103
- package/skills/dev-browser/dist/scripts/start.d.ts.map +0 -1
- package/skills/dev-browser/dist/scripts/start.js.map +0 -1
- package/skills/dev-browser/dist/src/client.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/client.js.map +0 -1
- package/skills/dev-browser/dist/src/entrypoint.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/entrypoint.js.map +0 -1
- package/skills/dev-browser/dist/src/index.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/index.js.map +0 -1
- package/skills/dev-browser/dist/src/page-api.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/page-api.js.map +0 -1
- package/skills/dev-browser/dist/src/relay.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/relay.js.map +0 -1
- package/skills/dev-browser/dist/src/runtime.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/runtime.js.map +0 -1
- package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/snapshot/browser-script.js.map +0 -1
- package/skills/dev-browser/dist/src/snapshot/index.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/snapshot/index.js.map +0 -1
- package/skills/dev-browser/dist/src/snapshot/inject.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/snapshot/inject.js.map +0 -1
- package/skills/dev-browser/dist/src/standalone.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/standalone.js.map +0 -1
- package/skills/dev-browser/dist/src/startup.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/startup.js.map +0 -1
- package/skills/dev-browser/dist/src/target-registry.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/target-registry.js.map +0 -1
- package/skills/dev-browser/dist/src/types.d.ts.map +0 -1
- package/skills/dev-browser/dist/src/types.js.map +0 -1
- package/skills/grok-search/gitignore.template +0 -4
- package/skills/grok-search/scripts/groksearch_entry.py +0 -131
package/lib/config/toml.mjs
CHANGED
|
@@ -1,127 +1,31 @@
|
|
|
1
|
-
import { parse
|
|
1
|
+
import { parse } from "smol-toml";
|
|
2
2
|
|
|
3
|
-
function
|
|
4
|
-
return content
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function updateTopLevelTomlField(content, field, value) {
|
|
8
|
-
const lineEnding = detectLineEnding(content);
|
|
9
|
-
if (value === null) {
|
|
10
|
-
return removeTopLevelTomlField(content, field);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const document = parseTomlDocument(content);
|
|
14
|
-
const entry = findTomlAssignment(document.assignments, field, null);
|
|
15
|
-
const nextLine = `${field} = ${JSON.stringify(value)}`;
|
|
16
|
-
|
|
17
|
-
if (entry) {
|
|
18
|
-
return `${content.slice(0, entry.start)}${entry.indent}${nextLine}${content.slice(entry.end)}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const topLevel = content.slice(0, document.topLevelEnd);
|
|
22
|
-
const rest = content.slice(document.topLevelEnd);
|
|
23
|
-
let nextTopLevel = topLevel.trimEnd()
|
|
24
|
-
? `${topLevel.trimEnd()}${lineEnding}${nextLine}`
|
|
25
|
-
: nextLine;
|
|
26
|
-
if (rest && nextTopLevel) {
|
|
27
|
-
nextTopLevel = `${nextTopLevel}${lineEnding}${lineEnding}`;
|
|
28
|
-
}
|
|
29
|
-
return `${nextTopLevel}${rest}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function removeTopLevelTomlField(content, field) {
|
|
33
|
-
const document = parseTomlDocument(content);
|
|
34
|
-
const entry = findTomlAssignment(document.assignments, field, null);
|
|
35
|
-
if (!entry) {
|
|
36
|
-
return content;
|
|
37
|
-
}
|
|
38
|
-
return `${content.slice(0, entry.start)}${content.slice(entry.lineEnd)}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function removeTomlSection(content, sectionName) {
|
|
42
|
-
const section = findTomlSection(parseTomlDocument(content), sectionName);
|
|
43
|
-
if (!section) {
|
|
44
|
-
return content;
|
|
45
|
-
}
|
|
46
|
-
return `${content.slice(0, section.start)}${content.slice(section.end)}`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function removeTomlSectionField(content, sectionName, field) {
|
|
50
|
-
const document = parseTomlDocument(content);
|
|
51
|
-
const section = findTomlSection(document, sectionName);
|
|
52
|
-
const entry = section && findTomlAssignment(document.assignments, field, section);
|
|
53
|
-
return entry
|
|
54
|
-
? `${content.slice(0, entry.start)}${content.slice(entry.lineEnd)}`
|
|
55
|
-
: content;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function buildTomlSection(sectionName, values, lineEnding = "\n") {
|
|
59
|
-
const lines = [`[${sectionName}]`];
|
|
60
|
-
for (const [key, value] of Object.entries(values)) {
|
|
61
|
-
if (value === undefined || value === null || value === "") {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
if (typeof value === "string") {
|
|
65
|
-
lines.push(`${key} = ${JSON.stringify(value)}`);
|
|
66
|
-
} else if (typeof value === "boolean") {
|
|
67
|
-
lines.push(`${key} = ${value ? "true" : "false"}`);
|
|
68
|
-
} else {
|
|
69
|
-
lines.push(`${key} = ${String(value)}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return `${lines.join(lineEnding)}${lineEnding}`;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function formatTomlValue(value) {
|
|
76
|
-
if (typeof value === "string") {
|
|
77
|
-
return JSON.stringify(value);
|
|
78
|
-
}
|
|
79
|
-
if (typeof value === "boolean") {
|
|
80
|
-
return value ? "true" : "false";
|
|
81
|
-
}
|
|
82
|
-
return String(value);
|
|
3
|
+
function parseToml(content) {
|
|
4
|
+
return parse(content, { integersAsBigInt: true });
|
|
83
5
|
}
|
|
84
6
|
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
return /^[A-Za-z0-9_-]+$/u.test(segment) ? segment : JSON.stringify(segment);
|
|
7
|
+
function detectLineEnding(content) {
|
|
8
|
+
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
88
9
|
}
|
|
89
10
|
|
|
90
|
-
function
|
|
11
|
+
function getLines(content) {
|
|
91
12
|
const lines = [];
|
|
92
13
|
for (let start = 0; start < content.length;) {
|
|
93
14
|
const newline = content.indexOf("\n", start);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
start,
|
|
99
|
-
text: content.slice(start)
|
|
100
|
-
});
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const contentEnd = content[newline - 1] === "\r" ? newline - 1 : newline;
|
|
105
|
-
lines.push({
|
|
106
|
-
contentEnd,
|
|
107
|
-
end: newline + 1,
|
|
108
|
-
start,
|
|
109
|
-
text: content.slice(start, contentEnd)
|
|
110
|
-
});
|
|
111
|
-
start = newline + 1;
|
|
15
|
+
const end = newline === -1 ? content.length : newline + 1;
|
|
16
|
+
const contentEnd = newline === -1 ? end : content[newline - 1] === "\r" ? newline - 1 : newline;
|
|
17
|
+
lines.push({ start, end, contentEnd, text: content.slice(start, contentEnd) });
|
|
18
|
+
start = end;
|
|
112
19
|
}
|
|
113
20
|
return lines;
|
|
114
21
|
}
|
|
115
22
|
|
|
116
|
-
function
|
|
117
|
-
while (
|
|
118
|
-
index += 1;
|
|
119
|
-
}
|
|
23
|
+
function skipWhitespace(text, index) {
|
|
24
|
+
while (text[index] === " " || text[index] === "\t") index += 1;
|
|
120
25
|
return index;
|
|
121
26
|
}
|
|
122
27
|
|
|
123
|
-
function
|
|
124
|
-
const escaped = text[index + 1];
|
|
28
|
+
function readBasicEscape(text, index) {
|
|
125
29
|
const simple = {
|
|
126
30
|
'"': '"',
|
|
127
31
|
"\\": "\\",
|
|
@@ -132,32 +36,24 @@ function readTomlBasicEscape(text, index) {
|
|
|
132
36
|
r: "\r",
|
|
133
37
|
t: "\t"
|
|
134
38
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
39
|
+
const escaped = text[index + 1];
|
|
40
|
+
if (escaped in simple) return { index: index + 2, value: simple[escaped] };
|
|
139
41
|
const length = { U: 8, u: 4, x: 2 }[escaped];
|
|
140
42
|
const hex = length ? text.slice(index + 2, index + 2 + length) : "";
|
|
141
|
-
if (!length || hex.length !== length || !/^[0-9A-Fa-f]+$/u.test(hex))
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
43
|
+
if (!length || hex.length !== length || !/^[0-9A-Fa-f]+$/u.test(hex)) return null;
|
|
144
44
|
const codePoint = Number.parseInt(hex, 16);
|
|
145
|
-
if (codePoint > 0x10ffff || (codePoint >= 0xd800 && codePoint <= 0xdfff))
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
45
|
+
if (codePoint > 0x10ffff || (codePoint >= 0xd800 && codePoint <= 0xdfff)) return null;
|
|
148
46
|
return { index: index + 2 + length, value: String.fromCodePoint(codePoint) };
|
|
149
47
|
}
|
|
150
48
|
|
|
151
|
-
function
|
|
49
|
+
function parseKeySegment(text, index) {
|
|
152
50
|
const quote = text[index];
|
|
153
|
-
if (quote ===
|
|
51
|
+
if (quote === '"' || quote === "'") {
|
|
154
52
|
let value = "";
|
|
155
53
|
for (index += 1; index < text.length;) {
|
|
156
|
-
if (text[index] === quote) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (quote === `"` && text[index] === "\\") {
|
|
160
|
-
const escape = readTomlBasicEscape(text, index);
|
|
54
|
+
if (text[index] === quote) return { index: index + 1, value };
|
|
55
|
+
if (quote === '"' && text[index] === "\\") {
|
|
56
|
+
const escape = readBasicEscape(text, index);
|
|
161
57
|
if (!escape) return null;
|
|
162
58
|
value += escape.value;
|
|
163
59
|
index = escape.index;
|
|
@@ -170,108 +66,80 @@ function parseTomlSimpleKey(text, index) {
|
|
|
170
66
|
}
|
|
171
67
|
|
|
172
68
|
const start = index;
|
|
173
|
-
while (
|
|
174
|
-
index += 1;
|
|
175
|
-
}
|
|
69
|
+
while (/[A-Za-z0-9_-]/u.test(text[index] ?? "")) index += 1;
|
|
176
70
|
return index === start ? null : { index, value: text.slice(start, index) };
|
|
177
71
|
}
|
|
178
72
|
|
|
179
|
-
function
|
|
73
|
+
function parseKeyPath(text, index = 0) {
|
|
180
74
|
const path = [];
|
|
181
75
|
while (true) {
|
|
182
|
-
index =
|
|
183
|
-
const
|
|
184
|
-
if (!
|
|
185
|
-
path.push(
|
|
186
|
-
index =
|
|
187
|
-
if (text[index] !== ".") {
|
|
188
|
-
return { index, path };
|
|
189
|
-
}
|
|
76
|
+
index = skipWhitespace(text, index);
|
|
77
|
+
const segment = parseKeySegment(text, index);
|
|
78
|
+
if (!segment) return null;
|
|
79
|
+
path.push(segment.value);
|
|
80
|
+
index = skipWhitespace(text, segment.index);
|
|
81
|
+
if (text[index] !== ".") return { index, path };
|
|
190
82
|
index += 1;
|
|
191
83
|
}
|
|
192
84
|
}
|
|
193
85
|
|
|
194
|
-
function
|
|
195
|
-
let index =
|
|
86
|
+
function parseHeader(text) {
|
|
87
|
+
let index = skipWhitespace(text, 0);
|
|
196
88
|
const arrayTable = text.startsWith("[[", index);
|
|
197
89
|
if (!arrayTable && text[index] !== "[") return null;
|
|
198
90
|
index += arrayTable ? 2 : 1;
|
|
199
|
-
|
|
200
|
-
const key = parseTomlKeyPath(text, index);
|
|
91
|
+
const key = parseKeyPath(text, index);
|
|
201
92
|
if (!key) return null;
|
|
202
|
-
index =
|
|
93
|
+
index = skipWhitespace(text, key.index);
|
|
203
94
|
const close = arrayTable ? "]]" : "]";
|
|
204
95
|
if (!text.startsWith(close, index)) return null;
|
|
205
|
-
index =
|
|
96
|
+
index = skipWhitespace(text, index + close.length);
|
|
206
97
|
if (index !== text.length && text[index] !== "#") return null;
|
|
207
98
|
return { arrayTable, path: key.path };
|
|
208
99
|
}
|
|
209
100
|
|
|
210
|
-
function
|
|
211
|
-
const
|
|
212
|
-
if (text[
|
|
213
|
-
const key =
|
|
101
|
+
function parseAssignmentHead(text) {
|
|
102
|
+
const start = skipWhitespace(text, 0);
|
|
103
|
+
if (text[start] === "#") return null;
|
|
104
|
+
const key = parseKeyPath(text, start);
|
|
214
105
|
if (!key) return null;
|
|
215
|
-
let index =
|
|
106
|
+
let index = skipWhitespace(text, key.index);
|
|
216
107
|
if (text[index] !== "=") return null;
|
|
217
|
-
index =
|
|
218
|
-
return {
|
|
219
|
-
indent: text.slice(0, keyStart),
|
|
220
|
-
path: key.path,
|
|
221
|
-
valueIndex: index
|
|
222
|
-
};
|
|
108
|
+
index = skipWhitespace(text, index + 1);
|
|
109
|
+
return { indent: text.slice(0, start), path: key.path, valueIndex: index };
|
|
223
110
|
}
|
|
224
111
|
|
|
225
|
-
function
|
|
112
|
+
function closeMultilineString(text, state, index, quote) {
|
|
226
113
|
let end = index + 3;
|
|
227
|
-
while (text[end] === quote)
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
if (end - index <= 5) {
|
|
231
|
-
state.mode = "normal";
|
|
232
|
-
}
|
|
114
|
+
while (text[end] === quote) end += 1;
|
|
115
|
+
if (end - index <= 5) state.mode = "normal";
|
|
233
116
|
return end;
|
|
234
117
|
}
|
|
235
118
|
|
|
236
|
-
function
|
|
119
|
+
function scanValueLine(text, start, state) {
|
|
237
120
|
let valueEnd = text.length;
|
|
238
121
|
for (let index = start; index < text.length;) {
|
|
239
122
|
if (state.mode === "multiline-basic") {
|
|
240
|
-
if (text[index] === "\\")
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
index = closeTomlMultilineString(text, state, index, `"`);
|
|
244
|
-
} else {
|
|
245
|
-
index += 1;
|
|
246
|
-
}
|
|
123
|
+
if (text[index] === "\\") index += 2;
|
|
124
|
+
else if (text.startsWith('"""', index)) index = closeMultilineString(text, state, index, '"');
|
|
125
|
+
else index += 1;
|
|
247
126
|
continue;
|
|
248
127
|
}
|
|
249
|
-
|
|
250
128
|
if (state.mode === "multiline-literal") {
|
|
251
|
-
if (text.startsWith(
|
|
252
|
-
|
|
253
|
-
} else {
|
|
254
|
-
index += 1;
|
|
255
|
-
}
|
|
129
|
+
if (text.startsWith("'''", index)) index = closeMultilineString(text, state, index, "'");
|
|
130
|
+
else index += 1;
|
|
256
131
|
continue;
|
|
257
132
|
}
|
|
258
|
-
|
|
259
133
|
if (state.mode === "basic") {
|
|
260
|
-
if (text[index] === "\\")
|
|
261
|
-
|
|
262
|
-
} else if (text[index] === `"`) {
|
|
134
|
+
if (text[index] === "\\") index += 2;
|
|
135
|
+
else if (text[index] === '"') {
|
|
263
136
|
state.mode = "normal";
|
|
264
137
|
index += 1;
|
|
265
|
-
} else
|
|
266
|
-
index += 1;
|
|
267
|
-
}
|
|
138
|
+
} else index += 1;
|
|
268
139
|
continue;
|
|
269
140
|
}
|
|
270
|
-
|
|
271
141
|
if (state.mode === "literal") {
|
|
272
|
-
if (text[index] ===
|
|
273
|
-
state.mode = "normal";
|
|
274
|
-
}
|
|
142
|
+
if (text[index] === "'") state.mode = "normal";
|
|
275
143
|
index += 1;
|
|
276
144
|
continue;
|
|
277
145
|
}
|
|
@@ -280,90 +148,62 @@ function scanTomlValueLine(text, start, state) {
|
|
|
280
148
|
valueEnd = index;
|
|
281
149
|
break;
|
|
282
150
|
}
|
|
283
|
-
if (text.startsWith(
|
|
151
|
+
if (text.startsWith('"""', index)) {
|
|
284
152
|
state.mode = "multiline-basic";
|
|
285
153
|
index += 3;
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
if (text.startsWith(`'''`, index)) {
|
|
154
|
+
} else if (text.startsWith("'''", index)) {
|
|
289
155
|
state.mode = "multiline-literal";
|
|
290
156
|
index += 3;
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
if (text[index] === `"`) {
|
|
157
|
+
} else if (text[index] === '"') {
|
|
294
158
|
state.mode = "basic";
|
|
295
|
-
|
|
159
|
+
index += 1;
|
|
160
|
+
} else if (text[index] === "'") {
|
|
296
161
|
state.mode = "literal";
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
state.arrayDepth -= 1;
|
|
301
|
-
|
|
302
|
-
state.
|
|
303
|
-
|
|
304
|
-
state.inlineTableDepth -= 1;
|
|
162
|
+
index += 1;
|
|
163
|
+
} else {
|
|
164
|
+
if (text[index] === "[") state.arrayDepth += 1;
|
|
165
|
+
else if (text[index] === "]" && state.arrayDepth) state.arrayDepth -= 1;
|
|
166
|
+
else if (text[index] === "{") state.inlineDepth += 1;
|
|
167
|
+
else if (text[index] === "}" && state.inlineDepth) state.inlineDepth -= 1;
|
|
168
|
+
index += 1;
|
|
305
169
|
}
|
|
306
|
-
index += 1;
|
|
307
|
-
}
|
|
308
|
-
while (valueEnd > start && (text[valueEnd - 1] === " " || text[valueEnd - 1] === "\t")) {
|
|
309
|
-
valueEnd -= 1;
|
|
310
170
|
}
|
|
171
|
+
while (valueEnd > start && /[ \t]/u.test(text[valueEnd - 1])) valueEnd -= 1;
|
|
311
172
|
return {
|
|
312
|
-
complete: state.mode === "normal" && state.arrayDepth === 0 && state.
|
|
173
|
+
complete: state.mode === "normal" && state.arrayDepth === 0 && state.inlineDepth === 0,
|
|
313
174
|
invalid: state.mode === "basic" || state.mode === "literal",
|
|
314
175
|
valueEnd
|
|
315
176
|
};
|
|
316
177
|
}
|
|
317
178
|
|
|
318
|
-
function
|
|
319
|
-
|
|
320
|
-
validateToml(content, { integersAsBigInt: true });
|
|
321
|
-
} catch (error) {
|
|
322
|
-
const message = error instanceof Error ? error.message.split(/\r?\n/u, 1)[0] : "Invalid TOML document";
|
|
323
|
-
throw new SyntaxError(message, { cause: error });
|
|
324
|
-
}
|
|
325
|
-
|
|
179
|
+
function parseDocument(content) {
|
|
180
|
+
parseToml(content);
|
|
326
181
|
const assignments = [];
|
|
327
|
-
const lines = getTomlLines(content);
|
|
328
182
|
const sections = [];
|
|
183
|
+
const lines = getLines(content);
|
|
329
184
|
let currentSection = null;
|
|
330
185
|
|
|
331
186
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
332
187
|
const line = lines[lineIndex];
|
|
333
|
-
const header =
|
|
188
|
+
const header = parseHeader(line.text);
|
|
334
189
|
if (header) {
|
|
335
190
|
if (currentSection) currentSection.end = line.start;
|
|
336
|
-
currentSection = {
|
|
337
|
-
...header,
|
|
338
|
-
end: content.length,
|
|
339
|
-
start: line.start
|
|
340
|
-
};
|
|
191
|
+
currentSection = { ...header, start: line.start, end: content.length };
|
|
341
192
|
sections.push(currentSection);
|
|
342
193
|
continue;
|
|
343
194
|
}
|
|
344
|
-
|
|
345
|
-
const head = parseTomlAssignmentHead(line.text);
|
|
195
|
+
const head = parseAssignmentHead(line.text);
|
|
346
196
|
if (!head) continue;
|
|
347
|
-
const state = { arrayDepth: 0,
|
|
348
|
-
let endLineIndex = lineIndex;
|
|
197
|
+
const state = { arrayDepth: 0, inlineDepth: 0, mode: "normal" };
|
|
349
198
|
let scan;
|
|
199
|
+
let endLineIndex = lineIndex;
|
|
350
200
|
for (; endLineIndex < lines.length; endLineIndex += 1) {
|
|
351
|
-
|
|
352
|
-
scan
|
|
353
|
-
valueLine.text,
|
|
354
|
-
endLineIndex === lineIndex ? head.valueIndex : 0,
|
|
355
|
-
state
|
|
356
|
-
);
|
|
357
|
-
if (scan.invalid) {
|
|
358
|
-
throw new SyntaxError(`Incomplete TOML string at offset ${valueLine.start}`);
|
|
359
|
-
}
|
|
201
|
+
scan = scanValueLine(lines[endLineIndex].text, endLineIndex === lineIndex ? head.valueIndex : 0, state);
|
|
202
|
+
if (scan.invalid) throw new SyntaxError(`Incomplete TOML string at offset ${lines[endLineIndex].start}`);
|
|
360
203
|
if (scan.complete) break;
|
|
361
204
|
}
|
|
362
|
-
if (!scan?.complete) {
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
if (endLineIndex >= lines.length) endLineIndex = lines.length - 1;
|
|
366
|
-
const endLine = lines[endLineIndex];
|
|
205
|
+
if (!scan?.complete) throw new SyntaxError(`Incomplete TOML assignment at offset ${line.start}`);
|
|
206
|
+
const endLine = lines[Math.min(endLineIndex, lines.length - 1)];
|
|
367
207
|
assignments.push({
|
|
368
208
|
end: endLine.contentEnd,
|
|
369
209
|
indent: head.indent,
|
|
@@ -376,262 +216,116 @@ function parseTomlDocument(content) {
|
|
|
376
216
|
});
|
|
377
217
|
lineIndex = endLineIndex;
|
|
378
218
|
}
|
|
379
|
-
|
|
380
|
-
return {
|
|
381
|
-
assignments,
|
|
382
|
-
sections,
|
|
383
|
-
topLevelEnd: sections[0]?.start ?? content.length
|
|
384
|
-
};
|
|
219
|
+
return { assignments, sections, topLevelEnd: sections[0]?.start ?? content.length };
|
|
385
220
|
}
|
|
386
221
|
|
|
387
|
-
function
|
|
222
|
+
function samePath(left, right) {
|
|
388
223
|
return left.length === right.length && left.every((part, index) => part === right[index]);
|
|
389
224
|
}
|
|
390
225
|
|
|
391
|
-
function
|
|
392
|
-
const parsed =
|
|
393
|
-
return parsed &&
|
|
226
|
+
function requestedPath(value) {
|
|
227
|
+
const parsed = parseKeyPath(value);
|
|
228
|
+
return parsed && skipWhitespace(value, parsed.index) === value.length ? parsed.path : null;
|
|
394
229
|
}
|
|
395
230
|
|
|
396
|
-
function
|
|
397
|
-
const path =
|
|
398
|
-
return path
|
|
399
|
-
? document.sections.find((section) => !section.arrayTable && sameTomlPath(section.path, path))
|
|
400
|
-
: null;
|
|
231
|
+
function findSection(document, sectionName) {
|
|
232
|
+
const path = requestedPath(sectionName);
|
|
233
|
+
return path ? document.sections.find((section) => !section.arrayTable && samePath(section.path, path)) : null;
|
|
401
234
|
}
|
|
402
235
|
|
|
403
|
-
function
|
|
404
|
-
return assignments.find((entry) =>
|
|
405
|
-
entry.section === section
|
|
406
|
-
&& entry.path.length === 1
|
|
407
|
-
&& entry.path[0] === field
|
|
408
|
-
));
|
|
236
|
+
function findAssignment(assignments, field, section) {
|
|
237
|
+
return assignments.find((entry) => entry.section === section && entry.path.length === 1 && entry.path[0] === field);
|
|
409
238
|
}
|
|
410
239
|
|
|
411
|
-
function
|
|
412
|
-
|
|
413
|
-
return
|
|
414
|
-
|
|
415
|
-
.map((entry) => ({
|
|
416
|
-
field: entry.path[0],
|
|
417
|
-
raw: content.slice(entry.start, entry.end)
|
|
418
|
-
}));
|
|
240
|
+
function formatValue(value) {
|
|
241
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
242
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
243
|
+
throw new TypeError("Managed TOML values must be strings or booleans");
|
|
419
244
|
}
|
|
420
245
|
|
|
421
|
-
function
|
|
422
|
-
|
|
423
|
-
|
|
246
|
+
function formatTomlKeySegment(value) {
|
|
247
|
+
const segment = String(value);
|
|
248
|
+
return /^[A-Za-z0-9_-]+$/u.test(segment) ? segment : JSON.stringify(segment);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function updateTopLevelTomlField(content, field, value) {
|
|
252
|
+
if (value === null) return removeTopLevelTomlField(content, field);
|
|
253
|
+
const document = parseDocument(content);
|
|
254
|
+
const entry = findAssignment(document.assignments, field, null);
|
|
255
|
+
const line = `${field} = ${formatValue(value)}`;
|
|
256
|
+
if (entry) {
|
|
257
|
+
return `${content.slice(0, entry.valueStart)}${formatValue(value)}${content.slice(entry.valueEnd)}`;
|
|
424
258
|
}
|
|
425
259
|
|
|
426
260
|
const lineEnding = detectLineEnding(content);
|
|
427
|
-
const
|
|
428
|
-
const topLevel = content.slice(0, document.topLevelEnd);
|
|
261
|
+
const top = content.slice(0, document.topLevelEnd);
|
|
429
262
|
const rest = content.slice(document.topLevelEnd);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
);
|
|
435
|
-
const missingEntries = entries.filter(({ field }) => !existingFields.has(field));
|
|
436
|
-
if (!missingEntries.length) {
|
|
437
|
-
return content;
|
|
438
|
-
}
|
|
263
|
+
let nextTop = top.trimEnd() ? `${top.trimEnd()}${lineEnding}${line}` : line;
|
|
264
|
+
if (rest) nextTop += `${lineEnding}${lineEnding}`;
|
|
265
|
+
return `${nextTop}${rest}`;
|
|
266
|
+
}
|
|
439
267
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
268
|
+
function removeTopLevelTomlField(content, field) {
|
|
269
|
+
const document = parseDocument(content);
|
|
270
|
+
const entry = findAssignment(document.assignments, field, null);
|
|
271
|
+
return entry ? `${content.slice(0, entry.start)}${content.slice(entry.lineEnd)}` : content;
|
|
272
|
+
}
|
|
446
273
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return `${
|
|
274
|
+
function removeTomlSectionField(content, sectionName, field) {
|
|
275
|
+
const document = parseDocument(content);
|
|
276
|
+
const section = findSection(document, sectionName);
|
|
277
|
+
const entry = section && findAssignment(document.assignments, field, section);
|
|
278
|
+
return entry ? `${content.slice(0, entry.start)}${content.slice(entry.lineEnd)}` : content;
|
|
452
279
|
}
|
|
453
280
|
|
|
454
|
-
function
|
|
455
|
-
let
|
|
456
|
-
for (const
|
|
457
|
-
|
|
281
|
+
function applyEdits(content, edits) {
|
|
282
|
+
let next = content;
|
|
283
|
+
for (const edit of edits.sort((left, right) => right.start - left.start)) {
|
|
284
|
+
next = `${next.slice(0, edit.start)}${edit.text}${next.slice(edit.end)}`;
|
|
458
285
|
}
|
|
459
|
-
return
|
|
286
|
+
return next;
|
|
460
287
|
}
|
|
461
288
|
|
|
462
289
|
function updateTomlSectionFields(content, sectionName, values) {
|
|
463
290
|
const lineEnding = detectLineEnding(content);
|
|
464
|
-
const document =
|
|
465
|
-
const section =
|
|
466
|
-
|
|
291
|
+
const document = parseDocument(content);
|
|
292
|
+
const section = findSection(document, sectionName);
|
|
293
|
+
const entries = Object.entries(values).filter(([, value]) => value !== undefined && value !== null && value !== "");
|
|
467
294
|
if (!section) {
|
|
468
|
-
const
|
|
295
|
+
const lines = [`[${sectionName}]`, ...entries.map(([field, value]) => `${field} = ${formatValue(value)}`)];
|
|
296
|
+
const block = lines.join(lineEnding);
|
|
469
297
|
return content.trimEnd()
|
|
470
|
-
? `${content.trimEnd()}${lineEnding}${lineEnding}${
|
|
471
|
-
: `${
|
|
298
|
+
? `${content.trimEnd()}${lineEnding}${lineEnding}${block}${lineEnding}`
|
|
299
|
+
: `${block}${lineEnding}`;
|
|
472
300
|
}
|
|
473
301
|
|
|
474
|
-
const remaining = new Map(
|
|
475
|
-
Object.entries(values).filter(([, value]) => value !== undefined && value !== null && value !== "")
|
|
476
|
-
);
|
|
477
|
-
const managedFields = new Set(remaining.keys());
|
|
478
|
-
const seenFields = new Set();
|
|
302
|
+
const remaining = new Map(entries);
|
|
479
303
|
const edits = [];
|
|
480
|
-
|
|
481
304
|
for (const entry of document.assignments) {
|
|
482
|
-
if (
|
|
483
|
-
entry.section !== section
|
|
484
|
-
|| entry.path.length !== 1
|
|
485
|
-
|| !managedFields.has(entry.path[0])
|
|
486
|
-
) continue;
|
|
305
|
+
if (entry.section !== section || entry.path.length !== 1 || !remaining.has(entry.path[0])) continue;
|
|
487
306
|
const field = entry.path[0];
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
text: `${entry.indent}${field} = ${formatTomlValue(remaining.get(field))}`
|
|
495
|
-
});
|
|
496
|
-
seenFields.add(field);
|
|
497
|
-
remaining.delete(field);
|
|
498
|
-
}
|
|
307
|
+
edits.push({
|
|
308
|
+
start: entry.valueStart,
|
|
309
|
+
end: entry.valueEnd,
|
|
310
|
+
text: formatValue(remaining.get(field))
|
|
311
|
+
});
|
|
312
|
+
remaining.delete(field);
|
|
499
313
|
}
|
|
500
|
-
|
|
501
314
|
if (remaining.size) {
|
|
502
|
-
const leading = section.end
|
|
503
|
-
const lines = [...remaining].map(([field, value]) => `${field} = ${formatTomlValue(value)}`);
|
|
315
|
+
const leading = section.end && content[section.end - 1] !== "\n" ? lineEnding : "";
|
|
504
316
|
edits.push({
|
|
505
|
-
end: section.end,
|
|
506
317
|
start: section.end,
|
|
507
|
-
|
|
318
|
+
end: section.end,
|
|
319
|
+
text: `${leading}${[...remaining].map(([field, value]) => `${field} = ${formatValue(value)}`).join(lineEnding)}${lineEnding}`
|
|
508
320
|
});
|
|
509
321
|
}
|
|
510
|
-
return
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
function parseTomlBasicString(value) {
|
|
514
|
-
if (value[0] !== `"` || value.startsWith(`"""`)) return null;
|
|
515
|
-
let parsed = "";
|
|
516
|
-
for (let index = 1; index < value.length;) {
|
|
517
|
-
if (value[index] === `"`) {
|
|
518
|
-
return index === value.length - 1 ? parsed : null;
|
|
519
|
-
}
|
|
520
|
-
if (value[index] === "\\") {
|
|
521
|
-
const escape = readTomlBasicEscape(value, index);
|
|
522
|
-
if (!escape) return null;
|
|
523
|
-
parsed += escape.value;
|
|
524
|
-
index = escape.index;
|
|
525
|
-
} else {
|
|
526
|
-
parsed += value[index];
|
|
527
|
-
index += 1;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
return null;
|
|
322
|
+
return applyEdits(content, edits);
|
|
531
323
|
}
|
|
532
324
|
|
|
533
|
-
function parseTomlMultilineString(value, quote) {
|
|
534
|
-
const delimiter = quote.repeat(3);
|
|
535
|
-
if (!value.startsWith(delimiter)) return null;
|
|
536
|
-
let content = value.slice(3).replace(/\r\n/gu, "\n");
|
|
537
|
-
if (content.startsWith("\n")) content = content.slice(1);
|
|
538
|
-
|
|
539
|
-
let parsed = "";
|
|
540
|
-
for (let index = 0; index < content.length;) {
|
|
541
|
-
if (content.startsWith(delimiter, index)) {
|
|
542
|
-
let end = index + 3;
|
|
543
|
-
while (content[end] === quote) end += 1;
|
|
544
|
-
const quoteCount = end - index;
|
|
545
|
-
return quoteCount <= 5 && end === content.length
|
|
546
|
-
? `${parsed}${quote.repeat(quoteCount - 3)}`
|
|
547
|
-
: null;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
if (quote === `'` || content[index] !== "\\") {
|
|
551
|
-
parsed += content[index];
|
|
552
|
-
index += 1;
|
|
553
|
-
continue;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
let continuation = index + 1;
|
|
557
|
-
while (content[continuation] === " " || content[continuation] === "\t") {
|
|
558
|
-
continuation += 1;
|
|
559
|
-
}
|
|
560
|
-
if (content[continuation] === "\n") {
|
|
561
|
-
index = continuation + 1;
|
|
562
|
-
while (content[index] === " " || content[index] === "\t" || content[index] === "\n") {
|
|
563
|
-
index += 1;
|
|
564
|
-
}
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
const escape = readTomlBasicEscape(content, index);
|
|
569
|
-
if (!escape) return null;
|
|
570
|
-
parsed += escape.value;
|
|
571
|
-
index = escape.index;
|
|
572
|
-
}
|
|
573
|
-
return parsed;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
function parseTomlScalar(rawValue) {
|
|
577
|
-
const multilineBasic = parseTomlMultilineString(rawValue, `"`);
|
|
578
|
-
if (multilineBasic !== null) return { parsed: true, value: multilineBasic };
|
|
579
|
-
const multilineLiteral = parseTomlMultilineString(rawValue, `'`);
|
|
580
|
-
if (multilineLiteral !== null) return { parsed: true, value: multilineLiteral };
|
|
581
|
-
const value = rawValue.trim();
|
|
582
|
-
const basicString = parseTomlBasicString(value);
|
|
583
|
-
if (basicString !== null) return { parsed: true, value: basicString };
|
|
584
|
-
if (/^'[^']*'$/u.test(value)) return { parsed: true, value: value.slice(1, -1) };
|
|
585
|
-
if (value === "true" || value === "false") {
|
|
586
|
-
return { parsed: true, value: value === "true" };
|
|
587
|
-
}
|
|
588
|
-
if (/^-?\d+(?:\.\d+)?$/u.test(value)) {
|
|
589
|
-
return { parsed: true, value: Number(value) };
|
|
590
|
-
}
|
|
591
|
-
return { parsed: false, value: undefined };
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
function readTopLevelTomlString(content, field) {
|
|
595
|
-
const document = parseTomlDocument(content);
|
|
596
|
-
const entry = findTomlAssignment(document.assignments, field, null);
|
|
597
|
-
if (!entry) return "";
|
|
598
|
-
const value = parseTomlScalar(content.slice(entry.valueStart, entry.valueEnd));
|
|
599
|
-
return value.parsed && typeof value.value === "string" ? value.value : "";
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
function parseTomlSection(content, sectionName) {
|
|
603
|
-
const document = parseTomlDocument(content);
|
|
604
|
-
const section = findTomlSection(document, sectionName);
|
|
605
|
-
if (!section) return {};
|
|
606
|
-
const values = {};
|
|
607
|
-
for (const entry of document.assignments) {
|
|
608
|
-
if (entry.section !== section || entry.path.length !== 1) continue;
|
|
609
|
-
const value = parseTomlScalar(content.slice(entry.valueStart, entry.valueEnd));
|
|
610
|
-
if (value.parsed) values[entry.path[0]] = value.value;
|
|
611
|
-
}
|
|
612
|
-
return values;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
function getTomlSectionFieldNames(content, sectionName) {
|
|
616
|
-
const document = parseTomlDocument(content);
|
|
617
|
-
const section = findTomlSection(document, sectionName);
|
|
618
|
-
if (!section) return [];
|
|
619
|
-
return document.assignments
|
|
620
|
-
.filter((entry) => entry.section === section && entry.path.length === 1)
|
|
621
|
-
.map((entry) => entry.path[0]);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
|
|
625
325
|
export {
|
|
626
|
-
buildTomlSection,
|
|
627
326
|
detectLineEnding,
|
|
628
|
-
extractTopLevelTomlEntries,
|
|
629
327
|
formatTomlKeySegment,
|
|
630
|
-
|
|
631
|
-
mergeMissingTopLevelTomlEntries,
|
|
632
|
-
parseTomlSection,
|
|
633
|
-
readTopLevelTomlString,
|
|
634
|
-
removeTomlSection,
|
|
328
|
+
parseToml,
|
|
635
329
|
removeTomlSectionField,
|
|
636
330
|
removeTopLevelTomlField,
|
|
637
331
|
updateTomlSectionFields,
|