@fern-api/fern-api-dev 3.27.3 → 3.28.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 +359 -14
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -1413817,7 +1413817,7 @@ var AccessTokenPosthogManager = class {
1413817
1413817
  properties: {
1413818
1413818
  ...event,
1413819
1413819
  ...event.properties,
1413820
- version: "3.27.3",
1413820
+ version: "3.28.0",
1413821
1413821
  usingAccessToken: true
1413822
1413822
  }
1413823
1413823
  });
@@ -1413916,7 +1413916,7 @@ var UserPosthogManager = class {
1413916
1413916
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
1413917
1413917
  event: "CLI",
1413918
1413918
  properties: {
1413919
- version: "3.27.3",
1413919
+ version: "3.28.0",
1413920
1413920
  ...event,
1413921
1413921
  ...event.properties,
1413922
1413922
  usingAccessToken: false,
@@ -1493982,7 +1493982,7 @@ var CliContext = class {
1493982
1493982
  if (false) {
1493983
1493983
  this.logger.error("CLI_VERSION is not defined");
1493984
1493984
  }
1493985
- return "3.27.3";
1493985
+ return "3.28.0";
1493986
1493986
  }
1493987
1493987
  getCliName() {
1493988
1493988
  if (false) {
@@ -1588481,7 +1588481,7 @@ var import_path35 = __toESM(require("path"), 1);
1588481
1588481
  var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
1588482
1588482
  var LOGS_FOLDER_NAME = "logs";
1588483
1588483
  function getCliSource() {
1588484
- const version6 = "3.27.3";
1588484
+ const version6 = "3.28.0";
1588485
1588485
  return `cli@${version6}`;
1588486
1588486
  }
1588487
1588487
  var DebugLogger = class {
@@ -1604996,7 +1604996,8 @@ function logViolationsGroup({
1604996
1604996
  if (title5 === "") {
1604997
1604997
  title5 = violation.relativeFilepath;
1604998
1604998
  }
1604999
- return violation.message;
1604999
+ const severityLabel = getSeverityLabel(violation.severity);
1605000
+ return `${severityLabel} ${violation.message}`;
1605000
1605001
  }).filter((message) => message != null).join("\n");
1605001
1605002
  context2.logger.log(
1605002
1605003
  getLogLevelForSeverity(severity),
@@ -1605032,6 +1605033,18 @@ function getLogLevelForSeverity(severity) {
1605032
1605033
  assertNever(severity);
1605033
1605034
  }
1605034
1605035
  }
1605036
+ function getSeverityLabel(severity) {
1605037
+ switch (severity) {
1605038
+ case "fatal":
1605039
+ return source_default.red("[error]");
1605040
+ case "error":
1605041
+ return source_default.red("[error]");
1605042
+ case "warning":
1605043
+ return source_default.yellow("[warning]");
1605044
+ default:
1605045
+ assertNever(severity);
1605046
+ }
1605047
+ }
1605035
1605048
  function logViolationsSummary({
1605036
1605049
  stats,
1605037
1605050
  context: context2,
@@ -1605079,6 +1605092,39 @@ function getViolationStats(violations) {
1605079
1605092
  }
1605080
1605093
 
1605081
1605094
  // src/commands/validate/validateDocsWorkspaceAndLogIssues.ts
1605095
+ async function collectDocsWorkspaceViolations({
1605096
+ workspace,
1605097
+ apiWorkspaces,
1605098
+ ossWorkspaces,
1605099
+ context: context2,
1605100
+ errorOnBrokenLinks,
1605101
+ excludeRules
1605102
+ }) {
1605103
+ if (workspace.config.settings?.substituteEnvVars) {
1605104
+ workspace.config = replaceEnvVariables(workspace.config, {
1605105
+ onError: (e6) => context2.failAndThrow(e6)
1605106
+ });
1605107
+ }
1605108
+ const startTime = performance.now();
1605109
+ const violations = await validateDocsWorkspace(
1605110
+ workspace,
1605111
+ context2,
1605112
+ apiWorkspaces,
1605113
+ ossWorkspaces,
1605114
+ false,
1605115
+ excludeRules
1605116
+ );
1605117
+ const elapsedMillis = performance.now() - startTime;
1605118
+ let hasErrors = violations.some((v21) => v21.severity === "fatal" || v21.severity === "error");
1605119
+ if (errorOnBrokenLinks) {
1605120
+ hasErrors = hasErrors || violations.some((violation) => violation.name === "valid-markdown-links");
1605121
+ }
1605122
+ return {
1605123
+ violations,
1605124
+ elapsedMillis,
1605125
+ hasErrors
1605126
+ };
1605127
+ }
1605082
1605128
  async function validateDocsWorkspaceWithoutExiting({
1605083
1605129
  workspace,
1605084
1605130
  apiWorkspaces,
@@ -1638023,6 +1638069,30 @@ async function runRulesOnOSSWorkspace({ workspace, context: context2, rules }) {
1638023
1638069
 
1638024
1638070
  // src/commands/validate/validateAPIWorkspaceAndLogIssues.ts
1638025
1638071
  var import_validate_npm_package_name = __toESM(require_lib20(), 1);
1638072
+ async function collectAPIWorkspaceViolations({
1638073
+ workspace,
1638074
+ context: context2,
1638075
+ ossWorkspace
1638076
+ }) {
1638077
+ if (!(0, import_validate_npm_package_name.default)(workspace.definition.rootApiFile.contents.name).validForNewPackages) {
1638078
+ context2.failAndThrow("API name is not valid.");
1638079
+ }
1638080
+ const startTime = performance.now();
1638081
+ const apiViolations = validateFernWorkspace(workspace, context2.logger);
1638082
+ const generatorViolations = await validateGeneratorsWorkspace(workspace, context2.logger);
1638083
+ const violations = [...apiViolations, ...generatorViolations];
1638084
+ if (ossWorkspace) {
1638085
+ violations.push(...await validateOSSWorkspace(ossWorkspace, context2));
1638086
+ }
1638087
+ const elapsedMillis = performance.now() - startTime;
1638088
+ const hasErrors = violations.some((v21) => v21.severity === "fatal" || v21.severity === "error");
1638089
+ return {
1638090
+ apiName: workspace.definition.rootApiFile.contents.name,
1638091
+ violations,
1638092
+ elapsedMillis,
1638093
+ hasErrors
1638094
+ };
1638095
+ }
1638026
1638096
  async function validateAPIWorkspaceWithoutExiting({
1638027
1638097
  workspace,
1638028
1638098
  context: context2,
@@ -1643812,6 +1643882,230 @@ async function validateDocsBrokenLinks({
1643812
1643882
  });
1643813
1643883
  }
1643814
1643884
 
1643885
+ // src/commands/validate/printCheckReport.ts
1643886
+ function printCheckReport({ apiResults, docsResult, logWarnings, context: context2 }) {
1643887
+ const startTime = performance.now();
1643888
+ let hasErrors = false;
1643889
+ const apiResultsWithViolations = apiResults.filter((result) => {
1643890
+ const stats = getViolationStats2(result.violations);
1643891
+ return stats.numErrors > 0 || logWarnings && stats.numWarnings > 0;
1643892
+ });
1643893
+ if (apiResultsWithViolations.length > 0) {
1643894
+ const totalSdkStats = getTotalStats(apiResults.map((r23) => r23.violations).flat());
1643895
+ const showApiNesting = apiResults.length > 1;
1643896
+ if (showApiNesting) {
1643897
+ context2.logger.info(source_default.cyan(source_default.bold("[sdk]")));
1643898
+ for (const apiResult of apiResults) {
1643899
+ const stats = getViolationStats2(apiResult.violations);
1643900
+ if (stats.numErrors > 0 || logWarnings && stats.numWarnings > 0) {
1643901
+ hasErrors = hasErrors || stats.numErrors > 0;
1643902
+ printApiSection({
1643903
+ apiName: apiResult.apiName,
1643904
+ violations: apiResult.violations,
1643905
+ stats,
1643906
+ logWarnings,
1643907
+ context: context2,
1643908
+ indent: " "
1643909
+ });
1643910
+ }
1643911
+ }
1643912
+ } else {
1643913
+ hasErrors = hasErrors || totalSdkStats.numErrors > 0;
1643914
+ printSdkSectionFlat({
1643915
+ violations: apiResults[0]?.violations ?? [],
1643916
+ stats: totalSdkStats,
1643917
+ logWarnings,
1643918
+ context: context2
1643919
+ });
1643920
+ }
1643921
+ }
1643922
+ if (docsResult != null) {
1643923
+ const docsStats = getViolationStats2(docsResult.violations);
1643924
+ if (docsStats.numErrors > 0 || logWarnings && docsStats.numWarnings > 0) {
1643925
+ hasErrors = hasErrors || docsStats.numErrors > 0;
1643926
+ printDocsSection({
1643927
+ violations: docsResult.violations,
1643928
+ stats: docsStats,
1643929
+ logWarnings,
1643930
+ context: context2
1643931
+ });
1643932
+ }
1643933
+ }
1643934
+ const totalElapsedMillis = performance.now() - startTime;
1643935
+ const allViolations = [...apiResults.map((r23) => r23.violations).flat(), ...docsResult?.violations ?? []];
1643936
+ const totalStats = getViolationStats2(allViolations);
1643937
+ printSummary({
1643938
+ stats: totalStats,
1643939
+ logWarnings,
1643940
+ elapsedMillis: totalElapsedMillis,
1643941
+ context: context2
1643942
+ });
1643943
+ return { hasErrors };
1643944
+ }
1643945
+ function printSdkSectionFlat({
1643946
+ violations,
1643947
+ stats,
1643948
+ logWarnings,
1643949
+ context: context2
1643950
+ }) {
1643951
+ const statsStr = formatStats(stats, logWarnings);
1643952
+ context2.logger.info(source_default.cyan(source_default.bold(`[sdk]`)) + ` ${statsStr}`);
1643953
+ printViolationsByType({
1643954
+ violations,
1643955
+ logWarnings,
1643956
+ context: context2,
1643957
+ indent: " "
1643958
+ });
1643959
+ }
1643960
+ function printApiSection({
1643961
+ apiName,
1643962
+ violations,
1643963
+ stats,
1643964
+ logWarnings,
1643965
+ context: context2,
1643966
+ indent: indent3
1643967
+ }) {
1643968
+ const statsStr = formatStats(stats, logWarnings);
1643969
+ context2.logger.info(`${indent3}${source_default.bold(`[${apiName}]`)} ${statsStr}`);
1643970
+ printViolationsByType({
1643971
+ violations,
1643972
+ logWarnings,
1643973
+ context: context2,
1643974
+ indent: indent3 + " "
1643975
+ });
1643976
+ }
1643977
+ function printDocsSection({
1643978
+ violations,
1643979
+ stats,
1643980
+ logWarnings,
1643981
+ context: context2
1643982
+ }) {
1643983
+ const statsStr = formatStats(stats, logWarnings);
1643984
+ context2.logger.info(source_default.magenta(source_default.bold(`[docs]`)) + ` ${statsStr}`);
1643985
+ printViolationsByType({
1643986
+ violations,
1643987
+ logWarnings,
1643988
+ context: context2,
1643989
+ indent: " "
1643990
+ });
1643991
+ }
1643992
+ function printViolationsByType({
1643993
+ violations,
1643994
+ logWarnings,
1643995
+ context: context2,
1643996
+ indent: indent3
1643997
+ }) {
1643998
+ const errors4 = violations.filter((v21) => v21.severity === "fatal" || v21.severity === "error");
1643999
+ const warnings = violations.filter((v21) => v21.severity === "warning");
1644000
+ if (logWarnings) {
1644001
+ for (const violation of warnings.sort(sortViolations)) {
1644002
+ printViolation({ violation, context: context2, indent: indent3 });
1644003
+ }
1644004
+ }
1644005
+ for (const violation of errors4.sort(sortViolations)) {
1644006
+ printViolation({ violation, context: context2, indent: indent3 });
1644007
+ }
1644008
+ }
1644009
+ function printViolation({
1644010
+ violation,
1644011
+ context: context2,
1644012
+ indent: indent3
1644013
+ }) {
1644014
+ const severityLabel = getSeverityLabel2(violation.severity);
1644015
+ const path68 = formatViolationPath(violation);
1644016
+ if (path68 === "") {
1644017
+ context2.logger.info(`${indent3}${severityLabel} ${violation.message}`);
1644018
+ } else {
1644019
+ context2.logger.info(`${indent3}${severityLabel}`);
1644020
+ context2.logger.info(`${indent3} path: ${source_default.blue(path68)}`);
1644021
+ context2.logger.info(`${indent3} issue: ${violation.message}`);
1644022
+ }
1644023
+ context2.logger.info("");
1644024
+ }
1644025
+ function formatViolationPath(violation) {
1644026
+ const parts = [];
1644027
+ if (violation.relativeFilepath !== "") {
1644028
+ parts.push(violation.relativeFilepath);
1644029
+ }
1644030
+ for (const nodePathItem of violation.nodePath) {
1644031
+ let itemStr = typeof nodePathItem === "string" ? nodePathItem : nodePathItem.key;
1644032
+ if (typeof nodePathItem !== "string" && nodePathItem.arrayIndex != null) {
1644033
+ itemStr += `[${nodePathItem.arrayIndex}]`;
1644034
+ }
1644035
+ parts.push(itemStr);
1644036
+ }
1644037
+ return parts.join(" -> ");
1644038
+ }
1644039
+ function getSeverityLabel2(severity) {
1644040
+ switch (severity) {
1644041
+ case "fatal":
1644042
+ return source_default.red("[error]");
1644043
+ case "error":
1644044
+ return source_default.red("[error]");
1644045
+ case "warning":
1644046
+ return source_default.yellow("[warning]");
1644047
+ default:
1644048
+ assertNever(severity);
1644049
+ }
1644050
+ }
1644051
+ function formatStats(stats, logWarnings) {
1644052
+ const parts = [];
1644053
+ if (stats.numErrors > 0) {
1644054
+ parts.push(`${stats.numErrors} error${stats.numErrors !== 1 ? "s" : ""}`);
1644055
+ }
1644056
+ if (logWarnings && stats.numWarnings > 0) {
1644057
+ parts.push(`${stats.numWarnings} warning${stats.numWarnings !== 1 ? "s" : ""}`);
1644058
+ }
1644059
+ return parts.join(", ");
1644060
+ }
1644061
+ function getViolationStats2(violations) {
1644062
+ let numErrors = 0;
1644063
+ let numWarnings = 0;
1644064
+ for (const violation of violations) {
1644065
+ switch (violation.severity) {
1644066
+ case "fatal":
1644067
+ case "error":
1644068
+ numErrors += 1;
1644069
+ break;
1644070
+ case "warning":
1644071
+ numWarnings += 1;
1644072
+ break;
1644073
+ default:
1644074
+ assertNever(violation.severity);
1644075
+ }
1644076
+ }
1644077
+ return { numErrors, numWarnings };
1644078
+ }
1644079
+ function getTotalStats(violations) {
1644080
+ return getViolationStats2(violations);
1644081
+ }
1644082
+ function sortViolations(a10, b18) {
1644083
+ const pathCompare = a10.relativeFilepath.localeCompare(b18.relativeFilepath);
1644084
+ if (pathCompare !== 0) {
1644085
+ return pathCompare;
1644086
+ }
1644087
+ return JSON.stringify(a10.nodePath).localeCompare(JSON.stringify(b18.nodePath));
1644088
+ }
1644089
+ function printSummary({
1644090
+ stats,
1644091
+ logWarnings,
1644092
+ elapsedMillis,
1644093
+ context: context2
1644094
+ }) {
1644095
+ const suffix = elapsedMillis > 0 ? ` in ${(elapsedMillis / 1e3).toFixed(3)} seconds.` : ".";
1644096
+ let message = `Found ${stats.numErrors} error${stats.numErrors !== 1 ? "s" : ""} and ${stats.numWarnings} warning${stats.numWarnings !== 1 ? "s" : ""}` + suffix;
1644097
+ if (!logWarnings && stats.numWarnings > 0) {
1644098
+ message += " Run fern check --warnings to print out the warnings not shown.";
1644099
+ }
1644100
+ if (stats.numErrors > 0) {
1644101
+ context2.logger.error(message);
1644102
+ } else if (stats.numWarnings > 0) {
1644103
+ context2.logger.warn(message);
1644104
+ } else {
1644105
+ context2.logger.info(source_default.green("All checks passed"));
1644106
+ }
1644107
+ }
1644108
+
1643815
1644109
  // src/commands/validate/validateWorkspaces.ts
1643816
1644110
  async function validateWorkspaces({
1643817
1644111
  project,
@@ -1643822,28 +1644116,41 @@ async function validateWorkspaces({
1643822
1644116
  isLocal,
1643823
1644117
  directFromOpenapi
1643824
1644118
  }) {
1644119
+ const apiResults = [];
1644120
+ let docsResult;
1644121
+ let hasAnyErrors = false;
1643825
1644122
  const docsWorkspace = project.docsWorkspaces;
1643826
1644123
  if (docsWorkspace != null) {
1644124
+ const excludeRules = brokenLinks || errorOnBrokenLinks ? [] : ["valid-markdown-links"];
1644125
+ const ossWorkspaces = await filterOssWorkspaces(project);
1644126
+ let collected;
1643827
1644127
  await cliContext.runTaskForWorkspace(docsWorkspace, async (context2) => {
1643828
- const excludeRules = brokenLinks || errorOnBrokenLinks ? [] : ["valid-markdown-links"];
1643829
- await validateDocsWorkspaceAndLogIssues({
1644128
+ collected = await collectDocsWorkspaceViolations({
1643830
1644129
  workspace: docsWorkspace,
1643831
1644130
  context: context2,
1643832
- logWarnings,
1643833
1644131
  apiWorkspaces: project.apiWorkspaces,
1643834
- ossWorkspaces: await filterOssWorkspaces(project),
1644132
+ ossWorkspaces,
1643835
1644133
  errorOnBrokenLinks,
1643836
1644134
  excludeRules
1643837
1644135
  });
1643838
1644136
  });
1644137
+ if (collected != null) {
1644138
+ docsResult = {
1644139
+ violations: collected.violations,
1644140
+ elapsedMillis: collected.elapsedMillis
1644141
+ };
1644142
+ if (collected.hasErrors) {
1644143
+ hasAnyErrors = true;
1644144
+ }
1644145
+ }
1643839
1644146
  }
1643840
1644147
  await Promise.all(
1643841
1644148
  project.apiWorkspaces.map(async (workspace) => {
1643842
- if (workspace.generatorsConfiguration?.groups.length === 0 && workspace.type != "fern") {
1644149
+ if (workspace.generatorsConfiguration?.groups.length === 0 && workspace.type !== "fern") {
1643843
1644150
  return;
1643844
1644151
  }
1643845
- await cliContext.runTaskForWorkspace(workspace, async (context2) => {
1643846
- if (workspace instanceof OSSWorkspace && directFromOpenapi) {
1644152
+ if (workspace instanceof OSSWorkspace && directFromOpenapi) {
1644153
+ await cliContext.runTaskForWorkspace(workspace, async (context2) => {
1643847
1644154
  await workspace.getIntermediateRepresentation({
1643848
1644155
  context: context2,
1643849
1644156
  audiences: { type: "all" },
@@ -1643851,18 +1644158,56 @@ async function validateWorkspaces({
1643851
1644158
  generateV1Examples: false,
1643852
1644159
  logWarnings
1643853
1644160
  });
1644161
+ });
1644162
+ return;
1644163
+ }
1644164
+ if (workspace instanceof LazyFernWorkspace) {
1644165
+ const absolutePathToApiYml = join2(
1644166
+ workspace.absoluteFilePath,
1644167
+ RelativeFilePath2.of(DEFINITION_DIRECTORY),
1644168
+ RelativeFilePath2.of(ROOT_API_FILENAME)
1644169
+ );
1644170
+ const apiYmlExists = await doesPathExist(absolutePathToApiYml);
1644171
+ if (!apiYmlExists) {
1644172
+ await cliContext.runTask(async (context2) => {
1644173
+ context2.logger.error(`Missing file: ${ROOT_API_FILENAME}`);
1644174
+ return context2.failAndThrow();
1644175
+ });
1643854
1644176
  return;
1643855
1644177
  }
1644178
+ }
1644179
+ let collected;
1644180
+ await cliContext.runTaskForWorkspace(workspace, async (context2) => {
1643856
1644181
  const fernWorkspace = await workspace.toFernWorkspace({ context: context2 });
1643857
- await validateAPIWorkspaceAndLogIssues({
1644182
+ collected = await collectAPIWorkspaceViolations({
1643858
1644183
  workspace: fernWorkspace,
1643859
1644184
  context: context2,
1643860
- logWarnings,
1643861
1644185
  ossWorkspace: workspace instanceof OSSWorkspace ? workspace : void 0
1643862
1644186
  });
1643863
1644187
  });
1644188
+ if (collected != null) {
1644189
+ apiResults.push({
1644190
+ apiName: collected.apiName,
1644191
+ violations: collected.violations,
1644192
+ elapsedMillis: collected.elapsedMillis
1644193
+ });
1644194
+ if (collected.hasErrors) {
1644195
+ hasAnyErrors = true;
1644196
+ }
1644197
+ }
1643864
1644198
  })
1643865
1644199
  );
1644200
+ const { hasErrors } = await cliContext.runTask((context2) => {
1644201
+ return printCheckReport({
1644202
+ apiResults,
1644203
+ docsResult,
1644204
+ logWarnings,
1644205
+ context: context2
1644206
+ });
1644207
+ });
1644208
+ if (hasErrors || hasAnyErrors) {
1644209
+ cliContext.failAndThrow();
1644210
+ }
1643866
1644211
  }
1643867
1644212
 
1643868
1644213
  // src/commands/write-definition/writeDefinitionForWorkspaces.ts
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.27.3",
2
+ "version": "3.28.0",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/fern-api/fern.git",