@fern-api/generator-cli 0.4.6 → 0.5.0

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/api.cjs CHANGED
@@ -6088,6 +6088,11 @@ var ClonedRepository = class _ClonedRepository {
6088
6088
  this.clonePath = clonePath;
6089
6089
  this.git = git;
6090
6090
  }
6091
+ async setUserAndEmail({ name, email }) {
6092
+ await this.git.cwd(this.clonePath);
6093
+ await this.git.addConfig("user.name", name);
6094
+ await this.git.addConfig("user.email", email);
6095
+ }
6091
6096
  static createAtPath(clonePath) {
6092
6097
  return new _ClonedRepository({
6093
6098
  clonePath,
@@ -6156,9 +6161,78 @@ var ClonedRepository = class _ClonedRepository {
6156
6161
  await this.git.cwd(this.clonePath);
6157
6162
  await this.git.pull("origin", branch);
6158
6163
  }
6164
+ async pullWithMerge(branch) {
6165
+ await this.git.cwd(this.clonePath);
6166
+ await this.git.raw(["pull", "origin", branch, "--no-rebase"]);
6167
+ }
6159
6168
  async push() {
6160
6169
  await this.git.cwd(this.clonePath);
6161
- await this.git.push();
6170
+ const currentBranch = await this.getCurrentBranch();
6171
+ try {
6172
+ await this.git.push();
6173
+ } catch (err) {
6174
+ const msg = String(err);
6175
+ const isNoUpstream = msg.includes("has no upstream branch") || msg.includes("no upstream branch");
6176
+ if (isNoUpstream) {
6177
+ await this.pushUpstream(currentBranch);
6178
+ return;
6179
+ }
6180
+ throw err;
6181
+ }
6182
+ }
6183
+ async pushWithMergingRemote() {
6184
+ await this.git.cwd(this.clonePath);
6185
+ const currentBranch = await this.getCurrentBranch();
6186
+ const isRemoteReject = (msg) => msg.includes("fetch first") || msg.includes("Updates were rejected") || msg.includes("non-fast-forward");
6187
+ const isDivergent = (msg) => msg.includes("divergent branches") || msg.includes("You have divergent branches");
6188
+ try {
6189
+ await this.push();
6190
+ } catch (err) {
6191
+ const errMsg = String(err);
6192
+ if (isRemoteReject(errMsg)) {
6193
+ try {
6194
+ await this.pull(currentBranch);
6195
+ await this.push();
6196
+ return;
6197
+ } catch (pullErr) {
6198
+ const pullMsg = String(pullErr);
6199
+ if (isDivergent(pullMsg)) {
6200
+ try {
6201
+ await this.pullWithMerge(currentBranch);
6202
+ await this.push();
6203
+ return;
6204
+ } catch (mergeErr) {
6205
+ throw err;
6206
+ }
6207
+ } else {
6208
+ throw err;
6209
+ }
6210
+ }
6211
+ } else {
6212
+ throw err;
6213
+ }
6214
+ }
6215
+ }
6216
+ async pushWithRebasingRemote() {
6217
+ await this.git.cwd(this.clonePath);
6218
+ const currentBranch = await this.getCurrentBranch();
6219
+ const isRemoteReject = (msg) => msg.includes("fetch first") || msg.includes("Updates were rejected") || msg.includes("non-fast-forward");
6220
+ try {
6221
+ await this.push();
6222
+ } catch (err) {
6223
+ const errMsg = String(err);
6224
+ if (isRemoteReject(errMsg)) {
6225
+ try {
6226
+ await this.git.raw(["pull", "origin", currentBranch, "--rebase"]);
6227
+ await this.push();
6228
+ return;
6229
+ } catch (pullErr) {
6230
+ throw new Error(`Push failed: ${errMsg}. Attempted to rebase but that also failed: ${String(pullErr)}`);
6231
+ }
6232
+ } else {
6233
+ throw err;
6234
+ }
6235
+ }
6162
6236
  }
6163
6237
  async isRemoteEmpty() {
6164
6238
  await this.git.cwd(this.clonePath);
@@ -6177,6 +6251,18 @@ var ClonedRepository = class _ClonedRepository {
6177
6251
  await this.git.checkoutLocalBranch(branch);
6178
6252
  }
6179
6253
  }
6254
+ async checkoutRemoteBranch(branch) {
6255
+ await this.git.cwd(this.clonePath);
6256
+ try {
6257
+ await this.git.checkout(branch);
6258
+ } catch (_error) {
6259
+ try {
6260
+ await this.git.checkout(["-b", branch, `origin/${branch}`]);
6261
+ } catch (_remoteError) {
6262
+ await this.git.checkoutLocalBranch(branch);
6263
+ }
6264
+ }
6265
+ }
6180
6266
  async pushUpstream(branch) {
6181
6267
  await this.git.cwd(this.clonePath);
6182
6268
  await this.git.push("origin", branch, { "--set-upstream": null });
@@ -6781,7 +6867,8 @@ var import_fs = __toESM(require("fs"), 1);
6781
6867
  var Writer = class {
6782
6868
  async writeCodeBlock(language, content) {
6783
6869
  await this.writeLine(`\`\`\`${language}`);
6784
- await this.write(content);
6870
+ const normalizedContent = content.endsWith("\n") ? content : content + "\n";
6871
+ await this.write(normalizedContent);
6785
6872
  await this.writeLine("```");
6786
6873
  }
6787
6874
  async writeLine(content) {
@@ -7124,7 +7211,23 @@ var ReadmeGenerator = class {
7124
7211
  if (index > 0) {
7125
7212
  await writer.writeLine();
7126
7213
  }
7127
- await writer.writeCodeBlock(this.readmeConfig.language.type, snippet);
7214
+ if (typeof snippet === "string") {
7215
+ await writer.writeCodeBlock(this.readmeConfig.language.type, snippet);
7216
+ } else {
7217
+ switch (snippet.type) {
7218
+ case "markdown":
7219
+ await writer.writeLine(snippet.content);
7220
+ break;
7221
+ case "code":
7222
+ await writer.writeCodeBlock(
7223
+ snippet.language ?? this.readmeConfig.language.type,
7224
+ snippet.content
7225
+ );
7226
+ break;
7227
+ default:
7228
+ assertNever(snippet);
7229
+ }
7230
+ }
7128
7231
  }
7129
7232
  if (feature.addendum != null) {
7130
7233
  await writer.writeLine(feature.addendum);
@@ -7160,6 +7263,15 @@ var ReadmeGenerator = class {
7160
7263
  githubRepository: this.readmeConfig.remote.repoUrl,
7161
7264
  installationToken: this.readmeConfig.remote.installationToken
7162
7265
  });
7266
+ if (this.readmeConfig.remote.branch != null) {
7267
+ try {
7268
+ await clonedRepository.checkout(this.readmeConfig.remote.branch);
7269
+ } catch (error) {
7270
+ console.warn(
7271
+ `Failed to checkout branch ${this.readmeConfig.remote.branch}, using default branch instead`
7272
+ );
7273
+ }
7274
+ }
7163
7275
  return await clonedRepository.getReadme();
7164
7276
  }
7165
7277
  return void 0;
package/dist/api.d.cts CHANGED
@@ -158,6 +158,8 @@ interface GithubRemote {
158
158
  repoUrl: string;
159
159
  /** The token used to clone the GitHub repository. */
160
160
  installationToken: string;
161
+ /** The branch to clone from. If not specified, the default branch will be used. */
162
+ branch?: string;
161
163
  }
162
164
 
163
165
  /**
@@ -168,7 +170,7 @@ interface GithubRemote {
168
170
  * A single feature supported by a generator (e.g. PAGINATION).
169
171
  */
170
172
  interface ReadmeFeature extends FeatureSpec {
171
- snippets?: string[];
173
+ snippets?: Snippet[];
172
174
  /**
173
175
  * If true, the feature block should be rendered even if we don't receive a snippet for it.
174
176
  * This is useful for features that are always supported, but might not require a snippet
@@ -177,6 +179,44 @@ interface ReadmeFeature extends FeatureSpec {
177
179
  snippetsAreOptional: boolean;
178
180
  }
179
181
 
182
+ /**
183
+ * This file was auto-generated by Fern from our API Definition.
184
+ */
185
+
186
+ /**
187
+ * A snippet that can be either a plain string (treated as code in the generator's language),
188
+ * markdown content, or a code block with optional language override.
189
+ * Plain strings are supported for backwards compatibility.
190
+ */
191
+ type Snippet = string | MarkdownSnippet | CodeSnippet;
192
+
193
+ /**
194
+ * This file was auto-generated by Fern from our API Definition.
195
+ */
196
+ /**
197
+ * A markdown snippet that will be rendered as-is without code fences.
198
+ */
199
+ interface MarkdownSnippet {
200
+ /** Discriminator field to identify this as a markdown snippet. */
201
+ type: "markdown";
202
+ content: string;
203
+ }
204
+
205
+ /**
206
+ * This file was auto-generated by Fern from our API Definition.
207
+ */
208
+ /**
209
+ * A code snippet that will be wrapped in a code fence with the specified language.
210
+ * If no language is specified, the generator's language will be used.
211
+ */
212
+ interface CodeSnippet {
213
+ /** Discriminator field to identify this as a code snippet. */
214
+ type: "code";
215
+ content: string;
216
+ /** The language for the code fence. If not specified, the generator's language will be used. */
217
+ language?: string;
218
+ }
219
+
180
220
  /**
181
221
  * This file was auto-generated by Fern from our API Definition.
182
222
  */
package/dist/cli.cjs CHANGED
@@ -12227,6 +12227,11 @@ var ClonedRepository = class _ClonedRepository {
12227
12227
  this.clonePath = clonePath;
12228
12228
  this.git = git;
12229
12229
  }
12230
+ async setUserAndEmail({ name, email }) {
12231
+ await this.git.cwd(this.clonePath);
12232
+ await this.git.addConfig("user.name", name);
12233
+ await this.git.addConfig("user.email", email);
12234
+ }
12230
12235
  static createAtPath(clonePath) {
12231
12236
  return new _ClonedRepository({
12232
12237
  clonePath,
@@ -12295,9 +12300,78 @@ var ClonedRepository = class _ClonedRepository {
12295
12300
  await this.git.cwd(this.clonePath);
12296
12301
  await this.git.pull("origin", branch);
12297
12302
  }
12303
+ async pullWithMerge(branch) {
12304
+ await this.git.cwd(this.clonePath);
12305
+ await this.git.raw(["pull", "origin", branch, "--no-rebase"]);
12306
+ }
12298
12307
  async push() {
12299
12308
  await this.git.cwd(this.clonePath);
12300
- await this.git.push();
12309
+ const currentBranch = await this.getCurrentBranch();
12310
+ try {
12311
+ await this.git.push();
12312
+ } catch (err) {
12313
+ const msg = String(err);
12314
+ const isNoUpstream = msg.includes("has no upstream branch") || msg.includes("no upstream branch");
12315
+ if (isNoUpstream) {
12316
+ await this.pushUpstream(currentBranch);
12317
+ return;
12318
+ }
12319
+ throw err;
12320
+ }
12321
+ }
12322
+ async pushWithMergingRemote() {
12323
+ await this.git.cwd(this.clonePath);
12324
+ const currentBranch = await this.getCurrentBranch();
12325
+ const isRemoteReject = (msg) => msg.includes("fetch first") || msg.includes("Updates were rejected") || msg.includes("non-fast-forward");
12326
+ const isDivergent = (msg) => msg.includes("divergent branches") || msg.includes("You have divergent branches");
12327
+ try {
12328
+ await this.push();
12329
+ } catch (err) {
12330
+ const errMsg = String(err);
12331
+ if (isRemoteReject(errMsg)) {
12332
+ try {
12333
+ await this.pull(currentBranch);
12334
+ await this.push();
12335
+ return;
12336
+ } catch (pullErr) {
12337
+ const pullMsg = String(pullErr);
12338
+ if (isDivergent(pullMsg)) {
12339
+ try {
12340
+ await this.pullWithMerge(currentBranch);
12341
+ await this.push();
12342
+ return;
12343
+ } catch (mergeErr) {
12344
+ throw err;
12345
+ }
12346
+ } else {
12347
+ throw err;
12348
+ }
12349
+ }
12350
+ } else {
12351
+ throw err;
12352
+ }
12353
+ }
12354
+ }
12355
+ async pushWithRebasingRemote() {
12356
+ await this.git.cwd(this.clonePath);
12357
+ const currentBranch = await this.getCurrentBranch();
12358
+ const isRemoteReject = (msg) => msg.includes("fetch first") || msg.includes("Updates were rejected") || msg.includes("non-fast-forward");
12359
+ try {
12360
+ await this.push();
12361
+ } catch (err) {
12362
+ const errMsg = String(err);
12363
+ if (isRemoteReject(errMsg)) {
12364
+ try {
12365
+ await this.git.raw(["pull", "origin", currentBranch, "--rebase"]);
12366
+ await this.push();
12367
+ return;
12368
+ } catch (pullErr) {
12369
+ throw new Error(`Push failed: ${errMsg}. Attempted to rebase but that also failed: ${String(pullErr)}`);
12370
+ }
12371
+ } else {
12372
+ throw err;
12373
+ }
12374
+ }
12301
12375
  }
12302
12376
  async isRemoteEmpty() {
12303
12377
  await this.git.cwd(this.clonePath);
@@ -12316,6 +12390,18 @@ var ClonedRepository = class _ClonedRepository {
12316
12390
  await this.git.checkoutLocalBranch(branch);
12317
12391
  }
12318
12392
  }
12393
+ async checkoutRemoteBranch(branch) {
12394
+ await this.git.cwd(this.clonePath);
12395
+ try {
12396
+ await this.git.checkout(branch);
12397
+ } catch (_error) {
12398
+ try {
12399
+ await this.git.checkout(["-b", branch, `origin/${branch}`]);
12400
+ } catch (_remoteError) {
12401
+ await this.git.checkoutLocalBranch(branch);
12402
+ }
12403
+ }
12404
+ }
12319
12405
  async pushUpstream(branch) {
12320
12406
  await this.git.cwd(this.clonePath);
12321
12407
  await this.git.push("origin", branch, { "--set-upstream": null });
@@ -12920,7 +13006,8 @@ var import_fs5 = __toESM(require("fs"), 1);
12920
13006
  var Writer = class {
12921
13007
  async writeCodeBlock(language, content) {
12922
13008
  await this.writeLine(`\`\`\`${language}`);
12923
- await this.write(content);
13009
+ const normalizedContent = content.endsWith("\n") ? content : content + "\n";
13010
+ await this.write(normalizedContent);
12924
13011
  await this.writeLine("```");
12925
13012
  }
12926
13013
  async writeLine(content) {
@@ -13263,7 +13350,23 @@ var ReadmeGenerator = class {
13263
13350
  if (index > 0) {
13264
13351
  await writer.writeLine();
13265
13352
  }
13266
- await writer.writeCodeBlock(this.readmeConfig.language.type, snippet);
13353
+ if (typeof snippet === "string") {
13354
+ await writer.writeCodeBlock(this.readmeConfig.language.type, snippet);
13355
+ } else {
13356
+ switch (snippet.type) {
13357
+ case "markdown":
13358
+ await writer.writeLine(snippet.content);
13359
+ break;
13360
+ case "code":
13361
+ await writer.writeCodeBlock(
13362
+ snippet.language ?? this.readmeConfig.language.type,
13363
+ snippet.content
13364
+ );
13365
+ break;
13366
+ default:
13367
+ assertNever(snippet);
13368
+ }
13369
+ }
13267
13370
  }
13268
13371
  if (feature.addendum != null) {
13269
13372
  await writer.writeLine(feature.addendum);
@@ -13299,6 +13402,15 @@ var ReadmeGenerator = class {
13299
13402
  githubRepository: this.readmeConfig.remote.repoUrl,
13300
13403
  installationToken: this.readmeConfig.remote.installationToken
13301
13404
  });
13405
+ if (this.readmeConfig.remote.branch != null) {
13406
+ try {
13407
+ await clonedRepository.checkout(this.readmeConfig.remote.branch);
13408
+ } catch (error) {
13409
+ console.warn(
13410
+ `Failed to checkout branch ${this.readmeConfig.remote.branch}, using default branch instead`
13411
+ );
13412
+ }
13413
+ }
13302
13414
  return await clonedRepository.getReadme();
13303
13415
  }
13304
13416
  return void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fern-api/generator-cli",
3
- "version": "0.4.6",
3
+ "version": "0.5.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/fern-api/fern"