@kubb/studio 5.12.3 → 5.12.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 { 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
@@ -31,12 +31,23 @@ import { gzipSync } from "node:zlib";
31
31
  *
32
32
  * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
33
33
  */
34
- function toCamelOrPascal(text, pascal) {
34
+ function convert(text, pascal) {
35
35
  return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
36
36
  if (word.length > 1 && word === word.toUpperCase()) return word;
37
37
  return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
38
38
  }).join("").replace(/[^a-zA-Z0-9]/g, "");
39
39
  }
40
+ const cache = /* @__PURE__ */ new Map();
41
+ const cacheLimit = 1e4;
42
+ function toCamelOrPascal(text, pascal) {
43
+ const key = `${pascal ? "P" : "c"}${text}`;
44
+ const cached = cache.get(key);
45
+ if (cached !== void 0) return cached;
46
+ const result = convert(text, pascal);
47
+ if (cache.size >= cacheLimit) cache.clear();
48
+ cache.set(key, result);
49
+ return result;
50
+ }
40
51
  /**
41
52
  * Converts `text` to camelCase.
42
53
  *
@@ -202,7 +213,7 @@ function getElapsedMs(hrStart) {
202
213
  }
203
214
  //#endregion
204
215
  //#region package.json
205
- var version = "5.12.3";
216
+ var version = "5.12.5";
206
217
  //#endregion
207
218
  //#region src/resolveConfig.ts
208
219
  /**
@@ -558,6 +569,44 @@ async function rebuildExtension({ disk, studioOptions, kind, extensions }) {
558
569
  });
559
570
  }))(mergeOptions(disk.options ?? {}, studioOptions));
560
571
  }
572
+ /** The root `output` members Studio may set, with the values each takes. The rest, `path` and `postGenerate` among them, stay with the config file. */
573
+ const OUTPUT_VALUES = {
574
+ barrel: (value) => value === false || isPlainObject(value) && Object.keys(value).length === 1 && (value.type === "named" || value.type === "all"),
575
+ format: (value) => value === false || [
576
+ "auto",
577
+ "prettier",
578
+ "biome",
579
+ "oxfmt"
580
+ ].includes(value),
581
+ lint: (value) => value === false || [
582
+ "auto",
583
+ "eslint",
584
+ "biome",
585
+ "oxlint"
586
+ ].includes(value),
587
+ clean: (value) => typeof value === "boolean",
588
+ defaultBanner: (value) => value === false || value === "simple" || value === "full"
589
+ };
590
+ /** Whether Studio may set the root `output` member `key`. */
591
+ function isOutputKey(key) {
592
+ return Object.hasOwn(OUTPUT_VALUES, key);
593
+ }
594
+ /** Whether Studio may set the root `output` member `key` to `value`. */
595
+ function isOutputValue({ key, value }) {
596
+ return isOutputKey(key) && OUTPUT_VALUES[key](value);
597
+ }
598
+ /** The members of `output` Studio may see and set. */
599
+ function pickOutput(output) {
600
+ return Object.fromEntries(Object.entries(output).filter(([key]) => isOutputKey(key)));
601
+ }
602
+ /** Merges Studio's valid `output` overrides, with `null` unsetting a member. */
603
+ function mergeOutput({ output, studio }) {
604
+ if (!isPlainObject(studio)) return output;
605
+ return mergeOptions(output, Object.fromEntries(Object.entries(studio).filter(([key, value]) => value === null ? isOutputKey(key) : isOutputValue({
606
+ key,
607
+ value
608
+ }))));
609
+ }
561
610
  /**
562
611
  * Merges Studio-provided adapter option overrides into the disk config's adapter, see {@link rebuildExtension}.
563
612
  */
@@ -615,14 +664,16 @@ function invalidEdit(edit) {
615
664
  if (typeof operation !== "string" || !OPERATIONS.has(operation)) return `unknown operation ${JSON.stringify(operation)}`;
616
665
  if (config !== void 0 && typeof config !== "string" && !Number.isSafeInteger(config)) return "config must name an entry or give its index";
617
666
  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";
667
+ const isOutput = operation === ConfigEditOperation.SET_OUTPUT || operation === ConfigEditOperation.REMOVE_OUTPUT;
668
+ if (!isOutput && (typeof plugin !== "string" || !plugin)) return "the edit names no plugin";
619
669
  if (kind !== void 0 && (typeof kind !== "string" || !KINDS.has(kind))) return `unknown kind ${JSON.stringify(kind)}`;
620
670
  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) {
671
+ if (isOutput || operation === ConfigEditOperation.SET || operation === ConfigEditOperation.REMOVE) {
622
672
  if (!Array.isArray(path) || !path.every((key) => typeof key === "string" && key)) return "path must be a list of option names";
623
673
  if (!path.length) return "no option path given";
624
674
  const unsafe = path.find((key) => !isSafeKey(key));
625
675
  if (unsafe !== void 0) return `${unsafe} cannot be used as an option name`;
676
+ if (isOutput && !isOutputKey(path[0])) return `output.${path[0]} can only be changed in the config file`;
626
677
  }
627
678
  }
628
679
  /** Where a node sits in the source text. */
@@ -923,9 +974,12 @@ function readPartial(node, prefix = []) {
923
974
  }
924
975
  /** The top-level options of a plugin call, each flagged with whether Studio may write it. */
925
976
  function readOptions(call) {
926
- const entries = {};
927
977
  const options = call.arguments[0];
928
- if (options?.type !== "ObjectExpression") return entries;
978
+ return options?.type === "ObjectExpression" ? readObject(options) : {};
979
+ }
980
+ /** The members of an object literal, each flagged with whether Studio may write it. */
981
+ function readObject(options) {
982
+ const entries = {};
929
983
  for (const [index, entry] of options.properties.entries()) {
930
984
  const key = memberKey(entry);
931
985
  if (key === void 0 || !isSafeKey(key)) continue;
@@ -998,11 +1052,13 @@ function readConfig(source) {
998
1052
  });
999
1053
  const [adapter] = factoryCalls(mod, config, "adapter").map(toView);
1000
1054
  const parsers = factoryCalls(mod, config, "parser").map(toView);
1055
+ const output = outputObject(config);
1001
1056
  return {
1002
1057
  name: configName(config),
1003
1058
  plugins,
1004
1059
  ...adapter && { adapter },
1005
- ...parsers.length ? { parsers } : {}
1060
+ ...parsers.length ? { parsers } : {},
1061
+ ...!("reason" in output) && { output: pickOutput(readObject(output.object)) }
1006
1062
  };
1007
1063
  })
1008
1064
  };
@@ -1051,6 +1107,16 @@ function applySet(source, call, path, value, quote) {
1051
1107
  return { source: splice(source, closing, closing, printValue(nest(path, value), quote)) };
1052
1108
  }
1053
1109
  if (options.type !== "ObjectExpression") return { reason: "the factory was not called with an object literal" };
1110
+ return setIn({
1111
+ source,
1112
+ options,
1113
+ path,
1114
+ value,
1115
+ quote
1116
+ });
1117
+ }
1118
+ /** Writes the literal `value` at `path` inside `options`, adding any intermediate object it needs. */
1119
+ function setIn({ source, options, path, value, quote }) {
1054
1120
  const target = walk(options, path);
1055
1121
  if ("reason" in target) return target;
1056
1122
  if ("missing" in target) {
@@ -1068,6 +1134,34 @@ function applySetInput(source, config, input, quote) {
1068
1134
  if (isShadowed(config, found.index)) return { reason: "a spread after input could override it" };
1069
1135
  return { source: splice(source, rangeOf(found.member.value).start, rangeOf(found.member.value).end, value) };
1070
1136
  }
1137
+ /** The config's root `output` object literal, or why Studio cannot edit inside it. */
1138
+ function outputObject(config) {
1139
+ const found = findMember(config, "output");
1140
+ if (found?.member.type !== "ObjectProperty" || found.member.value.type !== "ObjectExpression") return { reason: "output is not an object literal" };
1141
+ if (isShadowed(config, found.index)) return { reason: "a spread after output could override it" };
1142
+ return { object: found.member.value };
1143
+ }
1144
+ /** Writes or drops a member of the config's root `output` object. */
1145
+ function applyOutputEdit({ source, config, edit, quote }) {
1146
+ const output = outputObject(config);
1147
+ if ("reason" in output) return output;
1148
+ if (edit.operation === ConfigEditOperation.REMOVE_OUTPUT) return removeIn({
1149
+ source,
1150
+ options: output.object,
1151
+ path: edit.path
1152
+ });
1153
+ if (!isOptionValue(edit.value) || !isOutputValue({
1154
+ key: edit.path[0],
1155
+ value: nest(edit.path.slice(1), edit.value)
1156
+ })) return { reason: `the value is not one output.${edit.path[0]} takes` };
1157
+ return setIn({
1158
+ source,
1159
+ options: output.object,
1160
+ path: edit.path,
1161
+ value: edit.value,
1162
+ quote
1163
+ });
1164
+ }
1071
1165
  /**
1072
1166
  * Deletes the option at `path`, falling the plugin back to its default for it. An option the file
1073
1167
  * does not set already has its default, so removing it changes nothing.
@@ -1076,6 +1170,14 @@ function applyRemove(source, call, path) {
1076
1170
  const options = call.arguments[0];
1077
1171
  if (!options) return { source };
1078
1172
  if (options.type !== "ObjectExpression") return { reason: "the factory was not called with an object literal" };
1173
+ return removeIn({
1174
+ source,
1175
+ options,
1176
+ path
1177
+ });
1178
+ }
1179
+ /** Deletes the member at `path` inside `options`. A path that is not there already holds its default. */
1180
+ function removeIn({ source, options, path }) {
1079
1181
  const target = walk(options, path);
1080
1182
  if ("reason" in target) return target;
1081
1183
  if ("missing" in target) return { source };
@@ -1165,6 +1267,12 @@ function applyEdit({ source, edit, quote, extensions }) {
1165
1267
  const config = findConfig(parsed);
1166
1268
  if (!config) return { reason: `no config entry found for ${JSON.stringify(ref)}` };
1167
1269
  if (edit.operation === ConfigEditOperation.SET_INPUT) return applySetInput(source, config, edit.input, quote);
1270
+ if (edit.operation === ConfigEditOperation.SET_OUTPUT || edit.operation === ConfigEditOperation.REMOVE_OUTPUT) return applyOutputEdit({
1271
+ source,
1272
+ config,
1273
+ edit,
1274
+ quote
1275
+ });
1168
1276
  if (edit.operation === ConfigEditOperation.DISABLE_PLUGIN) {
1169
1277
  const result = disablePlugin(source, parsed.mod, config, edit.plugin);
1170
1278
  if (!("reason" in result) || !result.reason.includes("shares a line")) return result;
@@ -2364,6 +2472,10 @@ var Agent = class extends RpcTarget {
2364
2472
  ...config,
2365
2473
  root,
2366
2474
  input: checkout?.path ?? studioInput ?? config.input,
2475
+ output: mergeOutput({
2476
+ output: config.output,
2477
+ studio: patch?.output
2478
+ }),
2367
2479
  storage: outputRoot ? stagingStorage({
2368
2480
  root,
2369
2481
  directory: outputRoot
@@ -2823,6 +2935,7 @@ function toEntryView(config, extensions) {
2823
2935
  ...config.name !== void 0 && { name: config.name },
2824
2936
  ...input !== void 0 && { input },
2825
2937
  output: config.output.path,
2938
+ outputOptions: toJSONOptions(pickOutput(config.output)),
2826
2939
  plugins: config.plugins.map((plugin) => ({
2827
2940
  name: toStudioName({
2828
2941
  name: resolveMeta(plugin).name,