Skip to content

Commit

Permalink
feat: add api summary markdown pages (#3350)
Browse files Browse the repository at this point in the history
* stash: api summary markdown page

* wire up convertToNavigation

* revert tsconfig

* delete comments

* thread through fullSlug

* remove unused export

* fix: build failures
  • Loading branch information
abvthecity authored Apr 10, 2024
1 parent 3ba5a27 commit a1fb67b
Show file tree
Hide file tree
Showing 31 changed files with 468 additions and 291 deletions.
16 changes: 8 additions & 8 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ export async function generateFdrApiDefinitionForWorkspaces({

const apiDefinition = convertIrToFdrApi({
ir,
snippetsConfig: {},
navigation: undefined
snippetsConfig: {}
});

const resolvedOutputFilePath = path.resolve(outputFilepath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ export async function registerWorkspacesV2({
context,
token,
audiences: { type: "all" },
snippetsConfig: {},
navigation: undefined
snippetsConfig: {}
});
context.logger.info(chalk.green("Registered API"));
}
Expand Down
73 changes: 49 additions & 24 deletions packages/cli/configuration/fern/definition/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -369,37 +369,62 @@ types:
type: optional<boolean>
docs: Defaults to false
snippets: optional<SnippetsConfiguration>
layout:
type: optional<ApiSectionLayout>
docs: |
If `layout` is set to `sidebar`, the API section will render with a sidebar.
If `layout` is set to `full`, the API section will render without a sidebar.
ApiSectionLayout:
docs: |
summary:
type: optional<string>
docs: |
Relative path to the markdown file. This summary is displayed at the top of the API section.
layout:
type: optional<ApiNavigationItems>
docs: |
Advanced usage: when specified, this object will be used to customize the order that your API endpoints are displayed in the docs site, including subpackages, and additional markdown pages (to be rendered in between API endpoints). If not specified, the order will be inferred from the OpenAPI Spec or Fern Definition.
ApiNavigationItem:
docs: |
Use the `layout` object to customize the order that your API endpoints
are displayed in the docs site.
type: unknown
examples:
discriminated: false
union:
- type: string
docs: |
This should be either an endpoint, websocket, webhook, or subpackage ID
- type: map<string, ApiNavigationItems>
docs: |
Keyed by subpackage ID, this object allows you to group endpoints and pages together.
- type: PageConfiguration
docs: |
This should be a markdown file that will be displayed in the API section.
ApiNavigationItems:
type: list<ApiNavigationItem>
examples:
- name: Ordering Groups
value:
value:
- users # users endpoints will be displayed first
- roles
- permissions
- name: Ordering Endpoints
value:
- roles
- get
- create
- update
value:
- roles:
- get
- create
- update
- users:
- get
- create
- update
- permissions:
- get
- create
- update
- name: Ordering Groups and Pages
value:
- users
- get
- create
- update
- roles:
- get
- create
- ./pages/inner-page.mdx
- update
- permissions
- get
- create
- update

LinkConfiguration:
properties:
Expand All @@ -421,12 +446,12 @@ types:
The primary accent color is used for buttons, links, and other interactive elements.
@default: #818CF8
accentPrimary:
type: optional<ColorConfig>
name: accentPrimaryDeprecated
availability: deprecated
docs: |
docs: |
Use `accent-primary` instead.
background:
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/configuration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"dependencies": {
"@fern-api/core-utils": "workspace:*",
"@fern-api/fdr-sdk": "^0.73.0-d986da306",
"@fern-api/fdr-sdk": "0.73.1-9d67ec828",
"@fern-api/fs-utils": "workspace:*",
"@fern-api/task-context": "workspace:*",
"@fern-fern/fiddle-sdk": "^0.0.503",
Expand Down
46 changes: 20 additions & 26 deletions packages/cli/configuration/src/docs-yml/ParsedDocsConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DocsV1Write } from "@fern-api/fdr-sdk";
import { AbsoluteFilePath, RelativeFilePath } from "@fern-api/fs-utils";
import { z, ZodType } from "zod";
import { Audiences } from "../commons";
import { WithoutQuestionMarks } from "../commons/WithoutQuestionMarks";
import { DocsInstances, TabConfig, VersionAvailability } from "./schemas";
Expand Down Expand Up @@ -157,7 +156,8 @@ export declare namespace DocsNavigationItem {
audiences: Audiences;
showErrors: boolean;
snippetsConfiguration: SnippetsConfiguration | undefined;
navigation: APINavigationSchema | undefined;
summaryAbsolutePath: AbsoluteFilePath | undefined;
navigation: ParsedApiNavigationItem[];
}

export interface Link {
Expand All @@ -174,27 +174,21 @@ export declare namespace DocsNavigationItem {
}
}

// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
export interface ApiNavigationGroup {
[key: string]: ApiNavigationItem[];
}
export const ApiNavigationGroup: ZodType<ApiNavigationGroup> = z.lazy(() => z.record(z.array(ApiNavigationItem)));

export const ApiNavigationItem = z.union([z.string(), ApiNavigationGroup]);
export type ApiNavigationItem = z.infer<typeof ApiNavigationItem>;

/**
* NavigationSchema is a recursive schema that can be either a record,
* a list of records, or a list of strings where the strings are endpoint ids
* and the records are groups of endpoint ids for a subpackage.
*
* @example
* - groupA
* - groupB:
* - methodA
* - methodB
* - groupC:
* - methodC
*/
export const APINavigationSchema = z.array(ApiNavigationItem);
export type APINavigationSchema = z.infer<typeof APINavigationSchema>;
export declare namespace ParsedApiNavigationItem {
export interface Subpackage {
type: "subpackage";
subpackageId: string;
summaryAbsolutePath: AbsoluteFilePath | undefined;
items: ParsedApiNavigationItem[];
}

export interface Item {
type: "item";
value: string; // this could be either an endpoint or subpackage.
}
}

export type ParsedApiNavigationItem =
| ParsedApiNavigationItem.Item
| ParsedApiNavigationItem.Subpackage
| DocsNavigationItem.Page;
51 changes: 49 additions & 2 deletions packages/cli/configuration/src/docs-yml/getAllPages.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertNever } from "@fern-api/core-utils";
import { AbsoluteFilePath, RelativeFilePath, relativize } from "@fern-api/fs-utils";
import { readFile } from "fs/promises";
import { DocsNavigationConfiguration, DocsNavigationItem } from "./ParsedDocsConfiguration";
import { DocsNavigationConfiguration, DocsNavigationItem, ParsedApiNavigationItem } from "./ParsedDocsConfiguration";

export async function getAllPages({
navigation,
Expand Down Expand Up @@ -63,7 +63,21 @@ export async function getAllPagesFromNavigationItem({
absolutePathToFernFolder: AbsoluteFilePath;
}): Promise<Record<RelativeFilePath, string>> {
switch (item.type) {
case "apiSection":
case "apiSection": {
const toRet = combineMaps(
await Promise.all(
item.navigation.map((apiNavigation) =>
getAllPagesFromApiNavigationItem({ item: apiNavigation, absolutePathToFernFolder })
)
)
);
if (item.summaryAbsolutePath != null) {
toRet[await relativize(absolutePathToFernFolder, item.summaryAbsolutePath)] = (
await readFile(item.summaryAbsolutePath)
).toString();
}
return toRet;
}
case "link":
return {};
case "page":
Expand All @@ -88,3 +102,36 @@ export async function getAllPagesFromNavigationItem({
function combineMaps(maps: Record<RelativeFilePath, string>[]) {
return maps.reduce((acc, record) => ({ ...acc, ...record }), {});
}

async function getAllPagesFromApiNavigationItem({
item,
absolutePathToFernFolder
}: {
item: ParsedApiNavigationItem;
absolutePathToFernFolder: AbsoluteFilePath;
}): Promise<Record<RelativeFilePath, string>> {
if (item.type === "page") {
return {
[await relativize(absolutePathToFernFolder, item.absolutePath)]: (
await readFile(item.absolutePath)
).toString()
};
} else if (item.type === "subpackage") {
const toRet = combineMaps(
await Promise.all(
item.items.map(async (subItem) => {
return await getAllPagesFromApiNavigationItem({ item: subItem, absolutePathToFernFolder });
})
)
);

if (item.summaryAbsolutePath != null) {
toRet[await relativize(absolutePathToFernFolder, item.summaryAbsolutePath)] = (
await readFile(item.summaryAbsolutePath)
).toString();
}

return toRet;
}
return {};
}
Loading

0 comments on commit a1fb67b

Please sign in to comment.