Skip to content

Commit

Permalink
Port context.js to TypeScript (#50978)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterbe authored and pull[bot] committed Jun 25, 2024
1 parent 9b109a6 commit 17f99cc
Show file tree
Hide file tree
Showing 21 changed files with 473 additions and 138 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/link-check-daily.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
with:
path: external-link-checker-db.json
key: external-link-checker-${{ hashFiles('src/links/scripts/rendered-content-link-checker.js') }}
key: external-link-checker-${{ hashFiles('src/links/scripts/rendered-content-link-checker.ts') }}

- name: Insight into external link checker DB json file (before)
run: |
Expand Down Expand Up @@ -87,7 +87,7 @@ jobs:
EXTERNAL_SERVER_ERRORS_AS_WARNINGS: true
FAIL_ON_FLAW: false
timeout-minutes: 30
run: node src/links/scripts/rendered-content-link-checker.js
run: npm run rendered-content-link-checker

- name: Insight into external link checker DB json file (after)
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/link-check-on-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ jobs:
# been loaded.
ENABLED_LANGUAGES: en
FAIL_ON_FLAW: true
run: node src/links/scripts/rendered-content-link-checker.js
run: npm run rendered-content-link-checker
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
"prevent-pushes-to-main": "node src/workflows/prevent-pushes-to-main.js",
"release-banner": "node src/ghes-releases/scripts/release-banner.js",
"remove-version-markup": "node src/ghes-releases/scripts/remove-version-markup.js",
"rendered-content-link-checker-cli": "node src/links/scripts/rendered-content-link-checker-cli.js",
"rendered-content-link-checker": "tsx src/links/scripts/rendered-content-link-checker.ts",
"rendered-content-link-checker-cli": "tsx src/links/scripts/rendered-content-link-checker-cli.ts",
"rest-dev": "node src/rest/scripts/update-files.js",
"show-action-deps": "echo 'Action Dependencies:' && rg '^[\\s|-]*(uses:.*)$' .github -I -N --no-heading -r '$1$2' | sort | uniq | cut -c 7-",
"start": "cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon src/frame/server.ts",
Expand Down
15 changes: 5 additions & 10 deletions src/content-linter/tests/category-pages.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path'
import fs from 'fs'

import type { Response } from 'express'
import walk from 'walk-sync'
import { zip, difference } from 'lodash-es'
import GithubSlugger from 'github-slugger'
Expand All @@ -10,10 +11,10 @@ import { beforeAll, describe, expect, test } from 'vitest'
import matter from '@/frame/lib/read-frontmatter.js'
import { renderContent } from '@/content-render/index.js'
import getApplicableVersions from '@/versions/lib/get-applicable-versions.js'
import contextualize from '@/frame/middleware/context/context.js'
import contextualize from '@/frame/middleware/context/context'
import shortVersions from '@/versions/middleware/short-versions.js'
import { ROOT } from '@/frame/lib/constants.js'
import type { Context, FrontmatterVersions } from '@/types'
import type { Context, ExtendedRequest, FrontmatterVersions } from '@/types'

const slugger = new GithubSlugger()

Expand All @@ -29,12 +30,6 @@ type Frontmatter = {
hidden?: boolean
}

type MockedRequest = {
language: string
pagePath: string
context: Context
}

function getFrontmatterData(markdown: string): Frontmatter {
const parsed = matter(markdown)
if (!parsed.data) throw new Error('No frontmatter')
Expand Down Expand Up @@ -139,13 +134,13 @@ describe.skip('category pages', () => {
const next = () => {}
const res = {}
const context: Context = {}
const req: MockedRequest = {
const req = {
language: 'en',
pagePath: '/en',
context,
}

await contextualize(req, res, next)
await contextualize(req as ExtendedRequest, res as Response, next)
await shortVersions(req, res, next)

// Save the index title for later testing
Expand Down
8 changes: 5 additions & 3 deletions src/content-render/scripts/all-documents/lib.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Page } from '@/types'
import contextualize from '@/frame/middleware/context/context.js'
import type { Response } from 'express'

import type { ExtendedRequest, Page } from '@/types'
import contextualize from '@/frame/middleware/context/context'
import features from '@/versions/middleware/features.js'
import shortVersions from '@/versions/middleware/short-versions.js'

Expand Down Expand Up @@ -63,7 +65,7 @@ export async function allDocuments(options: Options): Promise<AllDocument[]> {
context,
}

await contextualize(req, res, next)
await contextualize(req as ExtendedRequest, res as Response, next)
await shortVersions(req, res, next)
req.context.page = page
await features(req, res, next)
Expand Down
2 changes: 1 addition & 1 deletion src/dev-toc/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { program } from 'commander'
import fpt from '#src/versions/lib/non-enterprise-default-version.js'
import { allVersionKeys } from '#src/versions/lib/all-versions.js'
import { liquid } from '#src/content-render/index.js'
import contextualize from '#src/frame/middleware/context/context.js'
import contextualize from '#src/frame/middleware/context/context'

const layoutFilename = path.posix.join(process.cwd(), 'src/dev-toc/layout.html')
const layout = fs.readFileSync(layoutFilename, 'utf8')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import languages from '#src/languages/lib/languages.js'
import enterpriseServerReleases from '#src/versions/lib/enterprise-server-releases.js'
import { allVersions } from '#src/versions/lib/all-versions.js'
import { productMap } from '#src/products/lib/all-products.js'
import type { NextFunction, Response } from 'express'

import type { ExtendedRequest, Context } from '@/types'

import languages from '@/languages/lib/languages.js'
import enterpriseServerReleases from '@/versions/lib/enterprise-server-releases.js'
import { allVersions } from '@/versions/lib/all-versions.js'
import { productMap } from '@/products/lib/all-products.js'
import {
getVersionStringFromPath,
getProductStringFromPath,
getCategoryStringFromPath,
getPathWithoutLanguage,
getPathWithoutVersion,
} from '#src/frame/lib/path-utils.js'
import productNames from '#src/products/lib/product-names.js'
import warmServer from '#src/frame/lib/warm-server.js'
import nonEnterpriseDefaultVersion from '#src/versions/lib/non-enterprise-default-version.js'
import { getDataByLanguage, getUIDataMerged } from '#src/data-directory/lib/get-data.js'
} from '@/frame/lib/path-utils.js'
import productNames from '@/products/lib/product-names.js'
import warmServer from '@/frame/lib/warm-server.js'
import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version.js'
import { getDataByLanguage, getUIDataMerged } from '@/data-directory/lib/get-data.js'

// This doesn't change just because the request changes, so compute it once.
const enterpriseServerVersions = Object.keys(allVersions).filter((version) =>
Expand All @@ -21,18 +25,24 @@ const enterpriseServerVersions = Object.keys(allVersions).filter((version) =>

// Supply all route handlers with a baseline `req.context` object
// Note that additional middleware in middleware/index.js adds to this context object
export default async function contextualize(req, res, next) {
export default async function contextualize(
req: ExtendedRequest,
res: Response,
next: NextFunction,
) {
// Ensure that we load some data only once on first request
const { redirects, siteTree, pages: pageMap } = await warmServer()
const { redirects, siteTree, pages: pageMap } = await warmServer([])

req.context = {}
const context: Context = {}
req.context = context
req.context.process = { env: {} }

// define each context property explicitly for code-search friendliness
// e.g. searches for "req.context.page" will include results from this file
req.context.currentLanguage = req.language
req.context.userLanguage = req.userLanguage
req.context.currentVersion = getVersionStringFromPath(req.pagePath)
req.context.currentVersion = getVersionStringFromPath(req.pagePath) as string

req.context.currentVersionObj = allVersions[req.context.currentVersion]
req.context.currentProduct = getProductStringFromPath(req.pagePath)
req.context.currentCategory = getCategoryStringFromPath(req.pagePath)
Expand Down Expand Up @@ -79,8 +89,8 @@ export default async function contextualize(req, res, next) {
if (!page) {
throw new Error("The 'page' has not been put into the context yet.")
}
const enPath = context.currentPath.replace(`/${page.languageCode}`, '/en')
const enPage = context.pages[enPath]
const enPath = context.currentPath!.replace(`/${page.languageCode}`, '/en')
const enPage = context.pages![enPath]
if (!enPage) {
throw new Error(`Unable to find equivalent English page by the path '${enPath}'`)
}
Expand Down
2 changes: 1 addition & 1 deletion src/frame/middleware/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import handleErrors from '@/observability/middleware/handle-errors'
import handleNextDataPath from './handle-next-data-path'
import detectLanguage from '@/languages/middleware/detect-language'
import reloadTree from './reload-tree'
import context from './context/context.js'
import context from './context/context'
import shortVersions from '@/versions/middleware/short-versions.js'
import languageCodeRedirects from '@/redirects/middleware/language-code-redirects.js'
import handleRedirects from '@/redirects/middleware/handle-redirects.js'
Expand Down
4 changes: 2 additions & 2 deletions src/links/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ If the action finds any broken links, it opens an internal issue for the Docs Co
<pre>
curl -Lso /dev/null -w "%{http_code}\n" <em>URL</em>
</pre>
A `200` response is success.
A `200` response is success.

- You can see a comprehensive list of HTTP response codes [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
- For external links that now `404` or have otherwise gone missing entirely, you may be able to use the [Wayback Machine](https://web.archive.org) to see the page before it went offline.
Expand All @@ -39,4 +39,4 @@ Before you decide whether to exclude a link from the daily link checker, you sho
- Has it has been flagged as a broken link for more than a week, but the URL works when a real user opens it in their browser?
- Has the URL been available for more than 3 months? You can check using the [Wayback Machine](https://web.archive.org).

If you are confident that the URL for the article should work for real users, then you can open a pull request to add it to the `src/links/lib/excluded-links.js` file.
If you are confident that the URL for the article should work for real users, then you can open a pull request to add it to the `src/links/lib/excluded-links.ts` file.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

/* eslint-disable prefer-regex-literals */

export default [
type ExcludedLink = string | RegExp

const excludedLinks: ExcludedLink[] = [
// Skip GitHub search links.
// E.g. https://github.com/search?foo=bar
regex('https://github.com/search?'),
Expand Down Expand Up @@ -79,6 +81,8 @@ export default [
'https://packages.ubuntu.com/search?keywords=netcat&searchon=names',
]

export default excludedLinks

// Return a regular expression from a URL string that matches the URL
// as a base. It's basically shorthand for "URL.startsWith(BASE_URL)"
// but as a RegExp object.
Expand All @@ -88,6 +92,6 @@ export default [
// true
// > regex('https://github.com').test('otherhttps://github.com/page')
// false
function regex(url) {
function regex(url: string) {
return new RegExp('^' + url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
}
7 changes: 4 additions & 3 deletions src/links/lib/validate-docs-urls.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type { Response } from 'express'
import cheerio from 'cheerio'

import warmServer from '@/frame/lib/warm-server.js'
import { liquid } from '@/content-render/index.js'
import shortVersions from '@/versions/middleware/short-versions.js'
import contextualize from '@/frame/middleware/context/context.js'
import contextualize from '@/frame/middleware/context/context'
import features from '@/versions/middleware/features.js'
import findPage from '@/frame/middleware/find-page.js'
import { createMinimalProcessor } from '@/content-render/unified/processor.js'
import getRedirect from '@/redirects/lib/get-redirect.js'
import type { Page } from '@/types'
import type { ExtendedRequest, Page } from '@/types'

export type DocsUrls = {
[identifier: string]: string
Expand Down Expand Up @@ -116,7 +117,7 @@ async function renderInnerHTML(page: Page, permalink: Permalink) {
// Here it just exists for the sake of TypeScript.
context: {},
}
await contextualize(req, res, next)
await contextualize(req as ExtendedRequest, res as Response, next)
await shortVersions(req, res, next)
await findPage(req, res, next)
await features(req, res, next)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,29 @@ import fs from 'fs'
import path from 'path'
import chalk from 'chalk'

import github from '#src/workflows/github.js'
import github from '@/workflows/github.js'

export type CoreInject = {
info: (message: string) => void
debug: (message: string) => void
warning: (message: string) => void
error: (message: string) => void
setOutput: (name: string, value: any) => void
setFailed: (message: string) => void
}
// Directs core logging to console
export function getCoreInject(debug) {
export function getCoreInject(debug: boolean): CoreInject {
return {
info: console.log,
debug: (message) => (debug ? console.warn(chalk.blue(message)) : {}),
warning: (message) => console.warn(chalk.yellow(message)),
debug: (message: string) => (debug ? console.warn(chalk.blue(message)) : {}),
warning: (message: string) => console.warn(chalk.yellow(message)),
error: console.error,
setOutput: (name, value) => {
setOutput: (name: string, value: any) => {
if (debug) {
console.log(`Output "${name}" set to: "${value}"`)
}
},
setFailed: (message) => {
setFailed: (message: string) => {
if (debug) {
console.log('setFailed called.')
}
Expand All @@ -36,8 +44,8 @@ const logsPath = path.join(cwd, '..', '..', 'logs')
if (!fs.existsSync(logsPath)) {
fs.mkdirSync(logsPath)
}
export function getUploadArtifactInject(debug) {
return (name, contents) => {
export function getUploadArtifactInject(debug: boolean) {
return (name: string, contents: string) => {
const logFilename = path.join(logsPath, `${new Date().toISOString().substr(0, 16)}-${name}`)
if (debug) {
fs.writeFileSync(logFilename, contents)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import fs from 'fs'
import path from 'path'
import { program, Option, InvalidArgumentError } from 'commander'
import renderedContentLinkChecker from '#src/links/scripts/rendered-content-link-checker.js'
import { getCoreInject, getUploadArtifactInject } from '#src/links/scripts/action-injections.js'
import { allVersions } from '#src/versions/lib/all-versions.js'
import github from '#src/workflows/github.js'
import renderedContentLinkChecker from './rendered-content-link-checker'
import { getCoreInject, getUploadArtifactInject } from '@/links/scripts/action-injections.js'
import { allVersions } from '@/versions/lib/all-versions.js'
import github from '@/workflows/github.js'

const STATIC_PREFIXES = {
assets: path.resolve('assets'),
Expand Down Expand Up @@ -115,7 +115,7 @@ program
return resolvedPath
},
)
.arguments('[files...]', 'Specific files to check')
.arguments('[files...]')
.parse(process.argv)

const opts = program.opts()
Expand Down
Loading

0 comments on commit 17f99cc

Please sign in to comment.