Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# ---------------------------------------------------------------
# To update the sha:
# https://github.com/github/gh-base-image/pkgs/container/gh-base-image%2Fgh-base-noble
FROM ghcr.io/github/gh-base-image/gh-base-noble:20250711-165924-g6f92253c7 AS base
FROM ghcr.io/github/gh-base-image/gh-base-noble:20250715-152201-gef17a3886 AS base

# Install curl for Node install and determining the early access branch
# Install git for cloning docs-early-access & translations repos
Expand Down
4 changes: 2 additions & 2 deletions content/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: '{% data variables.product.github %}{% ifversion fpt or ghec%}.com{% endif %} Help Documentation'
title: '{% data variables.product.github %}{% ifversion fpt or ghec %}.com{% endif %} Help Documentation'
featuredLinks:
gettingStarted:
- /get-started/git-basics/set-up-git
Expand Down Expand Up @@ -170,6 +170,7 @@ childGroups:
- codeql
- electron
- npm
- gh-wa
externalProducts:
electron:
id: electron
Expand All @@ -192,4 +193,3 @@ externalProducts:
href: 'https://wellarchitected.github.com/'
external: true
---

115 changes: 75 additions & 40 deletions src/rest/lib/index.js → src/rest/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,26 @@ import { readCompressedJsonFileFallback } from '@/frame/lib/read-json-file'
import { getAutomatedPageMiniTocItems } from '@/frame/lib/get-mini-toc-items'
import { allVersions, getOpenApiVersion } from '@/versions/lib/all-versions'
import languages from '@/languages/lib/languages'
import type { Context } from '@/types'
import type { Operation } from '@/rest/components/types'

export const REST_DATA_DIR = 'src/rest/data'
export const REST_SCHEMA_FILENAME = 'schema.json'
const REST_CONTENT_DIR = 'content/rest'

// Type definitions for REST operations
interface RestOperationCategory {
[subcategory: string]: Operation[]
}

interface RestOperationData {
[category: string]: RestOperationCategory
}

interface RestMiniTocData {
restOperationsMiniTocItems: any[]
}

/*
Loads the schemas from the static/decorated folder into a single
object organized by version. Not all products are calendar date
Expand Down Expand Up @@ -38,87 +53,107 @@ const REST_CONTENT_DIR = 'content/rest'
}
*/
const NOT_API_VERSIONED = 'not_api_versioned'
const restOperationData = new Map()
const restOperations = new Map()
const restOperationData = new Map<
string,
Map<string, Map<string, Map<string, Map<string, RestMiniTocData>>>>
>()
const restOperations = new Map<string, Map<string, RestOperationData>>()

Object.keys(languages).forEach((language) => {
Object.keys(languages).forEach((language: string) => {
restOperationData.set(language, new Map())
Object.keys(allVersions).forEach((version) => {
Object.keys(allVersions).forEach((version: string) => {
// setting to undefined will allow us to perform checks
// more easily later on
restOperationData.get(language).set(version, new Map())
restOperationData.get(language)!.set(version, new Map())
if (allVersions[version].apiVersions && allVersions[version].apiVersions.length > 0) {
allVersions[version].apiVersions.forEach((date) => {
restOperationData.get(language).get(version).set(date, new Map())
allVersions[version].apiVersions.forEach((date: string) => {
restOperationData.get(language)!.get(version)!.set(date, new Map())
})
} else {
// Products that are not been calendar date versioned
restOperationData.get(language).get(version).set(NOT_API_VERSIONED, new Map())
restOperationData.get(language)!.get(version)!.set(NOT_API_VERSIONED, new Map())
}
})
})

export const categoriesWithoutSubcategories = fs
export const categoriesWithoutSubcategories: string[] = fs
.readdirSync(REST_CONTENT_DIR)
.filter((file) => {
.filter((file: string) => {
return file.endsWith('.md') && !file.includes('index.md') && !file.includes('README.md')
})
.map((filteredFile) => filteredFile.replace('.md', ''))
.map((filteredFile: string) => filteredFile.replace('.md', ''))

// version: plan + release e.g. For ghes-3.5, ghes is the plan and 3.5 is the release
// apiVersion (not all versions have apiVersions): REST API Calendar Dates
// openApiVersion (below, every version has an openApiVersion mapping): There's a mapping between our Docs versions
// and the OpenApi Version bc it's not the same
export default async function getRest(version, apiVersion, category, subCategory) {

export default async function getRest(
version: string,
apiVersion?: string,
): Promise<RestOperationData> {
const openApiVersion = getOpenApiVersion(version)
const openapiSchemaName = apiVersion ? `${openApiVersion}-${apiVersion}` : `${openApiVersion}`
const apiDate = apiVersion || NOT_API_VERSIONED
const fileName = path.join(REST_DATA_DIR, openapiSchemaName, REST_SCHEMA_FILENAME)

if (!restOperations.has(openApiVersion)) {
restOperations.set(openApiVersion, new Map())
restOperations.get(openApiVersion).set(apiDate, new Map())
// The `readCompressedJsonFileFallback()` function
// will check for both a .br and .json extension.
restOperations.get(openApiVersion).set(apiDate, readCompressedJsonFileFallback(fileName))
} else if (!restOperations.get(openApiVersion).has(apiDate)) {
restOperations.get(openApiVersion).set(apiDate, new Map())
restOperations
.get(openApiVersion)!
.set(apiDate, readCompressedJsonFileFallback(fileName) as RestOperationData)
} else if (!restOperations.get(openApiVersion)!.has(apiDate)) {
// The `readCompressedJsonFileFallback()` function
// will check for both a .br and .json extension.
restOperations.get(openApiVersion).set(apiDate, readCompressedJsonFileFallback(fileName))
}
if (subCategory) {
return restOperations.get(openApiVersion).get(apiDate)[category][subCategory]
} else if (category) {
return restOperations.get(openApiVersion).get(apiDate)[category]
} else {
return restOperations.get(openApiVersion).get(apiDate)
restOperations
.get(openApiVersion)!
.set(apiDate, readCompressedJsonFileFallback(fileName) as RestOperationData)
}

return restOperations.get(openApiVersion)!.get(apiDate)!
}

// Generates the miniToc for a rest reference page.
export async function getRestMiniTocItems(
category,
subCategory,
apiVersion,
restOperations,
language,
version,
context,
) {
category: string,
subCategory: string,
apiVersion: string | undefined,
restOperations: Operation[],
language: string,
version: string,
context: Context,
): Promise<RestMiniTocData> {
const apiDate = apiVersion || NOT_API_VERSIONED

if (!restOperationData.get(language).get(version).get(apiDate).has(category)) {
restOperationData.get(language).get(version).get(apiDate).set(category, new Map())
const languageData = restOperationData.get(language)
if (!languageData) {
throw new Error(`Language ${language} not found in rest operation data`)
}

const versionData = languageData.get(version)
if (!versionData) {
throw new Error(`Version ${version} not found for language ${language}`)
}

const apiData = versionData.get(apiDate)
if (!apiData) {
throw new Error(`API date ${apiDate} not found for version ${version} and language ${language}`)
}

if (!apiData.has(category)) {
apiData.set(category, new Map())
}

if (!restOperationData.get(language).get(version).get(apiDate).get(category).get(subCategory)) {
const languageTree = restOperationData.get(language)
const titles = restOperations.map((operation) => operation.title)
const categoryData = apiData.get(category)!
if (!categoryData.get(subCategory)) {
const titles = restOperations.map((operation: Operation) => operation.title)
const restOperationsMiniTocItems = await getAutomatedPageMiniTocItems(titles, context, 3)
languageTree.get(version).get(apiDate).get(category).set(subCategory, {
categoryData.set(subCategory, {
restOperationsMiniTocItems,
})
restOperationData.set(restOperationData, languageTree)
}
return restOperationData.get(language).get(version).get(apiDate).get(category).get(subCategory)

return categoryData.get(subCategory)!
}
7 changes: 4 additions & 3 deletions src/rest/pages/category.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function Category({
}

export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const { default: getRest, getRestMiniTocItems } = await import('@/rest/lib/index.js')
const { default: getRest, getRestMiniTocItems } = await import('@/rest/lib/index')
const nonEnterpriseDefaultVersionModule = await import(
'src/versions/lib/non-enterprise-default-version.js'
)
Expand All @@ -86,15 +86,16 @@ export const getServerSideProps: GetServerSideProps<Props> = async (context) =>
subcategory = category
}

const restOperations = (await getRest(currentVersion, apiVersion, category, subcategory)) || []
const restData = await getRest(currentVersion, apiVersion)
const restOperations = (restData && restData[category] && restData[category][subcategory]) || []

// Build table of contents for all category operations for TocLanding:
//
// * get all operations for a category (will be broken up by subcategory)
// * loop over subcategories and get the operations per subcategory
// * get the minitoc items per set of subcategory operations
// * with this data, build a collection of toc items that can be used by TocLanding
const restCategoryOperations = (await getRest(currentVersion, apiVersion, category)) || []
const restCategoryOperations = (restData && restData[category]) || {}
const restCategoryTocItems = []

for (const [subCat, subCatOperations] of Object.entries(restCategoryOperations)) {
Expand Down
5 changes: 3 additions & 2 deletions src/rest/pages/subcategory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function SubCategory({ mainContext, automatedPageContext, restOpe
}

export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const { default: getRest, getRestMiniTocItems } = await import('@/rest/lib/index.js')
const { default: getRest, getRestMiniTocItems } = await import('@/rest/lib/index')

const req = context.req as any
const res = context.res as any
Expand All @@ -55,7 +55,8 @@ export const getServerSideProps: GetServerSideProps<Props> = async (context) =>
subCategory = category
}

const restOperations = (await getRest(currentVersion, apiVersion, category, subCategory)) || []
const restData = await getRest(currentVersion, apiVersion)
const restOperations = (restData && restData[category] && restData[category][subCategory]) || []

// Gets the miniTocItems in the article context. At this point it will only
// include miniTocItems generated from the Markdown pages in
Expand Down
4 changes: 3 additions & 1 deletion src/rest/tests/rendering.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ describe('REST references docs', () => {
test('loads schema data for all versions', async () => {
for (const version of Object.keys(allVersions)) {
const calendarDate = allVersions[version].latestApiVersion
const checksRestOperations = await getRest(version, calendarDate, 'checks', 'runs')
const restData = await getRest(version, calendarDate)
const checksRestOperations =
(restData && restData['checks'] && restData['checks']['runs']) || []
const $ = await getDOM(`/en/${version}/rest/checks/runs?restVersion=${calendarDate}`)
const domH2Ids = $('h2')
.map((i, h2) => $(h2).attr('id'))
Expand Down
Loading