@wrongstack/tools 0.313.0 → 0.316.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/dist/_edit-match.d.ts +3 -2
- package/dist/_output-spool.d.ts +4 -3
- package/dist/_shell-pick.d.ts +2 -1
- package/dist/_spawn-stream.d.ts +2 -1
- package/dist/_syntax-check.d.ts +2 -1
- package/dist/audit.js +10 -4055
- package/dist/bash-kill-guard.d.ts +3 -6
- package/dist/bash.js +9 -2308
- package/dist/batch-tool-use.js +2 -187
- package/dist/browser/index.js +25 -1339
- package/dist/browser/network-guard-proxy.d.ts +2 -1
- package/dist/builtin.js +69 -33949
- package/dist/chunk-22B7GE5T.js +260 -0
- package/dist/chunk-2VSZC6QM.js +113 -0
- package/dist/chunk-3PVYQFRQ.js +472 -0
- package/dist/chunk-42BHI7TN.js +337 -0
- package/dist/chunk-4BHUSMNL.js +104 -0
- package/dist/chunk-4I4LWFOO.js +431 -0
- package/dist/chunk-4UESMQDP.js +122 -0
- package/dist/chunk-553IQUMO.js +478 -0
- package/dist/chunk-5H4GSJAI.js +223 -0
- package/dist/chunk-6RNIFLG4.js +305 -0
- package/dist/chunk-7EY5DCRO.js +434 -0
- package/dist/chunk-A6BRWIXN.js +317 -0
- package/dist/chunk-AHHDWNXC.js +200 -0
- package/dist/chunk-BSLVR56S.js +199 -0
- package/dist/chunk-BTSFTGIL.js +7 -0
- package/dist/chunk-D33S4RQG.js +222 -0
- package/dist/chunk-DA4KNE2H.js +4412 -0
- package/dist/chunk-DR7JOQTC.js +520 -0
- package/dist/chunk-EEOFQDT6.js +898 -0
- package/dist/chunk-EJWSCQ6D.js +137 -0
- package/dist/chunk-EMRGN4KM.js +170 -0
- package/dist/chunk-FQZOHLG3.js +89 -0
- package/dist/chunk-GOIZNNOA.js +221 -0
- package/dist/chunk-HFXSNKCV.js +196 -0
- package/dist/chunk-HYX2TZ7O.js +1272 -0
- package/dist/chunk-I64BS3VC.js +15 -0
- package/dist/chunk-IVWV2UM6.js +955 -0
- package/dist/chunk-IXMNTNW5.js +238 -0
- package/dist/chunk-IYK7XGDZ.js +892 -0
- package/dist/chunk-J5SKD6LN.js +235 -0
- package/dist/chunk-JNNVRHMV.js +2111 -0
- package/dist/chunk-JOHXDF3D.js +295 -0
- package/dist/chunk-JRJJX3L5.js +424 -0
- package/dist/chunk-K3WNSHUF.js +1371 -0
- package/dist/chunk-L25CVUVR.js +2830 -0
- package/dist/chunk-LIJQMYYX.js +59 -0
- package/dist/chunk-LWKUTMD5.js +197 -0
- package/dist/chunk-MQX2KXVW.js +54 -0
- package/dist/chunk-MZZN7VCD.js +359 -0
- package/dist/chunk-NBDZMMG2.js +169 -0
- package/dist/chunk-NKJW5GFO.js +366 -0
- package/dist/chunk-NKNOBUBU.js +522 -0
- package/dist/chunk-O4MBV4AX.js +134 -0
- package/dist/chunk-OUBDL3WH.js +3515 -0
- package/dist/chunk-PQKK5JH7.js +101 -0
- package/dist/chunk-PY2IOS7C.js +1000 -0
- package/dist/chunk-Q5JPPCZC.js +12 -0
- package/dist/chunk-QBV725YG.js +128 -0
- package/dist/chunk-QZQSPUBF.js +315 -0
- package/dist/chunk-RGISBZBD.js +231 -0
- package/dist/chunk-RJZQWEMS.js +84 -0
- package/dist/chunk-RXISBFR5.js +315 -0
- package/dist/chunk-S5CCLZL3.js +99 -0
- package/dist/chunk-SDLVH5RZ.js +178 -0
- package/dist/chunk-T2F4S7U4.js +1723 -0
- package/dist/chunk-TEBQ4VPZ.js +163 -0
- package/dist/chunk-U4D5S3VQ.js +21 -0
- package/dist/chunk-U4VAATKP.js +193 -0
- package/dist/chunk-UCYQTZ7F.js +113 -0
- package/dist/chunk-UKU2ZX4C.js +203 -0
- package/dist/chunk-UNSKG6DC.js +159 -0
- package/dist/chunk-V43EQ6VR.js +68 -0
- package/dist/chunk-VB3MJGCV.js +610 -0
- package/dist/chunk-VFKPWSOX.js +154 -0
- package/dist/chunk-VJNHFZ7J.js +190 -0
- package/dist/chunk-VXECAJJ7.js +1091 -0
- package/dist/chunk-WHIIIREL.js +223 -0
- package/dist/chunk-Z6DAKQ3U.js +1 -0
- package/dist/chunk-ZJQ4IGXK.js +474 -0
- package/dist/chunk-ZLTFLC25.js +385 -0
- package/dist/circuit-breaker.js +3 -191
- package/dist/codebase-index/ast-invariant-engine.d.ts +5 -4
- package/dist/codebase-index/binary-frame.d.ts +0 -2
- package/dist/codebase-index/bm25.d.ts +1 -1
- package/dist/codebase-index/circuit-breaker.d.ts +2 -1
- package/dist/codebase-index/codebase-ast-replace-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +4 -3
- package/dist/codebase-index/codebase-invariant-check-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-repo-map-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-skeleton-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-targeted-test-tool.d.ts +3 -2
- package/dist/codebase-index/content-hash.d.ts +0 -2
- package/dist/codebase-index/import-extractor.d.ts +0 -13
- package/dist/codebase-index/index-service.d.ts +1 -1
- package/dist/codebase-index/index.js +84 -13688
- package/dist/codebase-index/languages.d.ts +2 -1
- package/dist/codebase-index/module-roots.d.ts +3 -2
- package/dist/codebase-index/parser-batch.d.ts +0 -5
- package/dist/codebase-index/parser-dispatch.d.ts +2 -1
- package/dist/codebase-index/parser-output.d.ts +4 -3
- package/dist/codebase-index/parser-worker-pool.d.ts +0 -2
- package/dist/codebase-index/parser-worker-script.d.ts +1 -16
- package/dist/codebase-index/parser-worker-script.js +8 -3995
- package/dist/codebase-index/project-server-client-state.d.ts +2 -2
- package/dist/codebase-index/project-server-endpoint.d.ts +0 -15
- package/dist/codebase-index/project-server.js +60 -8548
- package/dist/codebase-index/tree-sitter/visitor.d.ts +2 -1
- package/dist/codebase-index/tree-sitter-parser.d.ts +0 -2
- package/dist/codebase-index/ts-parser.d.ts +1 -1
- package/dist/codebase-index/vector-search.d.ts +2 -1
- package/dist/codebase-index/wal-maintenance.d.ts +3 -2
- package/dist/codebase-index/worker.js +20 -8416
- package/dist/codebase-index/writer-admin.d.ts +0 -1
- package/dist/codebase-index/writer-search.d.ts +0 -9
- package/dist/design.js +2 -299
- package/dist/diff.js +4 -256
- package/dist/document.js +4 -222
- package/dist/e2e.js +5 -476
- package/dist/edit.js +14 -10200
- package/dist/exec.js +16 -3131
- package/dist/fetch.js +8 -398
- package/dist/format.js +10 -3750
- package/dist/generic-parser-VUXDIAOZ.js +13 -0
- package/dist/git.js +4 -380
- package/dist/glob.js +6 -280
- package/dist/go-parser-JXYKJHRC.js +469 -0
- package/dist/grep.js +7 -604
- package/dist/index.js +318 -35387
- package/dist/install.js +10 -4091
- package/dist/json-parser-IBHZ4BZC.js +213 -0
- package/dist/json.js +4 -665
- package/dist/kanban-contract-actions.d.ts +1 -1
- package/dist/kanban-detail-actions.d.ts +2 -1
- package/dist/kanban-presence.d.ts +2 -1
- package/dist/kanban-serializer.d.ts +0 -8
- package/dist/kanban-split-task-handler.d.ts +2 -2
- package/dist/kanban-tool-types.d.ts +2 -1
- package/dist/kanban.js +3 -2096
- package/dist/languages/diagnostics.d.ts +2 -1
- package/dist/languages/index.js +23 -4664
- package/dist/languages/legacy-bridge.d.ts +3 -2
- package/dist/languages/types.d.ts +2 -1
- package/dist/legacy-bridge-7M6QLUQN.js +18 -0
- package/dist/lint.js +10 -3706
- package/dist/logs.js +4 -287
- package/dist/memory.js +6 -215
- package/dist/mode.js +3 -99
- package/dist/outdated.js +4 -5170
- package/dist/pack.js +65 -33897
- package/dist/parser-dispatch-QH4XPGG6.js +14 -0
- package/dist/patch.js +13 -9935
- package/dist/plan.js +5 -3286
- package/dist/process-registry.js +8 -651
- package/dist/ps-slash.js +12 -1439
- package/dist/pwsh.d.ts +0 -1
- package/dist/py-parser-IS4HKYMF.js +16 -0
- package/dist/read.js +13 -9816
- package/dist/replace.js +15 -10014
- package/dist/rs-parser-XHUUO2KZ.js +81 -0
- package/dist/scaffold.js +4 -253
- package/dist/search.js +5 -585
- package/dist/session-kanban-sync.d.ts +0 -6
- package/dist/session-kanban.js +30 -972
- package/dist/skill.js +2 -215
- package/dist/spawn-background.d.ts +1 -1
- package/dist/task.js +5 -3410
- package/dist/test.js +10 -3773
- package/dist/todo.js +4 -2891
- package/dist/tool-help.js +3 -123
- package/dist/tool-search.js +3 -79
- package/dist/tool-tier.js +68 -33984
- package/dist/tool-use.js +2 -93
- package/dist/tree-sitter-parser-AIERW3YI.js +15 -0
- package/dist/tree.js +4 -288
- package/dist/ts-parser-RCTYKSVI.js +232 -0
- package/dist/typecheck.js +10 -3753
- package/dist/win32.js +6 -60
- package/dist/write.js +14 -9882
- package/dist/yaml-parser-4SAXV3PL.js +157 -0
- package/package.json +5 -5
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
import {
|
|
2
|
+
capSubject,
|
|
3
|
+
compileUserRegex
|
|
4
|
+
} from "./chunk-Q5JPPCZC.js";
|
|
5
|
+
import {
|
|
6
|
+
safeResolveReal
|
|
7
|
+
} from "./chunk-D33S4RQG.js";
|
|
8
|
+
|
|
9
|
+
// src/json.ts
|
|
10
|
+
import * as fs from "node:fs/promises";
|
|
11
|
+
import { deepMerge as deepMergeCore } from "@wrongstack/core/utils";
|
|
12
|
+
var MAX_JSON_FILE_BYTES = 16 * 1024 * 1024;
|
|
13
|
+
var MAX_JSON_FILE_BYTES_HUMAN = "16 MiB";
|
|
14
|
+
var JsonFileTooLargeError = class extends Error {
|
|
15
|
+
constructor(filePath, size) {
|
|
16
|
+
super(
|
|
17
|
+
`json: "${filePath}" is ${size} bytes \u2014 exceeds the ${MAX_JSON_FILE_BYTES_HUMAN} file-size limit. Extract the relevant portion into a smaller file first, or use a shell tool to query it directly.`
|
|
18
|
+
);
|
|
19
|
+
this.name = "JsonFileTooLargeError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
async function readJsonFileBounded(filePath, ctx) {
|
|
23
|
+
const resolved = await safeResolveReal(filePath, ctx);
|
|
24
|
+
const stat2 = await fs.stat(resolved);
|
|
25
|
+
if (stat2.size > MAX_JSON_FILE_BYTES) {
|
|
26
|
+
throw new JsonFileTooLargeError(filePath, stat2.size);
|
|
27
|
+
}
|
|
28
|
+
return fs.readFile(resolved, "utf8");
|
|
29
|
+
}
|
|
30
|
+
var jsonTool = {
|
|
31
|
+
name: "json",
|
|
32
|
+
category: "Data",
|
|
33
|
+
description: "Parse, pretty-print, query, validate, transform, and merge JSON/JSON5/YAML. Use `action` to select the operation: parse (default), query, validate, transform, or merge.",
|
|
34
|
+
usageHint: 'VERY USEFUL FOR DATA INSPECTION:\n\n- `action: "parse"` (default): read/pretty-print/convert JSON, JSON5, or YAML from `file` or `data`.\n- `action: "query"`: JMESPath-like query (`a.b[0].c`, `items[*].name`, filters, functions).\n- `action: "validate"`: validate data against a JSON Schema (`schema` param).\n- `action: "transform"`: chain multiple JMESPath transforms (`transforms` param).\n- `action: "merge"`: deep merge `base` and `patch` objects (`conflictResolution` param).\nPrefer this over raw `read` + manual parsing when dealing with configuration or data files.',
|
|
35
|
+
permission: "auto",
|
|
36
|
+
mutating: false,
|
|
37
|
+
maxOutputBytes: 262144,
|
|
38
|
+
timeoutMs: 5e3,
|
|
39
|
+
capabilities: ["fs.read"],
|
|
40
|
+
icon: "json",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
action: {
|
|
45
|
+
type: "string",
|
|
46
|
+
enum: ["parse", "query", "validate", "transform", "merge"],
|
|
47
|
+
description: "Operation (default: parse). parse=read/pretty-print, query=JMESPath, validate=schema, transform=chained queries, merge=deep merge."
|
|
48
|
+
},
|
|
49
|
+
file: { type: "string", description: "Path to JSON/JSON5/YAML file (parse/query/validate)" },
|
|
50
|
+
data: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "JSON/JSON5/YAML string (parse/query/validate, alternative to file)"
|
|
53
|
+
},
|
|
54
|
+
format: {
|
|
55
|
+
type: "string",
|
|
56
|
+
enum: ["json", "json5", "yaml"],
|
|
57
|
+
description: "Output format for parse/query/transform (default: json)"
|
|
58
|
+
},
|
|
59
|
+
query: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "JMESPath-like query expression (query action)"
|
|
62
|
+
},
|
|
63
|
+
transforms: {
|
|
64
|
+
type: "array",
|
|
65
|
+
items: { type: "string" },
|
|
66
|
+
description: "Ordered JMESPath query strings (transform action)"
|
|
67
|
+
},
|
|
68
|
+
schema: {
|
|
69
|
+
type: "object",
|
|
70
|
+
description: "JSON Schema to validate against (validate action)"
|
|
71
|
+
},
|
|
72
|
+
base: { description: "Base JSON object (merge action)" },
|
|
73
|
+
patch: { description: "Patch JSON object to merge in (merge action)" },
|
|
74
|
+
conflictResolution: {
|
|
75
|
+
type: "string",
|
|
76
|
+
enum: ["prefer-base", "prefer-patch"],
|
|
77
|
+
description: "Merge conflict resolution (default: prefer-patch)"
|
|
78
|
+
},
|
|
79
|
+
validate: {
|
|
80
|
+
type: "boolean",
|
|
81
|
+
description: "Validate syntax only, no output (parse action, default: false)"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
async execute(input, ctx) {
|
|
86
|
+
const action = input.action ?? "parse";
|
|
87
|
+
switch (action) {
|
|
88
|
+
case "query":
|
|
89
|
+
return executeQuery(input, ctx);
|
|
90
|
+
case "validate":
|
|
91
|
+
return executeValidate(input, ctx);
|
|
92
|
+
case "transform":
|
|
93
|
+
return executeTransform(input, ctx);
|
|
94
|
+
case "merge":
|
|
95
|
+
return executeMerge(input);
|
|
96
|
+
default:
|
|
97
|
+
return executeParse(input, ctx);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
async function executeParse(input, ctx) {
|
|
102
|
+
const format = input.format ?? "json";
|
|
103
|
+
let parsed;
|
|
104
|
+
let raw;
|
|
105
|
+
if (input.file) {
|
|
106
|
+
try {
|
|
107
|
+
raw = await readJsonFileBounded(input.file, ctx);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
return {
|
|
110
|
+
data: null,
|
|
111
|
+
formatted: "",
|
|
112
|
+
type: "unknown",
|
|
113
|
+
action: "parse",
|
|
114
|
+
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read file"
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
} else if (input.data) {
|
|
118
|
+
raw = input.data;
|
|
119
|
+
} else {
|
|
120
|
+
return {
|
|
121
|
+
data: null,
|
|
122
|
+
formatted: "",
|
|
123
|
+
type: "unknown",
|
|
124
|
+
action: "parse",
|
|
125
|
+
error: "Provide file or data"
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
parsed = JSON.parse(raw);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
return {
|
|
132
|
+
data: null,
|
|
133
|
+
formatted: "",
|
|
134
|
+
type: "unknown",
|
|
135
|
+
action: "parse",
|
|
136
|
+
/* v8 ignore next -- JSON.parse only throws SyntaxError (an Error); the String(e) side is defensive. */
|
|
137
|
+
error: `Parse failed: ${e instanceof Error ? e.message : String(e)}`
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (input.validate) {
|
|
141
|
+
return {
|
|
142
|
+
data: parsed,
|
|
143
|
+
formatted: "valid",
|
|
144
|
+
type: Array.isArray(parsed) ? "array" : typeof parsed,
|
|
145
|
+
action: "parse",
|
|
146
|
+
keys: typeof parsed === "object" && parsed !== null ? Object.keys(parsed) : void 0
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (input.query) {
|
|
150
|
+
const queryResult = simpleQuery(parsed, input.query);
|
|
151
|
+
const formatted2 = formatOutput(queryResult, format);
|
|
152
|
+
return {
|
|
153
|
+
data: parsed,
|
|
154
|
+
formatted: formatted2,
|
|
155
|
+
type: Array.isArray(parsed) ? "array" : typeof parsed,
|
|
156
|
+
action: "parse",
|
|
157
|
+
keys: typeof parsed === "object" && parsed !== null ? Object.keys(parsed) : void 0,
|
|
158
|
+
query_result: queryResult
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const formatted = formatOutput(parsed, format);
|
|
162
|
+
return {
|
|
163
|
+
data: parsed,
|
|
164
|
+
formatted,
|
|
165
|
+
type: Array.isArray(parsed) ? "array" : typeof parsed,
|
|
166
|
+
action: "parse",
|
|
167
|
+
keys: typeof parsed === "object" && parsed !== null ? Object.keys(parsed) : void 0
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async function executeQuery(input, ctx) {
|
|
171
|
+
if (!input.query) {
|
|
172
|
+
return {
|
|
173
|
+
data: null,
|
|
174
|
+
formatted: "",
|
|
175
|
+
type: "unknown",
|
|
176
|
+
action: "query",
|
|
177
|
+
error: "query is required for action: query"
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
let parsed;
|
|
181
|
+
if (input.file) {
|
|
182
|
+
try {
|
|
183
|
+
const raw = await readJsonFileBounded(input.file, ctx);
|
|
184
|
+
parsed = JSON.parse(raw);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
return {
|
|
187
|
+
data: null,
|
|
188
|
+
formatted: "",
|
|
189
|
+
type: "unknown",
|
|
190
|
+
action: "query",
|
|
191
|
+
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read/parse file"
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
} else if (input.data) {
|
|
195
|
+
try {
|
|
196
|
+
parsed = JSON.parse(input.data);
|
|
197
|
+
} catch {
|
|
198
|
+
return {
|
|
199
|
+
data: null,
|
|
200
|
+
formatted: "",
|
|
201
|
+
type: "unknown",
|
|
202
|
+
action: "query",
|
|
203
|
+
error: "Could not parse data string"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
return {
|
|
208
|
+
data: null,
|
|
209
|
+
formatted: "",
|
|
210
|
+
type: "unknown",
|
|
211
|
+
action: "query",
|
|
212
|
+
error: "Provide file or data"
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const result = jmespathSearch(parsed, input.query);
|
|
217
|
+
const format = input.format ?? "json";
|
|
218
|
+
return {
|
|
219
|
+
data: parsed,
|
|
220
|
+
formatted: formatOutput(result, format),
|
|
221
|
+
type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result,
|
|
222
|
+
action: "query",
|
|
223
|
+
query_result: result
|
|
224
|
+
};
|
|
225
|
+
} catch (e) {
|
|
226
|
+
return {
|
|
227
|
+
data: null,
|
|
228
|
+
formatted: "",
|
|
229
|
+
type: "unknown",
|
|
230
|
+
action: "query",
|
|
231
|
+
/* v8 ignore next -- defensive String(e) */
|
|
232
|
+
error: `Query failed: ${e instanceof Error ? e.message : String(e)}`
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async function executeValidate(input, ctx) {
|
|
237
|
+
if (!input.schema) {
|
|
238
|
+
return {
|
|
239
|
+
data: null,
|
|
240
|
+
formatted: "",
|
|
241
|
+
type: "unknown",
|
|
242
|
+
action: "validate",
|
|
243
|
+
error: "schema is required for action: validate"
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
let parsed;
|
|
247
|
+
if (input.file) {
|
|
248
|
+
try {
|
|
249
|
+
const raw = await readJsonFileBounded(input.file, ctx);
|
|
250
|
+
parsed = JSON.parse(raw);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
return {
|
|
253
|
+
data: null,
|
|
254
|
+
formatted: "",
|
|
255
|
+
type: "unknown",
|
|
256
|
+
action: "validate",
|
|
257
|
+
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read/parse file"
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
} else if (input.data) {
|
|
261
|
+
try {
|
|
262
|
+
parsed = JSON.parse(input.data);
|
|
263
|
+
} catch {
|
|
264
|
+
return {
|
|
265
|
+
data: null,
|
|
266
|
+
formatted: "",
|
|
267
|
+
type: "unknown",
|
|
268
|
+
action: "validate",
|
|
269
|
+
error: "Could not parse data string"
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
return {
|
|
274
|
+
data: null,
|
|
275
|
+
formatted: "",
|
|
276
|
+
type: "unknown",
|
|
277
|
+
action: "validate",
|
|
278
|
+
error: "Provide file or data"
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
const { valid, errors } = validateJsonSchema(parsed, input.schema);
|
|
283
|
+
return {
|
|
284
|
+
data: parsed,
|
|
285
|
+
formatted: valid ? "valid" : "invalid",
|
|
286
|
+
type: Array.isArray(parsed) ? "array" : typeof parsed,
|
|
287
|
+
action: "validate",
|
|
288
|
+
valid,
|
|
289
|
+
errors
|
|
290
|
+
};
|
|
291
|
+
} catch (e) {
|
|
292
|
+
return {
|
|
293
|
+
data: null,
|
|
294
|
+
formatted: "",
|
|
295
|
+
type: "unknown",
|
|
296
|
+
action: "validate",
|
|
297
|
+
/* v8 ignore next -- defensive String(e) */
|
|
298
|
+
error: `Validation failed: ${e instanceof Error ? e.message : String(e)}`
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function executeTransform(input, ctx) {
|
|
303
|
+
if (!input.transforms || input.transforms.length === 0) {
|
|
304
|
+
return {
|
|
305
|
+
data: null,
|
|
306
|
+
formatted: "",
|
|
307
|
+
type: "unknown",
|
|
308
|
+
action: "transform",
|
|
309
|
+
error: "transforms array is required for action: transform"
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
let parsed;
|
|
313
|
+
if (input.file) {
|
|
314
|
+
try {
|
|
315
|
+
const raw = await readJsonFileBounded(input.file, ctx);
|
|
316
|
+
parsed = JSON.parse(raw);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
return {
|
|
319
|
+
data: null,
|
|
320
|
+
formatted: "",
|
|
321
|
+
type: "unknown",
|
|
322
|
+
action: "transform",
|
|
323
|
+
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read/parse file"
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
} else if (input.data) {
|
|
327
|
+
try {
|
|
328
|
+
parsed = JSON.parse(input.data);
|
|
329
|
+
} catch {
|
|
330
|
+
return {
|
|
331
|
+
data: null,
|
|
332
|
+
formatted: "",
|
|
333
|
+
type: "unknown",
|
|
334
|
+
action: "transform",
|
|
335
|
+
error: "Could not parse data string"
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
return {
|
|
340
|
+
data: null,
|
|
341
|
+
formatted: "",
|
|
342
|
+
type: "unknown",
|
|
343
|
+
action: "transform",
|
|
344
|
+
error: "Provide file or data"
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
let current = parsed;
|
|
349
|
+
const steps = [];
|
|
350
|
+
for (const t of input.transforms) {
|
|
351
|
+
current = jmespathSearch(current, t);
|
|
352
|
+
steps.push({ transform: t, result: current });
|
|
353
|
+
}
|
|
354
|
+
const format = input.format ?? "json";
|
|
355
|
+
return {
|
|
356
|
+
data: parsed,
|
|
357
|
+
formatted: formatOutput(current, format),
|
|
358
|
+
type: current === null ? "null" : Array.isArray(current) ? "array" : typeof current,
|
|
359
|
+
action: "transform",
|
|
360
|
+
result: current,
|
|
361
|
+
steps
|
|
362
|
+
};
|
|
363
|
+
} catch (e) {
|
|
364
|
+
return {
|
|
365
|
+
data: null,
|
|
366
|
+
formatted: "",
|
|
367
|
+
type: "unknown",
|
|
368
|
+
action: "transform",
|
|
369
|
+
/* v8 ignore next -- defensive String(e) */
|
|
370
|
+
error: `Transform failed: ${e instanceof Error ? e.message : String(e)}`
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async function executeMerge(input) {
|
|
375
|
+
if (input.base === void 0 || input.patch === void 0) {
|
|
376
|
+
return {
|
|
377
|
+
data: null,
|
|
378
|
+
formatted: "",
|
|
379
|
+
type: "unknown",
|
|
380
|
+
action: "merge",
|
|
381
|
+
error: "base and patch are required for action: merge"
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
const conflictResolution = input.conflictResolution ?? "prefer-patch";
|
|
385
|
+
try {
|
|
386
|
+
const result = deepMergeCore(input.base, input.patch, { conflictResolution });
|
|
387
|
+
const format = input.format ?? "json";
|
|
388
|
+
return {
|
|
389
|
+
data: result,
|
|
390
|
+
formatted: formatOutput(result, format),
|
|
391
|
+
type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result,
|
|
392
|
+
action: "merge",
|
|
393
|
+
result
|
|
394
|
+
};
|
|
395
|
+
} catch (e) {
|
|
396
|
+
return {
|
|
397
|
+
data: null,
|
|
398
|
+
formatted: "",
|
|
399
|
+
type: "unknown",
|
|
400
|
+
action: "merge",
|
|
401
|
+
/* v8 ignore next -- defensive String(e) */
|
|
402
|
+
error: `Merge failed: ${e instanceof Error ? e.message : String(e)}`
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function jmespathSearch(data, query) {
|
|
407
|
+
if (!query || query === "@") return data;
|
|
408
|
+
if (query === "$") return data;
|
|
409
|
+
const dotMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(?:\.(.+))?$/);
|
|
410
|
+
if (dotMatch) {
|
|
411
|
+
const key = dotMatch[1];
|
|
412
|
+
const rest = dotMatch[2];
|
|
413
|
+
const val = data?.[key];
|
|
414
|
+
if (rest === void 0) return val;
|
|
415
|
+
return jmespathSearch(val, rest);
|
|
416
|
+
}
|
|
417
|
+
const arrMatch = query.match(/^\[(\d+)\](?:\.(.+))?$/);
|
|
418
|
+
if (arrMatch) {
|
|
419
|
+
const idx = Number.parseInt(arrMatch[1], 10);
|
|
420
|
+
const rest = arrMatch[2];
|
|
421
|
+
const arr = data;
|
|
422
|
+
const val = arr?.[idx];
|
|
423
|
+
if (rest === void 0) return val;
|
|
424
|
+
return jmespathSearch(val, rest);
|
|
425
|
+
}
|
|
426
|
+
if (query === "[*]") {
|
|
427
|
+
if (Array.isArray(data)) {
|
|
428
|
+
return data;
|
|
429
|
+
}
|
|
430
|
+
return data;
|
|
431
|
+
}
|
|
432
|
+
const multiMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\[\*\](?:\.(.+))?$/);
|
|
433
|
+
if (multiMatch) {
|
|
434
|
+
const key = multiMatch[1];
|
|
435
|
+
const rest = multiMatch[2];
|
|
436
|
+
const arr = data?.[key];
|
|
437
|
+
if (!Array.isArray(arr)) return [];
|
|
438
|
+
if (rest === void 0) return arr;
|
|
439
|
+
return arr.map((item) => jmespathSearch(item, rest));
|
|
440
|
+
}
|
|
441
|
+
const filterMatch = query.match(
|
|
442
|
+
/^\[\\?([a-zA-Z_][a-zA-Z0-9_]*)(==|!=|<|>|<=|>=)(`[^`]+`|'[^']*')\](?:\.(.+))?$/
|
|
443
|
+
);
|
|
444
|
+
if (filterMatch) {
|
|
445
|
+
const field = filterMatch[1];
|
|
446
|
+
const op = filterMatch[2];
|
|
447
|
+
const rawVal = filterMatch[3];
|
|
448
|
+
const rest = filterMatch[4];
|
|
449
|
+
const cmpVal = JSON.parse(rawVal.slice(1, -1));
|
|
450
|
+
const arr = data;
|
|
451
|
+
if (!Array.isArray(arr)) return [];
|
|
452
|
+
const filtered = arr.filter((item) => {
|
|
453
|
+
const itemVal = item[field];
|
|
454
|
+
switch (op) {
|
|
455
|
+
case "==":
|
|
456
|
+
return itemVal === cmpVal;
|
|
457
|
+
case "!=":
|
|
458
|
+
return itemVal !== cmpVal;
|
|
459
|
+
case ">":
|
|
460
|
+
return Number(itemVal) > Number(cmpVal);
|
|
461
|
+
case "<":
|
|
462
|
+
return Number(itemVal) < Number(cmpVal);
|
|
463
|
+
case ">=":
|
|
464
|
+
return Number(itemVal) >= Number(cmpVal);
|
|
465
|
+
case "<=":
|
|
466
|
+
return Number(itemVal) <= Number(cmpVal);
|
|
467
|
+
/* v8 ignore next -- op is constrained to the six operators by the filter regex; default is unreachable. */
|
|
468
|
+
default:
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
if (rest === void 0) return filtered;
|
|
473
|
+
return filtered.map((item) => jmespathSearch(item, rest));
|
|
474
|
+
}
|
|
475
|
+
const fnMatch = query.match(/^(length|keys|values|type)\(@\)$/);
|
|
476
|
+
if (fnMatch) {
|
|
477
|
+
const fn = fnMatch[1];
|
|
478
|
+
switch (fn) {
|
|
479
|
+
case "length":
|
|
480
|
+
if (Array.isArray(data)) return data.length;
|
|
481
|
+
if (typeof data === "string") return data.length;
|
|
482
|
+
if (typeof data === "object" && data !== null) return Object.keys(data).length;
|
|
483
|
+
return 0;
|
|
484
|
+
case "keys":
|
|
485
|
+
if (typeof data === "object" && data !== null && !Array.isArray(data))
|
|
486
|
+
return Object.keys(data);
|
|
487
|
+
return [];
|
|
488
|
+
case "values":
|
|
489
|
+
if (typeof data === "object" && data !== null && !Array.isArray(data))
|
|
490
|
+
return Object.values(data);
|
|
491
|
+
return [];
|
|
492
|
+
case "type":
|
|
493
|
+
if (data === null) return "null";
|
|
494
|
+
if (Array.isArray(data)) return "array";
|
|
495
|
+
return typeof data;
|
|
496
|
+
/* v8 ignore next 2 -- fn is constrained to the four names by the function regex; default is unreachable. */
|
|
497
|
+
default:
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
function validateJsonSchema(data, schema) {
|
|
504
|
+
const errors = [];
|
|
505
|
+
function check(value, s, path) {
|
|
506
|
+
if (s["type"]) {
|
|
507
|
+
const expectedType = s["type"];
|
|
508
|
+
const actualType = Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
|
|
509
|
+
if (expectedType === "integer") {
|
|
510
|
+
if (!Number.isInteger(value)) errors.push(`${path}: expected integer, got ${actualType}`);
|
|
511
|
+
} else if (expectedType !== actualType) {
|
|
512
|
+
errors.push(`${path}: expected ${expectedType}, got ${actualType}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (typeof value === "string" && s["format"] === "uri" && value) {
|
|
516
|
+
try {
|
|
517
|
+
new URL(value);
|
|
518
|
+
} catch {
|
|
519
|
+
errors.push(`${path}: not a valid URI`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (typeof value === "string" && s["pattern"]) {
|
|
523
|
+
const compiled = compileUserRegex(s["pattern"], "");
|
|
524
|
+
if (!compiled.ok) {
|
|
525
|
+
errors.push(`${path}: invalid schema pattern \u2014 ${compiled.reason}`);
|
|
526
|
+
} else if (!compiled.regex.test(capSubject(value))) {
|
|
527
|
+
errors.push(`${path}: does not match pattern ${s["pattern"]}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (typeof value === "string" && s["minLength"] !== void 0 && value.length < s["minLength"]) {
|
|
531
|
+
errors.push(`${path}: string too short (min ${s["minLength"]})`);
|
|
532
|
+
}
|
|
533
|
+
if (typeof value === "string" && s["maxLength"] !== void 0 && value.length > s["maxLength"]) {
|
|
534
|
+
errors.push(`${path}: string too long (max ${s["maxLength"]})`);
|
|
535
|
+
}
|
|
536
|
+
if (typeof value === "number" && s["minimum"] !== void 0 && value < s["minimum"]) {
|
|
537
|
+
errors.push(`${path}: below minimum ${s["minimum"]}`);
|
|
538
|
+
}
|
|
539
|
+
if (typeof value === "number" && s["maximum"] !== void 0 && value > s["maximum"]) {
|
|
540
|
+
errors.push(`${path}: above maximum ${s["maximum"]}`);
|
|
541
|
+
}
|
|
542
|
+
if (Array.isArray(value) && s["items"] && Array.isArray(s["items"])) {
|
|
543
|
+
for (let i = 0; i < value.length; i++) {
|
|
544
|
+
check(value[i], s["items"], `${path}[${i}]`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && s["properties"]) {
|
|
548
|
+
const props = s["properties"];
|
|
549
|
+
for (const [k, propSchema] of Object.entries(props)) {
|
|
550
|
+
check(value[k], propSchema, `${path}.${k}`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
check(data, schema, "$");
|
|
555
|
+
return { valid: errors.length === 0, errors };
|
|
556
|
+
}
|
|
557
|
+
function simpleQuery(data, path) {
|
|
558
|
+
const parts = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
559
|
+
let current = data;
|
|
560
|
+
for (const part of parts) {
|
|
561
|
+
if (current === null || current === void 0) return void 0;
|
|
562
|
+
const idx = Number(part);
|
|
563
|
+
if (!Number.isNaN(idx) && Array.isArray(current)) {
|
|
564
|
+
current = current[idx];
|
|
565
|
+
} else if (typeof current === "object" && current !== null) {
|
|
566
|
+
current = current[part];
|
|
567
|
+
} else {
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return current;
|
|
572
|
+
}
|
|
573
|
+
function formatOutput(data, format) {
|
|
574
|
+
if (format === "json5") {
|
|
575
|
+
return JSON.stringify(data, null, 2).replace(/,\s*}/g, "}").replace(/,\s*\]/g, "]");
|
|
576
|
+
}
|
|
577
|
+
if (format === "yaml") {
|
|
578
|
+
return toYaml(data);
|
|
579
|
+
}
|
|
580
|
+
return JSON.stringify(data, null, 2);
|
|
581
|
+
}
|
|
582
|
+
function toYaml(data, indent = 0) {
|
|
583
|
+
if (data === null) return "null\n";
|
|
584
|
+
if (data === void 0) return "";
|
|
585
|
+
if (typeof data === "boolean") return String(data) + "\n";
|
|
586
|
+
if (typeof data === "number") return String(data) + "\n";
|
|
587
|
+
if (typeof data === "string") {
|
|
588
|
+
if (data.includes("\n") || data.includes(":") || data.includes("#")) {
|
|
589
|
+
return `"${data.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"
|
|
590
|
+
`;
|
|
591
|
+
}
|
|
592
|
+
return data + "\n";
|
|
593
|
+
}
|
|
594
|
+
if (Array.isArray(data)) {
|
|
595
|
+
if (data.length === 0) return "[]\n";
|
|
596
|
+
const prefix = " ".repeat(indent);
|
|
597
|
+
return data.map((item) => `${prefix}- ${toYaml(item, indent + 1).trimStart()}`).join("");
|
|
598
|
+
}
|
|
599
|
+
if (typeof data === "object") {
|
|
600
|
+
const prefix = " ".repeat(indent);
|
|
601
|
+
const entries = Object.entries(data);
|
|
602
|
+
return entries.map(([k, v]) => `${prefix}${k}: ${toYaml(v, indent + 1)}`).join("");
|
|
603
|
+
}
|
|
604
|
+
return String(data) + "\n";
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export {
|
|
608
|
+
jsonTool
|
|
609
|
+
};
|
|
610
|
+
//# sourceMappingURL=chunk-VB3MJGCV.js.map
|