@kubb/studio 5.11.4 → 5.11.5

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/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { E as InstalledExtensions, N as PublishedSnapshot, U as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, s as AgentPermission, u as ConfigEdit } from "./protocol-a_DcTFba.cjs";
1
+ import { E as InstalledExtensions, N as PublishedSnapshot, U as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, s as AgentPermission, u as ConfigEdit } from "./protocol--vpA4DkB.cjs";
2
2
  import { Config, Hookable, KubbHooks } from "@kubb/core";
3
3
  //#region src/connect.d.ts
4
4
  /**
@@ -47,6 +47,14 @@ declare global {
47
47
  'studio:command': [ctx: {
48
48
  command: 'generate' | 'saveConfig' | 'readFiles' | 'readInput' | 'readDiff';
49
49
  info: string;
50
+ /**
51
+ * The Studio user who asked for the command, when Studio names one.
52
+ */
53
+ requestedBy?: string;
54
+ /**
55
+ * Set when a generation failed. Its diagnostics went out through `kubb:generation:end`.
56
+ */
57
+ failed?: boolean;
50
58
  }];
51
59
  /**
52
60
  * A refused or ignored request, with the missing permission so the host can add a remedy.
@@ -242,6 +250,29 @@ export declare function createSnapshot({ studioUrl, apiKey, config, hooks, signa
242
250
  export declare const defaultStudioUrl = "https://kubb.studio";
243
251
  //#endregion
244
252
  //#region src/configFile.d.ts
253
+ /**
254
+ * Applies edits to a `kubb.config.ts` in place. Each edit rewrites only the text it targets, so
255
+ * comments, formatting, and hand-written code around the config survive.
256
+ *
257
+ * Edits are independent: one that cannot be applied is reported in `outcomes` and the rest still run.
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * const { source, outcomes } = applyConfigEdits({
262
+ * source: current,
263
+ * edits: [{ operation: 'set', plugin: '@kubb/plugin-ts', path: ['enum', 'type'], value: 'enum' }],
264
+ * })
265
+ * ```
266
+ */
267
+ export declare function applyConfigEdits({ source, edits, extensions }: {
268
+ source: string;
269
+ edits: Array<ConfigEdit>;
270
+ extensions?: InstalledExtensions;
271
+ }): {
272
+ source: string;
273
+ outcomes: Array<ConfigEditOutcome>;
274
+ changed: boolean;
275
+ };
245
276
  /**
246
277
  * Applies `edits` to the config file at `filePath`, writing it only when something changed.
247
278
  * `add-plugin` accepts `@kubb/plugin-*` packages and the plugins in `extensions`.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { E as InstalledExtensions, N as PublishedSnapshot, U as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, s as AgentPermission, u as ConfigEdit } from "./protocol-a_DcTFba.js";
1
+ import { E as InstalledExtensions, N as PublishedSnapshot, U as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, s as AgentPermission, u as ConfigEdit } from "./protocol--vpA4DkB.js";
2
2
  import { Config, Hookable, KubbHooks } from "@kubb/core";
3
3
  //#region src/connect.d.ts
4
4
  /**
@@ -47,6 +47,14 @@ declare global {
47
47
  'studio:command': [ctx: {
48
48
  command: 'generate' | 'saveConfig' | 'readFiles' | 'readInput' | 'readDiff';
49
49
  info: string;
50
+ /**
51
+ * The Studio user who asked for the command, when Studio names one.
52
+ */
53
+ requestedBy?: string;
54
+ /**
55
+ * Set when a generation failed. Its diagnostics went out through `kubb:generation:end`.
56
+ */
57
+ failed?: boolean;
50
58
  }];
51
59
  /**
52
60
  * A refused or ignored request, with the missing permission so the host can add a remedy.
@@ -242,6 +250,29 @@ export declare function createSnapshot({ studioUrl, apiKey, config, hooks, signa
242
250
  export declare const defaultStudioUrl = "https://kubb.studio";
243
251
  //#endregion
244
252
  //#region src/configFile.d.ts
253
+ /**
254
+ * Applies edits to a `kubb.config.ts` in place. Each edit rewrites only the text it targets, so
255
+ * comments, formatting, and hand-written code around the config survive.
256
+ *
257
+ * Edits are independent: one that cannot be applied is reported in `outcomes` and the rest still run.
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * const { source, outcomes } = applyConfigEdits({
262
+ * source: current,
263
+ * edits: [{ operation: 'set', plugin: '@kubb/plugin-ts', path: ['enum', 'type'], value: 'enum' }],
264
+ * })
265
+ * ```
266
+ */
267
+ export declare function applyConfigEdits({ source, edits, extensions }: {
268
+ source: string;
269
+ edits: Array<ConfigEdit>;
270
+ extensions?: InstalledExtensions;
271
+ }): {
272
+ source: string;
273
+ outcomes: Array<ConfigEditOutcome>;
274
+ changed: boolean;
275
+ };
245
276
  /**
246
277
  * Applies `edits` to the config file at `filePath`, writing it only when something changed.
247
278
  * `add-plugin` accepts `@kubb/plugin-*` packages and the plugins in `extensions`.
package/dist/index.js CHANGED
@@ -196,7 +196,7 @@ function getElapsedMs(hrStart) {
196
196
  }
197
197
  //#endregion
198
198
  //#region package.json
199
- var version = "5.11.4";
199
+ var version = "5.11.5";
200
200
  //#endregion
201
201
  //#region src/resolveConfig.ts
202
202
  /**
@@ -1058,13 +1058,17 @@ function applySet(source, call, path, value, quote) {
1058
1058
  }
1059
1059
  return { source: splice(source, rangeOf(target.value).start, rangeOf(target.value).end, printValue(value, quote)) };
1060
1060
  }
1061
- /** Deletes the option at `path`, falling the plugin back to its default for it. */
1061
+ /**
1062
+ * Deletes the option at `path`, falling the plugin back to its default for it. An option the file
1063
+ * does not set already has its default, so removing it changes nothing.
1064
+ */
1062
1065
  function applyRemove(source, call, path) {
1063
1066
  const options = call.arguments[0];
1064
- if (options?.type !== "ObjectExpression") return { reason: "the factory call has no options to remove" };
1067
+ if (!options) return { source };
1068
+ if (options.type !== "ObjectExpression") return { reason: "the factory was not called with an object literal" };
1065
1069
  const target = walk(options, path);
1066
1070
  if ("reason" in target) return target;
1067
- if ("missing" in target) return { reason: `${path.join(".")} is not set` };
1071
+ if ("missing" in target) return { source };
1068
1072
  return { source: removeMember(source, target.object, target.index) };
1069
1073
  }
1070
1074
  /**
@@ -1104,6 +1108,22 @@ function applyAddPlugin({ source, parsed, config, edit, quote, extensions }) {
1104
1108
  const next = insertItem(source, plugins, `${importName}(${Object.keys(options).length ? printValue(options, quote) : ""})`);
1105
1109
  return { source: taken ? next : insertImport(next, parsed, importName, edit.plugin) };
1106
1110
  }
1111
+ /**
1112
+ * Rewrites the config's `plugins` array with one item per line, so a call can be commented out without
1113
+ * taking its neighbors with it. Not done when a comment sits between the items, which would have to move.
1114
+ */
1115
+ function expandPluginsArray(source, config) {
1116
+ const array = property(config, "plugins");
1117
+ if (array?.type !== "ArrayExpression") return void 0;
1118
+ const items = array.elements.flatMap((element) => element ? [element] : []);
1119
+ const { start, end } = rangeOf(array);
1120
+ const ranges = items.map(rangeOf);
1121
+ const gaps = [source.slice(start + 1, ranges[0]?.start ?? end - 1), ...ranges.map((range, index) => source.slice(range.end, ranges[index + 1]?.start ?? end - 1))];
1122
+ if (!items.length || gaps.some((gap) => !/^[\s,]*$/.test(gap))) return void 0;
1123
+ const lineStart = source.lastIndexOf("\n", start - 1) + 1;
1124
+ const indent = source.slice(lineStart).match(/^[ \t]*/)?.[0] ?? "";
1125
+ return splice(source, start, end, `[\n${ranges.map((range) => `${indent} ${source.slice(range.start, range.end)},`).join("\n")}\n${indent}]`);
1126
+ }
1107
1127
  /** Comments out a plugin call in place, keeping its options on disk so `enable-plugin` can restore them exactly. */
1108
1128
  function disablePlugin(source, mod, config, plugin) {
1109
1129
  const loc = factoryCalls(mod, config).find((entry) => entry.packageName === plugin)?.call.loc;
@@ -1131,9 +1151,17 @@ function applyEdit({ source, edit, quote, extensions }) {
1131
1151
  const parsed = parseConfigs(source);
1132
1152
  if ("reason" in parsed) return parsed;
1133
1153
  const ref = edit.config;
1134
- const config = typeof ref === "string" ? parsed.configs.find((entry) => configName(entry) === ref) : parsed.configs[ref ?? 0];
1154
+ const findConfig = (entries) => typeof ref === "string" ? entries.configs.find((entry) => configName(entry) === ref) : entries.configs[ref ?? 0];
1155
+ const config = findConfig(parsed);
1135
1156
  if (!config) return { reason: `no config entry found for ${JSON.stringify(ref)}` };
1136
- if (edit.operation === "disable-plugin") return disablePlugin(source, parsed.mod, config, edit.plugin);
1157
+ if (edit.operation === "disable-plugin") {
1158
+ const result = disablePlugin(source, parsed.mod, config, edit.plugin);
1159
+ if (!("reason" in result) || !result.reason.includes("shares a line")) return result;
1160
+ const expanded = expandPluginsArray(source, config);
1161
+ const reparsed = expanded === void 0 ? void 0 : parseConfigs(expanded);
1162
+ const reparsedConfig = reparsed && !("reason" in reparsed) ? findConfig(reparsed) : void 0;
1163
+ return expanded !== void 0 && reparsed && !("reason" in reparsed) && reparsedConfig ? disablePlugin(expanded, reparsed.mod, reparsedConfig, edit.plugin) : result;
1164
+ }
1137
1165
  if (edit.operation === "enable-plugin") return enablePlugin(source, config, edit.plugin);
1138
1166
  if (edit.operation === "add-plugin") return applyAddPlugin({
1139
1167
  source,
@@ -1955,7 +1983,7 @@ var Agent = class extends RpcTarget {
1955
1983
  });
1956
1984
  return this.#store;
1957
1985
  }
1958
- async [Symbol.asyncDispose]() {
1986
+ async clear() {
1959
1987
  if (this.#sandbox) await rm(resolveCacheDir(this.#sandboxCacheRoot), {
1960
1988
  recursive: true,
1961
1989
  force: true
@@ -1985,10 +2013,12 @@ var Agent = class extends RpcTarget {
1985
2013
  message: "Studio must call connect() before any other command"
1986
2014
  });
1987
2015
  }
1988
- #logCommand(command, info) {
2016
+ #logCommand(command, info, requestedBy, failed) {
1989
2017
  return emit(this.#options.hooks, "studio:command", {
1990
2018
  command,
1991
- info
2019
+ info,
2020
+ requestedBy,
2021
+ failed
1992
2022
  });
1993
2023
  }
1994
2024
  async #readConfigFileView(source) {
@@ -2192,6 +2222,7 @@ var Agent = class extends RpcTarget {
2192
2222
  allowExec: this.#permissions.allowWrite && this.#permissions.allowExec
2193
2223
  }).catch(async (error) => {
2194
2224
  await this.#generations.drop(jobId);
2225
+ await this.#logCommand("generate", getErrorMessage(error), input.requestedBy, true);
2195
2226
  throw error;
2196
2227
  });
2197
2228
  const output = await this.#generations.keep({
@@ -2210,7 +2241,7 @@ var Agent = class extends RpcTarget {
2210
2241
  output,
2211
2242
  inputBytes
2212
2243
  });
2213
- await this.#logCommand("generate", `${activePlugins.length} plugin${activePlugins.length === 1 ? "" : "s"}, ${this.#permissions.allowWrite ? "written to disk" : "staged on disk"}${studioInput !== void 0 ? ", from a Studio spec" : ""}`);
2244
+ await this.#logCommand("generate", `${activePlugins.length} plugin${activePlugins.length === 1 ? "" : "s"}, ${this.#permissions.allowWrite ? "written to disk" : "staged on disk"}${studioInput !== void 0 ? ", from a Studio spec" : ""}`, input.requestedBy);
2214
2245
  return {
2215
2246
  status: "success",
2216
2247
  files: [...files.paths],
@@ -2249,7 +2280,7 @@ var Agent = class extends RpcTarget {
2249
2280
  extensions: await this.#installedExtensions()
2250
2281
  });
2251
2282
  const applied = outcomes.filter((outcome) => outcome.applied).length;
2252
- await this.#logCommand("saveConfig", `applied ${applied}/${outcomes.length} edits to ${configPath}`);
2283
+ await this.#logCommand("saveConfig", `applied ${applied}/${outcomes.length} edits to ${configPath}`, input.requestedBy);
2253
2284
  return {
2254
2285
  outcomes,
2255
2286
  changed
@@ -2441,7 +2472,7 @@ async function runSession({ options, openRpc, url, instanceId }) {
2441
2472
  await emit(hooks, "studio:warn", { message: "Canceled the running generation: the connection to Kubb Studio closed" });
2442
2473
  }
2443
2474
  await active?.settled;
2444
- await agent[Symbol.asyncDispose]();
2475
+ await agent.clear();
2445
2476
  return {
2446
2477
  ...close,
2447
2478
  connected: session.info !== void 0
@@ -2904,6 +2935,6 @@ async function createSnapshot({ studioUrl = defaultStudioUrl, apiKey, config, ho
2904
2935
  return _data.snapshot;
2905
2936
  }
2906
2937
  //#endregion
2907
- export { IncompatibleAgentError, InvalidAgentTokenError, PairingCanceledError, PairingDeniedError, PairingExpiredError, connectAgent, createSnapshot, defaultStudioUrl, pairAgent, writeConfigEdits };
2938
+ export { IncompatibleAgentError, InvalidAgentTokenError, PairingCanceledError, PairingDeniedError, PairingExpiredError, applyConfigEdits, connectAgent, createSnapshot, defaultStudioUrl, pairAgent, writeConfigEdits };
2908
2939
 
2909
2940
  //# sourceMappingURL=index.js.map