Skip to content

Commit ef16a60

Browse files
authored
Resolve TODO comments from codebase (#58691)
1 parent c5a9780 commit ef16a60

File tree

16 files changed

+211
-210
lines changed

16 files changed

+211
-210
lines changed

.github/instructions/all.instructions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ When you create a pull request:
2828

2929
3. Label with "llm-generated".
3030
4. If an issue exists, include "fixes owner/repo#issue" or "towards owner/repo#issue" as appropriate.
31-
5. Always _escape backticks_ when you use gh cli.
31+
5. Always create PRs in **draft mode** using `--draft` flag.
32+
6. Always _escape backticks_ when you use gh cli.

src/content-linter/lib/linting-rules/liquid-ifversion-versions.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,10 @@ async function getApplicableVersionFromLiquidTag(conditionStr: string) {
206206
const ands = ver.split(' and ')
207207
const firstAnd = ands[0].split(' ')[0]
208208
// if all ands don't start with the same version it's invalid
209+
// Note: This edge case (e.g., "fpt and ghes >= 3.1") doesn't occur in our content.
210+
// All actual uses have matching versions (e.g., "ghes and ghes > 3.19").
211+
// If this edge case appears in the future, additional logic would be needed here.
209212
if (!ands.every((and) => and.startsWith(firstAnd))) {
210-
// noop - we don't handle this case
211-
// TODO - handle this case in the future
212213
return []
213214
}
214215
const andValues = []

src/content-linter/tests/category-pages.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,17 @@ describe.skip('category pages', () => {
5050
// otherwise, if one of them has no categories, the tests will fail.
5151
for (const tuple of productTuples) {
5252
const [, productIndex] = tuple
53+
54+
const productDir = path.dirname(productIndex)
55+
5356
// Get links included in product index page.
5457
// Each link corresponds to a product subdirectory (category).
5558
// Example: "getting-started-with-github"
59+
// Note: We need to read this synchronously here because vitest's describe.each
60+
// can't asynchronously define tests
5661
const contents = fs.readFileSync(productIndex, 'utf8')
5762
const data = getFrontmatterData(contents)
5863

59-
const productDir = path.dirname(productIndex)
60-
6164
const children: string[] = data.children
6265
const categoryLinks = children
6366
// Only include category directories, not standalone category files like content/actions/quickstart.md
@@ -118,15 +121,19 @@ describe.skip('category pages', () => {
118121
await contextualize(req as ExtendedRequest, res as Response, next)
119122
await shortVersions(req as ExtendedRequest, res as Response, next)
120123

124+
// Read the product index data for rendering
125+
const productIndexContents = await fs.promises.readFile(productIndex, 'utf8')
126+
const productIndexData = getFrontmatterData(productIndexContents)
127+
121128
// Save the index title for later testing
122-
indexTitle = data.title.includes('{')
123-
? await renderContent(data.title, req.context, { textOnly: true })
124-
: data.title
125-
126-
if (data.shortTitle) {
127-
indexShortTitle = data.shortTitle.includes('{')
128-
? await renderContent(data.shortTitle, req.context, { textOnly: true })
129-
: data.shortTitle
129+
indexTitle = productIndexData.title.includes('{')
130+
? await renderContent(productIndexData.title, req.context, { textOnly: true })
131+
: productIndexData.title
132+
133+
if (productIndexData.shortTitle) {
134+
indexShortTitle = productIndexData.shortTitle.includes('{')
135+
? await renderContent(productIndexData.shortTitle, req.context, { textOnly: true })
136+
: productIndexData.shortTitle
130137
} else {
131138
indexShortTitle = ''
132139
}

src/fixtures/tests/minitoc.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import cheerio from 'cheerio'
44
import { getDOM } from '@/tests/helpers/e2etest'
55

66
describe('minitoc', () => {
7-
// TODO disable the mini TOC tests when we replace it with sticky TOC header
87
test('renders mini TOC in articles with more than one heading', async () => {
98
const $: cheerio.Root = await getDOM('/en/get-started/minitocs/multiple-headings')
109
expect($('h2#in-this-article').length).toBe(1)

src/frame/lib/path-utils.ts

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,32 +109,37 @@ export function getVersionObjectFromPath(href: string | undefined) {
109109
return allVersions[versionFromPath]
110110
}
111111

112-
// TODO needs refactoring + tests
113112
// Return the product segment from the path
113+
// Extracts the product identifier from various URL patterns including versioned paths
114114
export function getProductStringFromPath(href: string | undefined): string {
115+
// Handle empty or undefined paths
115116
if (!href) return 'homepage'
116-
href = getPathWithoutLanguage(href)
117117

118-
if (href === '/') return 'homepage'
118+
const normalizedHref = getPathWithoutLanguage(href)
119+
if (normalizedHref === '/') return 'homepage'
119120

120-
// The first segment will always be empty on this split
121-
const pathParts = href.split('/')
121+
// Split path into segments (first segment is always empty string)
122+
const pathParts = normalizedHref.split('/')
122123

124+
// Handle special product paths that appear anywhere in the URL
123125
if (pathParts.includes('early-access')) return 'early-access'
124126

125-
// For rest pages the currentProduct should be rest
126-
// We use this to show SidebarRest, which is a different sidebar than the rest of the site
127-
if (pathParts[1] === 'rest') return 'rest'
128-
if (pathParts[1] === 'copilot') return 'copilot'
129-
if (pathParts[1] === 'get-started') return 'get-started'
130-
131-
// Possible scenarios for href (assume part[0] is an empty string):
132-
//
133-
// * part[1] is a version and part[2] is undefined, so return part[1] as an enterprise landing page
134-
// * part[1] is a version and part[2] is defined, so return part[2] as the product
135-
// * part[1] is NOT a version, so return part[1] as the product
136-
const isEnterprise = supportedVersions.has(pathParts[1])
137-
const productString = isEnterprise && pathParts[2] ? pathParts[2] : pathParts[1]
127+
// Handle special products that always appear as the first segment
128+
// These products use custom sidebars and need explicit handling
129+
const specialProducts = ['rest', 'copilot', 'get-started']
130+
if (specialProducts.includes(pathParts[1])) {
131+
return pathParts[1]
132+
}
133+
134+
// Determine if first segment is a version (e.g., '[email protected]')
135+
// If yes, product is in pathParts[2], otherwise it's in pathParts[1]
136+
// Examples:
137+
// /[email protected]/admin -> product is 'admin'
138+
// /github/getting-started -> product is 'github'
139+
// /[email protected] -> product is '[email protected]' (enterprise landing)
140+
const hasVersionPrefix = supportedVersions.has(pathParts[1])
141+
const productString = hasVersionPrefix && pathParts[2] ? pathParts[2] : pathParts[1]
142+
138143
return productString
139144
}
140145

src/frame/middleware/find-page.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,9 @@ async function rereadByPath(
105105
const languageCode = match[1]
106106
const withoutLanguage = uri.replace(languagePrefixPathRegex, '/')
107107
const withoutVersion = withoutLanguage.replace(`/${currentVersion}`, '')
108-
// TODO: Support loading translations the same way.
109-
// NOTE: No one is going to test translations like this in development
110-
// but perhaps one day we can always and only do these kinds of lookups
111-
// at runtime.
108+
// Note: We don't support loading translations at runtime. All translations
109+
// are loaded at build time. This function only handles English content reloading
110+
// during development.
112111
const possible = path.join(contentRoot, withoutVersion)
113112
const filePath = existsSync(possible) ? path.join(possible, 'index.md') : `${possible}.md`
114113
const relativePath = path.relative(contentRoot, filePath)

src/frame/tests/path-utils.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { describe, expect, test } from 'vitest'
2+
3+
import { getProductStringFromPath } from '@/frame/lib/path-utils'
4+
5+
describe('getProductStringFromPath', () => {
6+
test('returns "homepage" for root paths', () => {
7+
expect(getProductStringFromPath('/')).toBe('homepage')
8+
expect(getProductStringFromPath('/en')).toBe('homepage')
9+
expect(getProductStringFromPath(undefined)).toBe('homepage')
10+
})
11+
12+
test('handles early-access product', () => {
13+
expect(getProductStringFromPath('/en/early-access/github/overview')).toBe('early-access')
14+
expect(getProductStringFromPath('/early-access/admin/guides')).toBe('early-access')
15+
})
16+
17+
test('handles special products (rest, copilot, get-started)', () => {
18+
expect(getProductStringFromPath('/en/rest/overview')).toBe('rest')
19+
expect(getProductStringFromPath('/rest/reference/repos')).toBe('rest')
20+
expect(getProductStringFromPath('/en/copilot/using-copilot')).toBe('copilot')
21+
expect(getProductStringFromPath('/copilot/features')).toBe('copilot')
22+
expect(getProductStringFromPath('/en/get-started/quickstart')).toBe('get-started')
23+
expect(getProductStringFromPath('/get-started/onboarding')).toBe('get-started')
24+
})
25+
26+
test('extracts product from non-versioned paths', () => {
27+
expect(getProductStringFromPath('/en/github/getting-started')).toBe('github')
28+
expect(getProductStringFromPath('/actions/quickstart')).toBe('actions')
29+
expect(getProductStringFromPath('/en/admin/installation')).toBe('admin')
30+
expect(getProductStringFromPath('/code-security/overview')).toBe('code-security')
31+
})
32+
33+
test('extracts product from versioned paths', () => {
34+
// Note: These tests use free-pro-team which is a supported version
35+
expect(getProductStringFromPath('/en/free-pro-team@latest/admin/installation')).toBe('admin')
36+
expect(getProductStringFromPath('/free-pro-team@latest/actions/quickstart')).toBe('actions')
37+
expect(getProductStringFromPath('/en/free-pro-team@latest/github/getting-started')).toBe(
38+
'github',
39+
)
40+
})
41+
42+
test('handles enterprise landing pages (version without product)', () => {
43+
// When a version is present but no product segment follows, return the version string
44+
expect(getProductStringFromPath('/en/free-pro-team@latest')).toBe('free-pro-team@latest')
45+
expect(getProductStringFromPath('/enterprise-server@latest')).toBe('enterprise-server@latest')
46+
})
47+
})

src/rest/scripts/utils/create-rest-examples.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,9 @@ export function getResponseExamples(operation: Operation): ResponseExample[] {
352352
contentType,
353353
description: examples[key].summary || operation.responses[statusCode].description,
354354
example: examples[key].value,
355-
// TODO adding the schema quadruples the JSON file size. Changing
356-
// how we write the JSON file helps a lot, but we should revisit
357-
// adding the response schema to ensure we have a way to view the
358-
// prettified JSON before minimizing it.
355+
// Note: Including the schema significantly increases JSON file size (~4x),
356+
// but it's necessary to support the schema/example toggle in the UI.
357+
// Users can switch between viewing the example response and the full schema.
359358
schema: operation.responses[statusCode].content[contentType].schema,
360359
},
361360
}

src/rest/scripts/utils/inject-models-schema.ts

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,36 +64,18 @@ export async function injectModelsSchema(schema: any, schemaName: string): Promi
6464

6565
// Use values from the YAML where possible
6666
const name = operationObject.summary || ''
67-
const description = operationObject.description || ''
68-
const category = operationObject['x-github']?.category || 'models'
6967

7068
console.log(`⏳ Processing operation: ${name} (${path} ${operation})`)
7169

72-
// Create enhanced operation preserving all original fields
73-
// TODO this should be cleaned up, most can be removed
70+
// Create enhanced operation with custom fields needed for our REST docs
71+
// The spread operator preserves all original OpenAPI fields
7472
const enhancedOperation = {
75-
...operationObject, // Keep all original fields
76-
operationId: operationObject.operationId, // Preserve original operationId with namespace
77-
tags: operationObject.tags || ['models'], // Only use 'models' if no tags present
73+
...operationObject,
74+
// Add custom fields for our docs processing
7875
verb: operation,
7976
requestPath: path,
80-
category,
81-
subcategory: operationObject['x-github']?.subcategory || '',
82-
summary: name,
83-
description,
84-
'x-github': {
85-
...operationObject['x-github'], // Preserve all x-github metadata
86-
category,
87-
enabledForGitHubApps: operationObject['x-github']?.enabledForGitHubApps,
88-
githubCloudOnly: operationObject['x-github']?.githubCloudOnly,
89-
permissions: operationObject['x-github']?.permissions || {},
90-
externalDocs: operationObject['x-github']?.externalDocs || {},
91-
},
92-
parameters: operationObject.parameters || [],
93-
responses: {
94-
...operationObject.responses,
95-
'200': operationObject.responses?.['200'],
96-
},
77+
// Override tags with default if not present
78+
tags: operationObject.tags || ['models'],
9779
}
9880

9981
// Preserve operation-level servers if present

src/search/lib/elasticsearch-indexes.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,9 @@ export function getElasticSearchIndex(
7171
// e.g. free-pro-team becomes fpt for the index name
7272
let indexVersion = versionToIndexVersionMap[version]
7373

74-
// TODO: For AI Search, we initially only supported the latest GHES version
75-
// Supporting more versions would involve adding more indexes and generating the data to fill them
76-
// As a work around, we will just use the latest version for all GHES suggestions / autocomplete
77-
// This is a temporary fix until we can support more versions
74+
// For AI Search autocomplete, we use the latest GHES version for all GHES versions.
75+
// This provides AI search functionality across all supported GHES versions without
76+
// requiring separate indexes for each version.
7877
if (type === 'aiSearchAutocomplete' && indexVersion.startsWith('ghes')) {
7978
indexVersion = versionToIndexVersionMap['enterprise-server']
8079
}

0 commit comments

Comments
 (0)