@fern-api/fern-api-dev 5.45.3 → 5.46.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.
Files changed (2) hide show
  1. package/cli.cjs +290 -132
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -422248,15 +422248,19 @@ var require_AutoVersionStep = __commonJS({
422248
422248
  analysis: { versionBump: "PATCH", message: this.brandMessage("SDK regeneration") }
422249
422249
  });
422250
422250
  }
422251
- const chunks = service.chunkDiff(cleanedDiff, index_1.MAX_AI_DIFF_BYTES);
422252
- const cappedChunks = chunks.slice(0, index_1.MAX_CHUNKS);
422253
- const skippedChunks = chunks.length - cappedChunks.length;
422254
- if (chunks.length > 1) {
422255
- this.logger.info(`AutoVersionStep: split diff into ${chunks.length} chunks` + (skippedChunks > 0 ? ` (capped at ${index_1.MAX_CHUNKS}, skipping ${skippedChunks})` : ""));
422256
- }
422257
422251
  let analysis;
422258
422252
  try {
422259
- analysis = cappedChunks.length <= 1 ? await this.analyzeSingle(cleanedDiff, language, previousVersion) : await this.analyzeChunks(cappedChunks, language, previousVersion);
422253
+ if (this.config.ai == null && this.config.fernToken != null) {
422254
+ analysis = await this.analyzeViaFaiService(cleanedDiff, language, previousVersion);
422255
+ } else {
422256
+ const chunks = service.chunkDiff(cleanedDiff, index_1.MAX_AI_DIFF_BYTES);
422257
+ const cappedChunks = chunks.slice(0, index_1.MAX_CHUNKS);
422258
+ const skippedChunks = chunks.length - cappedChunks.length;
422259
+ if (chunks.length > 1) {
422260
+ this.logger.info(`AutoVersionStep: split diff into ${chunks.length} chunks` + (skippedChunks > 0 ? ` (capped at ${index_1.MAX_CHUNKS}, skipping ${skippedChunks})` : ""));
422261
+ }
422262
+ analysis = cappedChunks.length <= 1 ? await this.analyzeSingle(cleanedDiff, language, previousVersion) : await this.analyzeChunks(cappedChunks, language, previousVersion);
422263
+ }
422260
422264
  } catch (error50) {
422261
422265
  this.logger.warn(`AutoVersionStep: FAI analysis failed (${String(error50)}); falling back to PATCH bump.`);
422262
422266
  analysis = { versionBump: "PATCH", message: this.brandMessage("SDK regeneration") };
@@ -422518,6 +422522,47 @@ ${newBlock}${remainder}`;
422518
422522
  };
422519
422523
  }
422520
422524
  }
422525
+ /**
422526
+ * Calls the hosted FAI service (`/sdks/analyze-commit-diff`) with the fern token.
422527
+ * Used when no BAML `ai` config is supplied (remote generation via fiddle). FAI
422528
+ * handles chunking, parallelism, and retries server-side. Returns null on
422529
+ * NO_CHANGE; throws on transport/HTTP errors so the caller's PATCH fallback applies.
422530
+ */
422531
+ async analyzeViaFaiService(cleanedDiff, language, previousVersion) {
422532
+ const baseUrl = this.config.faiBaseUrl ?? "https://fai.buildwithfern.com";
422533
+ const response = await fetch(`${baseUrl}/sdks/analyze-commit-diff`, {
422534
+ method: "POST",
422535
+ headers: {
422536
+ Authorization: `Bearer ${this.config.fernToken}`,
422537
+ "Content-Type": "application/json"
422538
+ },
422539
+ body: JSON.stringify({
422540
+ diff: cleanedDiff,
422541
+ language,
422542
+ previous_version: previousVersion,
422543
+ prior_changelog: this.config.priorChangelog ?? void 0,
422544
+ spec_commit_message: this.config.specCommitMessage ?? void 0
422545
+ })
422546
+ });
422547
+ if (!response.ok) {
422548
+ const body = await response.text().catch(() => "");
422549
+ throw new Error(`FAI analyze-commit-diff failed with status ${response.status}: ${body.slice(0, 500)}`);
422550
+ }
422551
+ const parsed = await response.json();
422552
+ if (!isFaiAnalyzeResponse(parsed)) {
422553
+ throw new Error("FAI analyze-commit-diff returned an unexpected response shape");
422554
+ }
422555
+ if (parsed.version_bump === "NO_CHANGE") {
422556
+ return null;
422557
+ }
422558
+ return {
422559
+ versionBump: parsed.version_bump,
422560
+ message: this.brandMessage(parsed.message),
422561
+ changelogEntry: nonEmpty2(parsed.changelog_entry),
422562
+ prDescription: nonEmpty2(parsed.pr_description),
422563
+ versionBumpReason: nonEmpty2(parsed.version_bump_reason)
422564
+ };
422565
+ }
422521
422566
  /**
422522
422567
  * Dynamically imports @fern-api/cli-ai only when autoversion actually needs to
422523
422568
  * call FAI. The package is ESM-only with extensionless internal imports, so
@@ -422560,6 +422605,20 @@ ${newBlock}${remainder}`;
422560
422605
  }
422561
422606
  };
422562
422607
  exports2.AutoVersionStep = AutoVersionStep;
422608
+ var FAI_VERSION_BUMPS = ["MAJOR", "MINOR", "PATCH", "NO_CHANGE"];
422609
+ function isFaiAnalyzeResponse(value2) {
422610
+ if (typeof value2 !== "object" || value2 == null) {
422611
+ return false;
422612
+ }
422613
+ const candidate = value2;
422614
+ return typeof candidate.message === "string" && typeof candidate.version_bump === "string" && FAI_VERSION_BUMPS.includes(candidate.version_bump) && isStringOrAbsent(candidate.changelog_entry) && isStringOrAbsent(candidate.pr_description) && isStringOrAbsent(candidate.version_bump_reason);
422615
+ }
422616
+ function isStringOrAbsent(value2) {
422617
+ return value2 == null || typeof value2 === "string";
422618
+ }
422619
+ function nonEmpty2(value2) {
422620
+ return value2 != null && value2.trim().length > 0 ? value2 : void 0;
422621
+ }
422563
422622
  }
422564
422623
  });
422565
422624
 
@@ -669211,7 +669270,7 @@ var AccessTokenPosthogManager = class {
669211
669270
  properties: {
669212
669271
  ...event,
669213
669272
  ...event.properties,
669214
- version: "5.45.3",
669273
+ version: "5.46.0",
669215
669274
  usingAccessToken: true,
669216
669275
  ...getRunIdProperties()
669217
669276
  }
@@ -669275,7 +669334,7 @@ var UserPosthogManager = class {
669275
669334
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
669276
669335
  event: "CLI",
669277
669336
  properties: {
669278
- version: "5.45.3",
669337
+ version: "5.46.0",
669279
669338
  ...event,
669280
669339
  ...event.properties,
669281
669340
  usingAccessToken: false,
@@ -856646,7 +856705,7 @@ function createDocsConfigFileAstVisitorForRules({ relativeFilepath, allRulesWith
856646
856705
  const ruleViolations = await visitFromRule(node4);
856647
856706
  const severityOverride = severityOverrides?.get(ruleName);
856648
856707
  addViolations(ruleViolations.map((violation) => ({
856649
- name: violation.name,
856708
+ name: violation.name ?? ruleName,
856650
856709
  severity: severityOverride ?? violation.severity,
856651
856710
  relativeFilepath: violation.relativeFilepath ?? RelativeFilePath2.of(""),
856652
856711
  nodePath: violation.nodePath ?? nodePath,
@@ -861013,7 +861072,7 @@ var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
861013
861072
  var LOGS_FOLDER_NAME = "logs";
861014
861073
  var MAX_LOGS_DIR_SIZE_BYTES = 100 * 1024 * 1024;
861015
861074
  function getCliSource() {
861016
- const version7 = "5.45.3";
861075
+ const version7 = "5.46.0";
861017
861076
  return `cli@${version7}`;
861018
861077
  }
861019
861078
  var DebugLogger = class {
@@ -892105,7 +892164,7 @@ var LegacyDocsPublisher = class {
892105
892164
  previewId,
892106
892165
  disableTemplates: void 0,
892107
892166
  skipUpload,
892108
- cliVersion: "5.45.3",
892167
+ cliVersion: "5.46.0",
892109
892168
  loginCommand: "fern auth login"
892110
892169
  });
892111
892170
  if (taskContext.getResult() === TaskResult.Failure) {
@@ -917533,13 +917592,16 @@ var EndpointSnippetGenerator3 = class {
917533
917592
  }
917534
917593
  getBytesBodyRequestArg({ value: value2 }) {
917535
917594
  const bytesValue = typeof value2 === "string" ? value2 : "";
917536
- return go_exports.TypeInstantiation.reference(go_exports.invokeFunc({
917537
- func: go_exports.typeReference({
917538
- name: "NewReader",
917539
- importPath: "bytes"
917540
- }),
917541
- arguments_: [go_exports.TypeInstantiation.bytes(bytesValue)]
917542
- }));
917595
+ if (this.context.customConfig?.useReaderForBytesRequest ?? true) {
917596
+ return go_exports.TypeInstantiation.reference(go_exports.invokeFunc({
917597
+ func: go_exports.typeReference({
917598
+ name: "NewReader",
917599
+ importPath: "bytes"
917600
+ }),
917601
+ arguments_: [go_exports.TypeInstantiation.bytes(bytesValue)]
917602
+ }));
917603
+ }
917604
+ return go_exports.TypeInstantiation.bytes(bytesValue);
917543
917605
  }
917544
917606
  getMethodArgsForInlinedRequest({ request: request7, snippet: snippet2 }) {
917545
917607
  const otherArgs = [];
@@ -917659,7 +917721,7 @@ var EndpointSnippetGenerator3 = class {
917659
917721
  getReferencedRequestBodyPropertyTypeInstantiation({ body, value: value2 }) {
917660
917722
  switch (body.type) {
917661
917723
  case "bytes":
917662
- return this.getBytesBodyRequestArg({ value: value2 });
917724
+ return go_exports.TypeInstantiation.bytes(typeof value2 === "string" ? value2 : "");
917663
917725
  case "typeReference":
917664
917726
  return this.context.dynamicTypeInstantiationMapper.convert({ typeReference: body.value, value: value2 });
917665
917727
  default:
@@ -943539,13 +943601,19 @@ function getGithubPublishConfig(githubPublishInfo) {
943539
943601
  secretKeyEnvironmentVariable: (0, import_api50.EnvironmentVariable)(value2.signature.secretKey ?? "")
943540
943602
  } : void 0
943541
943603
  }),
943542
- pypi: (value2) => import_generator_exec_sdk.FernGeneratorExec.GithubPublishInfo.pypi({
943543
- registryUrl: value2.registryUrl,
943544
- packageName: value2.packageName,
943545
- usernameEnvironmentVariable: (0, import_api50.EnvironmentVariable)("PYPI_USERNAME"),
943546
- passwordEnvironmentVariable: (0, import_api50.EnvironmentVariable)("PYPI_PASSWORD"),
943547
- pypiMetadata: value2.pypiMetadata
943548
- }),
943604
+ pypi: (value2) => {
943605
+ const password = (value2.credentials?.password ?? "").trim();
943606
+ const useOidc = password === "<USE_OIDC>" || password === "OIDC";
943607
+ const hasCredentials = value2.credentials != null;
943608
+ return import_generator_exec_sdk.FernGeneratorExec.GithubPublishInfo.pypi({
943609
+ registryUrl: value2.registryUrl,
943610
+ packageName: value2.packageName,
943611
+ usernameEnvironmentVariable: (0, import_api50.EnvironmentVariable)("PYPI_USERNAME"),
943612
+ passwordEnvironmentVariable: (0, import_api50.EnvironmentVariable)(useOidc ? "OIDC" : "PYPI_PASSWORD"),
943613
+ shouldGeneratePublishWorkflow: useOidc || hasCredentials,
943614
+ pypiMetadata: value2.pypiMetadata
943615
+ });
943616
+ },
943549
943617
  rubygems: (value2) => import_generator_exec_sdk.FernGeneratorExec.GithubPublishInfo.rubygems({
943550
943618
  registryUrl: value2.registryUrl,
943551
943619
  packageName: value2.packageName,
@@ -943667,10 +943735,11 @@ function getGeneratorConfig({ generatorInvocation, customConfig, workspaceName,
943667
943735
  });
943668
943736
  }
943669
943737
  });
943738
+ const publishConfig = getPublishConfigForGithubOidc(generatorInvocation, outputVersion);
943670
943739
  return {
943671
943740
  irFilepath: irPath,
943672
943741
  output: output2,
943673
- publish: void 0,
943742
+ publish: publishConfig,
943674
943743
  customConfig,
943675
943744
  workspaceName,
943676
943745
  organization,
@@ -943861,6 +943930,42 @@ function getPublishTargetFromPublishModeV2(mode) {
943861
943930
  _other: () => void 0
943862
943931
  });
943863
943932
  }
943933
+ function getPublishConfigForGithubOidc(generatorInvocation, version7) {
943934
+ const publishInfo = generatorInvocation.outputMode._visit({
943935
+ publish: () => void 0,
943936
+ publishV2: () => void 0,
943937
+ downloadFiles: () => void 0,
943938
+ github: (value2) => value2.publishInfo,
943939
+ githubV2: (value2) => value2._visit({
943940
+ push: (v9) => v9.publishInfo,
943941
+ commitAndRelease: (v9) => v9.publishInfo,
943942
+ pullRequest: (v9) => v9.publishInfo,
943943
+ _other: () => void 0
943944
+ }),
943945
+ _other: () => void 0
943946
+ });
943947
+ if (publishInfo == null || publishInfo.type !== "pypi") {
943948
+ return void 0;
943949
+ }
943950
+ const password = (publishInfo.credentials?.password ?? "").trim();
943951
+ if (password !== "OIDC" && password !== "<USE_OIDC>") {
943952
+ return void 0;
943953
+ }
943954
+ const registriesV2 = structuredClone(emptyRegistriesConfigV2);
943955
+ registriesV2.pypi = {
943956
+ registryUrl: publishInfo.registryUrl,
943957
+ username: "__token__",
943958
+ password: "OIDC",
943959
+ packageName: publishInfo.packageName,
943960
+ pypiMetadata: publishInfo.pypiMetadata
943961
+ };
943962
+ return {
943963
+ registries: structuredClone(emptyRegistriesConfig),
943964
+ registriesV2,
943965
+ publishTarget: void 0,
943966
+ version: version7
943967
+ };
943968
+ }
943864
943969
  var emptyRegistriesConfig = {
943865
943970
  maven: { registryUrl: "", username: "", password: "", group: "", signature: void 0 },
943866
943971
  npm: { registryUrl: "", token: "", scope: "" }
@@ -944444,7 +944549,7 @@ var LocalTaskHandler = class {
944444
944549
  const absolutePathToFernignore = AbsoluteFilePath2.of(join8(this.absolutePathToLocalOutput, RelativeFilePath2.of(FERNIGNORE_FILENAME)));
944445
944550
  const fernIgnorePaths = await getFernIgnorePaths({ absolutePathToFernignore });
944446
944551
  const pathsToPreserve = await this.getPathsToPreserve(fernIgnorePaths);
944447
- await (0, import_promises129.cp)(this.absolutePathToLocalOutput, tmpOutputResolutionDir, { recursive: true });
944552
+ await (0, import_promises129.cp)(this.absolutePathToLocalOutput, tmpOutputResolutionDir, { recursive: true, verbatimSymlinks: true });
944448
944553
  await this.runThrowawayGitCommand(["init"], tmpOutputResolutionDir);
944449
944554
  await this.runThrowawayGitCommand(["config", "gc.auto", "0"], tmpOutputResolutionDir);
944450
944555
  await this.runThrowawayGitCommand(["add", "."], tmpOutputResolutionDir);
@@ -944472,7 +944577,7 @@ var LocalTaskHandler = class {
944472
944577
  retryDelay: 100
944473
944578
  });
944474
944579
  await (0, import_promises129.rm)(this.absolutePathToLocalOutput, { recursive: true });
944475
- await (0, import_promises129.cp)(tmpOutputResolutionDir, this.absolutePathToLocalOutput, { recursive: true });
944580
+ await (0, import_promises129.cp)(tmpOutputResolutionDir, this.absolutePathToLocalOutput, { recursive: true, verbatimSymlinks: true });
944476
944581
  }
944477
944582
  async copyGeneratedFilesNoFernIgnorePreservingGit() {
944478
944583
  const contents = await (0, import_promises129.readdir)(this.absolutePathToLocalOutput);
@@ -944500,10 +944605,10 @@ var LocalTaskHandler = class {
944500
944605
  if (firstLocalOutputItem.endsWith(".zip")) {
944501
944606
  await (0, import_decompress2.default)(join8(this.absolutePathToTmpOutputDirectory, RelativeFilePath2.of(firstLocalOutputItem)), outputPath);
944502
944607
  for (const localOutputItem of remaininglocalOutputItems) {
944503
- await (0, import_promises129.cp)(join8(this.absolutePathToTmpOutputDirectory, RelativeFilePath2.of(localOutputItem)), join8(outputPath, RelativeFilePath2.of(localOutputItem)), { recursive: true });
944608
+ await (0, import_promises129.cp)(join8(this.absolutePathToTmpOutputDirectory, RelativeFilePath2.of(localOutputItem)), join8(outputPath, RelativeFilePath2.of(localOutputItem)), { recursive: true, verbatimSymlinks: true });
944504
944609
  }
944505
944610
  } else {
944506
- await (0, import_promises129.cp)(this.absolutePathToTmpOutputDirectory, outputPath, { recursive: true });
944611
+ await (0, import_promises129.cp)(this.absolutePathToTmpOutputDirectory, outputPath, { recursive: true, verbatimSymlinks: true });
944507
944612
  }
944508
944613
  }
944509
944614
  async copySnippetJSON({ absolutePathToTmpSnippetJSON, absolutePathToLocalSnippetJSON }) {
@@ -957243,7 +957348,7 @@ function getAutomationContextFromEnv() {
957243
957348
  config_branch: process.env.FERN_CONFIG_BRANCH,
957244
957349
  config_pr_number: process.env.FERN_CONFIG_PR_NUMBER,
957245
957350
  trigger: process.env.GITHUB_EVENT_NAME,
957246
- cli_version: "5.45.3"
957351
+ cli_version: "5.46.0"
957247
957352
  };
957248
957353
  }
957249
957354
  function isAutomationMode() {
@@ -958069,7 +958174,7 @@ var CliContext = class _CliContext {
958069
958174
  if (false) {
958070
958175
  this.logger.error("CLI_VERSION is not defined");
958071
958176
  }
958072
- return "5.45.3";
958177
+ return "5.46.0";
958073
958178
  }
958074
958179
  getCliName() {
958075
958180
  if (false) {
@@ -972785,101 +972890,132 @@ async function validateWorkspaces({
972785
972890
  const apiResults = [];
972786
972891
  let docsResult;
972787
972892
  let hasAnyErrors = false;
972893
+ let abortReason;
972788
972894
  const apiWorkspacesToValidate = commandLineApiWorkspace != null ? project.apiWorkspaces.filter((workspace) => workspace.workspaceName === commandLineApiWorkspace) : project.apiWorkspaces;
972789
- const docsWorkspace = project.docsWorkspaces;
972790
- if (docsWorkspace != null) {
972791
- const excludeRules = brokenLinks || errorOnBrokenLinks ? [] : ["valid-markdown-links"];
972792
- const ossWorkspaces = await filterOssWorkspaces(project);
972793
- let collected;
972794
- await cliContext.runTaskForWorkspace(docsWorkspace, async (context3) => {
972795
- collected = await collectDocsWorkspaceViolations({
972796
- workspace: docsWorkspace,
972797
- context: context3,
972798
- apiWorkspaces: project.apiWorkspaces,
972799
- ossWorkspaces,
972800
- errorOnBrokenLinks,
972801
- excludeRules
972802
- });
972803
- });
972804
- if (collected != null) {
972805
- docsResult = {
972806
- violations: collected.violations,
972807
- elapsedMillis: collected.elapsedMillis
972808
- };
972809
- if (collected.hasErrors) {
972810
- hasAnyErrors = true;
972811
- }
972812
- }
972813
- }
972814
- await Promise.all(
972815
- apiWorkspacesToValidate.map(async (workspace) => {
972816
- if (workspace.generatorsConfiguration?.groups.length === 0 && workspace.type !== "fern") {
972817
- return;
972818
- }
972819
- if (workspace instanceof OSSWorkspace && directFromOpenapi) {
972820
- await cliContext.runTaskForWorkspace(workspace, async (context3) => {
972821
- await workspace.getIntermediateRepresentation({
972822
- context: context3,
972823
- audiences: { type: "all" },
972824
- enableUniqueErrorsPerEndpoint: false,
972825
- generateV1Examples: false,
972826
- logWarnings
972827
- });
972828
- });
972829
- return;
972830
- }
972831
- if (workspace instanceof LazyFernWorkspace) {
972832
- const absolutePathToApiYml = join8(
972833
- workspace.absoluteFilePath,
972834
- RelativeFilePath2.of(DEFINITION_DIRECTORY),
972835
- RelativeFilePath2.of(ROOT_API_FILENAME)
972836
- );
972837
- const apiYmlExists = await doesPathExist(absolutePathToApiYml);
972838
- if (!apiYmlExists) {
972839
- await cliContext.runTask(async (context3) => {
972840
- context3.logger.error(`Missing file: ${ROOT_API_FILENAME}`);
972841
- return context3.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
972842
- });
972843
- return;
972844
- }
972845
- }
972895
+ let hasErrors = false;
972896
+ try {
972897
+ const docsWorkspace = project.docsWorkspaces;
972898
+ if (docsWorkspace != null) {
972899
+ const excludeRules = brokenLinks || errorOnBrokenLinks ? [] : ["valid-markdown-links"];
972900
+ const ossWorkspaces = await filterOssWorkspaces(project);
972846
972901
  let collected;
972847
- await cliContext.runTaskForWorkspace(workspace, async (context3) => {
972848
- const fernWorkspace = await workspace.toFernWorkspace({ context: context3 });
972849
- collected = await collectAPIWorkspaceViolations({
972850
- workspace: fernWorkspace,
972902
+ await cliContext.runTaskForWorkspace(docsWorkspace, async (context3) => {
972903
+ collected = await collectDocsWorkspaceViolations({
972904
+ workspace: docsWorkspace,
972851
972905
  context: context3,
972852
- ossWorkspace: workspace instanceof OSSWorkspace ? workspace : void 0
972906
+ apiWorkspaces: project.apiWorkspaces,
972907
+ ossWorkspaces,
972908
+ errorOnBrokenLinks,
972909
+ excludeRules
972853
972910
  });
972854
972911
  });
972855
972912
  if (collected != null) {
972856
- apiResults.push({
972857
- apiName: collected.apiName,
972913
+ docsResult = {
972858
972914
  violations: collected.violations,
972859
972915
  elapsedMillis: collected.elapsedMillis
972860
- });
972916
+ };
972861
972917
  if (collected.hasErrors) {
972862
972918
  hasAnyErrors = true;
972863
972919
  }
972864
972920
  }
972865
- })
972866
- );
972867
- const { hasErrors } = await cliContext.runTask((context3) => {
972868
- return printCheckReport({
972869
- apiResults,
972870
- docsResult,
972871
- logWarnings,
972872
- context: context3
972873
- });
972874
- });
972875
- if (cliContext.isJsonMode) {
972876
- const showApiNames = apiResults.length > 1;
972877
- cliContext.writeJsonToStdout(
972878
- buildCheckJsonResult({ apiResults, docsResult, hasErrors: hasErrors || hasAnyErrors, showApiNames })
972921
+ }
972922
+ await Promise.all(
972923
+ apiWorkspacesToValidate.map(async (workspace) => {
972924
+ if (workspace.generatorsConfiguration?.groups.length === 0 && workspace.type !== "fern") {
972925
+ return;
972926
+ }
972927
+ if (workspace instanceof OSSWorkspace && directFromOpenapi) {
972928
+ await cliContext.runTaskForWorkspace(workspace, async (context3) => {
972929
+ await workspace.getIntermediateRepresentation({
972930
+ context: context3,
972931
+ audiences: { type: "all" },
972932
+ enableUniqueErrorsPerEndpoint: false,
972933
+ generateV1Examples: false,
972934
+ logWarnings
972935
+ });
972936
+ });
972937
+ return;
972938
+ }
972939
+ if (workspace instanceof LazyFernWorkspace) {
972940
+ const absolutePathToApiYml = join8(
972941
+ workspace.absoluteFilePath,
972942
+ RelativeFilePath2.of(DEFINITION_DIRECTORY),
972943
+ RelativeFilePath2.of(ROOT_API_FILENAME)
972944
+ );
972945
+ const apiYmlExists = await doesPathExist(absolutePathToApiYml);
972946
+ if (!apiYmlExists) {
972947
+ abortReason = "missing api.yml";
972948
+ await cliContext.runTask(async (context3) => {
972949
+ context3.logger.error(`Missing file: ${ROOT_API_FILENAME}`);
972950
+ return context3.failAndThrow(void 0, void 0, {
972951
+ code: CliError.Code.ValidationError
972952
+ });
972953
+ });
972954
+ return;
972955
+ }
972956
+ }
972957
+ let collected;
972958
+ await cliContext.runTaskForWorkspace(workspace, async (context3) => {
972959
+ const fernWorkspace = await workspace.toFernWorkspace({ context: context3 });
972960
+ collected = await collectAPIWorkspaceViolations({
972961
+ workspace: fernWorkspace,
972962
+ context: context3,
972963
+ ossWorkspace: workspace instanceof OSSWorkspace ? workspace : void 0
972964
+ });
972965
+ });
972966
+ if (collected != null) {
972967
+ apiResults.push({
972968
+ apiName: collected.apiName,
972969
+ violations: collected.violations,
972970
+ elapsedMillis: collected.elapsedMillis
972971
+ });
972972
+ if (collected.hasErrors) {
972973
+ hasAnyErrors = true;
972974
+ }
972975
+ }
972976
+ })
972879
972977
  );
972880
- }
972881
- if (hasErrors || hasAnyErrors) {
972882
- cliContext.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
972978
+ const reportResult = await cliContext.runTask((context3) => {
972979
+ return printCheckReport({
972980
+ apiResults,
972981
+ docsResult,
972982
+ logWarnings,
972983
+ context: context3
972984
+ });
972985
+ });
972986
+ hasErrors = reportResult.hasErrors;
972987
+ if (cliContext.isJsonMode) {
972988
+ const showApiNames = apiResults.length > 1;
972989
+ cliContext.writeJsonToStdout(
972990
+ buildCheckJsonResult({ apiResults, docsResult, hasErrors: hasErrors || hasAnyErrors, showApiNames })
972991
+ );
972992
+ }
972993
+ if (hasErrors || hasAnyErrors) {
972994
+ abortReason = "validation errors";
972995
+ cliContext.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
972996
+ }
972997
+ } catch (error50) {
972998
+ if (abortReason == null) {
972999
+ abortReason = error50 instanceof Error ? error50.message.slice(0, 100) : "unexpected error";
973000
+ }
973001
+ throw error50;
973002
+ } finally {
973003
+ const allViolations = [...apiResults.flatMap((r5) => r5.violations), ...docsResult?.violations ?? []];
973004
+ const firedRules = [
973005
+ ...new Set(allViolations.map((v9) => v9.name).filter((name2) => name2 != null))
973006
+ ];
973007
+ const numErrors = allViolations.filter((v9) => v9.severity === "fatal" || v9.severity === "error").length;
973008
+ const numWarnings = allViolations.filter((v9) => v9.severity === "warning").length;
973009
+ cliContext.instrumentPostHogEvent({
973010
+ command: "fern check",
973011
+ properties: {
973012
+ validationRules: firedRules,
973013
+ numErrors,
973014
+ numWarnings,
973015
+ passed: !hasErrors && !hasAnyErrors,
973016
+ abortReason
973017
+ }
973018
+ });
972883
973019
  }
972884
973020
  }
972885
973021
 
@@ -974233,24 +974369,46 @@ function addValidateCommand(cli, cliContext) {
974233
974369
  default: false
974234
974370
  }),
974235
974371
  async (argv) => {
974236
- const project = await loadProjectAndRegisterWorkspacesWithContext(cliContext, {
974237
- commandLineApiWorkspace: void 0,
974238
- defaultToAllApiWorkspaces: true
974239
- });
974240
- if (argv.api != null && !project.apiWorkspaces.some((ws5) => ws5.workspaceName === argv.api)) {
974241
- cliContext.failAndThrow(`API does not exist: ${argv.api}`, void 0, {
974242
- code: CliError.Code.ConfigError
974372
+ let project;
974373
+ try {
974374
+ project = await loadProjectAndRegisterWorkspacesWithContext(cliContext, {
974375
+ commandLineApiWorkspace: void 0,
974376
+ defaultToAllApiWorkspaces: true
974243
974377
  });
974378
+ if (argv.api != null && !project.apiWorkspaces.some((ws5) => ws5.workspaceName === argv.api)) {
974379
+ cliContext.instrumentPostHogEvent({
974380
+ command: "fern check",
974381
+ properties: {
974382
+ passed: false,
974383
+ abortReason: `API does not exist: ${argv.api}`
974384
+ }
974385
+ });
974386
+ cliContext.failAndThrow(`API does not exist: ${argv.api}`, void 0, {
974387
+ code: CliError.Code.ConfigError
974388
+ });
974389
+ }
974390
+ await validateWorkspaces({
974391
+ project,
974392
+ cliContext,
974393
+ logWarnings: argv.warnings,
974394
+ brokenLinks: argv.brokenLinks,
974395
+ errorOnBrokenLinks: argv.strictBrokenLinks,
974396
+ directFromOpenapi: argv.fromOpenapi,
974397
+ commandLineApiWorkspace: argv.api
974398
+ });
974399
+ } catch (error50) {
974400
+ if (project == null) {
974401
+ const reason = error50 instanceof Error ? error50.message.slice(0, 100) : "project load failed";
974402
+ cliContext.instrumentPostHogEvent({
974403
+ command: "fern check",
974404
+ properties: {
974405
+ passed: false,
974406
+ abortReason: reason
974407
+ }
974408
+ });
974409
+ }
974410
+ throw error50;
974244
974411
  }
974245
- await validateWorkspaces({
974246
- project,
974247
- cliContext,
974248
- logWarnings: argv.warnings,
974249
- brokenLinks: argv.brokenLinks,
974250
- errorOnBrokenLinks: argv.strictBrokenLinks,
974251
- directFromOpenapi: argv.fromOpenapi,
974252
- commandLineApiWorkspace: argv.api
974253
- });
974254
974412
  }
974255
974413
  );
974256
974414
  }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.45.3",
2
+ "version": "5.46.0",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/fern-api/fern.git",