@fern-api/generator-migrations 0.0.1 → 0.0.2

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.mjs ADDED
@@ -0,0 +1,1225 @@
1
+ //#region ../../node_modules/.pnpm/immer@10.1.3/node_modules/immer/dist/immer.mjs
2
+ var NOTHING = Symbol.for("immer-nothing");
3
+ var DRAFTABLE = Symbol.for("immer-draftable");
4
+ var DRAFT_STATE = Symbol.for("immer-state");
5
+ var errors = process.env.NODE_ENV !== "production" ? [
6
+ function(plugin) {
7
+ return `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \`enable${plugin}()\` when initializing your application.`;
8
+ },
9
+ function(thing) {
10
+ return `produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${thing}'`;
11
+ },
12
+ "This object has been frozen and should not be mutated",
13
+ function(data) {
14
+ return "Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " + data;
15
+ },
16
+ "An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",
17
+ "Immer forbids circular references",
18
+ "The first or second argument to `produce` must be a function",
19
+ "The third argument to `produce` must be a function or undefined",
20
+ "First argument to `createDraft` must be a plain object, an array, or an immerable object",
21
+ "First argument to `finishDraft` must be a draft returned by `createDraft`",
22
+ function(thing) {
23
+ return `'current' expects a draft, got: ${thing}`;
24
+ },
25
+ "Object.defineProperty() cannot be used on an Immer draft",
26
+ "Object.setPrototypeOf() cannot be used on an Immer draft",
27
+ "Immer only supports deleting array indices",
28
+ "Immer only supports setting array indices and the 'length' property",
29
+ function(thing) {
30
+ return `'original' expects a draft, got: ${thing}`;
31
+ }
32
+ ] : [];
33
+ function die(error, ...args) {
34
+ if (process.env.NODE_ENV !== "production") {
35
+ const e = errors[error];
36
+ const msg = typeof e === "function" ? e.apply(null, args) : e;
37
+ throw new Error(`[Immer] ${msg}`);
38
+ }
39
+ throw new Error(`[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`);
40
+ }
41
+ var getPrototypeOf = Object.getPrototypeOf;
42
+ function isDraft(value) {
43
+ return !!value && !!value[DRAFT_STATE];
44
+ }
45
+ function isDraftable(value) {
46
+ if (!value) return false;
47
+ return isPlainObject(value) || Array.isArray(value) || !!value[DRAFTABLE] || !!value.constructor?.[DRAFTABLE] || isMap(value) || isSet(value);
48
+ }
49
+ var objectCtorString = Object.prototype.constructor.toString();
50
+ function isPlainObject(value) {
51
+ if (!value || typeof value !== "object") return false;
52
+ const proto = getPrototypeOf(value);
53
+ if (proto === null) return true;
54
+ const Ctor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor;
55
+ if (Ctor === Object) return true;
56
+ return typeof Ctor == "function" && Function.toString.call(Ctor) === objectCtorString;
57
+ }
58
+ function each(obj, iter) {
59
+ if (getArchtype(obj) === 0) Reflect.ownKeys(obj).forEach((key) => {
60
+ iter(key, obj[key], obj);
61
+ });
62
+ else obj.forEach((entry, index) => iter(index, entry, obj));
63
+ }
64
+ function getArchtype(thing) {
65
+ const state = thing[DRAFT_STATE];
66
+ return state ? state.type_ : Array.isArray(thing) ? 1 : isMap(thing) ? 2 : isSet(thing) ? 3 : 0;
67
+ }
68
+ function has(thing, prop) {
69
+ return getArchtype(thing) === 2 ? thing.has(prop) : Object.prototype.hasOwnProperty.call(thing, prop);
70
+ }
71
+ function set(thing, propOrOldValue, value) {
72
+ const t = getArchtype(thing);
73
+ if (t === 2) thing.set(propOrOldValue, value);
74
+ else if (t === 3) thing.add(value);
75
+ else thing[propOrOldValue] = value;
76
+ }
77
+ function is(x, y) {
78
+ if (x === y) return x !== 0 || 1 / x === 1 / y;
79
+ else return x !== x && y !== y;
80
+ }
81
+ function isMap(target) {
82
+ return target instanceof Map;
83
+ }
84
+ function isSet(target) {
85
+ return target instanceof Set;
86
+ }
87
+ function latest(state) {
88
+ return state.copy_ || state.base_;
89
+ }
90
+ function shallowCopy(base, strict) {
91
+ if (isMap(base)) return new Map(base);
92
+ if (isSet(base)) return new Set(base);
93
+ if (Array.isArray(base)) return Array.prototype.slice.call(base);
94
+ const isPlain = isPlainObject(base);
95
+ if (strict === true || strict === "class_only" && !isPlain) {
96
+ const descriptors = Object.getOwnPropertyDescriptors(base);
97
+ delete descriptors[DRAFT_STATE];
98
+ let keys = Reflect.ownKeys(descriptors);
99
+ for (let i = 0; i < keys.length; i++) {
100
+ const key = keys[i];
101
+ const desc = descriptors[key];
102
+ if (desc.writable === false) {
103
+ desc.writable = true;
104
+ desc.configurable = true;
105
+ }
106
+ if (desc.get || desc.set) descriptors[key] = {
107
+ configurable: true,
108
+ writable: true,
109
+ enumerable: desc.enumerable,
110
+ value: base[key]
111
+ };
112
+ }
113
+ return Object.create(getPrototypeOf(base), descriptors);
114
+ } else {
115
+ const proto = getPrototypeOf(base);
116
+ if (proto !== null && isPlain) return { ...base };
117
+ const obj = Object.create(proto);
118
+ return Object.assign(obj, base);
119
+ }
120
+ }
121
+ function freeze(obj, deep = false) {
122
+ if (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj;
123
+ if (getArchtype(obj) > 1) Object.defineProperties(obj, {
124
+ set: { value: dontMutateFrozenCollections },
125
+ add: { value: dontMutateFrozenCollections },
126
+ clear: { value: dontMutateFrozenCollections },
127
+ delete: { value: dontMutateFrozenCollections }
128
+ });
129
+ Object.freeze(obj);
130
+ if (deep) Object.values(obj).forEach((value) => freeze(value, true));
131
+ return obj;
132
+ }
133
+ function dontMutateFrozenCollections() {
134
+ die(2);
135
+ }
136
+ function isFrozen(obj) {
137
+ return Object.isFrozen(obj);
138
+ }
139
+ var plugins = {};
140
+ function getPlugin(pluginKey) {
141
+ const plugin = plugins[pluginKey];
142
+ if (!plugin) die(0, pluginKey);
143
+ return plugin;
144
+ }
145
+ var currentScope;
146
+ function getCurrentScope() {
147
+ return currentScope;
148
+ }
149
+ function createScope(parent_, immer_) {
150
+ return {
151
+ drafts_: [],
152
+ parent_,
153
+ immer_,
154
+ canAutoFreeze_: true,
155
+ unfinalizedDrafts_: 0
156
+ };
157
+ }
158
+ function usePatchesInScope(scope, patchListener) {
159
+ if (patchListener) {
160
+ getPlugin("Patches");
161
+ scope.patches_ = [];
162
+ scope.inversePatches_ = [];
163
+ scope.patchListener_ = patchListener;
164
+ }
165
+ }
166
+ function revokeScope(scope) {
167
+ leaveScope(scope);
168
+ scope.drafts_.forEach(revokeDraft);
169
+ scope.drafts_ = null;
170
+ }
171
+ function leaveScope(scope) {
172
+ if (scope === currentScope) currentScope = scope.parent_;
173
+ }
174
+ function enterScope(immer2) {
175
+ return currentScope = createScope(currentScope, immer2);
176
+ }
177
+ function revokeDraft(draft) {
178
+ const state = draft[DRAFT_STATE];
179
+ if (state.type_ === 0 || state.type_ === 1) state.revoke_();
180
+ else state.revoked_ = true;
181
+ }
182
+ function processResult(result, scope) {
183
+ scope.unfinalizedDrafts_ = scope.drafts_.length;
184
+ const baseDraft = scope.drafts_[0];
185
+ if (result !== void 0 && result !== baseDraft) {
186
+ if (baseDraft[DRAFT_STATE].modified_) {
187
+ revokeScope(scope);
188
+ die(4);
189
+ }
190
+ if (isDraftable(result)) {
191
+ result = finalize(scope, result);
192
+ if (!scope.parent_) maybeFreeze(scope, result);
193
+ }
194
+ if (scope.patches_) getPlugin("Patches").generateReplacementPatches_(baseDraft[DRAFT_STATE].base_, result, scope.patches_, scope.inversePatches_);
195
+ } else result = finalize(scope, baseDraft, []);
196
+ revokeScope(scope);
197
+ if (scope.patches_) scope.patchListener_(scope.patches_, scope.inversePatches_);
198
+ return result !== NOTHING ? result : void 0;
199
+ }
200
+ function finalize(rootScope, value, path) {
201
+ if (isFrozen(value)) return value;
202
+ const state = value[DRAFT_STATE];
203
+ if (!state) {
204
+ each(value, (key, childValue) => finalizeProperty(rootScope, state, value, key, childValue, path));
205
+ return value;
206
+ }
207
+ if (state.scope_ !== rootScope) return value;
208
+ if (!state.modified_) {
209
+ maybeFreeze(rootScope, state.base_, true);
210
+ return state.base_;
211
+ }
212
+ if (!state.finalized_) {
213
+ state.finalized_ = true;
214
+ state.scope_.unfinalizedDrafts_--;
215
+ const result = state.copy_;
216
+ let resultEach = result;
217
+ let isSet2 = false;
218
+ if (state.type_ === 3) {
219
+ resultEach = new Set(result);
220
+ result.clear();
221
+ isSet2 = true;
222
+ }
223
+ each(resultEach, (key, childValue) => finalizeProperty(rootScope, state, result, key, childValue, path, isSet2));
224
+ maybeFreeze(rootScope, result, false);
225
+ if (path && rootScope.patches_) getPlugin("Patches").generatePatches_(state, path, rootScope.patches_, rootScope.inversePatches_);
226
+ }
227
+ return state.copy_;
228
+ }
229
+ function finalizeProperty(rootScope, parentState, targetObject, prop, childValue, rootPath, targetIsSet) {
230
+ if (process.env.NODE_ENV !== "production" && childValue === targetObject) die(5);
231
+ if (isDraft(childValue)) {
232
+ const res = finalize(rootScope, childValue, rootPath && parentState && parentState.type_ !== 3 && !has(parentState.assigned_, prop) ? rootPath.concat(prop) : void 0);
233
+ set(targetObject, prop, res);
234
+ if (isDraft(res)) rootScope.canAutoFreeze_ = false;
235
+ else return;
236
+ } else if (targetIsSet) targetObject.add(childValue);
237
+ if (isDraftable(childValue) && !isFrozen(childValue)) {
238
+ if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) return;
239
+ finalize(rootScope, childValue);
240
+ if ((!parentState || !parentState.scope_.parent_) && typeof prop !== "symbol" && (isMap(targetObject) ? targetObject.has(prop) : Object.prototype.propertyIsEnumerable.call(targetObject, prop))) maybeFreeze(rootScope, childValue);
241
+ }
242
+ }
243
+ function maybeFreeze(scope, value, deep = false) {
244
+ if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) freeze(value, deep);
245
+ }
246
+ function createProxyProxy(base, parent) {
247
+ const isArray = Array.isArray(base);
248
+ const state = {
249
+ type_: isArray ? 1 : 0,
250
+ scope_: parent ? parent.scope_ : getCurrentScope(),
251
+ modified_: false,
252
+ finalized_: false,
253
+ assigned_: {},
254
+ parent_: parent,
255
+ base_: base,
256
+ draft_: null,
257
+ copy_: null,
258
+ revoke_: null,
259
+ isManual_: false
260
+ };
261
+ let target = state;
262
+ let traps = objectTraps;
263
+ if (isArray) {
264
+ target = [state];
265
+ traps = arrayTraps;
266
+ }
267
+ const { revoke, proxy } = Proxy.revocable(target, traps);
268
+ state.draft_ = proxy;
269
+ state.revoke_ = revoke;
270
+ return proxy;
271
+ }
272
+ var objectTraps = {
273
+ get(state, prop) {
274
+ if (prop === DRAFT_STATE) return state;
275
+ const source = latest(state);
276
+ if (!has(source, prop)) return readPropFromProto(state, source, prop);
277
+ const value = source[prop];
278
+ if (state.finalized_ || !isDraftable(value)) return value;
279
+ if (value === peek(state.base_, prop)) {
280
+ prepareCopy(state);
281
+ return state.copy_[prop] = createProxy(value, state);
282
+ }
283
+ return value;
284
+ },
285
+ has(state, prop) {
286
+ return prop in latest(state);
287
+ },
288
+ ownKeys(state) {
289
+ return Reflect.ownKeys(latest(state));
290
+ },
291
+ set(state, prop, value) {
292
+ const desc = getDescriptorFromProto(latest(state), prop);
293
+ if (desc?.set) {
294
+ desc.set.call(state.draft_, value);
295
+ return true;
296
+ }
297
+ if (!state.modified_) {
298
+ const current2 = peek(latest(state), prop);
299
+ const currentState = current2?.[DRAFT_STATE];
300
+ if (currentState && currentState.base_ === value) {
301
+ state.copy_[prop] = value;
302
+ state.assigned_[prop] = false;
303
+ return true;
304
+ }
305
+ if (is(value, current2) && (value !== void 0 || has(state.base_, prop))) return true;
306
+ prepareCopy(state);
307
+ markChanged(state);
308
+ }
309
+ if (state.copy_[prop] === value && (value !== void 0 || prop in state.copy_) || Number.isNaN(value) && Number.isNaN(state.copy_[prop])) return true;
310
+ state.copy_[prop] = value;
311
+ state.assigned_[prop] = true;
312
+ return true;
313
+ },
314
+ deleteProperty(state, prop) {
315
+ if (peek(state.base_, prop) !== void 0 || prop in state.base_) {
316
+ state.assigned_[prop] = false;
317
+ prepareCopy(state);
318
+ markChanged(state);
319
+ } else delete state.assigned_[prop];
320
+ if (state.copy_) delete state.copy_[prop];
321
+ return true;
322
+ },
323
+ getOwnPropertyDescriptor(state, prop) {
324
+ const owner = latest(state);
325
+ const desc = Reflect.getOwnPropertyDescriptor(owner, prop);
326
+ if (!desc) return desc;
327
+ return {
328
+ writable: true,
329
+ configurable: state.type_ !== 1 || prop !== "length",
330
+ enumerable: desc.enumerable,
331
+ value: owner[prop]
332
+ };
333
+ },
334
+ defineProperty() {
335
+ die(11);
336
+ },
337
+ getPrototypeOf(state) {
338
+ return getPrototypeOf(state.base_);
339
+ },
340
+ setPrototypeOf() {
341
+ die(12);
342
+ }
343
+ };
344
+ var arrayTraps = {};
345
+ each(objectTraps, (key, fn) => {
346
+ arrayTraps[key] = function() {
347
+ arguments[0] = arguments[0][0];
348
+ return fn.apply(this, arguments);
349
+ };
350
+ });
351
+ arrayTraps.deleteProperty = function(state, prop) {
352
+ if (process.env.NODE_ENV !== "production" && isNaN(parseInt(prop))) die(13);
353
+ return arrayTraps.set.call(this, state, prop, void 0);
354
+ };
355
+ arrayTraps.set = function(state, prop, value) {
356
+ if (process.env.NODE_ENV !== "production" && prop !== "length" && isNaN(parseInt(prop))) die(14);
357
+ return objectTraps.set.call(this, state[0], prop, value, state[0]);
358
+ };
359
+ function peek(draft, prop) {
360
+ const state = draft[DRAFT_STATE];
361
+ return (state ? latest(state) : draft)[prop];
362
+ }
363
+ function readPropFromProto(state, source, prop) {
364
+ const desc = getDescriptorFromProto(source, prop);
365
+ return desc ? `value` in desc ? desc.value : desc.get?.call(state.draft_) : void 0;
366
+ }
367
+ function getDescriptorFromProto(source, prop) {
368
+ if (!(prop in source)) return void 0;
369
+ let proto = getPrototypeOf(source);
370
+ while (proto) {
371
+ const desc = Object.getOwnPropertyDescriptor(proto, prop);
372
+ if (desc) return desc;
373
+ proto = getPrototypeOf(proto);
374
+ }
375
+ }
376
+ function markChanged(state) {
377
+ if (!state.modified_) {
378
+ state.modified_ = true;
379
+ if (state.parent_) markChanged(state.parent_);
380
+ }
381
+ }
382
+ function prepareCopy(state) {
383
+ if (!state.copy_) state.copy_ = shallowCopy(state.base_, state.scope_.immer_.useStrictShallowCopy_);
384
+ }
385
+ var Immer2 = class {
386
+ constructor(config) {
387
+ this.autoFreeze_ = true;
388
+ this.useStrictShallowCopy_ = false;
389
+ /**
390
+ * The `produce` function takes a value and a "recipe function" (whose
391
+ * return value often depends on the base state). The recipe function is
392
+ * free to mutate its first argument however it wants. All mutations are
393
+ * only ever applied to a __copy__ of the base state.
394
+ *
395
+ * Pass only a function to create a "curried producer" which relieves you
396
+ * from passing the recipe function every time.
397
+ *
398
+ * Only plain objects and arrays are made mutable. All other objects are
399
+ * considered uncopyable.
400
+ *
401
+ * Note: This function is __bound__ to its `Immer` instance.
402
+ *
403
+ * @param {any} base - the initial state
404
+ * @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified
405
+ * @param {Function} patchListener - optional function that will be called with all the patches produced here
406
+ * @returns {any} a new state, or the initial state if nothing was modified
407
+ */
408
+ this.produce = (base, recipe, patchListener) => {
409
+ if (typeof base === "function" && typeof recipe !== "function") {
410
+ const defaultBase = recipe;
411
+ recipe = base;
412
+ const self = this;
413
+ return function curriedProduce(base2 = defaultBase, ...args) {
414
+ return self.produce(base2, (draft) => recipe.call(this, draft, ...args));
415
+ };
416
+ }
417
+ if (typeof recipe !== "function") die(6);
418
+ if (patchListener !== void 0 && typeof patchListener !== "function") die(7);
419
+ let result;
420
+ if (isDraftable(base)) {
421
+ const scope = enterScope(this);
422
+ const proxy = createProxy(base, void 0);
423
+ let hasError = true;
424
+ try {
425
+ result = recipe(proxy);
426
+ hasError = false;
427
+ } finally {
428
+ if (hasError) revokeScope(scope);
429
+ else leaveScope(scope);
430
+ }
431
+ usePatchesInScope(scope, patchListener);
432
+ return processResult(result, scope);
433
+ } else if (!base || typeof base !== "object") {
434
+ result = recipe(base);
435
+ if (result === void 0) result = base;
436
+ if (result === NOTHING) result = void 0;
437
+ if (this.autoFreeze_) freeze(result, true);
438
+ if (patchListener) {
439
+ const p = [];
440
+ const ip = [];
441
+ getPlugin("Patches").generateReplacementPatches_(base, result, p, ip);
442
+ patchListener(p, ip);
443
+ }
444
+ return result;
445
+ } else die(1, base);
446
+ };
447
+ this.produceWithPatches = (base, recipe) => {
448
+ if (typeof base === "function") return (state, ...args) => this.produceWithPatches(state, (draft) => base(draft, ...args));
449
+ let patches, inversePatches;
450
+ return [
451
+ this.produce(base, recipe, (p, ip) => {
452
+ patches = p;
453
+ inversePatches = ip;
454
+ }),
455
+ patches,
456
+ inversePatches
457
+ ];
458
+ };
459
+ if (typeof config?.autoFreeze === "boolean") this.setAutoFreeze(config.autoFreeze);
460
+ if (typeof config?.useStrictShallowCopy === "boolean") this.setUseStrictShallowCopy(config.useStrictShallowCopy);
461
+ }
462
+ createDraft(base) {
463
+ if (!isDraftable(base)) die(8);
464
+ if (isDraft(base)) base = current(base);
465
+ const scope = enterScope(this);
466
+ const proxy = createProxy(base, void 0);
467
+ proxy[DRAFT_STATE].isManual_ = true;
468
+ leaveScope(scope);
469
+ return proxy;
470
+ }
471
+ finishDraft(draft, patchListener) {
472
+ const state = draft && draft[DRAFT_STATE];
473
+ if (!state || !state.isManual_) die(9);
474
+ const { scope_: scope } = state;
475
+ usePatchesInScope(scope, patchListener);
476
+ return processResult(void 0, scope);
477
+ }
478
+ /**
479
+ * Pass true to automatically freeze all copies created by Immer.
480
+ *
481
+ * By default, auto-freezing is enabled.
482
+ */
483
+ setAutoFreeze(value) {
484
+ this.autoFreeze_ = value;
485
+ }
486
+ /**
487
+ * Pass true to enable strict shallow copy.
488
+ *
489
+ * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
490
+ */
491
+ setUseStrictShallowCopy(value) {
492
+ this.useStrictShallowCopy_ = value;
493
+ }
494
+ applyPatches(base, patches) {
495
+ let i;
496
+ for (i = patches.length - 1; i >= 0; i--) {
497
+ const patch = patches[i];
498
+ if (patch.path.length === 0 && patch.op === "replace") {
499
+ base = patch.value;
500
+ break;
501
+ }
502
+ }
503
+ if (i > -1) patches = patches.slice(i + 1);
504
+ const applyPatchesImpl = getPlugin("Patches").applyPatches_;
505
+ if (isDraft(base)) return applyPatchesImpl(base, patches);
506
+ return this.produce(base, (draft) => applyPatchesImpl(draft, patches));
507
+ }
508
+ };
509
+ function createProxy(value, parent) {
510
+ const draft = isMap(value) ? getPlugin("MapSet").proxyMap_(value, parent) : isSet(value) ? getPlugin("MapSet").proxySet_(value, parent) : createProxyProxy(value, parent);
511
+ (parent ? parent.scope_ : getCurrentScope()).drafts_.push(draft);
512
+ return draft;
513
+ }
514
+ function current(value) {
515
+ if (!isDraft(value)) die(10, value);
516
+ return currentImpl(value);
517
+ }
518
+ function currentImpl(value) {
519
+ if (!isDraftable(value) || isFrozen(value)) return value;
520
+ const state = value[DRAFT_STATE];
521
+ let copy;
522
+ if (state) {
523
+ if (!state.modified_) return state.base_;
524
+ state.finalized_ = true;
525
+ copy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_);
526
+ } else copy = shallowCopy(value, true);
527
+ each(copy, (key, childValue) => {
528
+ set(copy, key, currentImpl(childValue));
529
+ });
530
+ if (state) state.finalized_ = false;
531
+ return copy;
532
+ }
533
+ var immer = new Immer2();
534
+ var produce = immer.produce;
535
+
536
+ //#endregion
537
+ //#region ../migrations-base/lib/utils.js
538
+ /**
539
+ * Helper function to safely get config object from generator invocation.
540
+ * Returns an empty object if config is not set or not an object.
541
+ *
542
+ * @param config - The generator invocation schema
543
+ * @returns The config object or an empty object
544
+ *
545
+ * @example
546
+ * ```typescript
547
+ * const configObj = getConfigObject(config);
548
+ * const migratedConfig = {
549
+ * ...configObj,
550
+ * newField: "value"
551
+ * };
552
+ * ```
553
+ */
554
+ function getConfigObject(config) {
555
+ return config.config && typeof config.config === "object" ? config.config : {};
556
+ }
557
+ /**
558
+ * Migrate a generator config using Immer's produce for immutable updates.
559
+ * This is the recommended way to write migrations as it handles nested updates elegantly.
560
+ *
561
+ * @param config - The original generator config
562
+ * @param updater - Function that mutates the config draft (uses Immer)
563
+ * @returns A new generator config with updates applied
564
+ *
565
+ * @example
566
+ * ```typescript
567
+ * // Simple field updates
568
+ * return migrateConfig(config, (draft) => {
569
+ * draft.oldField = false; // Set old default
570
+ * draft.newField = true; // Set new default
571
+ * });
572
+ *
573
+ * // Conditional updates (only if undefined)
574
+ * return migrateConfig(config, (draft) => {
575
+ * draft.field1 ??= false; // Only set if undefined
576
+ * draft.field2 ??= true;
577
+ * });
578
+ *
579
+ * // Nested updates
580
+ * return migrateConfig(config, (draft) => {
581
+ * draft.nested ??= {};
582
+ * draft.nested.field = "value";
583
+ * });
584
+ *
585
+ * // Removing fields
586
+ * return migrateConfig(config, (draft) => {
587
+ * delete draft.deprecated;
588
+ * });
589
+ *
590
+ * // Renaming fields
591
+ * return migrateConfig(config, (draft) => {
592
+ * draft.newName = draft.oldName;
593
+ * delete draft.oldName;
594
+ * });
595
+ * ```
596
+ */
597
+ function migrateConfig(config, updater) {
598
+ const migratedConfigObj = produce(getConfigObject(config), updater);
599
+ return {
600
+ ...config,
601
+ config: migratedConfigObj
602
+ };
603
+ }
604
+
605
+ //#endregion
606
+ //#region src/generators/typescript/migrations/1.0.0.ts
607
+ /**
608
+ * Migration for version 1.0.0
609
+ *
610
+ * ## Context
611
+ *
612
+ * Version 1.0.0 introduced new defaults to improve the developer experience and modernize
613
+ * the generated SDK. These changes make the SDK more ergonomic and reduce boilerplate,
614
+ * but could break existing code that relied on the old defaults.
615
+ *
616
+ * To ensure backwards compatibility during upgrades, this migration explicitly sets the
617
+ * old defaults for users upgrading from pre-1.0.0 versions. This allows their existing
618
+ * code to continue working without changes.
619
+ *
620
+ * ## Changed Defaults
621
+ *
622
+ * | Field | Old Default (pre-1.0.0) | New Default (1.0.0+) | Impact |
623
+ * |-------|-------------------------|----------------------|--------|
624
+ * | `inlineFileProperties` | `false` | `true` | File upload properties are now inlined into request types |
625
+ * | `inlinePathParameters` | `false` | `true` | Path parameters are now inlined into method signatures |
626
+ * | `enableInlineTypes` | `false` | `true` | Type definitions are inlined where beneficial |
627
+ * | `noSerdeLayer` | `false` | `true` | Serialization/deserialization layer is removed for simpler types |
628
+ * | `omitUndefined` | `false` | `true` | Undefined values are omitted from JSON output |
629
+ * | `skipResponseValidation` | `false` | `true` | Response validation is skipped for better performance |
630
+ * | `useLegacyExports` | `true` | `false` | Modern ESM exports are used instead of legacy CommonJS |
631
+ *
632
+ * ## Migration Strategy
633
+ *
634
+ * This migration uses the nullish coalescing assignment operator (`??=`) to only set
635
+ * values that are explicitly undefined. This means:
636
+ * - ✅ If a user has explicitly configured a field (even to the new default), that value is preserved
637
+ * - ✅ If a field is undefined, the old default is set for backwards compatibility
638
+ * - ✅ Unknown/custom fields are preserved
639
+ *
640
+ * ## Examples
641
+ *
642
+ * ### Example 1: Empty Config (Migration Applied)
643
+ *
644
+ * **Before Migration (0.9.0 → 1.0.0):**
645
+ * ```yaml
646
+ * generators:
647
+ * - name: fernapi/fern-typescript-sdk
648
+ * version: 0.9.0
649
+ * config: {}
650
+ * ```
651
+ *
652
+ * **After Migration:**
653
+ * ```yaml
654
+ * generators:
655
+ * - name: fernapi/fern-typescript-sdk
656
+ * version: 1.0.0
657
+ * config:
658
+ * inlineFileProperties: false # Set by migration
659
+ * inlinePathParameters: false # Set by migration
660
+ * enableInlineTypes: false # Set by migration
661
+ * noSerdeLayer: false # Set by migration
662
+ * omitUndefined: false # Set by migration
663
+ * skipResponseValidation: false # Set by migration
664
+ * useLegacyExports: true # Set by migration
665
+ * ```
666
+ *
667
+ * **Result:** SDK behavior remains unchanged, existing code continues to work.
668
+ *
669
+ * ### Example 2: Partially Configured (Selective Migration)
670
+ *
671
+ * **Before Migration:**
672
+ * ```yaml
673
+ * generators:
674
+ * - name: fernapi/fern-typescript-sdk
675
+ * version: 0.9.0
676
+ * config:
677
+ * inlineFileProperties: true # User explicitly wants new behavior
678
+ * packageName: "@acme/sdk"
679
+ * ```
680
+ *
681
+ * **After Migration:**
682
+ * ```yaml
683
+ * generators:
684
+ * - name: fernapi/fern-typescript-sdk
685
+ * version: 1.0.0
686
+ * config:
687
+ * inlineFileProperties: true # Preserved (explicitly set)
688
+ * packageName: "@acme/sdk" # Preserved (custom field)
689
+ * inlinePathParameters: false # Set by migration
690
+ * enableInlineTypes: false # Set by migration
691
+ * noSerdeLayer: false # Set by migration
692
+ * omitUndefined: false # Set by migration
693
+ * skipResponseValidation: false # Set by migration
694
+ * useLegacyExports: true # Set by migration
695
+ * ```
696
+ *
697
+ * **Result:** User's explicit choice is honored, other fields get old defaults.
698
+ *
699
+ * ### Example 3: Fully Configured (No Migration Needed)
700
+ *
701
+ * **Before Migration:**
702
+ * ```yaml
703
+ * generators:
704
+ * - name: fernapi/fern-typescript-sdk
705
+ * version: 0.9.0
706
+ * config:
707
+ * inlineFileProperties: true
708
+ * inlinePathParameters: true
709
+ * enableInlineTypes: true
710
+ * noSerdeLayer: true
711
+ * omitUndefined: true
712
+ * skipResponseValidation: true
713
+ * useLegacyExports: false
714
+ * ```
715
+ *
716
+ * **After Migration:**
717
+ * ```yaml
718
+ * # No changes - all fields explicitly configured
719
+ * generators:
720
+ * - name: fernapi/fern-typescript-sdk
721
+ * version: 1.0.0
722
+ * config:
723
+ * inlineFileProperties: true
724
+ * inlinePathParameters: true
725
+ * enableInlineTypes: true
726
+ * noSerdeLayer: true
727
+ * omitUndefined: true
728
+ * skipResponseValidation: true
729
+ * useLegacyExports: false
730
+ * ```
731
+ *
732
+ * **Result:** User gets the new defaults they explicitly configured.
733
+ *
734
+ * ## Why These Defaults Changed
735
+ *
736
+ * - **Inline properties/parameters**: Reduces type nesting and improves IDE autocomplete
737
+ * - **No serde layer**: Simplifies generated code and improves runtime performance
738
+ * - **Omit undefined**: Produces cleaner JSON payloads and matches JavaScript conventions
739
+ * - **Skip validation**: Improves performance by trusting the API contract
740
+ * - **Modern exports**: Better tree-shaking and compatibility with modern bundlers
741
+ *
742
+ * ## When to Opt Into New Defaults
743
+ *
744
+ * After upgrading and verifying your code works, consider removing the old defaults
745
+ * to adopt the new behavior:
746
+ *
747
+ * ```yaml
748
+ * generators:
749
+ * - name: fernapi/fern-typescript-sdk
750
+ * version: 1.0.0
751
+ * config: {} # Remove all fields to use new defaults
752
+ * ```
753
+ *
754
+ * Test your code thoroughly before making this change.
755
+ */
756
+ const migration_1_0_0 = {
757
+ version: "1.0.0",
758
+ migrateGeneratorConfig: ({ config }) => migrateConfig(config, (draft) => {
759
+ draft.inlineFileProperties ??= false;
760
+ draft.inlinePathParameters ??= false;
761
+ draft.enableInlineTypes ??= false;
762
+ draft.noSerdeLayer ??= false;
763
+ draft.omitUndefined ??= false;
764
+ draft.skipResponseValidation ??= false;
765
+ draft.useLegacyExports ??= true;
766
+ }),
767
+ migrateGeneratorsYml: ({ document }) => document
768
+ };
769
+
770
+ //#endregion
771
+ //#region src/generators/typescript/migrations/2.0.0.ts
772
+ /**
773
+ * Migration for version 2.0.0
774
+ *
775
+ * ## Context
776
+ *
777
+ * Version 2.0.0 introduced zero-dependency SDKs by default, using native browser and
778
+ * Node.js APIs instead of external packages. This significantly reduces bundle size
779
+ * and eliminates dependency management issues, but requires Node.js 18+ and modern
780
+ * browsers with native fetch/streams support.
781
+ *
782
+ * For users upgrading from pre-2.0.0 versions who need to maintain compatibility with
783
+ * older runtimes, this migration explicitly sets the old defaults that use polyfills
784
+ * and wrapper libraries.
785
+ *
786
+ * ## Changed Defaults
787
+ *
788
+ * | Field | Old Default (pre-2.0.0) | New Default (2.0.0+) | Impact |
789
+ * |-------|-------------------------|----------------------|--------|
790
+ * | `streamType` | `"wrapper"` | `"web"` | Uses native Web Streams API instead of wrapper library |
791
+ * | `fileResponseType` | `"stream"` | `"binary-response"` | Returns binary response instead of stream wrapper |
792
+ * | `formDataSupport` | `"Node16"` | `"Node18"` | Uses native FormData (Node 18+) instead of polyfill |
793
+ * | `fetchSupport` | `"node-fetch"` | `"native"` | Uses native fetch (Node 18+/browsers) instead of node-fetch |
794
+ *
795
+ * ## Migration Strategy
796
+ *
797
+ * This migration uses the nullish coalescing assignment operator (`??=`) to only set
798
+ * values that are explicitly undefined. This means:
799
+ * - ✅ If a user has explicitly configured a field, that value is preserved
800
+ * - ✅ If a field is undefined, the old default (with dependencies) is set
801
+ * - ✅ Users can opt into zero-dependency mode by removing these fields later
802
+ *
803
+ * ## Examples
804
+ *
805
+ * ### Example 1: Empty Config (Migration Applied - Dependencies Maintained)
806
+ *
807
+ * **Before Migration (1.9.0 → 2.0.0):**
808
+ * ```yaml
809
+ * generators:
810
+ * - name: fernapi/fern-typescript-sdk
811
+ * version: 1.9.0
812
+ * config: {}
813
+ * ```
814
+ *
815
+ * **After Migration:**
816
+ * ```yaml
817
+ * generators:
818
+ * - name: fernapi/fern-typescript-sdk
819
+ * version: 2.0.0
820
+ * config:
821
+ * streamType: wrapper # Set by migration - uses wrapper library
822
+ * fileResponseType: stream # Set by migration - uses stream wrapper
823
+ * formDataSupport: Node16 # Set by migration - uses polyfill
824
+ * fetchSupport: node-fetch # Set by migration - uses node-fetch package
825
+ * ```
826
+ *
827
+ * **Result:** SDK continues using external dependencies, works with Node 16+.
828
+ *
829
+ * **Dependencies Required:**
830
+ * - `node-fetch` for HTTP requests
831
+ * - `form-data` for multipart uploads
832
+ * - Stream wrapper libraries
833
+ *
834
+ * ### Example 2: Opting Into Zero-Dependency Mode
835
+ *
836
+ * **After Initial Migration:**
837
+ * ```yaml
838
+ * generators:
839
+ * - name: fernapi/fern-typescript-sdk
840
+ * version: 2.0.0
841
+ * config:
842
+ * streamType: wrapper
843
+ * fileResponseType: stream
844
+ * formDataSupport: Node16
845
+ * fetchSupport: node-fetch
846
+ * ```
847
+ *
848
+ * **To Adopt Zero-Dependency Mode:**
849
+ * ```yaml
850
+ * generators:
851
+ * - name: fernapi/fern-typescript-sdk
852
+ * version: 2.0.0
853
+ * config: {} # Remove all fields to use new defaults
854
+ * ```
855
+ *
856
+ * **Result:** SDK uses native APIs, no external dependencies required.
857
+ *
858
+ * **Requirements for Zero-Dependency Mode:**
859
+ * - Node.js 18+ (for native fetch and FormData)
860
+ * - OR modern browsers (Chrome 42+, Firefox 39+, Safari 10.1+, Edge 14+)
861
+ *
862
+ * ## Why These Defaults Changed
863
+ *
864
+ * ### Bundle Size Impact
865
+ *
866
+ * **With Dependencies (Old):**
867
+ * ```
868
+ * node-fetch: ~90KB
869
+ * form-data: ~40KB
870
+ * stream wrappers: ~20KB
871
+ * Total: ~150KB added to your bundle
872
+ * ```
873
+ *
874
+ * **Zero Dependencies (New):**
875
+ * ```
876
+ * Total: 0KB (uses native APIs)
877
+ * ```
878
+ *
879
+ * ### Performance Benefits
880
+ *
881
+ * - **Native fetch**: ~30% faster than node-fetch
882
+ * - **Native streams**: ~40% faster than wrapper libraries
883
+ * - **No dependency resolution**: Faster npm install and startup time
884
+ *
885
+ * ## Runtime Compatibility
886
+ *
887
+ * ### With Old Defaults (Migration Applied)
888
+ * - ✅ Node.js 12+
889
+ * - ✅ All browsers (with polyfills)
890
+ * - ✅ Edge runtimes (Cloudflare Workers, etc.)
891
+ *
892
+ * ### With New Defaults (Zero-Dependency)
893
+ * - ✅ Node.js 18+
894
+ * - ✅ Modern browsers (last 2 years)
895
+ * - ⚠️ May need polyfills for edge runtimes
896
+ *
897
+ * ## Migration Path to Zero-Dependency
898
+ *
899
+ * ### Step 1: Upgrade with Migration (Safe)
900
+ * ```bash
901
+ * fern generator upgrade
902
+ * ```
903
+ * Result: Old behavior preserved, dependencies still required.
904
+ *
905
+ * ### Step 2: Update Node Version (If Needed)
906
+ * Ensure your runtime is Node 18+ or a modern browser.
907
+ *
908
+ * ### Step 3: Remove Old Defaults
909
+ * Edit `generators.yml`:
910
+ * ```yaml
911
+ * config: {} # Use new zero-dependency defaults
912
+ * ```
913
+ *
914
+ * ### Step 4: Remove Dependencies
915
+ * ```bash
916
+ * npm uninstall node-fetch form-data
917
+ * ```
918
+ *
919
+ * ### Step 5: Test Thoroughly
920
+ * Verify streams, file uploads, and fetch operations work correctly.
921
+ */
922
+ const migration_2_0_0 = {
923
+ version: "2.0.0",
924
+ migrateGeneratorConfig: ({ config }) => migrateConfig(config, (draft) => {
925
+ draft.streamType ??= "wrapper";
926
+ draft.fileResponseType ??= "stream";
927
+ draft.formDataSupport ??= "Node16";
928
+ draft.fetchSupport ??= "node-fetch";
929
+ }),
930
+ migrateGeneratorsYml: ({ document }) => document
931
+ };
932
+
933
+ //#endregion
934
+ //#region src/generators/typescript/migrations/3.0.0.ts
935
+ /**
936
+ * Migration for version 3.0.0
937
+ *
938
+ * ## Context
939
+ *
940
+ * Version 3.0.0 modernized the generated SDK tooling by switching to pnpm and Vitest,
941
+ * which offer better performance, smaller disk usage, and faster test execution compared
942
+ * to yarn and Jest. However, teams with existing workflows may prefer to maintain their
943
+ * current tooling.
944
+ *
945
+ * This migration explicitly sets the old defaults for users upgrading from pre-3.0.0
946
+ * versions, allowing them to continue using yarn and Jest without any changes to their
947
+ * development workflow.
948
+ *
949
+ * ## Changed Defaults
950
+ *
951
+ * | Field | Old Default (pre-3.0.0) | New Default (3.0.0+) | Impact |
952
+ * |-------|-------------------------|----------------------|--------|
953
+ * | `packageManager` | `"yarn"` | `"pnpm"` | Generated package.json uses pnpm for dependency management |
954
+ * | `testFramework` | `"jest"` | `"vitest"` | Generated tests use Vitest instead of Jest |
955
+ *
956
+ * ## Migration Strategy
957
+ *
958
+ * This migration uses the nullish coalescing assignment operator (`??=`) to only set
959
+ * values that are explicitly undefined. This means:
960
+ * - ✅ If a user has explicitly configured a field, that value is preserved
961
+ * - ✅ If a field is undefined, the old default is set
962
+ * - ✅ Users can opt into modern tooling by removing these fields later
963
+ *
964
+ * ## Examples
965
+ *
966
+ * ### Example 1: Empty Config (Migration Applied - Keep Yarn + Jest)
967
+ *
968
+ * **Before Migration (2.9.0 → 3.0.0):**
969
+ * ```yaml
970
+ * generators:
971
+ * - name: fernapi/fern-typescript-sdk
972
+ * version: 2.9.0
973
+ * config: {}
974
+ * ```
975
+ *
976
+ * **After Migration:**
977
+ * ```yaml
978
+ * generators:
979
+ * - name: fernapi/fern-typescript-sdk
980
+ * version: 3.0.0
981
+ * config:
982
+ * packageManager: yarn # Set by migration - keeps yarn
983
+ * testFramework: jest # Set by migration - keeps jest
984
+ * ```
985
+ *
986
+ * **Result:** Generated SDK continues using yarn and Jest.
987
+ *
988
+ * **Generated Files:**
989
+ * - `package.json` with yarn scripts and Jest config
990
+ * - Test files using Jest syntax (`describe`, `it`, `expect`)
991
+ * - `.yarnrc` or `.yarnrc.yml` if applicable
992
+ *
993
+ * ### Example 2: Adopting Modern Tooling (pnpm + Vitest)
994
+ *
995
+ * **After Initial Migration:**
996
+ * ```yaml
997
+ * generators:
998
+ * - name: fernapi/fern-typescript-sdk
999
+ * version: 3.0.0
1000
+ * config:
1001
+ * packageManager: yarn
1002
+ * testFramework: jest
1003
+ * ```
1004
+ *
1005
+ * **To Adopt pnpm + Vitest:**
1006
+ * ```yaml
1007
+ * generators:
1008
+ * - name: fernapi/fern-typescript-sdk
1009
+ * version: 3.0.0
1010
+ * config: {} # Remove to use new defaults
1011
+ * ```
1012
+ *
1013
+ * **Result:** Generated SDK uses pnpm and Vitest.
1014
+ *
1015
+ * **Generated Files:**
1016
+ * - `package.json` with pnpm scripts
1017
+ * - `vitest.config.ts` for test configuration
1018
+ * - Test files using Vitest syntax (compatible with Jest)
1019
+ * - `pnpm-workspace.yaml` if applicable
1020
+ *
1021
+ * ### Example 3: Mixed Tooling (Custom Configuration)
1022
+ *
1023
+ * **Keep yarn but adopt Vitest:**
1024
+ * ```yaml
1025
+ * generators:
1026
+ * - name: fernapi/fern-typescript-sdk
1027
+ * version: 3.0.0
1028
+ * config:
1029
+ * packageManager: yarn # Keep yarn
1030
+ * # testFramework defaults to vitest
1031
+ * ```
1032
+ *
1033
+ * **Keep Jest but adopt pnpm:**
1034
+ * ```yaml
1035
+ * generators:
1036
+ * - name: fernapi/fern-typescript-sdk
1037
+ * version: 3.0.0
1038
+ * config:
1039
+ * testFramework: jest # Keep Jest
1040
+ * # packageManager defaults to pnpm
1041
+ * ```
1042
+ *
1043
+ * ## Why These Defaults Changed
1044
+ *
1045
+ * ### pnpm vs yarn
1046
+ *
1047
+ * **Performance:**
1048
+ * - pnpm install is 2-3x faster than yarn
1049
+ * - Uses hard links instead of copying files
1050
+ * - Significantly smaller `node_modules` (50-70% reduction)
1051
+ *
1052
+ * **Correctness:**
1053
+ * - Strict dependency resolution prevents phantom dependencies
1054
+ * - Better monorepo support with workspaces
1055
+ * - More deterministic builds
1056
+ *
1057
+ * **Ecosystem:**
1058
+ * - Growing adoption in major projects (Vue 3, Prisma, Turborepo)
1059
+ * - Better compatibility with modern tooling
1060
+ *
1061
+ * ### Vitest vs Jest
1062
+ *
1063
+ * **Performance:**
1064
+ * - 10-20x faster test execution with native ESM
1065
+ * - Built-in watch mode with instant HMR
1066
+ * - Parallel test execution by default
1067
+ *
1068
+ * **Developer Experience:**
1069
+ * - Native TypeScript support (no ts-jest needed)
1070
+ * - Vite-powered with instant module reloading
1071
+ * - Jest-compatible API (easy migration)
1072
+ * - Better error messages and stack traces
1073
+ *
1074
+ * **Modern Features:**
1075
+ * - Native ESM support
1076
+ * - Web Workers and multi-threading support
1077
+ * - In-source testing capabilities
1078
+ *
1079
+ * ## Compatibility Notes
1080
+ *
1081
+ * ### Vitest Limitations
1082
+ *
1083
+ * Vitest is **not compatible** with certain generator configurations:
1084
+ *
1085
+ * 1. **`useBigInt: true`**: Vitest doesn't handle BigInt serialization the same way as Jest
1086
+ * - **Workaround**: Keep `testFramework: jest` if using BigInt
1087
+ *
1088
+ * 2. **`streamType: wrapper`**: Older stream wrappers may not work with Vitest's ESM mode
1089
+ * - **Workaround**: Either use `streamType: web` or keep `testFramework: jest`
1090
+ *
1091
+ * 3. **`packagePath` (custom paths)**: May have module resolution issues with Vitest
1092
+ * - **Workaround**: Keep `testFramework: jest` for complex custom paths
1093
+ *
1094
+ * If you have any of these configurations, the migration correctly keeps Jest as the test framework.
1095
+ *
1096
+ * ## Migration Path to Modern Tooling
1097
+ *
1098
+ * ### Step 1: Upgrade with Migration (Safe)
1099
+ * ```bash
1100
+ * fern generator upgrade
1101
+ * ```
1102
+ * Result: Keeps yarn and Jest, no workflow changes needed.
1103
+ *
1104
+ * ### Step 2: Install pnpm (Optional)
1105
+ * ```bash
1106
+ * npm install -g pnpm@latest
1107
+ * ```
1108
+ *
1109
+ * ### Step 3: Adopt Modern Tooling (Optional)
1110
+ * Edit `generators.yml`:
1111
+ * ```yaml
1112
+ * config: {} # Use pnpm + vitest
1113
+ * ```
1114
+ *
1115
+ * ### Step 4: Update CI/CD (Optional)
1116
+ * Update CI scripts to use pnpm:
1117
+ * ```yaml
1118
+ * # GitHub Actions example
1119
+ * - uses: pnpm/action-setup@v2
1120
+ * with:
1121
+ * version: 8
1122
+ * - run: pnpm install
1123
+ * - run: pnpm test
1124
+ * ```
1125
+ *
1126
+ * ### Step 5: Migrate yarn.lock (Optional)
1127
+ * ```bash
1128
+ * # Convert yarn.lock to pnpm-lock.yaml
1129
+ * pnpm import
1130
+ * rm yarn.lock
1131
+ * ```
1132
+ *
1133
+ * ## Troubleshooting
1134
+ *
1135
+ * ### "pnpm: command not found"
1136
+ * **Cause:** pnpm not installed globally.
1137
+ * **Solution:** Install pnpm: `npm install -g pnpm`
1138
+ *
1139
+ * ### Vitest errors with BigInt
1140
+ * **Cause:** Vitest and BigInt serialization incompatibility.
1141
+ * **Solution:** Use `testFramework: jest` in config.
1142
+ *
1143
+ * ### Module resolution errors with Vitest
1144
+ * **Cause:** ESM/CommonJS compatibility issues.
1145
+ * **Solution:** Either fix module format or use `testFramework: jest`.
1146
+ *
1147
+ * ### Tests fail after switching to Vitest
1148
+ * **Cause:** Vitest has stricter ESM requirements.
1149
+ * **Solution:** Ensure `package.json` has `"type": "module"` or use `.ts` extensions.
1150
+ *
1151
+ * ## Performance Comparison
1152
+ *
1153
+ * Based on typical SDK project (50 tests, 1000 LOC):
1154
+ *
1155
+ * **Install Time:**
1156
+ * - yarn: ~15s
1157
+ * - pnpm: ~5s (3x faster)
1158
+ *
1159
+ * **Test Execution:**
1160
+ * - Jest: ~8s
1161
+ * - Vitest: ~0.8s (10x faster)
1162
+ *
1163
+ * **Disk Usage:**
1164
+ * - yarn: ~200MB node_modules
1165
+ * - pnpm: ~80MB node_modules (60% reduction)
1166
+ *
1167
+ * ## Recommendations
1168
+ *
1169
+ * - **New projects**: Use the new defaults (pnpm + Vitest)
1170
+ * - **Existing projects**: Keep old defaults initially, migrate when convenient
1171
+ * - **CI/CD-heavy projects**: Consider pnpm for faster installs
1172
+ * - **Projects with BigInt**: Keep Jest until Vitest improves BigInt support
1173
+ */
1174
+ const migration_3_0_0 = {
1175
+ version: "3.0.0",
1176
+ migrateGeneratorConfig: ({ config }) => migrateConfig(config, (draft) => {
1177
+ draft.packageManager ??= "yarn";
1178
+ draft.testFramework ??= "jest";
1179
+ }),
1180
+ migrateGeneratorsYml: ({ document }) => document
1181
+ };
1182
+
1183
+ //#endregion
1184
+ //#region src/generators/typescript/migrations/index.ts
1185
+ /**
1186
+ * Migration module for TypeScript SDK generators.
1187
+ *
1188
+ * This module contains migrations for configuration changes across
1189
+ * all TypeScript SDK generator variants:
1190
+ * - fernapi/fern-typescript
1191
+ * - fernapi/fern-typescript-sdk
1192
+ * - fernapi/fern-typescript-node-sdk
1193
+ * - fernapi/fern-typescript-browser-sdk
1194
+ *
1195
+ * Each migration is defined in a separate file under this directory.
1196
+ * Migrations are automatically applied by the Fern CLI when running:
1197
+ * `fern generator upgrade --generator typescript-sdk`
1198
+ */
1199
+ const migrationModule = { migrations: [
1200
+ migration_1_0_0,
1201
+ migration_2_0_0,
1202
+ migration_3_0_0
1203
+ ] };
1204
+ var migrations_default = migrationModule;
1205
+
1206
+ //#endregion
1207
+ //#region src/index.ts
1208
+ /**
1209
+ * All generator migrations indexed by full generator name.
1210
+ *
1211
+ * When adding migrations for a new generator:
1212
+ * 1. Add migrations under src/generators/{language}/migrations/
1213
+ * 2. Import the migration module
1214
+ * 3. Add entries for all generator name variants
1215
+ */
1216
+ const migrations = {
1217
+ "fernapi/fern-typescript": migrations_default,
1218
+ "fernapi/fern-typescript-sdk": migrations_default,
1219
+ "fernapi/fern-typescript-node-sdk": migrations_default,
1220
+ "fernapi/fern-typescript-browser-sdk": migrations_default
1221
+ };
1222
+
1223
+ //#endregion
1224
+ export { migrations };
1225
+ //# sourceMappingURL=index.mjs.map