@kubb/studio 5.12.3 → 5.12.4

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 { J as SnapshotUploadMetadata, R as PublishedSnapshot, a as AgentConnectInfo, c as AgentPermissions, f as ConfigEditOutcome, j as InstalledExtensions, s as AgentPermission, u as ConfigEdit } from "./protocol-WYICLbSg.cjs";
1
+ import { Y as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, f as ConfigEditOutcome, j as InstalledExtensions, s as AgentPermission, u as ConfigEdit, z as PublishedSnapshot } from "./protocol-C4loKcxw.cjs";
2
2
  import { Config, Hookable, KubbHooks } from "@kubb/core";
3
3
  //#region src/connect.d.ts
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { J as SnapshotUploadMetadata, R as PublishedSnapshot, a as AgentConnectInfo, c as AgentPermissions, f as ConfigEditOutcome, j as InstalledExtensions, s as AgentPermission, u as ConfigEdit } from "./protocol-WYICLbSg.js";
1
+ import { Y as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, f as ConfigEditOutcome, j as InstalledExtensions, s as AgentPermission, u as ConfigEdit, z as PublishedSnapshot } from "./protocol-C4loKcxw.js";
2
2
  import { Config, Hookable, KubbHooks } from "@kubb/core";
3
3
  //#region src/connect.d.ts
4
4
  /**
package/dist/index.js CHANGED
@@ -202,7 +202,7 @@ function getElapsedMs(hrStart) {
202
202
  }
203
203
  //#endregion
204
204
  //#region package.json
205
- var version = "5.12.3";
205
+ var version = "5.12.4";
206
206
  //#endregion
207
207
  //#region src/resolveConfig.ts
208
208
  /**
@@ -558,6 +558,44 @@ async function rebuildExtension({ disk, studioOptions, kind, extensions }) {
558
558
  });
559
559
  }))(mergeOptions(disk.options ?? {}, studioOptions));
560
560
  }
561
+ /** The root `output` members Studio may set, with the values each takes. The rest, `path` and `postGenerate` among them, stay with the config file. */
562
+ const OUTPUT_VALUES = {
563
+ barrel: (value) => value === false || isPlainObject(value) && Object.keys(value).length === 1 && (value.type === "named" || value.type === "all"),
564
+ format: (value) => value === false || [
565
+ "auto",
566
+ "prettier",
567
+ "biome",
568
+ "oxfmt"
569
+ ].includes(value),
570
+ lint: (value) => value === false || [
571
+ "auto",
572
+ "eslint",
573
+ "biome",
574
+ "oxlint"
575
+ ].includes(value),
576
+ clean: (value) => typeof value === "boolean",
577
+ defaultBanner: (value) => value === false || value === "simple" || value === "full"
578
+ };
579
+ /** Whether Studio may set the root `output` member `key`. */
580
+ function isOutputKey(key) {
581
+ return Object.hasOwn(OUTPUT_VALUES, key);
582
+ }
583
+ /** Whether Studio may set the root `output` member `key` to `value`. */
584
+ function isOutputValue({ key, value }) {
585
+ return isOutputKey(key) && OUTPUT_VALUES[key](value);
586
+ }
587
+ /** The members of `output` Studio may see and set. */
588
+ function pickOutput(output) {
589
+ return Object.fromEntries(Object.entries(output).filter(([key]) => isOutputKey(key)));
590
+ }
591
+ /** Merges Studio's valid `output` overrides, with `null` unsetting a member. */
592
+ function mergeOutput({ output, studio }) {
593
+ if (!isPlainObject(studio)) return output;
594
+ return mergeOptions(output, Object.fromEntries(Object.entries(studio).filter(([key, value]) => value === null ? isOutputKey(key) : isOutputValue({
595
+ key,
596
+ value
597
+ }))));
598
+ }
561
599
  /**
562
600
  * Merges Studio-provided adapter option overrides into the disk config's adapter, see {@link rebuildExtension}.
563
601
  */
@@ -615,14 +653,16 @@ function invalidEdit(edit) {
615
653
  if (typeof operation !== "string" || !OPERATIONS.has(operation)) return `unknown operation ${JSON.stringify(operation)}`;
616
654
  if (config !== void 0 && typeof config !== "string" && !Number.isSafeInteger(config)) return "config must name an entry or give its index";
617
655
  if (operation === ConfigEditOperation.SET_INPUT) return typeof input === "string" && input.trim() ? void 0 : "the edit names no input";
618
- if (typeof plugin !== "string" || !plugin) return "the edit names no plugin";
656
+ const isOutput = operation === ConfigEditOperation.SET_OUTPUT || operation === ConfigEditOperation.REMOVE_OUTPUT;
657
+ if (!isOutput && (typeof plugin !== "string" || !plugin)) return "the edit names no plugin";
619
658
  if (kind !== void 0 && (typeof kind !== "string" || !KINDS.has(kind))) return `unknown kind ${JSON.stringify(kind)}`;
620
659
  if (kind !== void 0 && operation !== ConfigEditOperation.SET && operation !== ConfigEditOperation.REMOVE) return `${operation} edits the plugins array, so it takes no kind`;
621
- if (operation === ConfigEditOperation.SET || operation === ConfigEditOperation.REMOVE) {
660
+ if (isOutput || operation === ConfigEditOperation.SET || operation === ConfigEditOperation.REMOVE) {
622
661
  if (!Array.isArray(path) || !path.every((key) => typeof key === "string" && key)) return "path must be a list of option names";
623
662
  if (!path.length) return "no option path given";
624
663
  const unsafe = path.find((key) => !isSafeKey(key));
625
664
  if (unsafe !== void 0) return `${unsafe} cannot be used as an option name`;
665
+ if (isOutput && !isOutputKey(path[0])) return `output.${path[0]} can only be changed in the config file`;
626
666
  }
627
667
  }
628
668
  /** Where a node sits in the source text. */
@@ -923,9 +963,12 @@ function readPartial(node, prefix = []) {
923
963
  }
924
964
  /** The top-level options of a plugin call, each flagged with whether Studio may write it. */
925
965
  function readOptions(call) {
926
- const entries = {};
927
966
  const options = call.arguments[0];
928
- if (options?.type !== "ObjectExpression") return entries;
967
+ return options?.type === "ObjectExpression" ? readObject(options) : {};
968
+ }
969
+ /** The members of an object literal, each flagged with whether Studio may write it. */
970
+ function readObject(options) {
971
+ const entries = {};
929
972
  for (const [index, entry] of options.properties.entries()) {
930
973
  const key = memberKey(entry);
931
974
  if (key === void 0 || !isSafeKey(key)) continue;
@@ -998,11 +1041,13 @@ function readConfig(source) {
998
1041
  });
999
1042
  const [adapter] = factoryCalls(mod, config, "adapter").map(toView);
1000
1043
  const parsers = factoryCalls(mod, config, "parser").map(toView);
1044
+ const output = outputObject(config);
1001
1045
  return {
1002
1046
  name: configName(config),
1003
1047
  plugins,
1004
1048
  ...adapter && { adapter },
1005
- ...parsers.length ? { parsers } : {}
1049
+ ...parsers.length ? { parsers } : {},
1050
+ ...!("reason" in output) && { output: pickOutput(readObject(output.object)) }
1006
1051
  };
1007
1052
  })
1008
1053
  };
@@ -1051,6 +1096,16 @@ function applySet(source, call, path, value, quote) {
1051
1096
  return { source: splice(source, closing, closing, printValue(nest(path, value), quote)) };
1052
1097
  }
1053
1098
  if (options.type !== "ObjectExpression") return { reason: "the factory was not called with an object literal" };
1099
+ return setIn({
1100
+ source,
1101
+ options,
1102
+ path,
1103
+ value,
1104
+ quote
1105
+ });
1106
+ }
1107
+ /** Writes the literal `value` at `path` inside `options`, adding any intermediate object it needs. */
1108
+ function setIn({ source, options, path, value, quote }) {
1054
1109
  const target = walk(options, path);
1055
1110
  if ("reason" in target) return target;
1056
1111
  if ("missing" in target) {
@@ -1068,6 +1123,34 @@ function applySetInput(source, config, input, quote) {
1068
1123
  if (isShadowed(config, found.index)) return { reason: "a spread after input could override it" };
1069
1124
  return { source: splice(source, rangeOf(found.member.value).start, rangeOf(found.member.value).end, value) };
1070
1125
  }
1126
+ /** The config's root `output` object literal, or why Studio cannot edit inside it. */
1127
+ function outputObject(config) {
1128
+ const found = findMember(config, "output");
1129
+ if (found?.member.type !== "ObjectProperty" || found.member.value.type !== "ObjectExpression") return { reason: "output is not an object literal" };
1130
+ if (isShadowed(config, found.index)) return { reason: "a spread after output could override it" };
1131
+ return { object: found.member.value };
1132
+ }
1133
+ /** Writes or drops a member of the config's root `output` object. */
1134
+ function applyOutputEdit({ source, config, edit, quote }) {
1135
+ const output = outputObject(config);
1136
+ if ("reason" in output) return output;
1137
+ if (edit.operation === ConfigEditOperation.REMOVE_OUTPUT) return removeIn({
1138
+ source,
1139
+ options: output.object,
1140
+ path: edit.path
1141
+ });
1142
+ if (!isOptionValue(edit.value) || !isOutputValue({
1143
+ key: edit.path[0],
1144
+ value: nest(edit.path.slice(1), edit.value)
1145
+ })) return { reason: `the value is not one output.${edit.path[0]} takes` };
1146
+ return setIn({
1147
+ source,
1148
+ options: output.object,
1149
+ path: edit.path,
1150
+ value: edit.value,
1151
+ quote
1152
+ });
1153
+ }
1071
1154
  /**
1072
1155
  * Deletes the option at `path`, falling the plugin back to its default for it. An option the file
1073
1156
  * does not set already has its default, so removing it changes nothing.
@@ -1076,6 +1159,14 @@ function applyRemove(source, call, path) {
1076
1159
  const options = call.arguments[0];
1077
1160
  if (!options) return { source };
1078
1161
  if (options.type !== "ObjectExpression") return { reason: "the factory was not called with an object literal" };
1162
+ return removeIn({
1163
+ source,
1164
+ options,
1165
+ path
1166
+ });
1167
+ }
1168
+ /** Deletes the member at `path` inside `options`. A path that is not there already holds its default. */
1169
+ function removeIn({ source, options, path }) {
1079
1170
  const target = walk(options, path);
1080
1171
  if ("reason" in target) return target;
1081
1172
  if ("missing" in target) return { source };
@@ -1165,6 +1256,12 @@ function applyEdit({ source, edit, quote, extensions }) {
1165
1256
  const config = findConfig(parsed);
1166
1257
  if (!config) return { reason: `no config entry found for ${JSON.stringify(ref)}` };
1167
1258
  if (edit.operation === ConfigEditOperation.SET_INPUT) return applySetInput(source, config, edit.input, quote);
1259
+ if (edit.operation === ConfigEditOperation.SET_OUTPUT || edit.operation === ConfigEditOperation.REMOVE_OUTPUT) return applyOutputEdit({
1260
+ source,
1261
+ config,
1262
+ edit,
1263
+ quote
1264
+ });
1168
1265
  if (edit.operation === ConfigEditOperation.DISABLE_PLUGIN) {
1169
1266
  const result = disablePlugin(source, parsed.mod, config, edit.plugin);
1170
1267
  if (!("reason" in result) || !result.reason.includes("shares a line")) return result;
@@ -2364,6 +2461,10 @@ var Agent = class extends RpcTarget {
2364
2461
  ...config,
2365
2462
  root,
2366
2463
  input: checkout?.path ?? studioInput ?? config.input,
2464
+ output: mergeOutput({
2465
+ output: config.output,
2466
+ studio: patch?.output
2467
+ }),
2367
2468
  storage: outputRoot ? stagingStorage({
2368
2469
  root,
2369
2470
  directory: outputRoot
@@ -2823,6 +2924,7 @@ function toEntryView(config, extensions) {
2823
2924
  ...config.name !== void 0 && { name: config.name },
2824
2925
  ...input !== void 0 && { input },
2825
2926
  output: config.output.path,
2927
+ outputOptions: toJSONOptions(pickOutput(config.output)),
2826
2928
  plugins: config.plugins.map((plugin) => ({
2827
2929
  name: toStudioName({
2828
2930
  name: resolveMeta(plugin).name,