Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions docs-yml.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,16 @@
"type": "null"
}
]
},
"blog": {
"oneOf": [
{
"$ref": "#/definitions/docs.ChangelogFolderRelativePath"
},
{
"type": "null"
}
]
}
},
"required": [
Expand Down Expand Up @@ -2954,6 +2964,89 @@
],
"additionalProperties": false
},
"docs.BlogConfiguration": {
"type": "object",
"properties": {
"viewers": {
"oneOf": [
{
"$ref": "#/definitions/docs.Role"
},
{
"type": "null"
}
]
},
"orphaned": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "When `orphaned` is set to `true`, the roles will not inherit from parents."
},
"feature-flag": {
"oneOf": [
{
"$ref": "#/definitions/docs.FeatureFlagConfiguration"
},
{
"type": "null"
}
]
},
"blog": {
"$ref": "#/definitions/docs.ChangelogFolderRelativePath"
},
"title": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"slug": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"icon": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"hidden": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "null"
}
]
}
},
"required": [
"blog"
],
"additionalProperties": false
},
"docs.TitleSource": {
"type": "string",
"enum": [
Expand Down Expand Up @@ -3130,6 +3223,9 @@
{
"$ref": "#/definitions/docs.ChangelogConfiguration"
},
{
"$ref": "#/definitions/docs.BlogConfiguration"
},
{
"$ref": "#/definitions/docs.FolderConfiguration"
}
Expand Down
81 changes: 81 additions & 0 deletions fern-yml.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,9 @@
},
"changelog": {
"type": "string"
},
"blog": {
"type": "string"
}
},
"required": [
Expand Down Expand Up @@ -5782,6 +5785,84 @@
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"viewers": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"orphaned": {
"type": "boolean"
},
"feature-flag": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"flag": {
"type": "string"
},
"fallback-value": {},
"match": {}
},
"required": [
"flag"
],
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"flag": {
"type": "string"
},
"fallback-value": {},
"match": {}
},
"required": [
"flag"
],
"additionalProperties": false
}
}
]
},
"blog": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"icon": {
"type": "string"
},
"hidden": {
"type": "boolean"
}
},
"required": [
"blog"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
Expand Down
12 changes: 12 additions & 0 deletions fern/apis/docs-yml/definition/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ types:
Tabs with `href` must not have children in the navigation config.
target: optional<Target>
changelog: optional<ChangelogFolderRelativePath>
blog: optional<ChangelogFolderRelativePath>

ChangelogFolderRelativePath:
type: string
Expand Down Expand Up @@ -816,6 +817,7 @@ types:
- LibraryReferenceConfiguration
- LinkConfiguration
- ChangelogConfiguration
- BlogConfiguration
- FolderConfiguration

LogoConfiguration:
Expand Down Expand Up @@ -1411,6 +1413,16 @@ types:
hidden: optional<boolean>
# skip-slug: optional<boolean> # skip-slug is not needed for changelog

BlogConfiguration:
extends: [WithPermissions, WithFeatureFlags]
properties:
blog: ChangelogFolderRelativePath
title: optional<string> # defaults to "Blog"
slug: optional<string>
icon: optional<string>
hidden: optional<boolean>
# skip-slug: optional<boolean> # skip-slug is not needed for blog

SectionConfiguration:
extends: [WithPermissions, WithFeatureFlags]
properties:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json

- summary: |
Add a blog navigation item as an alias for changelog navigation.
type: feat
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { docsYml } from "@fern-api/configuration";
import { AbsoluteFilePath } from "@fern-api/fs-utils";
import { createMockTaskContext } from "@fern-api/task-context";
import { describe, expect, it } from "vitest";

import { parseDocsConfiguration } from "../parseDocsConfiguration.js";

const FAKE_FERN_DIR = "/fern" as AbsoluteFilePath;
const FAKE_CONFIG_PATH = "/fern/docs.yml" as AbsoluteFilePath;

async function parseRawDocsYml(rawDocsYml: unknown): Promise<docsYml.ParsedDocsConfiguration> {
const rawDocsConfiguration = docsYml.RawSchemas.Serializer.DocsConfiguration.parseOrThrow(rawDocsYml);
return await parseDocsConfiguration({
rawDocsConfiguration,
absolutePathToFernFolder: FAKE_FERN_DIR,
absoluteFilepathToDocsConfig: FAKE_CONFIG_PATH,
context: createMockTaskContext()
});
}

describe("blog navigation alias", () => {
it("normalizes a top-level blog item to a changelog item", async () => {
const changelog = await parseRawDocsYml({
instances: [],
navigation: [{ changelog: "blog" }]
});
const blog = await parseRawDocsYml({
instances: [],
navigation: [{ blog: "blog" }]
});
if (changelog.navigation.type !== "untabbed" || blog.navigation.type !== "untabbed") {
throw new Error("Expected untabbed navigation");
}

expect(changelog.navigation).toEqual({
type: "untabbed",
items: [
{
type: "changelog",
changelog: [],
hidden: false,
icon: undefined,
title: "Changelog",
slug: undefined,
viewers: undefined,
orphaned: undefined,
featureFlags: undefined
}
]
});
expect(blog.navigation).toEqual({
...changelog.navigation,
items: [{ ...changelog.navigation.items[0], title: "Blog" }]
});
});

it("normalizes a tab blog item to a changelog child", async () => {
const changelog = await parseRawDocsYml({
instances: [],
tabs: {
posts: {
"display-name": "Posts",
changelog: "blog"
}
},
navigation: [{ tab: "posts" }]
});
const blog = await parseRawDocsYml({
instances: [],
tabs: {
posts: {
"display-name": "Posts",
blog: "blog"
}
},
navigation: [{ tab: "posts" }]
});

expect(changelog.navigation).toEqual({
type: "tabbed",
items: [
{
title: "Posts",
icon: undefined,
slug: undefined,
skipUrlSlug: undefined,
hidden: undefined,
child: {
type: "changelog",
changelog: []
},
viewers: undefined,
orphaned: undefined,
featureFlags: undefined
}
]
});
expect(blog.navigation).toEqual(changelog.navigation);
});

it("preserves an explicit blog title", async () => {
const parsed = await parseRawDocsYml({
instances: [],
navigation: [{ blog: "blog", title: "Engineering Blog" }]
});

if (parsed.navigation.type !== "untabbed") {
throw new Error("Expected untabbed navigation");
}
expect(parsed.navigation.items[0]).toMatchObject({
type: "changelog",
title: "Engineering Blog"
});
});
});
Loading
Loading