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
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ import { runRule } from '../../lib/init-test'
import { githubOwnedActionReferences } from '../../lib/linting-rules/github-owned-action-references'

describe(githubOwnedActionReferences.names.join(' - '), () => {
test('Using hardcoded GitHub-owned actions causes error', async () => {
const markdown = [
test('Using hardcoded GitHub-owned actions causes error', async (): Promise<void> => {
const markdown: string = [
'Hello actions/checkout@v2 apps.',
'A actions/delete-package-versions@v2 for apps.',
'Hello actions/download-artifact@v2.',
'actions/cache@432433423423',
'actions/cache@',
'[link title](/actions/cache)',
].join('\n')
const result = await runRule(githubOwnedActionReferences, { strings: { markdown } })
const result = await runRule(githubOwnedActionReferences, {
strings: { markdown },
files: undefined,
ruleConfig: true,
})
const errors = result.markdown
expect(errors.length).toBe(3)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import { tableLiquidVersioning } from '../../lib/linting-rules/table-liquid-vers
const FIXTURE_FILEPATH = 'src/content-linter/tests/fixtures/tables.md'

describe(tableLiquidVersioning.names.join(' - '), () => {
test('non-early access file with early access references fails', async () => {
const result = await runRule(tableLiquidVersioning, { files: [FIXTURE_FILEPATH] })
test('non-early access file with early access references fails', async (): Promise<void> => {
const result = await runRule(tableLiquidVersioning, {
strings: undefined,
files: [FIXTURE_FILEPATH],
ruleConfig: true,
})
const errors = result[FIXTURE_FILEPATH]
expect(errors.length).toBe(11)
const lineNumbers = errors.map((error) => error.lineNumber)
const expectedErrorLines = [38, 40, 43, 44, 51, 53, 54, 55, 57, 58, 59]
const lineNumbers: number[] = errors.map((error) => error.lineNumber)
const expectedErrorLines: number[] = [38, 40, 43, 44, 51, 53, 54, 55, 57, 58, 59]
expect(JSON.stringify(lineNumbers)).toEqual(JSON.stringify(expectedErrorLines))
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { decode } from 'html-entities'
// Take advantage of the subtle fact that a lot of the times, the html value
// we get here is a single line that starts with `<p>` and ends with `</p>`
// and contains no longer HTML tags.
export function fastTextOnly(html) {
export function fastTextOnly(html: string): string {
if (!html) return ''
if (html.startsWith('<p>') && html.endsWith('</p>')) {
const middle = html.slice(3, -4)
if (!middle.includes('<')) return decode(middle.trim())
}
return cheerio.load(html, { xmlMode: true }).text().trim()
const $ = cheerio.load(html, { xmlMode: true })
return $.root().text().trim()
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { schema } from '@/frame/lib/frontmatter'

interface FeatureVersionsSchema {
type: 'object'
properties: {
versions: any
}
additionalProperties: false
}

// Copy the properties from the frontmatter schema.
const featureVersions = {
const featureVersions: FeatureVersionsSchema = {
type: 'object',
properties: {
versions: Object.assign({}, schema.properties.versions),
versions: Object.assign({}, (schema.properties as any).versions),
},
additionalProperties: false,
}

// Remove the feature versions properties.
// We don't want to allow features within features! We just want pure versioning.
delete featureVersions.properties.versions.properties.feature

// Call it invalid if any properties other than version properties are found.
featureVersions.additionalProperties = false

// avoid ajv strict warning
featureVersions.type = 'object'

export default featureVersions
18 changes: 0 additions & 18 deletions src/data-directory/lib/data-schemas/glossaries-candidates.js

This file was deleted.

43 changes: 43 additions & 0 deletions src/data-directory/lib/data-schemas/glossaries-candidates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export interface TermSchema {
type: 'string'
minLength: number
pattern: string
}

export const term: TermSchema = {
type: 'string',
minLength: 1,
pattern: '^((?!\\*).)*$', // no asterisks allowed
}

export interface GlossaryCandidateItem {
term: string
}

export interface GlossaryCandidatesSchema {
type: 'array'
items: {
type: 'object'
required: ['term']
additionalProperties: false
properties: {
term: TermSchema
}
}
minItems: number
}

const schema: GlossaryCandidatesSchema = {
type: 'array',
items: {
type: 'object',
required: ['term'],
additionalProperties: false,
properties: {
term,
},
},
minItems: 21,
}

export default schema
18 changes: 0 additions & 18 deletions src/data-directory/lib/data-schemas/glossaries-external.js

This file was deleted.

44 changes: 44 additions & 0 deletions src/data-directory/lib/data-schemas/glossaries-external.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { term, type TermSchema } from './glossaries-candidates'

export interface GlossaryExternalItem {
term: string
description: string
}

export interface DescriptionSchema {
type: 'string'
lintable: boolean
}

export interface GlossariesExternalSchema {
type: 'array'
items: {
type: 'object'
required: ['term', 'description']
additionalProperties: false
properties: {
term: TermSchema
description: DescriptionSchema
}
}
minItems: number
}

const schema: GlossariesExternalSchema = {
type: 'array',
items: {
type: 'object',
required: ['term', 'description'],
additionalProperties: false,
properties: {
term,
description: {
type: 'string',
lintable: true,
},
},
},
minItems: 21,
}

export default schema
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { describe, expect, test } from 'vitest'
import filenameToKey from '@/data-directory/lib/filename-to-key'

describe('filename-to-key', () => {
test('converts filenames to object keys', () => {
test('converts filenames to object keys', (): void => {
expect(filenameToKey('foo/bar/baz.txt')).toBe('foo.bar.baz')
})

test('ignores leading slash on filenames', () => {
test('ignores leading slash on filenames', (): void => {
expect(filenameToKey('/foo/bar/baz.txt')).toBe('foo.bar.baz')
})

test('supports MS Windows paths', () => {
test('supports MS Windows paths', (): void => {
expect(filenameToKey('path\\to\\file.txt')).toBe('path.to.file')
})
})
4 changes: 2 additions & 2 deletions src/frame/tests/api.js → src/frame/tests/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { get } from '@/tests/helpers/e2etest'
describe('general /api pages', () => {
vi.setConfig({ testTimeout: 60 * 1000 })

test("any /api URL that isn't found should JSON", async () => {
test("any /api URL that isn't found should JSON", async (): Promise<void> => {
const res = await get('/api')
expect(res.statusCode).toBe(404)
expect(res.headers['content-type']).toMatch(/application\/json/)
})

test("any /api/* URL that isn't found should be JSON", async () => {
test("any /api/* URL that isn't found should be JSON", async (): Promise<void> => {
const res = await get('/api/yadayada')
expect(res.statusCode).toBe(404)
expect(JSON.parse(res.body).error).toBe('/yadayada not found')
Expand Down
15 changes: 0 additions & 15 deletions src/graphql/scripts/utils/process-upcoming-changes.js

This file was deleted.

28 changes: 28 additions & 0 deletions src/graphql/scripts/utils/process-upcoming-changes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import yaml from 'js-yaml'
import { groupBy } from 'lodash-es'
import { renderContent } from '@/content-render/index'

interface UpcomingChange {
date: string
reason: string
description: string
[key: string]: unknown
}

interface UpcomingChangesData {
upcoming_changes: UpcomingChange[]
}

export default async function processUpcomingChanges(
upcomingChangesYml: string,
): Promise<Record<string, UpcomingChange[]>> {
const upcomingChanges = (yaml.load(upcomingChangesYml) as UpcomingChangesData).upcoming_changes

for (const change of upcomingChanges) {
change.date = change.date.slice(0, 10)
change.reason = await renderContent(change.reason)
change.description = await renderContent(change.description)
}

return groupBy(upcomingChanges.reverse(), 'date')
}
6 changes: 3 additions & 3 deletions src/rest/lib/config.js → src/rest/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
// in the JSON file.

// These paths must match the paths in src/pages/[versionId]/rest
export const nonAutomatedRestPaths = [
export const nonAutomatedRestPaths: readonly string[] = [
'/rest/quickstart',
'/rest/about-the-rest-api',
'/rest/using-the-rest-api',
'/rest/authentication',
'/rest/guides',
]
] as const

// This path is used to set the page in the
// src/rest/components/ApiVersionPicker.tsx component. That component
// has a link to the page that describes what api versioning is.
export const apiVersionPath = '/rest/about-the-rest-api/api-versions'
export const apiVersionPath: string = '/rest/about-the-rest-api/api-versions'
16 changes: 0 additions & 16 deletions src/tests/helpers/caching-headers.js

This file was deleted.

34 changes: 34 additions & 0 deletions src/tests/helpers/caching-headers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { expect } from 'vitest'

import { SURROGATE_ENUMS } from '@/frame/middleware/set-fastly-surrogate-key'

interface ResponseWithHeaders {
headers: Record<string, string | string[] | undefined>
}

export function checkCachingHeaders(
res: ResponseWithHeaders,
defaultSurrogateKey: boolean = false,
minMaxAge: number = 60 * 60,
): void {
expect(res.headers['set-cookie']).toBeUndefined()
expect(res.headers['cache-control']).toContain('public')

const cacheControlHeader = res.headers['cache-control'] as string
const maxAgeMatch = cacheControlHeader.match(/max-age=(\d+)/)

if (!maxAgeMatch) {
throw new Error('Cache-Control header does not contain max-age directive')
}

const maxAgeSeconds = parseInt(maxAgeMatch[1], 10)
// Let's not be too specific in the tests, just as long as it's testing
// that it's a reasonably large number of seconds.
expect(maxAgeSeconds).toBeGreaterThanOrEqual(minMaxAge)

// Because it doesn't have a unique URL
const surrogateKeyHeader = res.headers['surrogate-key'] as string
expect(surrogateKeyHeader.split(/\s/g)[0]).toBe(
defaultSurrogateKey ? SURROGATE_ENUMS.DEFAULT : SURROGATE_ENUMS.MANUAL,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import semver from 'semver'

// Where "release" is a release number, like `3.1` for Enterprise Server,
// and "range" is a semver range operator with another number, like `<=3.2`.
export default function versionSatisfiesRange(release, range) {
export default function versionSatisfiesRange(release: string | undefined, range: string): boolean {
// Handle undefined release
if (!release) {
return false
}

// workaround for Enterprise Server 11.10.340 because we can't use semver to
// compare it to 2.x like we can with 2.0+
if (release === '11.10.340') return range.startsWith('<')
Expand All @@ -15,5 +20,10 @@ export default function versionSatisfiesRange(release, range) {
release = '1.0'
}

return semver.satisfies(semver.coerce(release), range)
const coercedRelease = semver.coerce(release)
if (!coercedRelease) {
throw new Error(`Unable to coerce release version: ${release}`)
}

return semver.satisfies(coercedRelease, range)
}
Loading