Migrate TypeScript: 9 files converted (#57928)
This commit is contained in:
@@ -2,9 +2,19 @@ import { Tokenizer, TokenKind } from 'liquidjs'
|
||||
|
||||
import { deprecated } from '@/versions/lib/enterprise-server-releases'
|
||||
|
||||
const liquidTokenCache = new Map()
|
||||
// Using `any` for the cache because TopLevelToken is a complex union type from liquidjs
|
||||
// that includes TagToken, OutputToken, and HTMLToken with different properties.
|
||||
// The cache is private to this module and we control all access to it.
|
||||
const liquidTokenCache = new Map<string, any>()
|
||||
|
||||
export function getLiquidTokens(content, { noCache = false } = {}) {
|
||||
// Returns `any[]` instead of `TopLevelToken[]` because TopLevelToken is a union type
|
||||
// (TagToken | OutputToken | HTMLToken) and consumers of this function access properties
|
||||
// like `name` and `args` that only exist on TagToken. Using `any` here avoids complex
|
||||
// type narrowing throughout the codebase.
|
||||
export function getLiquidTokens(
|
||||
content: string,
|
||||
{ noCache = false }: { noCache?: boolean } = {},
|
||||
): any[] {
|
||||
if (!content) return []
|
||||
|
||||
if (noCache) {
|
||||
@@ -30,7 +40,12 @@ export const TAG_CLOSE = '}}'
|
||||
export const conditionalTags = ['if', 'elseif', 'unless', 'case', 'ifversion']
|
||||
const CONDITIONAL_TAG_NAMES = ['if', 'ifversion', 'elsif', 'else', 'endif']
|
||||
|
||||
export function getPositionData(token, lines) {
|
||||
// Token is `any` because it's used with different token types from liquidjs
|
||||
// that all have `begin` and `end` properties but are part of complex union types.
|
||||
export function getPositionData(
|
||||
token: any,
|
||||
lines: string[],
|
||||
): { lineNumber: number; column: number; length: number } {
|
||||
// Liquid indexes are 0-based, but we want to
|
||||
// covert to the system used by Markdownlint
|
||||
const begin = token.begin + 1
|
||||
@@ -62,9 +77,14 @@ export function getPositionData(token, lines) {
|
||||
* by Markdownlint:
|
||||
* [ { lineNumber: 1, column: 1, deleteCount: 3, }]
|
||||
*/
|
||||
export function getContentDeleteData(token, tokenEnd, lines) {
|
||||
// Token is `any` because it's used with different token types from liquidjs.
|
||||
export function getContentDeleteData(
|
||||
token: any,
|
||||
tokenEnd: number,
|
||||
lines: string[],
|
||||
): Array<{ lineNumber: number; column: number; deleteCount: number }> {
|
||||
const { lineNumber, column } = getPositionData(token, lines)
|
||||
const errorInfo = []
|
||||
const errorInfo: Array<{ lineNumber: number; column: number; deleteCount: number }> = []
|
||||
let begin = column - 1
|
||||
// Subtract one from end of next token tag. The end of the
|
||||
// current tag is one position before that.
|
||||
@@ -103,13 +123,15 @@ export function getContentDeleteData(token, tokenEnd, lines) {
|
||||
// related elsif, else, and endif tags).
|
||||
// Docs doesn't use the standard `if` tag for versioning, instead the
|
||||
// `ifversion` tag is used.
|
||||
export function getLiquidIfVersionTokens(content) {
|
||||
// Returns `any[]` because the tokens need to be accessed as TagToken with `name` and `args` properties,
|
||||
// but TopLevelToken union type would require complex type narrowing.
|
||||
export function getLiquidIfVersionTokens(content: string): any[] {
|
||||
const tokens = getLiquidTokens(content)
|
||||
.filter((token) => token.kind === TokenKind.Tag)
|
||||
.filter((token) => CONDITIONAL_TAG_NAMES.includes(token.name))
|
||||
|
||||
let inIfStatement = false
|
||||
const ifVersionTokens = []
|
||||
const ifVersionTokens: any[] = []
|
||||
for (const token of tokens) {
|
||||
if (token.name === 'if') {
|
||||
inIfStatement = true
|
||||
@@ -125,7 +147,7 @@ export function getLiquidIfVersionTokens(content) {
|
||||
return ifVersionTokens
|
||||
}
|
||||
|
||||
export function getSimplifiedSemverRange(release) {
|
||||
export function getSimplifiedSemverRange(release: string): string {
|
||||
// Liquid conditionals only use the format > or < but not
|
||||
// >= or <=. Not sure exactly why.
|
||||
// if startswith >, we'll check to see if the release number
|
||||
@@ -2,10 +2,21 @@ import fs from 'fs'
|
||||
import yaml from 'js-yaml'
|
||||
|
||||
const allowedCodeFenceLanguages = Object.keys(
|
||||
yaml.load(fs.readFileSync('data/code-languages.yml', 'utf8')),
|
||||
yaml.load(fs.readFileSync('data/code-languages.yml', 'utf8')) as Record<string, unknown>,
|
||||
)
|
||||
|
||||
export const baseConfig = {
|
||||
type RuleConfig = {
|
||||
severity: 'error' | 'warning'
|
||||
'partial-markdown-files': boolean
|
||||
'yml-files': boolean
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
type BaseConfig = {
|
||||
[key: string]: boolean | RuleConfig
|
||||
}
|
||||
|
||||
export const baseConfig: BaseConfig = {
|
||||
// Don't run all rules by default. This must be done first to
|
||||
// enable a specific set of rules.
|
||||
default: false,
|
||||
@@ -47,7 +47,7 @@ function getDeletedContentFiles() {
|
||||
return getContentFiles(process.env.DELETED_FILES)
|
||||
}
|
||||
|
||||
function getContentFiles(spaceSeparatedList) {
|
||||
function getContentFiles(spaceSeparatedList: string | undefined): string[] {
|
||||
return (spaceSeparatedList || '').split(/\s+/g).filter((filePath) => {
|
||||
// This filters out things like '', or `data/foo.md` or `content/something/README.md`
|
||||
return (
|
||||
@@ -69,9 +69,11 @@ describe('changed-content', () => {
|
||||
|
||||
// `test.each` will throw if the array is empty, so we need to add a dummy
|
||||
// when there are no changed files in the environment.
|
||||
if (!changedContentFiles.length) changedContentFiles.push(EMPTY)
|
||||
const testFiles: Array<string | symbol> = changedContentFiles.length
|
||||
? changedContentFiles
|
||||
: [EMPTY]
|
||||
|
||||
test.each(changedContentFiles)('changed-content: %s', async (file) => {
|
||||
test.each(testFiles)('changed-content: %s', async (file: string | symbol) => {
|
||||
// Necessary because `test.each` will throw if the array is empty
|
||||
if (file === EMPTY) return
|
||||
|
||||
@@ -79,13 +81,13 @@ describe('changed-content', () => {
|
||||
return path.join(p.basePath, p.relativePath) === file
|
||||
})
|
||||
if (!page) {
|
||||
throw new Error(`Could not find page for ${file} in all loaded English content`)
|
||||
throw new Error(`Could not find page for ${file as string} in all loaded English content`)
|
||||
}
|
||||
// Each version of the page should successfully render
|
||||
for (const { href } of page.permalinks) {
|
||||
const res = await get(href)
|
||||
if (!res.ok) {
|
||||
let msg = `This error happened when rendering from: ${file}\n`
|
||||
let msg = `This error happened when rendering from: ${file as string}\n`
|
||||
msg +=
|
||||
'To see the full error from vitest re-run the test with DEBUG_MIDDLEWARE_TESTS=true set\n'
|
||||
msg += `Or, to view it locally start the server (npm run dev) and visit http://localhost:4000${href}`
|
||||
@@ -101,9 +103,11 @@ describe('deleted-content', () => {
|
||||
|
||||
// `test.each` will throw if the array is empty, so we need to add a dummy
|
||||
// when there are no deleted files in the environment.
|
||||
if (!deletedContentFiles.length) deletedContentFiles.push(EMPTY)
|
||||
const testFiles: Array<string | symbol> = deletedContentFiles.length
|
||||
? deletedContentFiles
|
||||
: [EMPTY]
|
||||
|
||||
test.each(deletedContentFiles)('deleted-content: %s', async (file) => {
|
||||
test.each(testFiles)('deleted-content: %s', async (file: string | symbol) => {
|
||||
// Necessary because `test.each` will throw if the array is empty
|
||||
if (file === EMPTY) return
|
||||
|
||||
@@ -111,20 +115,22 @@ describe('deleted-content', () => {
|
||||
return path.join(p.basePath, p.relativePath) === file
|
||||
})
|
||||
if (page) {
|
||||
throw new Error(`The supposedly deleted file ${file} is still in list of loaded pages`)
|
||||
throw new Error(
|
||||
`The supposedly deleted file ${file as string} is still in list of loaded pages`,
|
||||
)
|
||||
}
|
||||
// You can't know what the possible permalinks were for a deleted page,
|
||||
// because it's deleted so we can't look at its `versions` front matter.
|
||||
// However, we always make sure all pages work in versionless.
|
||||
const indexmdSuffixRegex = new RegExp(`${path.sep}index\\.md$`)
|
||||
const mdSuffixRegex = /\.md$/
|
||||
const relativePath = file.split(path.sep).slice(1).join(path.sep)
|
||||
const relativePath = (file as string).split(path.sep).slice(1).join(path.sep)
|
||||
const href = `/en/${relativePath.replace(indexmdSuffixRegex, '').replace(mdSuffixRegex, '')}`
|
||||
|
||||
const res = await head(href)
|
||||
const error =
|
||||
res.statusCode === 404
|
||||
? `The deleted file ${file} did not set up a redirect when deleted.`
|
||||
? `The deleted file ${file as string} did not set up a redirect when deleted.`
|
||||
: ''
|
||||
// Certain articles that are deleted and moved under a directory with the same article name
|
||||
// should just route to the subcategory page instead of redirecting (docs content team confirmed).
|
||||
@@ -9,7 +9,8 @@ const supportedVersions = new Set(Object.keys(allVersions))
|
||||
|
||||
// Extracts the language code from the path
|
||||
// if href is '/en/something', returns 'en'
|
||||
export function getLangFromPath(href) {
|
||||
export function getLangFromPath(href: string | undefined): string | null {
|
||||
if (!href) return null
|
||||
// first remove the version from the path so we don't match, say, `/free-pro-team` as `/fr/`
|
||||
const match = getPathWithoutVersion(href).match(patterns.getLanguageCode)
|
||||
return match ? match[1] : null
|
||||
@@ -17,7 +18,8 @@ export function getLangFromPath(href) {
|
||||
|
||||
// Add the language to the given HREF
|
||||
// /articles/foo -> /en/articles/foo
|
||||
export function getPathWithLanguage(href, languageCode) {
|
||||
export function getPathWithLanguage(href: string | undefined, languageCode: string): string {
|
||||
if (!href) return `/${languageCode}`
|
||||
return slash(path.posix.join('/', languageCode, getPathWithoutLanguage(href))).replace(
|
||||
patterns.trailingSlash,
|
||||
'$1',
|
||||
@@ -26,12 +28,14 @@ export function getPathWithLanguage(href, languageCode) {
|
||||
|
||||
// Remove the language from the given HREF
|
||||
// /en/articles/foo -> /articles/foo
|
||||
export function getPathWithoutLanguage(href) {
|
||||
export function getPathWithoutLanguage(href: string | undefined): string {
|
||||
if (!href) return '/'
|
||||
return slash(href.replace(patterns.hasLanguageCode, '/'))
|
||||
}
|
||||
|
||||
// Remove the version segment from the path
|
||||
export function getPathWithoutVersion(href) {
|
||||
export function getPathWithoutVersion(href: string | undefined): string {
|
||||
if (!href) return '/'
|
||||
const versionFromPath = getVersionStringFromPath(href)
|
||||
|
||||
// If the derived version is not found in the list of all versions, just return the HREF
|
||||
@@ -41,7 +45,16 @@ export function getPathWithoutVersion(href) {
|
||||
}
|
||||
|
||||
// Return the version segment in a path
|
||||
export function getVersionStringFromPath(href, supportedOnly = false) {
|
||||
export function getVersionStringFromPath(
|
||||
href: string | undefined,
|
||||
supportedOnly: true,
|
||||
): string | undefined
|
||||
export function getVersionStringFromPath(href: string | undefined, supportedOnly?: false): string
|
||||
export function getVersionStringFromPath(
|
||||
href: string | undefined,
|
||||
supportedOnly = false,
|
||||
): string | undefined {
|
||||
if (!href) return nonEnterpriseDefaultVersion
|
||||
href = getPathWithoutLanguage(href)
|
||||
|
||||
// Some URLs don't ever have a version in the URL and it won't be found
|
||||
@@ -90,15 +103,16 @@ export function getVersionStringFromPath(href, supportedOnly = false) {
|
||||
}
|
||||
|
||||
// Return the corresponding object for the version segment in a path
|
||||
export function getVersionObjectFromPath(href) {
|
||||
const versionFromPath = getVersionStringFromPath(href)
|
||||
export function getVersionObjectFromPath(href: string | undefined) {
|
||||
const versionFromPath = getVersionStringFromPath(href, false)
|
||||
|
||||
return allVersions[versionFromPath]
|
||||
}
|
||||
|
||||
// TODO needs refactoring + tests
|
||||
// Return the product segment from the path
|
||||
export function getProductStringFromPath(href) {
|
||||
export function getProductStringFromPath(href: string | undefined): string {
|
||||
if (!href) return 'homepage'
|
||||
href = getPathWithoutLanguage(href)
|
||||
|
||||
if (href === '/') return 'homepage'
|
||||
@@ -124,14 +138,15 @@ export function getProductStringFromPath(href) {
|
||||
return productString
|
||||
}
|
||||
|
||||
export function getCategoryStringFromPath(href) {
|
||||
export function getCategoryStringFromPath(href: string | undefined): string | undefined {
|
||||
if (!href) return undefined
|
||||
href = getPathWithoutLanguage(href)
|
||||
|
||||
if (href === '/') return null
|
||||
if (href === '/') return undefined
|
||||
|
||||
const pathParts = href.split('/')
|
||||
|
||||
if (pathParts.includes('early-access')) return null
|
||||
if (pathParts.includes('early-access')) return undefined
|
||||
|
||||
const productIndex = productIds.includes(pathParts[2]) ? 2 : 1
|
||||
|
||||
@@ -3,16 +3,22 @@ import path from 'path'
|
||||
import http from 'http'
|
||||
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import type { Response } from 'express'
|
||||
|
||||
import Page from '@/frame/lib/page'
|
||||
import findPage from '@/frame/middleware/find-page'
|
||||
import type { ExtendedRequest } from '@/types'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
function makeRequestResponse(url, currentVersion = 'free-pro-team@latest') {
|
||||
const req = new http.IncomingMessage(null)
|
||||
function makeRequestResponse(
|
||||
url: string,
|
||||
currentVersion = 'free-pro-team@latest',
|
||||
): [ExtendedRequest, Response & { _status?: number; _message?: string }] {
|
||||
const req = new http.IncomingMessage(null as any) as ExtendedRequest
|
||||
req.method = 'GET'
|
||||
req.url = url
|
||||
// @ts-expect-error - path is read-only but we need to set it for testing
|
||||
req.path = url
|
||||
req.cookies = {}
|
||||
req.headers = {}
|
||||
@@ -23,14 +29,17 @@ function makeRequestResponse(url, currentVersion = 'free-pro-team@latest') {
|
||||
req.context.currentVersion = currentVersion
|
||||
req.context.pages = {}
|
||||
|
||||
const res = new http.ServerResponse(req)
|
||||
res.status = function (code) {
|
||||
const res = new http.ServerResponse(req) as Response & {
|
||||
_status?: number
|
||||
_message?: string
|
||||
}
|
||||
res.status = function (code: number) {
|
||||
this._status = code
|
||||
return {
|
||||
send: function (message) {
|
||||
send: (message: string) => {
|
||||
this._message = message
|
||||
}.bind(this),
|
||||
}
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
return [req, res]
|
||||
@@ -40,12 +49,15 @@ describe('find page middleware', () => {
|
||||
test('attaches page on req.context', async () => {
|
||||
const url = '/en/foo/bar'
|
||||
const [req, res] = makeRequestResponse(url)
|
||||
req.context.pages = {
|
||||
'/en/foo/bar': await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
}),
|
||||
const page = await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
})
|
||||
if (page && req.context) {
|
||||
req.context.pages = {
|
||||
'/en/foo/bar': page as any,
|
||||
}
|
||||
}
|
||||
|
||||
let nextCalls = 0
|
||||
@@ -53,7 +65,7 @@ describe('find page middleware', () => {
|
||||
nextCalls++
|
||||
})
|
||||
expect(nextCalls).toBe(1)
|
||||
expect(req.context.page).toBeInstanceOf(Page)
|
||||
expect(req.context?.page).toBeInstanceOf(Page)
|
||||
})
|
||||
|
||||
test('does not attach page on req.context if not found', async () => {
|
||||
@@ -64,52 +76,61 @@ describe('find page middleware', () => {
|
||||
nextCalls++
|
||||
})
|
||||
expect(nextCalls).toBe(1)
|
||||
expect(req.context.page).toBe(undefined)
|
||||
expect(req.context?.page).toBe(undefined)
|
||||
})
|
||||
|
||||
test('re-reads from disk if in development mode', async () => {
|
||||
const [req, res] = makeRequestResponse('/en/page-with-redirects')
|
||||
req.context.pages = {
|
||||
'/en/page-with-redirects': await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
}),
|
||||
const page = await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
})
|
||||
if (page && req.context) {
|
||||
req.context.pages = {
|
||||
'/en/page-with-redirects': page as any,
|
||||
}
|
||||
}
|
||||
|
||||
await findPage(req, res, () => {}, {
|
||||
isDev: true,
|
||||
contentRoot: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
})
|
||||
expect(req.context.page).toBeInstanceOf(Page)
|
||||
expect(req.context?.page).toBeInstanceOf(Page)
|
||||
})
|
||||
test('finds it for non-fpt version URLS', async () => {
|
||||
const [req, res] = makeRequestResponse('/en/page-with-redirects', 'enterprise-cloud@latest')
|
||||
req.context.pages = {
|
||||
'/en/page-with-redirects': await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
}),
|
||||
const page = await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
})
|
||||
if (page && req.context) {
|
||||
req.context.pages = {
|
||||
'/en/page-with-redirects': page as any,
|
||||
}
|
||||
}
|
||||
|
||||
await findPage(req, res, () => {}, {
|
||||
isDev: true,
|
||||
contentRoot: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
})
|
||||
expect(req.context.page).toBeInstanceOf(Page)
|
||||
expect(req.context?.page).toBeInstanceOf(Page)
|
||||
})
|
||||
|
||||
test("will 404 if the request version doesn't match the page", async () => {
|
||||
// The 'versions:' frontmatter on 'page-with-redirects.md' does
|
||||
// not include ghes. So this'll eventually 404.
|
||||
const [req, res] = makeRequestResponse('/en/page-with-redirects', 'enterprise-server@latest')
|
||||
req.context.pages = {
|
||||
'/en/page-with-redirects': await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
}),
|
||||
const page = await Page.init({
|
||||
relativePath: 'page-with-redirects.md',
|
||||
basePath: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
languageCode: 'en',
|
||||
})
|
||||
if (page && req.context) {
|
||||
req.context.pages = {
|
||||
'/en/page-with-redirects': page as any,
|
||||
}
|
||||
}
|
||||
|
||||
await findPage(req, res, () => {}, {
|
||||
@@ -118,7 +139,7 @@ describe('find page middleware', () => {
|
||||
})
|
||||
expect(res._status).toBe(404)
|
||||
expect(res._message).toMatch('')
|
||||
expect(req.context.page).toBeUndefined()
|
||||
expect(req.context?.page).toBeUndefined()
|
||||
})
|
||||
|
||||
test('re-reads from disk if in development mode and finds nothing', async () => {
|
||||
@@ -128,6 +149,6 @@ describe('find page middleware', () => {
|
||||
isDev: true,
|
||||
contentRoot: path.join(__dirname, '../../../src/fixtures/fixtures'),
|
||||
})
|
||||
expect(req.context.page).toBe(undefined)
|
||||
expect(req.context?.page).toBe(undefined)
|
||||
})
|
||||
})
|
||||
@@ -10,6 +10,29 @@ import { getDocsVersion } from '@/versions/lib/all-versions'
|
||||
import { REST_DATA_DIR, REST_SCHEMA_FILENAME } from '../../lib/index'
|
||||
import { deprecated } from '@/versions/lib/enterprise-server-releases'
|
||||
|
||||
type RestVersions = {
|
||||
[category: string]: {
|
||||
[subcategory: string]: {
|
||||
versions: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type MarkdownUpdate = {
|
||||
data: {
|
||||
title: string
|
||||
shortTitle: string
|
||||
intro: string
|
||||
versions: any
|
||||
[key: string]: any
|
||||
}
|
||||
content: string
|
||||
}
|
||||
|
||||
type MarkdownUpdates = {
|
||||
[filepath: string]: MarkdownUpdate
|
||||
}
|
||||
|
||||
const { frontmatterDefaults, targetDirectory, indexOrder } = JSON.parse(
|
||||
await readFile('src/rest/lib/config.json', 'utf-8'),
|
||||
)
|
||||
@@ -32,7 +55,7 @@ export async function updateRestFiles() {
|
||||
* @param {string} filePath - File path to parse
|
||||
* @returns {string|null} - GHES version or null if not a GHES file
|
||||
*/
|
||||
export function getGHESVersionFromFilepath(filePath) {
|
||||
export function getGHESVersionFromFilepath(filePath: string): string | null {
|
||||
// Normalize path separators to handle both Unix and Windows paths
|
||||
const normalizedPath = filePath.replace(/\\/g, '/')
|
||||
const pathParts = normalizedPath.split('/')
|
||||
@@ -49,7 +72,10 @@ export function getGHESVersionFromFilepath(filePath) {
|
||||
|
||||
// The data files are split up by version, so all files must be
|
||||
// read to get a complete list of versions.
|
||||
async function getDataFrontmatter(dataDirectory, schemaFilename) {
|
||||
async function getDataFrontmatter(
|
||||
dataDirectory: string,
|
||||
schemaFilename: string,
|
||||
): Promise<RestVersions> {
|
||||
const fileList = walk(dataDirectory, { includeBasePath: true })
|
||||
.filter((file) => path.basename(file) === schemaFilename)
|
||||
// Ignore any deprecated versions. This allows us to stop supporting
|
||||
@@ -67,7 +93,7 @@ async function getDataFrontmatter(dataDirectory, schemaFilename) {
|
||||
return !deprecated.includes(ghesVersion)
|
||||
})
|
||||
|
||||
const restVersions = {}
|
||||
const restVersions: RestVersions = {}
|
||||
|
||||
for (const file of fileList) {
|
||||
const data = JSON.parse(await readFile(file, 'utf-8'))
|
||||
@@ -112,8 +138,8 @@ async function getDataFrontmatter(dataDirectory, schemaFilename) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
async function getMarkdownContent(versions) {
|
||||
const markdownUpdates = {}
|
||||
async function getMarkdownContent(versions: RestVersions): Promise<MarkdownUpdates> {
|
||||
const markdownUpdates: MarkdownUpdates = {}
|
||||
|
||||
for (const [category, subcategoryObject] of Object.entries(versions)) {
|
||||
const subcategories = Object.keys(subcategoryObject)
|
||||
@@ -3,11 +3,12 @@ import {
|
||||
shouldShowRequestContentType,
|
||||
shouldShowResponseContentType,
|
||||
generateExampleOptionTexts,
|
||||
type CodeExample,
|
||||
} from '@/rest/lib/code-example-utils'
|
||||
|
||||
describe('Request Content Type Logic', () => {
|
||||
test('detects request content types differ correctly', () => {
|
||||
const codeExamples = [
|
||||
const codeExamples: CodeExample[] = [
|
||||
{
|
||||
description: 'Example',
|
||||
request: { contentType: 'text/plain' },
|
||||
@@ -25,7 +26,7 @@ describe('Request Content Type Logic', () => {
|
||||
})
|
||||
|
||||
test('detects response content types differ correctly', () => {
|
||||
const codeExamples = [
|
||||
const codeExamples: CodeExample[] = [
|
||||
{
|
||||
description: 'JSON example',
|
||||
request: { contentType: 'application/json' },
|
||||
@@ -43,7 +44,7 @@ describe('Request Content Type Logic', () => {
|
||||
})
|
||||
|
||||
test('generates correct options for markdown/raw scenario', () => {
|
||||
const markdownRawExamples = [
|
||||
const markdownRawExamples: CodeExample[] = [
|
||||
{
|
||||
description: 'Example',
|
||||
request: {
|
||||
@@ -70,7 +71,7 @@ describe('Request Content Type Logic', () => {
|
||||
})
|
||||
|
||||
test('generates correct options when both request and response differ', () => {
|
||||
const mixedExamples = [
|
||||
const mixedExamples: CodeExample[] = [
|
||||
{
|
||||
description: 'JSON request',
|
||||
request: {
|
||||
@@ -100,7 +101,7 @@ describe('Request Content Type Logic', () => {
|
||||
})
|
||||
|
||||
test('does not show content types when they are all the same', () => {
|
||||
const sameContentTypeExamples = [
|
||||
const sameContentTypeExamples: CodeExample[] = [
|
||||
{
|
||||
description: 'First example',
|
||||
request: {
|
||||
@@ -127,7 +128,7 @@ describe('Request Content Type Logic', () => {
|
||||
})
|
||||
|
||||
test('handles single example correctly', () => {
|
||||
const singleExample = [
|
||||
const singleExample: CodeExample[] = [
|
||||
{
|
||||
description: 'Only example',
|
||||
request: {
|
||||
Reference in New Issue
Block a user