From 4f16a0cc1176ce0ff906a110b771a9d83e1013bc Mon Sep 17 00:00:00 2001 From: Deep Singhvi Date: Wed, 28 Feb 2024 11:39:23 -0500 Subject: [PATCH] (feature, beta): support reading `changelog` dir from api directory (#3075) read changelog dir and send it to docs --- .pnp.cjs | 16 +- ...0.12-4-gdf2d015-09f61a30fd-e688367577.zip} | Bin 614035 -> 619214 bytes .../docs-configuration/package.json | 2 +- .../project-configuration/src/constants.ts | 1 + packages/cli/docs-preview/package.json | 2 +- .../tests/fdr/__snapshots__/fdr.test.ts.snap | 727 ++++++++++++++++++ .../cli/ete-tests/src/tests/fdr/fdr.test.ts | 3 + .../changelog/fern/changelog/2022-02-02.mdx | 1 + .../changelog/fern/definition/api.yml | 19 + .../changelog/fern/definition/commons.yml | 12 + .../changelog/fern/definition/director.yml | 16 + .../changelog/fern/definition/imdb.yml | 150 ++++ .../fixtures/changelog/fern/fern.config.json | 4 + .../fixtures/changelog/fern/generators.yml | 1 + .../remote-workspace-runner/package.json | 2 +- .../src/publishDocs.ts | 359 ++++++--- packages/cli/register/package.json | 2 +- .../workspace-loader/src/loadAPIChangelog.ts | 28 + .../workspace-loader/src/loadAPIWorkspace.ts | 16 +- .../workspace-loader/src/types/Workspace.ts | 11 + .../convertOpenApiWorkspaceToFernWorkspace.ts | 3 +- packages/core/package.json | 2 +- .../docs-config-sdk/fern/definition/docs.yml | 15 + .../docs/types/ApiSectionConfiguration.ts | 11 + .../docs/types/ChangelogConfiguration.ts | 8 + .../src/sdk/api/resources/docs/types/index.ts | 1 + .../docs/types/ApiSectionConfiguration.ts | 2 + .../docs/types/ChangelogConfiguration.ts | 16 + .../resources/docs/types/index.ts | 1 + yarn.lock | 18 +- 30 files changed, 1300 insertions(+), 149 deletions(-) rename .yarn/cache/{@fern-api-fdr-sdk-npm-0.50.8-1-gace1ff5-e436b1d2bc-32de6d37ef.zip => @fern-api-fdr-sdk-npm-0.50.12-4-gdf2d015-09f61a30fd-e688367577.zip} (79%) create mode 100644 packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/changelog/2022-02-02.mdx create mode 100644 packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/api.yml create mode 100644 packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/commons.yml create mode 100644 packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/director.yml create mode 100644 packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/imdb.yml create mode 100644 packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/fern.config.json create mode 100644 packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/generators.yml create mode 100644 packages/cli/workspace-loader/src/loadAPIChangelog.ts create mode 100644 packages/docs-config-sdk/src/sdk/api/resources/docs/types/ChangelogConfiguration.ts create mode 100644 packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ChangelogConfiguration.ts diff --git a/.pnp.cjs b/.pnp.cjs index 254a24a75d3..62f58df4a5f 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -4575,7 +4575,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/core/",\ "packageDependencies": [\ ["@fern-api/core", "workspace:packages/core"],\ - ["@fern-api/fdr-sdk", "npm:0.50.8-1-gace1ff5"],\ + ["@fern-api/fdr-sdk", "npm:0.50.12-4-gdf2d015"],\ ["@fern-api/venus-api-sdk", "npm:0.0.38"],\ ["@fern-fern/fiddle-sdk", "npm:0.0.411"],\ ["@types/jest", "npm:29.0.3"],\ @@ -4723,7 +4723,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@fern-api/config-management-commons", "workspace:packages/cli/config-management/commons"],\ ["@fern-api/core-utils", "workspace:packages/commons/core-utils"],\ ["@fern-api/docs-config-sdk", "workspace:packages/docs-config-sdk"],\ - ["@fern-api/fdr-sdk", "npm:0.50.8-1-gace1ff5"],\ + ["@fern-api/fdr-sdk", "npm:0.50.12-4-gdf2d015"],\ ["@fern-api/fs-utils", "workspace:packages/commons/fs-utils"],\ ["@fern-api/task-context", "workspace:packages/cli/task-context"],\ ["@types/jest", "npm:29.0.3"],\ @@ -4750,7 +4750,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@fern-api/core-utils", "workspace:packages/commons/core-utils"],\ ["@fern-api/docs-config-sdk", "workspace:packages/docs-config-sdk"],\ ["@fern-api/docs-configuration", "workspace:packages/cli/config-management/docs-configuration"],\ - ["@fern-api/fdr-sdk", "npm:0.50.8-1-gace1ff5"],\ + ["@fern-api/fdr-sdk", "npm:0.50.12-4-gdf2d015"],\ ["@fern-api/fs-utils", "workspace:packages/commons/fs-utils"],\ ["@fern-api/ir-generator", "workspace:packages/cli/generation/ir-generator"],\ ["@fern-api/register", "workspace:packages/cli/register"],\ @@ -4826,10 +4826,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["@fern-api/fdr-sdk", [\ - ["npm:0.50.8-1-gace1ff5", {\ - "packageLocation": "./.yarn/cache/@fern-api-fdr-sdk-npm-0.50.8-1-gace1ff5-e436b1d2bc-32de6d37ef.zip/node_modules/@fern-api/fdr-sdk/",\ + ["npm:0.50.12-4-gdf2d015", {\ + "packageLocation": "./.yarn/cache/@fern-api-fdr-sdk-npm-0.50.12-4-gdf2d015-09f61a30fd-e688367577.zip/node_modules/@fern-api/fdr-sdk/",\ "packageDependencies": [\ - ["@fern-api/fdr-sdk", "npm:0.50.8-1-gace1ff5"],\ + ["@fern-api/fdr-sdk", "npm:0.50.12-4-gdf2d015"],\ ["@ungap/url-search-params", "npm:0.2.2"],\ ["axios", "npm:0.27.2"],\ ["js-base64", "npm:3.7.2"],\ @@ -5574,7 +5574,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@fern-api/config-management-commons", "workspace:packages/cli/config-management/commons"],\ ["@fern-api/core", "workspace:packages/core"],\ ["@fern-api/core-utils", "workspace:packages/commons/core-utils"],\ - ["@fern-api/fdr-sdk", "npm:0.50.8-1-gace1ff5"],\ + ["@fern-api/fdr-sdk", "npm:0.50.12-4-gdf2d015"],\ ["@fern-api/ir-generator", "workspace:packages/cli/generation/ir-generator"],\ ["@fern-api/ir-sdk", "workspace:packages/ir-sdk"],\ ["@fern-api/task-context", "workspace:packages/cli/task-context"],\ @@ -5604,7 +5604,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@fern-api/core-utils", "workspace:packages/commons/core-utils"],\ ["@fern-api/docs-config-sdk", "workspace:packages/docs-config-sdk"],\ ["@fern-api/docs-configuration", "workspace:packages/cli/config-management/docs-configuration"],\ - ["@fern-api/fdr-sdk", "npm:0.50.8-1-gace1ff5"],\ + ["@fern-api/fdr-sdk", "npm:0.50.12-4-gdf2d015"],\ ["@fern-api/fs-utils", "workspace:packages/commons/fs-utils"],\ ["@fern-api/generators-configuration", "workspace:packages/cli/config-management/generators-configuration"],\ ["@fern-api/ir-generator", "workspace:packages/cli/generation/ir-generator"],\ diff --git a/.yarn/cache/@fern-api-fdr-sdk-npm-0.50.8-1-gace1ff5-e436b1d2bc-32de6d37ef.zip b/.yarn/cache/@fern-api-fdr-sdk-npm-0.50.12-4-gdf2d015-09f61a30fd-e688367577.zip similarity index 79% rename from .yarn/cache/@fern-api-fdr-sdk-npm-0.50.8-1-gace1ff5-e436b1d2bc-32de6d37ef.zip rename to .yarn/cache/@fern-api-fdr-sdk-npm-0.50.12-4-gdf2d015-09f61a30fd-e688367577.zip index 5d2f54139be33dd6dcabeb1eda3354f7d966d738..bfd140aa58c69e407d413491d7b281932ba55024 100644 GIT binary patch delta 38044 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 diff --git a/packages/cli/config-management/docs-configuration/package.json b/packages/cli/config-management/docs-configuration/package.json index 29cce6576f5..e6d9d971b3d 100644 --- a/packages/cli/config-management/docs-configuration/package.json +++ b/packages/cli/config-management/docs-configuration/package.json @@ -30,7 +30,7 @@ "@fern-api/config-management-commons": "workspace:*", "@fern-api/core-utils": "workspace:*", "@fern-api/docs-config-sdk": "workspace:*", - "@fern-api/fdr-sdk": "0.50.8-1-gace1ff5", + "@fern-api/fdr-sdk": "0.50.12-4-gdf2d015", "@fern-api/fs-utils": "workspace:*", "@fern-api/task-context": "workspace:*", "js-yaml": "^4.1.0", diff --git a/packages/cli/config-management/project-configuration/src/constants.ts b/packages/cli/config-management/project-configuration/src/constants.ts index 7353a0fab8f..105324f8c91 100644 --- a/packages/cli/config-management/project-configuration/src/constants.ts +++ b/packages/cli/config-management/project-configuration/src/constants.ts @@ -1,6 +1,7 @@ export const FERN_DIRECTORY = "fern"; export const DEFINITION_DIRECTORY = "definition"; export const OPENAPI_DIRECTORY = "openapi"; +export const CHANGELOG_DIRECTORY = "changelog"; export const ASYNCAPI_DIRECTORY = "asyncapi"; export const ROOT_API_FILENAME = "api.yml"; export const FERN_PACKAGE_MARKER_FILENAME = "__package__.yml"; diff --git a/packages/cli/docs-preview/package.json b/packages/cli/docs-preview/package.json index e3670508462..529ceefb70c 100644 --- a/packages/cli/docs-preview/package.json +++ b/packages/cli/docs-preview/package.json @@ -30,7 +30,7 @@ "@fern-api/core-utils": "workspace:*", "@fern-api/docs-config-sdk": "workspace:*", "@fern-api/docs-configuration": "workspace:*", - "@fern-api/fdr-sdk": "0.50.8-1-gace1ff5", + "@fern-api/fdr-sdk": "0.50.12-4-gdf2d015", "@fern-api/fs-utils": "workspace:*", "@fern-api/ir-generator": "workspace:*", "@fern-api/register": "workspace:*", diff --git a/packages/cli/ete-tests/src/tests/fdr/__snapshots__/fdr.test.ts.snap b/packages/cli/ete-tests/src/tests/fdr/__snapshots__/fdr.test.ts.snap index 746401f5311..ab7c0810160 100644 --- a/packages/cli/ete-tests/src/tests/fdr/__snapshots__/fdr.test.ts.snap +++ b/packages/cli/ete-tests/src/tests/fdr/__snapshots__/fdr.test.ts.snap @@ -1,5 +1,732 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`fdr {"name":"changelog"} 1`] = ` +"{ + "types": { + "type_commons:UndiscriminatedUnion": { + "name": "UndiscriminatedUnion", + "shape": { + "type": "undiscriminatedUnion", + "variants": [ + { + "type": { + "type": "primitive", + "value": { + "type": "string" + } + } + }, + { + "type": { + "type": "list", + "itemType": { + "type": "primitive", + "value": { + "type": "string" + } + } + } + }, + { + "type": { + "type": "primitive", + "value": { + "type": "integer" + } + } + }, + { + "type": { + "type": "list", + "itemType": { + "type": "list", + "itemType": { + "type": "primitive", + "value": { + "type": "integer" + } + } + } + } + } + ] + } + }, + "type_director:Director": { + "name": "Director", + "shape": { + "type": "object", + "extends": [], + "properties": [ + { + "key": "name", + "valueType": { + "type": "primitive", + "value": { + "type": "string" + } + } + }, + { + "key": "age", + "valueType": { + "type": "id", + "value": "type_director:Age" + } + } + ] + } + }, + "type_director:Age": { + "name": "Age", + "shape": { + "type": "alias", + "value": { + "type": "primitive", + "value": { + "type": "integer" + } + } + } + }, + "type_director:LiteralString": { + "name": "LiteralString", + "shape": { + "type": "alias", + "value": { + "type": "literal", + "value": { + "type": "stringLiteral", + "value": "hello" + } + } + } + }, + "type_imdb:CurrencyAmount": { + "name": "CurrencyAmount", + "shape": { + "type": "alias", + "value": { + "type": "primitive", + "value": { + "type": "string" + } + } + } + }, + "type_imdb:MovieId": { + "name": "MovieId", + "shape": { + "type": "alias", + "value": { + "type": "primitive", + "value": { + "type": "string" + } + } + } + }, + "type_imdb:ActorId": { + "name": "ActorId", + "shape": { + "type": "alias", + "value": { + "type": "primitive", + "value": { + "type": "string" + } + } + } + }, + "type_imdb:Movie": { + "name": "Movie", + "shape": { + "type": "object", + "extends": [], + "properties": [ + { + "key": "id", + "valueType": { + "type": "id", + "value": "type_imdb:MovieId" + } + }, + { + "key": "title", + "valueType": { + "type": "primitive", + "value": { + "type": "string" + } + } + }, + { + "key": "rating", + "valueType": { + "type": "primitive", + "value": { + "type": "double" + } + } + } + ] + } + }, + "type_imdb:CreateMovieRequest": { + "name": "CreateMovieRequest", + "shape": { + "type": "object", + "extends": [], + "properties": [ + { + "key": "title", + "valueType": { + "type": "primitive", + "value": { + "type": "string" + } + } + }, + { + "key": "ratings", + "valueType": { + "type": "list", + "itemType": { + "type": "primitive", + "value": { + "type": "double" + } + } + } + } + ] + } + }, + "type_imdb:DirectorWrapper": { + "name": "DirectorWrapper", + "shape": { + "type": "object", + "extends": [], + "properties": [ + { + "key": "director", + "valueType": { + "type": "id", + "value": "type_director:Director" + } + } + ] + } + }, + "type_imdb:Person": { + "name": "Person", + "shape": { + "type": "discriminatedUnion", + "discriminant": "type", + "variants": [ + { + "discriminantValue": "actor", + "additionalProperties": { + "extends": [], + "properties": [ + { + "key": "value", + "valueType": { + "type": "id", + "value": "type_imdb:ActorId" + } + } + ] + } + }, + { + "discriminantValue": "director", + "additionalProperties": { + "extends": [ + "type_director:Director" + ], + "properties": [] + } + }, + { + "discriminantValue": "producer", + "additionalProperties": { + "extends": [], + "properties": [] + } + }, + { + "description": "i am docs", + "discriminantValue": "cinematographer", + "additionalProperties": { + "extends": [], + "properties": [] + } + } + ] + } + }, + "type_imdb:RecursiveType": { + "name": "RecursiveType", + "shape": { + "type": "object", + "extends": [ + "type_imdb:CreateMovieRequest" + ], + "properties": [ + { + "key": "selfReferencing", + "valueType": { + "type": "list", + "itemType": { + "type": "id", + "value": "type_imdb:RecursiveType" + } + } + } + ] + } + } + }, + "subpackages": { + "subpackage_commons": { + "subpackageId": "subpackage_commons", + "name": "commons", + "endpoints": [], + "webhooks": [], + "websockets": [], + "types": [ + "type_commons:UndiscriminatedUnion" + ], + "subpackages": [] + }, + "subpackage_director": { + "subpackageId": "subpackage_director", + "name": "director", + "endpoints": [], + "webhooks": [], + "websockets": [], + "types": [ + "type_director:Director", + "type_director:Age", + "type_director:LiteralString" + ], + "subpackages": [] + }, + "subpackage_imdb": { + "subpackageId": "subpackage_imdb", + "name": "imdb", + "endpoints": [ + { + "auth": false, + "method": "POST", + "id": "createMovie", + "name": "Create Movie", + "path": { + "pathParameters": [], + "parts": [ + { + "type": "literal", + "value": "/movies" + }, + { + "type": "literal", + "value": "" + } + ] + }, + "queryParameters": [], + "headers": [], + "request": { + "type": { + "type": "json", + "contentType": "application/json", + "shape": { + "type": "reference", + "value": { + "type": "id", + "value": "type_imdb:CreateMovieRequest" + } + } + } + }, + "response": { + "type": { + "type": "reference", + "value": { + "type": "id", + "value": "type_imdb:MovieId" + } + } + }, + "errors": [ + { + "statusCode": 400 + } + ], + "errorsV2": [ + { + "statusCode": 400, + "name": "BadRequestError" + } + ], + "examples": [ + { + "path": "/movies", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "title": "Shrek", + "ratings": [ + 10, + 10, + 10, + 10 + ] + }, + "requestBodyV3": { + "type": "json", + "value": { + "title": "Shrek", + "ratings": [ + 10, + 10, + 10, + 10 + ] + } + }, + "responseStatusCode": 200, + "responseBody": "shrek-123", + "responseBodyV3": { + "type": "json", + "value": "shrek-123" + } + }, + { + "path": "/movies", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "title": "Winnie the Pooh", + "ratings": [ + 1, + 2, + 3 + ] + }, + "requestBodyV3": { + "type": "json", + "value": { + "title": "Winnie the Pooh", + "ratings": [ + 1, + 2, + 3 + ] + } + }, + "responseStatusCode": 200, + "responseBody": "shrek-123", + "responseBodyV3": { + "type": "json", + "value": "shrek-123" + } + } + ] + }, + { + "auth": false, + "method": "GET", + "id": "getMovie", + "name": "Get Movie by Id", + "path": { + "pathParameters": [ + { + "key": "movieId", + "type": { + "type": "id", + "value": "type_imdb:MovieId" + } + } + ], + "parts": [ + { + "type": "literal", + "value": "/movies" + }, + { + "type": "literal", + "value": "/" + }, + { + "type": "pathParameter", + "value": "movieId" + }, + { + "type": "literal", + "value": "" + } + ] + }, + "queryParameters": [ + { + "key": "movieName", + "type": { + "type": "primitive", + "value": { + "type": "string" + } + } + } + ], + "headers": [], + "response": { + "type": { + "type": "reference", + "value": { + "type": "id", + "value": "type_imdb:Movie" + } + } + }, + "errors": [ + { + "type": { + "type": "primitive", + "value": { + "type": "string" + } + }, + "statusCode": 404 + }, + { + "statusCode": 400 + } + ], + "errorsV2": [ + { + "type": { + "type": "object", + "extends": [], + "properties": [ + { + "key": "error", + "valueType": { + "type": "literal", + "value": { + "type": "stringLiteral", + "value": "NotFoundError" + } + } + }, + { + "key": "content", + "valueType": { + "type": "primitive", + "value": { + "type": "string" + } + } + } + ] + }, + "statusCode": 404, + "name": "NotFoundError" + }, + { + "statusCode": 400, + "name": "BadRequestError" + } + ], + "examples": [ + { + "path": "/movies/id-123", + "pathParameters": { + "movieId": "id-123" + }, + "queryParameters": { + "movieName": "hello" + }, + "headers": {}, + "responseStatusCode": 200, + "responseBody": { + "id": "id-123", + "title": "Shrek", + "rating": 10 + }, + "responseBodyV3": { + "type": "json", + "value": { + "id": "id-123", + "title": "Shrek", + "rating": 10 + } + } + }, + { + "path": "/movies/id-123", + "pathParameters": { + "movieId": "id-123" + }, + "queryParameters": { + "movieName": "hello" + }, + "headers": {}, + "responseStatusCode": 404, + "responseBody": "id-123", + "responseBodyV3": { + "type": "json", + "value": "id-123" + } + } + ] + }, + { + "auth": false, + "method": "DELETE", + "id": "delete", + "name": "Delete", + "path": { + "pathParameters": [ + { + "key": "movieId", + "type": { + "type": "id", + "value": "type_imdb:MovieId" + } + } + ], + "parts": [ + { + "type": "literal", + "value": "/movies" + }, + { + "type": "literal", + "value": "/" + }, + { + "type": "pathParameter", + "value": "movieId" + }, + { + "type": "literal", + "value": "" + } + ] + }, + "queryParameters": [], + "headers": [], + "errors": [ + { + "statusCode": 400 + } + ], + "errorsV2": [ + { + "statusCode": 400, + "name": "BadRequestError" + } + ], + "examples": [] + }, + { + "auth": false, + "method": "POST", + "id": "upload", + "name": "Upload", + "path": { + "pathParameters": [ + { + "key": "movieId", + "type": { + "type": "id", + "value": "type_imdb:MovieId" + } + } + ], + "parts": [ + { + "type": "literal", + "value": "/movies" + }, + { + "type": "literal", + "value": "/upload/" + }, + { + "type": "pathParameter", + "value": "movieId" + }, + { + "type": "literal", + "value": "" + } + ] + }, + "queryParameters": [], + "headers": [], + "errors": [ + { + "statusCode": 400 + } + ], + "errorsV2": [ + { + "statusCode": 400, + "name": "BadRequestError" + } + ], + "examples": [] + } + ], + "webhooks": [], + "websockets": [], + "types": [ + "type_imdb:CurrencyAmount", + "type_imdb:MovieId", + "type_imdb:ActorId", + "type_imdb:Movie", + "type_imdb:CreateMovieRequest", + "type_imdb:DirectorWrapper", + "type_imdb:Person", + "type_imdb:RecursiveType" + ], + "subpackages": [] + } + }, + "rootPackage": { + "endpoints": [], + "webhooks": [], + "websockets": [], + "types": [], + "subpackages": [ + "subpackage_commons", + "subpackage_director", + "subpackage_imdb" + ] + }, + "snippetsConfiguration": {}, + "globalHeaders": [ + { + "key": "X-API-VERSION", + "type": { + "type": "optional", + "itemType": { + "type": "primitive", + "value": { + "type": "string" + } + } + } + } + ] +}" +`; + exports[`fdr {"name":"simple"} 1`] = ` "{ "types": { diff --git a/packages/cli/ete-tests/src/tests/fdr/fdr.test.ts b/packages/cli/ete-tests/src/tests/fdr/fdr.test.ts index d92bd4c9021..01c538f386a 100644 --- a/packages/cli/ete-tests/src/tests/fdr/fdr.test.ts +++ b/packages/cli/ete-tests/src/tests/fdr/fdr.test.ts @@ -7,6 +7,9 @@ const FIXTURES_DIR = join(AbsoluteFilePath.of(__dirname), RelativeFilePath.of("f const FIXTURES: Fixture[] = [ { name: "simple" + }, + { + name: "changelog" } ]; diff --git a/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/changelog/2022-02-02.mdx b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/changelog/2022-02-02.mdx new file mode 100644 index 00000000000..8a802039f7f --- /dev/null +++ b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/changelog/2022-02-02.mdx @@ -0,0 +1 @@ +## Changelog diff --git a/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/api.yml b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/api.yml new file mode 100644 index 00000000000..85b1be39773 --- /dev/null +++ b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/api.yml @@ -0,0 +1,19 @@ +imports: + commons: commons.yml +name: my-api +docs: foo bar baz +headers: + X-API-VERSION: + name: apiVersion + type: optional +error-discrimination: + strategy: property + property-name: error +audiences: + - test +errors: + - commons.BadRequestError + +base-path: /test/{rootPathParam} +path-parameters: + rootPathParam: string diff --git a/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/commons.yml b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/commons.yml new file mode 100644 index 00000000000..9eaa66c3ad5 --- /dev/null +++ b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/commons.yml @@ -0,0 +1,12 @@ +types: + UndiscriminatedUnion: + discriminated: false + union: + - string + - list + - integer + - list> + +errors: + BadRequestError: + status-code: 400 diff --git a/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/director.yml b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/director.yml new file mode 100644 index 00000000000..9e3e27ad6a2 --- /dev/null +++ b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/director.yml @@ -0,0 +1,16 @@ +types: + Director: + properties: + name: string + age: Age + examples: + - name: GeorgeExample + value: + name: George the Director + age: $Age.Example1 + Age: + type: integer + examples: + - name: Example1 + value: 20 + LiteralString: literal<"hello"> diff --git a/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/imdb.yml b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/imdb.yml new file mode 100644 index 00000000000..673dc3b3bb9 --- /dev/null +++ b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/definition/imdb.yml @@ -0,0 +1,150 @@ +imports: + director: director.yml +types: + CurrencyAmount: + type: string + examples: + - value: \$4.50 + MovieId: + type: string + examples: + - value: id1 + - value: id2 + ActorId: string + Movie: + properties: + id: MovieId + title: string + rating: double + examples: + - value: + id: my-movie-id + title: Goodwill Hunting + rating: 14.5 + CreateMovieRequest: + properties: + title: string + ratings: list + examples: + - name: Example1 + value: + title: Winnie the Pooh + ratings: [1, 2, 3] + DirectorWrapper: + properties: + director: director.Director + examples: + - value: + director: $director.Director.GeorgeExample + Person: + union: + actor: ActorId + director: director.Director + producer: {} + cinematographer: + docs: i am docs + type: {} + examples: + - name: PersonExample1 + docs: this is a person example + value: + type: actor + value: Matt Damon + - value: + type: director + name: George the Directory + age: 100 + - value: + type: producer + RecursiveType: + extends: CreateMovieRequest + properties: + selfReferencing: list + examples: + - value: + title: The Godfather + ratings: [10, 5, 9] + selfReferencing: + - title: The Godfather II + ratings: [10, 11] + selfReferencing: [] + - title: The Godfather III + ratings: [] + selfReferencing: [] + - value: + title: Goodfellas + ratings: [1, 2, 3] + selfReferencing: [] +errors: + NotFoundError: + status-code: 404 + type: string +service: + auth: false + base-path: /movies + endpoints: + createMovie: + method: POST + path: "" + request: CreateMovieRequest + response: MovieId + audiences: + - test + examples: + - path-parameters: + rootPathParam: root + request: + title: Shrek + ratings: [10, 10, 10, 10] + response: + body: shrek-123 + - path-parameters: + rootPathParam: root + request: $CreateMovieRequest.Example1 + response: + body: shrek-123 + getMovie: + method: GET + display-name: "Get Movie by Id" + path: /{movieId} + path-parameters: + movieId: MovieId + request: + name: GetMovieRequest + query-parameters: + movieName: + type: string + allow-multiple: true + response: Movie + errors: + - NotFoundError + examples: + - path-parameters: + rootPathParam: root + movieId: id-123 + query-parameters: + movieName: hello + response: + body: + id: id-123 + title: Shrek + rating: 10 + - path-parameters: + rootPathParam: root + movieId: id-123 + query-parameters: + movieName: hello + response: + error: NotFoundError + body: id-123 + delete: + method: DELETE + path: /{movieId} + path-parameters: + movieId: MovieId + upload: + method: POST + path: /upload/{movieId} + path-parameters: + movieId: MovieId + request: bytes diff --git a/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/fern.config.json b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/fern.config.json new file mode 100644 index 00000000000..9538944f200 --- /dev/null +++ b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "version": "*", + "organization": "fern" +} diff --git a/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/generators.yml b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/cli/ete-tests/src/tests/fdr/fixtures/changelog/fern/generators.yml @@ -0,0 +1 @@ +{} diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json index 82e772626e4..8d3b91b89d1 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json @@ -33,7 +33,7 @@ "@fern-api/core-utils": "workspace:*", "@fern-api/docs-config-sdk": "workspace:*", "@fern-api/docs-configuration": "workspace:*", - "@fern-api/fdr-sdk": "0.50.8-1-gace1ff5", + "@fern-api/fdr-sdk": "0.50.12-4-gdf2d015", "@fern-api/fs-utils": "workspace:*", "@fern-api/generators-configuration": "workspace:*", "@fern-api/ir-generator": "workspace:*", diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts index a64093e49c0..657860d021d 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts @@ -206,27 +206,31 @@ async function constructRegisterDocsRequest({ version: string | undefined; editThisPage: FernDocsConfig.EditThisPageConfig | undefined; }): Promise { + const convertedDocsConfiguration = await convertDocsConfiguration({ + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + uploadUrls, + version + }); return { docsDefinition: { - pages: entries(parsedDocsConfig.pages).reduce( - (pages, [pageFilepath, pageContents]) => ({ - ...pages, - [pageFilepath]: { - markdown: pageContents, - editThisPageUrl: createEditThisPageUrl(editThisPage, pageFilepath) - } - }), - {} - ), - config: await convertDocsConfiguration({ - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - uploadUrls, - version - }) + pages: { + ...entries(parsedDocsConfig.pages).reduce( + (pages, [pageFilepath, pageContents]) => ({ + ...pages, + [pageFilepath]: { + markdown: pageContents, + editThisPageUrl: createEditThisPageUrl(editThisPage, pageFilepath) + } + }), + {} + ), + ...convertedDocsConfiguration.pages + }, + config: convertedDocsConfiguration.config } }; } @@ -244,6 +248,11 @@ function createEditThisPageUrl( return `${wrapWithHttps(host)}/${owner}/${repo}/blob/${branch}/fern/${pageFilepath}`; } +interface ConvertedDocsConfiguration { + config: Omit, "logo" | "colors" | "typography" | "colorsV2">; + pages: Record; +} + async function convertDocsConfiguration({ parsedDocsConfig, organization, @@ -260,8 +269,18 @@ async function convertDocsConfiguration({ token: FernToken; uploadUrls: Record; version: string | undefined; -}): Promise, "logo" | "colors" | "typography" | "colorsV2">> { - return { +}): Promise { + const convertedNavigation = await convertNavigationConfig({ + navigationConfig: parsedDocsConfig.navigation, + tabs: parsedDocsConfig.tabs, + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + version + }); + const config: Omit, "logo" | "colors" | "typography" | "colorsV2"> = { title: parsedDocsConfig.title, logoV2: { dark: @@ -303,16 +322,7 @@ async function convertDocsConfiguration({ context }) : undefined, - navigation: await convertNavigationConfig({ - navigationConfig: parsedDocsConfig.navigation, - tabs: parsedDocsConfig.tabs, - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - version - }), + navigation: convertedNavigation.config, colorsV3: parsedDocsConfig.colors, navbarLinks: parsedDocsConfig.navbarLinks, typographyV2: convertDocsTypographyConfiguration({ @@ -325,6 +335,17 @@ async function convertDocsConfiguration({ css: parsedDocsConfig.css, js: convertJavascriptConfiguration(parsedDocsConfig.js, uploadUrls, parsedDocsConfig) }; + return { + config, + pages: { + ...convertedNavigation.pages + } + }; +} + +interface ConvertedNavigationConfig { + config: DocsV1Write.NavigationConfig; + pages: Record; } async function convertNavigationConfig({ @@ -345,68 +366,81 @@ async function convertNavigationConfig({ context: TaskContext; token: FernToken; version: string | undefined; -}): Promise { +}): Promise { + let config: DocsV1Write.NavigationConfig; + let pages: Record = {}; switch (navigationConfig.type) { - case "untabbed": - return { - items: await Promise.all( - navigationConfig.items.map((item) => - convertNavigationItem({ - item, - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - version - }) - ) + case "untabbed": { + const untabbedItems = await Promise.all( + navigationConfig.items.map((item) => + convertNavigationItem({ + item, + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + version + }) ) + ); + pages = untabbedItems.reduce((pages, untabbedItem) => ({ ...pages, ...untabbedItem.pages }), {}); + config = { + items: untabbedItems.map((item) => item.item) }; + break; + } case "tabbed": - return { + config = { tabs: await Promise.all( navigationConfig.items.map(async (tabbedItem) => { const tabConfig = tabs?.[tabbedItem.tab]; if (tabConfig == null) { throw new Error(`Couldn't find config for tab id ${tabbedItem.tab}`); } + const tabbedItems = await Promise.all( + tabbedItem.layout.map((item) => + convertNavigationItem({ + item, + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + version + }) + ) + ); return { title: tabConfig.displayName, icon: tabConfig.icon, - items: await Promise.all( - tabbedItem.layout.map((item) => - convertNavigationItem({ - item, - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - version - }) - ) - ) + items: tabbedItems.map((tabItem) => tabItem.item) }; }) ) }; + break; case "versioned": - return { + config = { versions: await Promise.all( navigationConfig.versions.map( async (version): Promise => { + const convertedNavigation = await convertUnversionedNavigationConfig({ + navigationConfig: version.navigation, + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + version: version.version + }); + pages = { + ...pages, + ...convertedNavigation.pages + }; return { version: version.version, - config: await convertUnversionedNavigationConfig({ - navigationConfig: version.navigation, - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - version: version.version - }), + config: convertedNavigation.config, availability: version.availability != null ? convertAvailability(version.availability) @@ -417,9 +451,14 @@ async function convertNavigationConfig({ ) ) }; + break; default: assertNever(navigationConfig); } + return { + config, + pages: {} + }; } function convertAvailability(availability: VersionAvailability): DocsV1Write.VersionAvailability { @@ -437,6 +476,11 @@ function convertAvailability(availability: VersionAvailability): DocsV1Write.Ver } } +interface ConvertedUnversionedNavigationConfig { + config: DocsV1Write.UnversionedNavigationConfig; + pages: Record; +} + async function convertUnversionedNavigationConfig({ navigationConfig, tabs, @@ -455,56 +499,80 @@ async function convertUnversionedNavigationConfig({ context: TaskContext; token: FernToken; version: string | undefined; -}): Promise { +}): Promise { + let config: DocsV1Write.UnversionedNavigationConfig; + let pages: Record = {}; switch (navigationConfig.type) { - case "untabbed": - return { - items: await Promise.all( - navigationConfig.items.map((item) => - convertNavigationItem({ - item, - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - version - }) - ) + case "untabbed": { + const untabbedItems = await Promise.all( + navigationConfig.items.map((item) => + convertNavigationItem({ + item, + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + version + }) ) + ); + config = { + items: untabbedItems.map((item) => item.item) }; - case "tabbed": - return { + for (const untabbedItem of untabbedItems) { + pages = { + ...pages, + ...untabbedItem.pages + }; + } + break; + } + case "tabbed": { + config = { tabs: await Promise.all( navigationConfig.items.map(async (tabbedItem) => { const tabConfig = tabs?.[tabbedItem.tab]; if (tabConfig == null) { throw new Error(`Couldn't find config for tab id ${tabbedItem.tab}`); } + const tabItems = await Promise.all( + tabbedItem.layout.map((item) => + convertNavigationItem({ + item, + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + version + }) + ) + ); + for (const tabItem of tabItems) { + pages = { + ...pages, + ...tabItem.pages + }; + } return { title: tabConfig.displayName, icon: tabConfig.icon, - items: await Promise.all( - tabbedItem.layout.map((item) => - convertNavigationItem({ - item, - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - version - }) - ) - ), + items: tabItems.map((tabItem) => tabItem.item), urlSlugOverride: tabConfig.slug }; }) ) }; + break; + } default: assertNever(navigationConfig); } + return { + config, + pages: {} + }; } function convertDocsTypographyConfiguration({ @@ -639,6 +707,11 @@ async function convertImageReference({ return file.fileId; } +interface ConvertedNavigationItem { + item: DocsV1Write.NavigationItem; + pages: Record; +} + async function convertNavigationItem({ item, parsedDocsConfig, @@ -655,39 +728,53 @@ async function convertNavigationItem({ context: TaskContext; token: FernToken; version: string | undefined; -}): Promise { +}): Promise { + let convertedItem: DocsV1Write.NavigationItem; + let pages: Record = {}; switch (item.type) { - case "page": - return { + case "page": { + convertedItem = { type: "page", title: item.title, id: relative(dirname(parsedDocsConfig.absoluteFilepath), item.absolutePath), urlSlugOverride: item.slug }; - case "section": - return { + break; + } + case "section": { + const sectionItems = await Promise.all( + item.contents.map((nestedItem) => + convertNavigationItem({ + item: nestedItem, + parsedDocsConfig, + organization, + fernWorkspaces, + context, + token, + version + }) + ) + ); + convertedItem = { type: "section", title: item.title, - items: await Promise.all( - item.contents.map((nestedItem) => - convertNavigationItem({ - item: nestedItem, - parsedDocsConfig, - organization, - fernWorkspaces, - context, - token, - version - }) - ) - ), + items: sectionItems.map((sectionItem) => sectionItem.item), urlSlugOverride: item.slug, collapsed: item.collapsed }; + for (const sectionItem of sectionItems) { + pages = { + ...pages, + ...sectionItem.pages + }; + } + break; + } case "apiSection": { + const workspace = getFernWorkspaceForApiSection({ apiSection: item, fernWorkspaces }); const apiDefinitionId = await registerApi({ organization, - workspace: getFernWorkspaceForApiSection({ apiSection: item, fernWorkspaces }), + workspace, context, token, audiences: item.audiences, @@ -700,22 +787,48 @@ async function convertNavigationItem({ } }) }); - return { + if (workspace.changelog != null) { + for (const file of workspace.changelog.files) { + pages[file.absoluteFilepath] = { + markdown: file.contents + }; + } + } + convertedItem = { type: "api", title: item.title, api: apiDefinitionId, - showErrors: item.showErrors + showErrors: item.showErrors, + changelog: + workspace.changelog != null + ? { + urlSlug: "changelog", + items: workspace.changelog.files.map((file) => { + return { + date: new Date().toISOString(), + pageId: file.absoluteFilepath + }; + }) + } + : undefined }; + break; } - case "link": - return { + case "link": { + convertedItem = { type: "link", title: item.text, url: item.url }; + break; + } default: assertNever(item); } + return { + item: convertedItem, + pages + }; } function convertDocsSnippetsConfigurationToFdr({ diff --git a/packages/cli/register/package.json b/packages/cli/register/package.json index 10177da5cee..4c458b863d5 100644 --- a/packages/cli/register/package.json +++ b/packages/cli/register/package.json @@ -31,7 +31,7 @@ "@fern-api/config-management-commons": "workspace:*", "@fern-api/core": "workspace:*", "@fern-api/core-utils": "workspace:*", - "@fern-api/fdr-sdk": "0.50.8-1-gace1ff5", + "@fern-api/fdr-sdk": "0.50.12-4-gdf2d015", "@fern-api/ir-generator": "workspace:*", "@fern-api/ir-sdk": "workspace:*", "@fern-api/task-context": "workspace:*", diff --git a/packages/cli/workspace-loader/src/loadAPIChangelog.ts b/packages/cli/workspace-loader/src/loadAPIChangelog.ts new file mode 100644 index 00000000000..64c58957632 --- /dev/null +++ b/packages/cli/workspace-loader/src/loadAPIChangelog.ts @@ -0,0 +1,28 @@ +import { AbsoluteFilePath, doesPathExist, join, RelativeFilePath } from "@fern-api/fs-utils"; +import { CHANGELOG_DIRECTORY } from "@fern-api/project-configuration"; +import { listFiles } from "./listFiles"; +import { APIChangelog } from "./types/Workspace"; + +export async function loadAPIChangelog({ + absolutePathToWorkspace +}: { + absolutePathToWorkspace: AbsoluteFilePath; +}): Promise> { + const absolutePathToChangelogDirectory = join(absolutePathToWorkspace, RelativeFilePath.of(CHANGELOG_DIRECTORY)); + const changelogDirectoryExists = await doesPathExist(absolutePathToChangelogDirectory); + if (!changelogDirectoryExists) { + return undefined; + } + + const mdFiles = await listFiles(absolutePathToChangelogDirectory, "{md,mdx}"); + return { + files: await Promise.all( + mdFiles.map((file) => { + return { + absoluteFilepath: join(absolutePathToChangelogDirectory, file.filepath), + contents: file.fileContents + }; + }) + ) + }; +} diff --git a/packages/cli/workspace-loader/src/loadAPIWorkspace.ts b/packages/cli/workspace-loader/src/loadAPIWorkspace.ts index 25ce0b960c8..d78a17842ee 100644 --- a/packages/cli/workspace-loader/src/loadAPIWorkspace.ts +++ b/packages/cli/workspace-loader/src/loadAPIWorkspace.ts @@ -4,11 +4,13 @@ import { GeneratorsConfiguration, loadGeneratorsConfiguration } from "@fern-api/ import { ASYNCAPI_DIRECTORY, DEFINITION_DIRECTORY, OPENAPI_DIRECTORY } from "@fern-api/project-configuration"; import { TaskContext } from "@fern-api/task-context"; import { listFiles } from "./listFiles"; +import { loadAPIChangelog } from "./loadAPIChangelog"; import { getValidAbsolutePathToAsyncAPI, getValidAbsolutePathToAsyncAPIFromFolder } from "./loadAsyncAPIFile"; import { getValidAbsolutePathToOpenAPI, getValidAbsolutePathToOpenAPIFromFolder } from "./loadOpenAPIFile"; import { parseYamlFiles } from "./parseYamlFiles"; import { processPackageMarkers } from "./processPackageMarkers"; import { WorkspaceLoader } from "./types/Result"; +import { APIChangelog } from "./types/Workspace"; import { validateStructureOfYamlFiles } from "./validateStructureOfYamlFiles"; export async function loadAPIWorkspace({ @@ -27,6 +29,11 @@ export async function loadAPIWorkspace({ generatorsConfiguration = await loadGeneratorsConfiguration({ absolutePathToWorkspace, context }); } catch (err) {} + let changelog: APIChangelog | undefined = undefined; + try { + changelog = await loadAPIChangelog({ absolutePathToWorkspace }); + } catch (err) {} + const absolutePathToOpenAPIFolder = join(absolutePathToWorkspace, RelativeFilePath.of(OPENAPI_DIRECTORY)); const openApiDirectoryExists = await doesPathExist(absolutePathToOpenAPIFolder); @@ -51,7 +58,8 @@ export async function loadAPIWorkspace({ absoluteFilepath: absolutePathToWorkspace, generatorsConfiguration, absolutePathToOpenAPI, - absolutePathToAsyncAPI + absolutePathToAsyncAPI, + changelog } }; } @@ -72,7 +80,8 @@ export async function loadAPIWorkspace({ absoluteFilepath: absolutePathToWorkspace, generatorsConfiguration, absolutePathToOpenAPI, - absolutePathToAsyncAPI + absolutePathToAsyncAPI, + changelog } }; } @@ -120,7 +129,8 @@ export async function loadAPIWorkspace({ namedDefinitionFiles: structuralValidationResult.namedDefinitionFiles, packageMarkers: processPackageMarkersResult.packageMarkers, importedDefinitions: processPackageMarkersResult.importedDefinitions - } + }, + changelog } }; } diff --git a/packages/cli/workspace-loader/src/types/Workspace.ts b/packages/cli/workspace-loader/src/types/Workspace.ts index c3a98844826..f83786a7255 100644 --- a/packages/cli/workspace-loader/src/types/Workspace.ts +++ b/packages/cli/workspace-loader/src/types/Workspace.ts @@ -25,6 +25,16 @@ export interface OpenAPIWorkspace { generatorsConfiguration: GeneratorsConfiguration | undefined; absolutePathToOpenAPI: AbsoluteFilePath; absolutePathToAsyncAPI: AbsoluteFilePath | undefined; + changelog: APIChangelog | undefined; +} + +export interface APIChangelog { + files: ChangelogFile[]; +} + +export interface ChangelogFile { + absoluteFilepath: AbsoluteFilePath; + contents: string; } export interface OpenAPIFile { @@ -45,6 +55,7 @@ export interface FernWorkspace { generatorsConfiguration: GeneratorsConfiguration | undefined; dependenciesConfiguration: DependenciesConfiguration; definition: FernDefinition; + changelog: APIChangelog | undefined; } export interface FernDefinition { diff --git a/packages/cli/workspace-loader/src/utils/convertOpenApiWorkspaceToFernWorkspace.ts b/packages/cli/workspace-loader/src/utils/convertOpenApiWorkspaceToFernWorkspace.ts index e07efd0a51c..fc7ab1908f3 100644 --- a/packages/cli/workspace-loader/src/utils/convertOpenApiWorkspaceToFernWorkspace.ts +++ b/packages/cli/workspace-loader/src/utils/convertOpenApiWorkspaceToFernWorkspace.ts @@ -62,7 +62,8 @@ export async function convertOpenApiWorkspaceToFernWorkspace( }, packageMarkers: {}, importedDefinitions: {} - } + }, + changelog: openapiWorkspace.changelog }; } diff --git a/packages/core/package.json b/packages/core/package.json index f9de04e4ffb..bc03150269b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,7 +27,7 @@ "depcheck": "depcheck" }, "dependencies": { - "@fern-api/fdr-sdk": "0.50.8-1-gace1ff5", + "@fern-api/fdr-sdk": "0.50.12-4-gdf2d015", "@fern-api/venus-api-sdk": "0.0.38", "@fern-fern/fiddle-sdk": "^0.0.411" }, diff --git a/packages/docs-config-sdk/fern/definition/docs.yml b/packages/docs-config-sdk/fern/definition/docs.yml index 3e374cf6adf..e0f097a6987 100644 --- a/packages/docs-config-sdk/fern/definition/docs.yml +++ b/packages/docs-config-sdk/fern/definition/docs.yml @@ -311,6 +311,21 @@ types: type: optional docs: Defaults to false snippets: optional + # changelog: + # type: optional + # docs: | + # Defaults to the changelog directory in the API workspace if present. + # > fern/ + # changelog/ + # ... + # definition/ + # ... + + # ChangelogConfiguration: + # discriminated: false + # union: + # - type: string + # docs: Path to a custom folder which contains markdown files for the changelog. LinkConfiguration: properties: diff --git a/packages/docs-config-sdk/src/sdk/api/resources/docs/types/ApiSectionConfiguration.ts b/packages/docs-config-sdk/src/sdk/api/resources/docs/types/ApiSectionConfiguration.ts index 5a74f0220e0..6f88742f000 100644 --- a/packages/docs-config-sdk/src/sdk/api/resources/docs/types/ApiSectionConfiguration.ts +++ b/packages/docs-config-sdk/src/sdk/api/resources/docs/types/ApiSectionConfiguration.ts @@ -12,4 +12,15 @@ export interface ApiSectionConfiguration { /** Defaults to false */ displayErrors?: boolean; snippets?: FernDocsConfig.SnippetsConfiguration; + /** + * Defaults to the changelog directory in the API workspace if present. + * + * > fern/ + * + * changelog/ + * ... + * definition/ + * ... + */ + changelog?: FernDocsConfig.ChangelogConfiguration; } diff --git a/packages/docs-config-sdk/src/sdk/api/resources/docs/types/ChangelogConfiguration.ts b/packages/docs-config-sdk/src/sdk/api/resources/docs/types/ChangelogConfiguration.ts new file mode 100644 index 00000000000..3fa05504ca7 --- /dev/null +++ b/packages/docs-config-sdk/src/sdk/api/resources/docs/types/ChangelogConfiguration.ts @@ -0,0 +1,8 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +export type ChangelogConfiguration = + /** + * Path to a custom folder which contains markdown files for the changelog. */ + string; diff --git a/packages/docs-config-sdk/src/sdk/api/resources/docs/types/index.ts b/packages/docs-config-sdk/src/sdk/api/resources/docs/types/index.ts index 0f292b9d80e..caacabe769e 100644 --- a/packages/docs-config-sdk/src/sdk/api/resources/docs/types/index.ts +++ b/packages/docs-config-sdk/src/sdk/api/resources/docs/types/index.ts @@ -25,6 +25,7 @@ export * from "./FontConfigVariant"; export * from "./PageConfiguration"; export * from "./SectionConfiguration"; export * from "./ApiSectionConfiguration"; +export * from "./ChangelogConfiguration"; export * from "./LinkConfiguration"; export * from "./SnippetsConfiguration"; export * from "./ColorsConfiguration"; diff --git a/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ApiSectionConfiguration.ts b/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ApiSectionConfiguration.ts index 42d2a7a8aa7..729316c9f7f 100644 --- a/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ApiSectionConfiguration.ts +++ b/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ApiSectionConfiguration.ts @@ -15,6 +15,7 @@ export const ApiSectionConfiguration: core.serialization.ObjectSchema< audiences: core.serialization.list(core.serialization.string()).optional(), displayErrors: core.serialization.property("display-errors", core.serialization.boolean().optional()), snippets: core.serialization.lazyObject(async () => (await import("../../..")).SnippetsConfiguration).optional(), + changelog: core.serialization.lazy(async () => (await import("../../..")).ChangelogConfiguration).optional(), }); export declare namespace ApiSectionConfiguration { @@ -24,5 +25,6 @@ export declare namespace ApiSectionConfiguration { audiences?: string[] | null; "display-errors"?: boolean | null; snippets?: serializers.SnippetsConfiguration.Raw | null; + changelog?: serializers.ChangelogConfiguration.Raw | null; } } diff --git a/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ChangelogConfiguration.ts b/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ChangelogConfiguration.ts new file mode 100644 index 00000000000..689d3b8c754 --- /dev/null +++ b/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/ChangelogConfiguration.ts @@ -0,0 +1,16 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as serializers from "../../.."; +import * as FernDocsConfig from "../../../../api"; +import * as core from "../../../../core"; + +export const ChangelogConfiguration: core.serialization.Schema< + serializers.ChangelogConfiguration.Raw, + FernDocsConfig.ChangelogConfiguration +> = core.serialization.undiscriminatedUnion([core.serialization.string()]); + +export declare namespace ChangelogConfiguration { + type Raw = string; +} diff --git a/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/index.ts b/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/index.ts index 0f292b9d80e..caacabe769e 100644 --- a/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/index.ts +++ b/packages/docs-config-sdk/src/sdk/serialization/resources/docs/types/index.ts @@ -25,6 +25,7 @@ export * from "./FontConfigVariant"; export * from "./PageConfiguration"; export * from "./SectionConfiguration"; export * from "./ApiSectionConfiguration"; +export * from "./ChangelogConfiguration"; export * from "./LinkConfiguration"; export * from "./SnippetsConfiguration"; export * from "./ColorsConfiguration"; diff --git a/yarn.lock b/yarn.lock index b307ac31f87..cf46a44a508 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2447,7 +2447,7 @@ __metadata: version: 0.0.0-use.local resolution: "@fern-api/core@workspace:packages/core" dependencies: - "@fern-api/fdr-sdk": 0.50.8-1-gace1ff5 + "@fern-api/fdr-sdk": 0.50.12-4-gdf2d015 "@fern-api/venus-api-sdk": 0.0.38 "@fern-fern/fiddle-sdk": ^0.0.411 "@types/jest": ^29.0.3 @@ -2563,7 +2563,7 @@ __metadata: "@fern-api/config-management-commons": "workspace:*" "@fern-api/core-utils": "workspace:*" "@fern-api/docs-config-sdk": "workspace:*" - "@fern-api/fdr-sdk": 0.50.8-1-gace1ff5 + "@fern-api/fdr-sdk": 0.50.12-4-gdf2d015 "@fern-api/fs-utils": "workspace:*" "@fern-api/task-context": "workspace:*" "@types/jest": ^29.0.3 @@ -2588,7 +2588,7 @@ __metadata: "@fern-api/core-utils": "workspace:*" "@fern-api/docs-config-sdk": "workspace:*" "@fern-api/docs-configuration": "workspace:*" - "@fern-api/fdr-sdk": 0.50.8-1-gace1ff5 + "@fern-api/fdr-sdk": 0.50.12-4-gdf2d015 "@fern-api/fs-utils": "workspace:*" "@fern-api/ir-generator": "workspace:*" "@fern-api/register": "workspace:*" @@ -2658,9 +2658,9 @@ __metadata: languageName: unknown linkType: soft -"@fern-api/fdr-sdk@npm:0.50.8-1-gace1ff5": - version: 0.50.8-1-gace1ff5 - resolution: "@fern-api/fdr-sdk@npm:0.50.8-1-gace1ff5" +"@fern-api/fdr-sdk@npm:0.50.12-4-gdf2d015": + version: 0.50.12-4-gdf2d015 + resolution: "@fern-api/fdr-sdk@npm:0.50.12-4-gdf2d015" dependencies: "@ungap/url-search-params": 0.2.2 axios: 0.27.2 @@ -2668,7 +2668,7 @@ __metadata: lodash: ^4.17.21 marked: ^5.1.0 url-join: 4.0.1 - checksum: 32de6d37ef8116a59e94dfd053eb954f6f53e12fd40110974c7eb51dfdc3531b7dc445a2e435a68e2e16c889563c66bdbacbba8c8f3a510568e2d96536732971 + checksum: e688367577a88a2cceab4016a1d5521f1c0e76e495462d167d06de782411300a23ead33ca314d28660ed6bde70a9801799841497e425fe7d98908727e4db8016 languageName: node linkType: hard @@ -3363,7 +3363,7 @@ __metadata: "@fern-api/config-management-commons": "workspace:*" "@fern-api/core": "workspace:*" "@fern-api/core-utils": "workspace:*" - "@fern-api/fdr-sdk": 0.50.8-1-gace1ff5 + "@fern-api/fdr-sdk": 0.50.12-4-gdf2d015 "@fern-api/ir-generator": "workspace:*" "@fern-api/ir-sdk": "workspace:*" "@fern-api/task-context": "workspace:*" @@ -3391,7 +3391,7 @@ __metadata: "@fern-api/core-utils": "workspace:*" "@fern-api/docs-config-sdk": "workspace:*" "@fern-api/docs-configuration": "workspace:*" - "@fern-api/fdr-sdk": 0.50.8-1-gace1ff5 + "@fern-api/fdr-sdk": 0.50.12-4-gdf2d015 "@fern-api/fs-utils": "workspace:*" "@fern-api/generators-configuration": "workspace:*" "@fern-api/ir-generator": "workspace:*"