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

Convert 6 JavaScript files to TypeScript (#57975)

This commit is contained in:
Kevin Heis
2025-10-15 12:20:32 -07:00
committed by GitHub
parent 7e4d07cce6
commit 97568cfa45
7 changed files with 137 additions and 55 deletions

View File

@@ -6,7 +6,7 @@ import { EOL } from 'os'
// Use platform-specific line endings for realistic tests when templates have
// been loaded from disk
const nl = (str) => str.replace(/\n/g, EOL)
const nl = (str: string): string => str.replace(/\n/g, EOL)
describe('renderContent', () => {
test('takes a template and a context and returns a string (async)', async () => {
@@ -44,7 +44,7 @@ describe('renderContent', () => {
const html = await renderContent(template)
const $ = cheerio.load(html, { xmlMode: true })
expect($('ul p').length, 0)
expect($('ul p').length).toBe(0)
})
test('renders text only', async () => {

View File

@@ -35,10 +35,35 @@ import { visit } from 'unist-util-visit'
import { h } from 'hastscript'
import { fromMarkdown } from 'mdast-util-from-markdown'
import { toHast } from 'mdast-util-to-hast'
import type { Root } from 'mdast'
import { header } from './code-header'
import findPage from '@/frame/lib/find-page'
const languages = yaml.load(fs.readFileSync('./data/code-languages.yml', 'utf8'))
interface LanguageConfig {
comment: 'number' | 'slash' | 'xml' | 'percent' | 'hyphen'
[key: string]: any
}
interface ElementNode {
type: 'element'
tagName: string
properties: {
className?: string[]
[key: string]: any
}
children: any[]
data?: {
meta?: {
annotate?: boolean
[key: string]: any
}
}
}
const languages = yaml.load(fs.readFileSync('./data/code-languages.yml', 'utf8')) as Record<
string,
LanguageConfig
>
const commentRegexes = {
// Also known has hash or sharp; but the unicode name is "number sign".
@@ -64,18 +89,25 @@ const commentRegexes = {
hyphen: /^\s*--\s*/,
}
const matcher = (node) =>
node.type === 'element' && node.tagName === 'pre' && getPreMeta(node).annotate
// Using 'any' for node because unist-util-visit requires broad type compatibility
const matcher = (node: any): node is ElementNode =>
node.type === 'element' && node.tagName === 'pre' && Boolean(getPreMeta(node).annotate)
export default function annotate(context) {
return (tree) => {
visit(tree, matcher, (node, index, parent) => {
parent.children[index] = createAnnotatedNode(node, context)
// Using 'any' for context because unified plugins receive different context types depending on processor configuration
export default function annotate(context: any) {
// Using 'any' for tree because unified's AST types are complex and vary between processors
return (tree: any) => {
// Using 'any' for parent because unist-util-visit's callback typing doesn't provide specific parent types
visit(tree, matcher, (node: ElementNode, index: number | undefined, parent: any) => {
if (index !== undefined && parent) {
parent.children[index] = createAnnotatedNode(node, context)
}
})
}
}
function createAnnotatedNode(node, context) {
// Using 'any' for context to match the plugin signature, and return type because hastscript returns complex hast types
function createAnnotatedNode(node: ElementNode, context: any): any {
const lang = node.children[0].properties.className[0].replace('language-', '')
const code = node.children[0].children[0].value
@@ -102,7 +134,7 @@ function createAnnotatedNode(node, context) {
return template({ lang, code, rows, context })
}
function validate(lang, code) {
function validate(lang: string, code: string): void {
if (!lang) {
throw new Error('No language specific for annotate info string.')
}
@@ -128,33 +160,34 @@ function validate(lang, code) {
}
}
function getRegexp(lang) {
function getRegexp(lang: string): RegExp {
return commentRegexes[languages[lang].comment]
}
function hasChar(line) {
function hasChar(line: string): boolean {
return Boolean(line.trim())
}
function chunkBy(arr, predicate) {
const groups = [[]]
function chunkBy(arr: string[], predicate: (item: string) => boolean): string[][] {
const groups: string[][] = [[]]
let on = predicate(arr[0])
for (const item of arr) {
if ((!on && predicate(item)) || (on && !predicate(item))) {
on = !on
groups.push([])
}
last(groups).push(item)
last(groups)!.push(item)
}
return groups
}
function matchComment(lang) {
function matchComment(lang: string): (line: string) => boolean {
const regex = getRegexp(lang)
return (line) => regex.test(line)
}
function getSubnav() {
// Using 'any' return type because hastscript's h() function returns complex hast element types
function getSubnav(): any {
const besideBtn = h(
'button',
{
@@ -179,7 +212,18 @@ function getSubnav() {
return h('div', { className: 'annotate-toggle' }, [besideBtn, inlineBtn])
}
function template({ lang, code, rows, context }) {
// Using 'any' for context and return type due to hastscript's complex type definitions
function template({
lang,
code,
rows,
context,
}: {
lang: string
code: string
rows: string[][][]
context: any
}): any {
return h(
'div',
{ class: 'annotate beside' },
@@ -210,20 +254,20 @@ function template({ lang, code, rows, context }) {
)
}
function mdToHast(text, context) {
const mdast = fromMarkdown(text)
// Using 'any' for context and return type to maintain compatibility with mdast-util-to-hast complex types
function mdToHast(text: string, context: any): any {
const mdast: Root = fromMarkdown(text)
// Process AUTOTITLE links if context is available
if (context) {
processAutotitleInMdast(mdast, context)
}
// Process AUTOTITLE links
processAutotitleInMdast(mdast, context)
return toHast(mdast)
}
// Helper method to process AUTOTITLE links in MDAST
// This can be reused for other MDAST processing that needs AUTOTITLE support
function processAutotitleInMdast(mdast, context) {
// Using 'any' for context because it may or may not have pages/redirects properties depending on usage
function processAutotitleInMdast(mdast: Root, context: any): void {
visit(mdast, 'link', (node) => {
if (node.url && node.url.startsWith('/')) {
for (const child of node.children) {
@@ -236,7 +280,10 @@ function processAutotitleInMdast(mdast, context) {
child.value = page.rawTitle || 'AUTOTITLE'
} catch (error) {
// Keep AUTOTITLE if we can't get the title
console.warn(`Could not resolve AUTOTITLE for ${node.url}:`, error.message)
console.warn(
`Could not resolve AUTOTITLE for ${node.url}:`,
error instanceof Error ? error.message : String(error),
)
}
}
}
@@ -245,12 +292,12 @@ function processAutotitleInMdast(mdast, context) {
})
}
function removeComment(lang) {
function removeComment(lang: string): (line: string) => string {
const regex = getRegexp(lang)
return (line) => line.replace(regex, '')
}
function getPreMeta(node) {
function getPreMeta(node: ElementNode): { annotate?: boolean; [key: string]: any } {
// Here's why this monstrosity works:
// https://github.com/syntax-tree/mdast-util-to-hast/blob/c87cd606731c88a27dbce4bfeaab913a9589bf83/lib/handlers/code.js#L40-L42
return node.children[0]?.data?.meta || {}