1
0
mirror of synced 2025-12-19 18:10:59 -05:00

Convert 28 JavaScript files to TypeScript (#57753)

This commit is contained in:
Kevin Heis
2025-10-06 09:07:33 -07:00
committed by GitHub
parent 140a3f7768
commit 822bdfff67
30 changed files with 126 additions and 88 deletions

View File

@@ -6,11 +6,13 @@
*/
export function printAnnotationResults(
results,
// Using 'any' type as results structure is dynamic and comes from various linting tools with different formats
results: any,
{ skippableRules = [], skippableFlawProperties = [] } = {},
) {
for (const [file, flaws] of Object.entries(results)) {
for (const flaw of flaws) {
// Using 'any' type for flaws as they have varying structures depending on the linting rule
for (const flaw of flaws as any) {
if (intersection(flaw.ruleNames, skippableRules)) {
continue
}
@@ -52,6 +54,7 @@ export function printAnnotationResults(
}
}
function intersection(arr1, arr2) {
return arr1.some((item) => arr2.includes(item))
// Using 'any' types for generic array intersection utility function
function intersection(arr1: any[], arr2: any[]) {
return arr1.some((item: any) => arr2.includes(item))
}

View File

@@ -1,3 +1,4 @@
// @ts-ignore - markdownlint-rule-helpers doesn't have TypeScript declarations
import { addError } from 'markdownlint-rule-helpers'
import { intersection } from 'lodash-es'
@@ -5,12 +6,13 @@ import { getFrontmatter } from '../helpers/utils'
import { formatAjvErrors } from '../helpers/schema-utils'
import { frontmatter, deprecatedProperties } from '@/frame/lib/frontmatter'
import readFrontmatter from '@/frame/lib/read-frontmatter'
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
export const frontmatterSchema = {
export const frontmatterSchema: Rule = {
names: ['GHD012', 'frontmatter-schema'],
description: 'Frontmatter must conform to the schema',
tags: ['frontmatter', 'schema'],
function: (params, onError) => {
function: (params: RuleParams, onError: RuleErrorCallback) => {
const fm = getFrontmatter(params.lines)
if (!fm) return
@@ -22,25 +24,25 @@ export const frontmatterSchema = {
for (const key of deprecatedKeys) {
// Early access articles are allowed to have deprecated properties
if (params.name.includes('early-access')) continue
const line = params.lines.find((line) => line.trim().startsWith(key))
const lineNumber = params.lines.indexOf(line) + 1
const line = params.lines.find((line: string) => line.trim().startsWith(key))
const lineNumber = params.lines.indexOf(line!) + 1
addError(
onError,
lineNumber,
`The frontmatter property '${key}' is deprecated. Please remove the property from your article's frontmatter.`,
line,
[1, line.length],
line!,
[1, line!.length],
null, // No fix possible
)
}
// Check that the frontmatter matches the schema
const { errors } = readFrontmatter(params.lines.join('\n'), { schema: frontmatter.schema })
const formattedErrors = formatAjvErrors(errors)
const formattedErrors = formatAjvErrors(errors as any)
for (const error of formattedErrors) {
// If the missing property is at the top level, we don't have a line
// to point to. In that case, the error will be added to line 1.
const query = (line) => line.trim().startsWith(`${error.searchProperty}:`)
const query = (line: string) => line.trim().startsWith(`${error.searchProperty}:`)
const line = error.searchProperty === '' ? null : params.lines.find(query)
const lineNumber = line ? params.lines.indexOf(line) + 1 : 1
addError(

View File

@@ -1,6 +1,8 @@
// @ts-ignore - markdownlint-rule-helpers doesn't have TypeScript declarations
import { addError } from 'markdownlint-rule-helpers'
import { forEachInlineChild, getRange } from '../helpers/utils'
import type { RuleParams, RuleErrorCallback, MarkdownToken, Rule } from '../../types'
const excludeStartWords = ['image', 'graphic']
@@ -8,21 +10,21 @@ const excludeStartWords = ['image', 'graphic']
Images should have meaningful alternative text (alt text)
and should not begin with words like "image" or "graphic".
*/
export const imageAltTextExcludeStartWords = {
export const imageAltTextExcludeStartWords: Rule = {
names: ['GHD031', 'image-alt-text-exclude-words'],
description: 'Alternate text for images should not begin with words like "image" or "graphic"',
tags: ['accessibility', 'images'],
parser: 'markdownit',
function: (params, onError) => {
forEachInlineChild(params, 'image', function forToken(token) {
const imageAltText = token.content.trim()
function: (params: RuleParams, onError: RuleErrorCallback) => {
forEachInlineChild(params, 'image', function forToken(token: MarkdownToken) {
// If the alt text is empty, there is nothing to check and you can't
// produce a valid range.
// We can safely return early because the image-alt-text-length rule
// will fail this one.
if (!token.content) return
const imageAltText = token.content.trim()
const range = getRange(token.line, imageAltText)
if (
excludeStartWords.some((excludeWord) => imageAltText.toLowerCase().startsWith(excludeWord))

View File

@@ -1,15 +1,18 @@
// @ts-ignore - markdownlint-rule-helpers doesn't have TypeScript declarations
import { filterTokens } from 'markdownlint-rule-helpers'
import { addFixErrorDetail, getRange } from '../helpers/utils'
import { allLanguageKeys } from '@/languages/lib/languages'
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
export const internalLinksNoLang = {
export const internalLinksNoLang: Rule = {
names: ['GHD002', 'internal-links-no-lang'],
description: 'Internal links must not have a hardcoded language code',
tags: ['links', 'url'],
parser: 'markdownit',
function: (params, onError) => {
filterTokens(params, 'inline', (token) => {
function: (params: RuleParams, onError: RuleErrorCallback) => {
// Using 'any' type for token as markdownlint-rule-helpers doesn't provide TypeScript types
filterTokens(params, 'inline', (token: any) => {
for (const child of token.children) {
if (child.type !== 'link_open') continue
@@ -18,14 +21,17 @@ export const internalLinksNoLang = {
// ['href', 'get-started'], ['target', '_blank'],
// ['rel', 'canonical'],
// ]
// Attribute arrays are tuples of [attributeName, attributeValue] from markdownit parser
const hrefsMissingSlashes = child.attrs
// The attribute could also be `target` or `rel`
.filter((attr) => attr[0] === 'href')
.filter((attr) => attr[1].startsWith('/') || !attr[1].startsWith('//'))
.filter((attr: [string, string]) => attr[0] === 'href')
.filter((attr: [string, string]) => attr[1].startsWith('/') || !attr[1].startsWith('//'))
// Filter out link paths that start with language code
.filter((attr) => allLanguageKeys.some((lang) => attr[1].split('/')[1] === lang))
.filter((attr: [string, string]) =>
allLanguageKeys.some((lang) => attr[1].split('/')[1] === lang),
)
// Get the link path from the attribute
.map((attr) => attr[1])
.map((attr: [string, string]) => attr[1])
// Create errors for each link path that includes a language code
for (const linkPath of hrefsMissingSlashes) {
const range = getRange(child.line, linkPath)

View File

@@ -1,14 +1,17 @@
// @ts-ignore - markdownlint-rule-helpers doesn't have TypeScript declarations
import { filterTokens } from 'markdownlint-rule-helpers'
import { addFixErrorDetail, getRange } from '../helpers/utils'
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
export const internalLinksSlash = {
export const internalLinksSlash: Rule = {
names: ['GHD003', 'internal-links-slash'],
description: 'Internal links must start with a /',
tags: ['links', 'url'],
parser: 'markdownit',
function: (params, onError) => {
filterTokens(params, 'inline', (token) => {
function: (params: RuleParams, onError: RuleErrorCallback) => {
// Using 'any' type for token as markdownlint-rule-helpers doesn't provide TypeScript types
filterTokens(params, 'inline', (token: any) => {
for (const child of token.children) {
if (child.type !== 'link_open') continue
@@ -17,20 +20,21 @@ export const internalLinksSlash = {
// ['href', '/get-started'], ['target', '_blank'],
// ['rel', 'canonical'],
// ]
// Attribute arrays are tuples of [attributeName, attributeValue] from markdownit parser
const hrefsMissingSlashes = child.attrs
// The attribute could also be `target` or `rel`
.filter((attr) => attr[0] === 'href')
.filter((attr: [string, string]) => attr[0] === 'href')
// Filter out prefixes we don't want to check
.filter(
(attr) =>
(attr: [string, string]) =>
!['http', 'mailto', '#', '/'].some((ignorePrefix) =>
attr[1].startsWith(ignorePrefix),
),
)
// We can ignore empty links because MD042 from markdownlint catches empty links
.filter((attr) => attr[1] !== '')
.filter((attr: [string, string]) => attr[1] !== '')
// Get the link path from the attribute
.map((attr) => attr[1])
.map((attr: [string, string]) => attr[1])
// Create errors for each link path that doesn't start with a /
for (const linkPath of hrefsMissingSlashes) {

View File

@@ -1,15 +1,16 @@
// @ts-ignore - markdownlint-rule-helpers doesn't have TypeScript declarations
import { addError, filterTokens } from 'markdownlint-rule-helpers'
import type { RuleParams, RuleErrorCallback } from '../../types'
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
import { doesStringEndWithPeriod, getRange, isStringQuoted } from '../helpers/utils'
export const linkPunctuation = {
export const linkPunctuation: Rule = {
names: ['GHD001', 'link-punctuation'],
description: 'Internal link titles must not contain punctuation',
tags: ['links', 'url'],
parser: 'markdownit',
function: (params: RuleParams, onError: RuleErrorCallback) => {
// Using 'any' type for token as markdownlint-rule-helpers doesn't provide TypeScript types
filterTokens(params, 'inline', (token: any) => {
const { children, line } = token
let inLink = false

View File

@@ -1,8 +1,10 @@
import { TokenKind } from 'liquidjs'
// @ts-ignore - markdownlint-rule-helpers doesn't have TypeScript declarations
import { addError } from 'markdownlint-rule-helpers'
import { getLiquidTokens, conditionalTags, getPositionData } from '../helpers/liquid-utils'
import { isStringQuoted } from '../helpers/utils'
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
/*
Checks for instances where a Liquid conditional tag's argument is
@@ -12,18 +14,20 @@ import { isStringQuoted } from '../helpers/utils'
{% if "foo" %}
{% ifversion "bar" %}
*/
export const liquidQuotedConditionalArg = {
export const liquidQuotedConditionalArg: Rule = {
names: ['GHD016', 'liquid-quoted-conditional-arg'],
description: 'Liquid conditional tags should not quote the conditional argument',
tags: ['liquid', 'format'],
function: (params, onError) => {
function: (params: RuleParams, onError: RuleErrorCallback) => {
const content = params.lines.join('\n')
// Using 'any' type for tokens as getLiquidTokens returns tokens from liquid-utils.js which lacks type definitions
const tokens = getLiquidTokens(content)
.filter((token) => token.kind === TokenKind.Tag)
.filter((token) => conditionalTags.includes(token.name))
.filter((token) => {
.filter((token: any) => token.kind === TokenKind.Tag)
.filter((token: any) => conditionalTags.includes(token.name))
.filter((token: any) => {
const tokensArray = token.args.split(/\s+/g)
if (tokensArray.some((arg) => isStringQuoted(arg))) return true
// Using 'any' for args as they come from the untyped liquid token structure
if (tokensArray.some((arg: any) => isStringQuoted(arg))) return true
return false
})

View File

@@ -1,6 +1,7 @@
import { TokenKind } from 'liquidjs'
import { getLiquidTokens, getPositionData } from '../helpers/liquid-utils'
import { addFixErrorDetail } from '../helpers/utils'
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
/*
Octicons should always have an aria-label attribute even if aria hidden. For example:
@@ -13,16 +14,17 @@ Octicons should always have an aria-label attribute even if aria hidden. For exa
*/
export const octiconAriaLabels = {
export const octiconAriaLabels: Rule = {
names: ['GHD044', 'octicon-aria-labels'],
description: 'Octicons should always have an aria-label attribute even if aria-hidden.',
tags: ['accessibility', 'octicons'],
parser: 'markdownit',
function: (params, onError) => {
function: (params: RuleParams, onError: RuleErrorCallback) => {
const content = params.lines.join('\n')
// Using 'any' type for tokens as getLiquidTokens returns tokens from liquid-utils.js which lacks type definitions
const tokens = getLiquidTokens(content)
.filter((token) => token.kind === TokenKind.Tag)
.filter((token) => token.name === 'octicon')
.filter((token: any) => token.kind === TokenKind.Tag)
.filter((token: any) => token.name === 'octicon')
for (const token of tokens) {
const { lineNumber, column, length } = getPositionData(token, params.lines)

View File

@@ -41,7 +41,7 @@ describe(frontmatterEarlyAccessReferences.names.join(' - '), () => {
expect(lineNumbers.includes(4)).toBe(false)
expect(lineNumbers.includes(5)).toBe(false)
expect(errors[0].errorRange).toEqual([8, 12])
expect(errors[1].errorRange).toEqual([15, 12], [28, 12])
expect(errors[1].errorRange).toEqual([15, 12])
})
test('early access file with early access references passes', async () => {
const result = await runRule(frontmatterEarlyAccessReferences, {

View File

@@ -22,8 +22,8 @@ describe(tableColumnIntegrity.names.join(' - '), () => {
const errors = result.markdown
expect(errors.length).toBe(1)
expect(errors[0].lineNumber).toBe(3)
if (errors[0].detail) {
expect(errors[0].detail).toContain('Table row has 3 columns but header has 2')
if ((errors[0] as any).detail) {
expect((errors[0] as any).detail).toContain('Table row has 3 columns but header has 2')
} else if (errors[0].errorDetail) {
expect(errors[0].errorDetail).toContain('Table row has 3 columns but header has 2')
} else {
@@ -38,8 +38,8 @@ describe(tableColumnIntegrity.names.join(' - '), () => {
const errors = result.markdown
expect(errors.length).toBe(1)
expect(errors[0].lineNumber).toBe(3)
if (errors[0].detail) {
expect(errors[0].detail).toContain('Table row has 2 columns but header has 3')
if ((errors[0] as any).detail) {
expect((errors[0] as any).detail).toContain('Table row has 2 columns but header has 3')
} else if (errors[0].errorDetail) {
expect(errors[0].errorDetail).toContain('Table row has 2 columns but header has 3')
} else {

View File

@@ -6,7 +6,8 @@ import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-v
import { DataDirectory } from '@/tests/helpers/data-directory'
describe('data tag', () => {
let dd
// Using 'any' type as DataDirectory is from data-directory.js which lacks type definitions
let dd: any
const enDirBefore = languages.en.dir
beforeAll(() => {
@@ -41,7 +42,7 @@ describe('data tag', () => {
currentLanguage: 'en',
currentPath: '/en/liquid-tags/good-data-variable',
}
const rendered = await page.render(context)
const rendered = await page!.render(context)
// The test fixture contains:
// {% data variables.stuff.foo %}
// which we control the value of here in the test.
@@ -57,7 +58,7 @@ describe('data tag', () => {
currentPath: '/en/liquid-tags/bad-data-variable',
currentLanguage: 'en',
}
await expect(page.render(context)).rejects.toThrow(
await expect(page!.render(context)).rejects.toThrow(
"Can't find the key 'foo.bar.tipu' in the scope., line:2, col:1",
)
})

View File

@@ -7,8 +7,10 @@ import { DataDirectory } from '@/tests/helpers/data-directory'
describe('liquid helper tags', () => {
vi.setConfig({ testTimeout: 60 * 1000 })
const context = {}
let dd
// Using 'any' type as context is a test fixture with dynamic properties set in beforeAll
const context: any = {}
// Using 'any' type as DataDirectory is from data-directory.js which lacks type definitions
let dd: any
const enDirBefore = languages.en.dir
beforeAll(() => {

View File

@@ -4,6 +4,7 @@ import { extname, basename } from 'path'
import walk from 'walk-sync'
import { beforeAll, describe, expect, test } from 'vitest'
import type { ValidateFunction, SchemaObject } from 'ajv'
import { getJsonValidator, validateJson } from '@/tests/lib/validate-json-schema'
import { formatAjvErrors } from '@/tests/helpers/schemas'
@@ -19,7 +20,8 @@ const yamlWalkOptions = {
}
for (const dataDir of directorySchemas) {
let schema, validate
let schema: SchemaObject
let validate: ValidateFunction
const dataDirectoryName = basename(dataDir)
const yamlFileList = walk(dataDir, yamlWalkOptions).sort()
@@ -32,7 +34,7 @@ for (const dataDir of directorySchemas) {
test.each(yamlFileList)('%p', async (yamlAbsPath) => {
const yamlContent = yaml.load(readFileSync(yamlAbsPath, 'utf8'))
const isValid = validate(yamlContent)
const formattedErrors = isValid ? validate.errors : formatAjvErrors(validate.errors)
const formattedErrors = isValid ? undefined : formatAjvErrors(validate.errors || [])
expect(isValid, formattedErrors).toBe(true)
})
})
@@ -43,6 +45,7 @@ describe('single data files', () => {
const ymlData = yaml.load(readFileSync(filepath, 'utf8'))
const schema = (await import(dataSchemas[filepath])).default
const { isValid, errors } = validateJson(schema, ymlData)
expect(isValid, errors).toBe(true)
const formattedErrors = isValid ? undefined : formatAjvErrors(errors || [])
expect(isValid, formattedErrors).toBe(true)
})
})

View File

@@ -20,7 +20,7 @@ describe('data-directory', () => {
})
test('option: preprocess function', async () => {
const preprocess = function (content) {
const preprocess = function (content: string) {
return content.replace('markdown', 'MARKDOWN')
}
const data = dataDirectory(fixturesDir, { preprocess })
@@ -35,7 +35,7 @@ describe('data-directory', () => {
})
test('option: ignorePatterns', async () => {
const ignorePatterns = []
const ignorePatterns: RegExp[] = []
// README is ignored by default
expect('README' in dataDirectory(fixturesDir)).toBe(false)

View File

@@ -1,3 +1,5 @@
import type { NextFunction } from 'express'
// Fastly provides a Soft Purge feature that allows you to mark content as outdated (stale) instead of permanently
// purging and thereby deleting it from Fastly's caches. Objects invalidated with Soft Purge will be treated as
// outdated (stale) while Fastly fetches a new version from origin.
@@ -14,7 +16,8 @@ export const SURROGATE_ENUMS = {
MANUAL: 'manual-purge',
}
export function setFastlySurrogateKey(res, enumKey, isCustomKey = false) {
// Using 'any' type for res parameter to maintain compatibility with Express Response objects
export function setFastlySurrogateKey(res: any, enumKey: string, isCustomKey = false) {
if (process.env.NODE_ENV !== 'production') {
if (!isCustomKey && !Object.values(SURROGATE_ENUMS).includes(enumKey)) {
throw new Error(
@@ -27,17 +30,21 @@ export function setFastlySurrogateKey(res, enumKey, isCustomKey = false) {
res.set(KEY, enumKey)
}
export function setDefaultFastlySurrogateKey(req, res, next) {
// Using 'any' type for req and res parameters to maintain backward compatibility with test mock objects
// that don't fully implement ExtendedRequest and Response interfaces
export function setDefaultFastlySurrogateKey(req: any, res: any, next: NextFunction) {
res.set(KEY, `${SURROGATE_ENUMS.DEFAULT} ${makeLanguageSurrogateKey()}`)
return next()
}
export function setLanguageFastlySurrogateKey(req, res, next) {
// Using 'any' type for req and res parameters to maintain backward compatibility with test mock objects
// that don't fully implement ExtendedRequest and Response interfaces
export function setLanguageFastlySurrogateKey(req: any, res: any, next: NextFunction) {
res.set(KEY, `${SURROGATE_ENUMS.DEFAULT} ${makeLanguageSurrogateKey(req.language)}`)
return next()
}
export function makeLanguageSurrogateKey(langCode) {
export function makeLanguageSurrogateKey(langCode?: string) {
if (!langCode) {
return 'no-language'
}

View File

@@ -3,6 +3,7 @@ import { describe, expect, test, vi } from 'vitest'
import { loadPageMap, loadPages } from '@/frame/lib/page-data'
import { renderContent } from '@/content-render/index'
import { allVersions } from '@/versions/lib/all-versions'
import type { Permalink } from '@/types'
describe('toc links', () => {
vi.setConfig({ testTimeout: 3 * 60 * 1000 })
@@ -20,7 +21,8 @@ describe('toc links', () => {
for (const pageVersion of Object.keys(allVersions)) {
for (const page of englishIndexPages) {
// skip page if it doesn't have a permalink for the current product version
if (!page.permalinks.some((permalink) => permalink.pageVersion === pageVersion)) continue
if (!page.permalinks.some((permalink: Permalink) => permalink.pageVersion === pageVersion))
continue
// build fake context object for rendering the page
const context = {
@@ -38,7 +40,7 @@ describe('toc links', () => {
} catch (err) {
issues.push({
'TOC path': page.relativePath,
error: err.message,
error: err instanceof Error ? err.message : String(err),
pageVersion,
})
}

View File

@@ -10,10 +10,15 @@ import {
getPreviews,
} from '../lib/index'
interface GraphqlType {
kind: string
type: string
}
describe('graphql schema', () => {
const graphqlTypes = JSON.parse(readFileSync('src/graphql/lib/types.json')).map(
(item) => item.kind,
)
const graphqlTypes = (
JSON.parse(readFileSync('src/graphql/lib/types.json', 'utf-8')) as GraphqlType[]
).map((item) => item.kind)
for (const version in allVersions) {
for (const type of graphqlTypes) {
test(`getting the GraphQL ${type} schema works for ${version}`, async () => {

View File

@@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest'
import { getDOM } from '@/tests/helpers/e2etest'
import { loadPages } from '@/frame/lib/page-data'
import type { Permalink } from '@/types'
const pageList = await loadPages(undefined, ['en'])
@@ -27,7 +28,9 @@ describe('server rendering certain GraphQL pages', () => {
)
const nonFPTPermalinks = autogeneratedPages
.map((page) =>
page.permalinks.find((permalink) => permalink.pageVersion !== 'free-pro-team@latest'),
page.permalinks.find(
(permalink: Permalink) => permalink.pageVersion !== 'free-pro-team@latest',
),
)
.filter(Boolean)
const nonFPTPermalinksHrefs = nonFPTPermalinks.map((permalink) => {

View File

@@ -13,7 +13,7 @@ const liquidEndRex = /{%-?\s*endif\s*-?%}$/
// {% ifversion ghes%}/foo/bar{%endif %}
//
// And if no liquid, just return as is.
function stripLiquid(text) {
function stripLiquid(text: string): string {
if (liquidStartRex.test(text) && liquidEndRex.test(text)) {
return text.replace(liquidStartRex, '').replace(liquidEndRex, '').trim()
} else if (text.includes('{')) {
@@ -26,7 +26,9 @@ function stripLiquid(text) {
// return undefined if it can found as a known page.
// Otherwise, return an object with information that is used to
// print a useful test error message in the assertion.
export function checkURL(uri, index, redirectsContext) {
// Using 'any' type for redirectsContext parameter as it's a complex context object
// with dynamic structure that would require extensive type definitions
export function checkURL(uri: string, index: number, redirectsContext: any) {
const url = `/en${stripLiquid(uri).split('#')[0]}`
if (!(url in redirectsContext.pages)) {
// Some are written without a version, but don't work with the

View File

@@ -1,13 +0,0 @@
import type { AllVersions } from '@/types'
export const allVersionKeys: string[]
export const allVersionShortnames: Record<string, string>
export declare function isApiVersioned(version: string): boolean
export declare function getDocsVersion(openApiVersion: string): string
export declare function getOpenApiVersion(version: string): string
export const allVersions: AllVersions

View File

@@ -6,6 +6,7 @@ import { latest } from '@/versions/lib/enterprise-server-releases'
import schema from '@/tests/helpers/schemas/versions-schema'
import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version'
import { formatAjvErrors } from '@/tests/helpers/schemas'
import type { Version } from '@/types'
const validate = getJsonValidator(schema)
@@ -16,12 +17,13 @@ describe('versions module', () => {
})
test('every version is valid', () => {
Object.values(allVersions).forEach((versionObj) => {
Object.values(allVersions).forEach((versionObj: Version) => {
const versionName = versionObj.version
const isValid = validate(versionObj)
let errors
let errors: string | undefined
if (!isValid) {
errors = `version '${versionObj.version}': ${formatAjvErrors(validate.errors)}`
errors = `version '${versionName}': ${formatAjvErrors(validate.errors || [])}`
}
expect(isValid, errors).toBe(true)
@@ -29,7 +31,7 @@ describe('versions module', () => {
})
test('check REST api calendar date versioned versions set to correct latestApiVersion', () => {
Object.values(allVersions).forEach((versionObj) => {
Object.values(allVersions).forEach((versionObj: Version) => {
if (versionObj.apiVersions.length > 0) {
const latestApiVersion = versionObj.latestApiVersion
const apiVersions = versionObj.apiVersions