Skip to content

Commit ef059ac

Browse files
heiskrCopilot
andauthored
Remove no-explicit-any from annotate unified plugin (#61670)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent df6986d commit ef059ac

3 files changed

Lines changed: 45 additions & 30 deletions

File tree

eslint.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ export default [
235235
{
236236
files: [
237237
'src/article-api/transformers/rest-transformer.ts',
238-
'src/content-render/unified/annotate.ts',
239238
'src/frame/components/context/MainContext.tsx',
240239
'src/landings/components/CookBookFilter.tsx',
241240
'src/languages/lib/correct-translation-content.ts',

src/content-render/unified/annotate.ts

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,33 +32,53 @@ import yaml from 'js-yaml'
3232
import fs from 'fs'
3333
import { chunk, last } from 'lodash-es'
3434
import { visit } from 'unist-util-visit'
35+
import type { Test } from 'unist-util-visit'
36+
import type { Node, Parent } from 'unist'
37+
import type { Element, Nodes } from 'hast'
3538
import { h } from 'hastscript'
3639
import { fromMarkdown } from 'mdast-util-from-markdown'
3740
import { toHast } from 'mdast-util-to-hast'
3841
import type { Root } from 'mdast'
3942
import { header } from './code-header'
4043
import findPage from '@/frame/lib/find-page'
4144
import { createLogger } from '@/observability/logger'
45+
import type { Context } from '@/types'
4246

4347
const logger = createLogger(import.meta.url)
4448

4549
interface LanguageConfig {
4650
comment: 'number' | 'slash' | 'xml' | 'percent' | 'hyphen'
47-
[key: string]: any
51+
[key: string]: unknown
52+
}
53+
54+
interface HastNode {
55+
type?: string
56+
value?: string
57+
properties?: {
58+
className?: string[]
59+
[key: string]: unknown
60+
}
61+
children?: HastNode[]
62+
data?: {
63+
meta?: {
64+
annotate?: boolean
65+
[key: string]: unknown
66+
}
67+
}
4868
}
4969

5070
interface ElementNode {
5171
type: 'element'
5272
tagName: string
5373
properties: {
5474
className?: string[]
55-
[key: string]: any
75+
[key: string]: unknown
5676
}
57-
children: any[]
77+
children: HastNode[]
5878
data?: {
5979
meta?: {
6080
annotate?: boolean
61-
[key: string]: any
81+
[key: string]: unknown
6282
}
6383
}
6484
}
@@ -92,27 +112,27 @@ const commentRegexes = {
92112
hyphen: /^\s*--\s*/,
93113
}
94114

95-
// Using 'any' for node because unist-util-visit requires broad type compatibility
96-
const matcher = (node: any): node is ElementNode =>
97-
node.type === 'element' && node.tagName === 'pre' && Boolean(getPreMeta(node).annotate)
115+
const matcher = (node: Node): boolean =>
116+
node.type === 'element' &&
117+
(node as unknown as ElementNode).tagName === 'pre' &&
118+
Boolean(getPreMeta(node as unknown as ElementNode).annotate)
98119

99-
// Using 'any' for context because unified plugins receive different context types depending on processor configuration
100-
export default function annotate(context: any) {
101-
// Using 'any' for tree because unified's AST types are complex and vary between processors
102-
return (tree: any) => {
103-
// Using 'any' for parent because unist-util-visit's callback typing doesn't provide specific parent types
104-
visit(tree, matcher, (node: ElementNode, index: number | undefined, parent: any) => {
120+
export default function annotate(context: Context) {
121+
return (tree: Node) => {
122+
visit(tree, matcher as Test, (node, index, parent) => {
105123
if (index !== undefined && parent) {
106-
parent.children[index] = createAnnotatedNode(node, context)
124+
;(parent as Parent).children[index] = createAnnotatedNode(
125+
node as unknown as ElementNode,
126+
context,
127+
) as unknown as Node
107128
}
108129
})
109130
}
110131
}
111132

112-
// Using 'any' for context to match the plugin signature, and return type because hastscript returns complex hast types
113-
function createAnnotatedNode(node: ElementNode, context: any): any {
114-
const lang = node.children[0].properties.className[0].replace('language-', '')
115-
const code = node.children[0].children[0].value
133+
function createAnnotatedNode(node: ElementNode, context: Context): Element {
134+
const lang = node.children[0].properties!.className![0].replace('language-', '')
135+
const code = node.children[0].children![0].value as string
116136

117137
// Check the code is parse-able
118138
validate(lang, code)
@@ -189,8 +209,7 @@ function matchComment(lang: string): (line: string) => boolean {
189209
return (line) => regex.test(line)
190210
}
191211

192-
// Using 'any' return type because hastscript's h() function returns complex hast element types
193-
function getSubnav(): any {
212+
function getSubnav(): Element {
194213
const besideBtn = h(
195214
'button',
196215
{
@@ -215,7 +234,6 @@ function getSubnav(): any {
215234
return h('div', { className: 'annotate-toggle' }, [besideBtn, inlineBtn])
216235
}
217236

218-
// Using 'any' for context and return type due to hastscript's complex type definitions
219237
function template({
220238
lang,
221239
code,
@@ -225,8 +243,8 @@ function template({
225243
lang: string
226244
code: string
227245
rows: string[][][]
228-
context: any
229-
}): any {
246+
context: Context
247+
}): Element {
230248
return h(
231249
'div',
232250
{ class: 'annotate beside' },
@@ -257,8 +275,7 @@ function template({
257275
)
258276
}
259277

260-
// Using 'any' for context and return type to maintain compatibility with mdast-util-to-hast complex types
261-
function mdToHast(text: string, context: any): any {
278+
function mdToHast(text: string, context: Context): Nodes {
262279
const mdast: Root = fromMarkdown(text)
263280

264281
// Process AUTOTITLE links
@@ -269,8 +286,7 @@ function mdToHast(text: string, context: any): any {
269286

270287
// Helper method to process AUTOTITLE links in MDAST
271288
// This can be reused for other MDAST processing that needs AUTOTITLE support
272-
// Using 'any' for context because it may or may not have pages/redirects properties depending on usage
273-
function processAutotitleInMdast(mdast: Root, context: any): void {
289+
function processAutotitleInMdast(mdast: Root, context: Context): void {
274290
visit(mdast, 'link', (node) => {
275291
if (node.url && node.url.startsWith('/')) {
276292
for (const child of node.children) {
@@ -300,7 +316,7 @@ function removeComment(lang: string): (line: string) => string {
300316
return (line) => line.replace(regex, '')
301317
}
302318

303-
function getPreMeta(node: ElementNode): { annotate?: boolean; [key: string]: any } {
319+
function getPreMeta(node: ElementNode): { annotate?: boolean; [key: string]: unknown } {
304320
// Here's why this monstrosity works:
305321
// https://github.com/syntax-tree/mdast-util-to-hast/blob/c87cd606731c88a27dbce4bfeaab913a9589bf83/lib/handlers/code.js#L40-L42
306322
return node.children[0]?.data?.meta || {}

src/content-render/unified/processor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function createProcessor(context: Context): UnifiedProcessor {
5454
.use(useEnglishHeadings as unknown as (ctx: Context) => void, context || {})
5555
.use(headingLinks)
5656
.use(codeHeader)
57-
.use(annotate, context)
57+
.use(annotate as unknown as (ctx: Context) => void, context)
5858
// Using type assertion for highlight plugin due to complex type mismatch between unified and rehype-highlight
5959
.use(highlight as unknown as (options: unknown) => void, {
6060
languages: { ...common, graphql, dockerfile, http, groovy, erb, powershell },

0 commit comments

Comments
 (0)