Skip to content

Commit 97568cf

Browse files
authored
Convert 6 JavaScript files to TypeScript (#57975)
1 parent 7e4d07c commit 97568cf

File tree

7 files changed

+137
-55
lines changed

7 files changed

+137
-55
lines changed

src/content-linter/lib/linting-rules/code-annotation-comment-spacing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const codeAnnotationCommentSpacing = {
88
description:
99
'Code comments in annotation blocks must have exactly one space after the comment character(s)',
1010
tags: ['code', 'comments', 'annotate', 'spacing'],
11-
parser: 'markdownit',
11+
parser: 'markdownit' as const,
1212
function: (params: RuleParams, onError: RuleErrorCallback) => {
1313
filterTokens(params, 'fence', (token: MarkdownToken) => {
1414
if (!token.info?.includes('annotate')) return

src/content-linter/tests/unit/liquid-ifversion-versions.js renamed to src/content-linter/tests/unit/liquid-ifversion-versions.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@ import { validateIfversionConditionalsVersions } from '../../lib/linting-rules/l
55
import { liquidIfversionVersions } from '../../lib/linting-rules/liquid-ifversion-versions'
66
import { supported } from '@/versions/lib/enterprise-server-releases'
77

8+
type FeatureVersions = {
9+
versions: {
10+
[key: string]: string
11+
}
12+
}
13+
14+
type AllFeatures = Record<string, FeatureVersions>
15+
816
describe(liquidIfversionVersions.names.join(' - '), () => {
9-
const envVarValueBefore = process.env.ROOT
17+
const envVarValueBefore: string | undefined = process.env.ROOT
1018

1119
beforeAll(() => {
1220
process.env.ROOT = 'src/fixtures/fixtures'
@@ -136,13 +144,13 @@ describe(liquidIfversionVersions.names.join(' - '), () => {
136144
describe.skip('test validateIfversionConditionalsVersions function', () => {
137145
test('most basic example without feature', () => {
138146
const condition = 'ghes or ghec or fpt'
139-
const allFeatures = {}
147+
const allFeatures: AllFeatures = {}
140148
const errors = validateIfversionConditionalsVersions(condition, allFeatures)
141149
expect(errors.length).toBe(1)
142150
})
143151
test('most basic example with feature', () => {
144152
const condition = 'some-feature'
145-
const allFeatures = {
153+
const allFeatures: AllFeatures = {
146154
'some-feature': {
147155
versions: {
148156
ghec: '*',
@@ -156,19 +164,19 @@ describe.skip('test validateIfversionConditionalsVersions function', () => {
156164
})
157165
test("any 'and' always yields no errors", () => {
158166
const condition = 'ghes and ghec or fpt'
159-
const allFeatures = {}
167+
const allFeatures: AllFeatures = {}
160168
const errors = validateIfversionConditionalsVersions(condition, allFeatures)
161169
expect(errors.length).toBe(0)
162170
})
163171
test("any 'not' always yields no errors", () => {
164172
const condition = 'ghes or ghec or not fpt'
165-
const allFeatures = {}
173+
const allFeatures: AllFeatures = {}
166174
const errors = validateIfversionConditionalsVersions(condition, allFeatures)
167175
expect(errors.length).toBe(0)
168176
})
169177
test('combined with feature it is all versions', () => {
170178
const condition = 'ghec or fpt or some-feature'
171-
const allFeatures = {
179+
const allFeatures: AllFeatures = {
172180
'some-feature': {
173181
versions: {
174182
ghes: `>=${supported.at(-1)}`,
@@ -180,8 +188,8 @@ describe.skip('test validateIfversionConditionalsVersions function', () => {
180188
})
181189
test('less or equal than a future version', () => {
182190
const condition = 'ghec or fpt or some-feature'
183-
const latestToday = parseFloat(supported.at(-1))
184-
const allFeatures = {
191+
const latestToday = parseFloat(supported.at(-1)!)
192+
const allFeatures: AllFeatures = {
185193
'some-feature': {
186194
versions: {
187195
ghes: `<=${latestToday + 0.1}`,
@@ -193,8 +201,8 @@ describe.skip('test validateIfversionConditionalsVersions function', () => {
193201
})
194202
test('less than a future version', () => {
195203
const condition = 'ghec or fpt or some-feature'
196-
const latestToday = parseFloat(supported.at(-1))
197-
const allFeatures = {
204+
const latestToday = parseFloat(supported.at(-1)!)
205+
const allFeatures: AllFeatures = {
198206
'some-feature': {
199207
versions: {
200208
ghes: `<${latestToday + 0.1}`,
@@ -206,7 +214,7 @@ describe.skip('test validateIfversionConditionalsVersions function', () => {
206214
})
207215
test('combined with feature it is eventually all versions (1)', () => {
208216
const condition = `ghec or fpt or ghes >${supported.at(-1)} or some-feature`
209-
const allFeatures = {
217+
const allFeatures: AllFeatures = {
210218
'some-feature': {
211219
versions: {
212220
ghes: `>=${supported.at(-1)}`,
@@ -218,7 +226,7 @@ describe.skip('test validateIfversionConditionalsVersions function', () => {
218226
})
219227
test('combined with feature it is eventually all versions (2)', () => {
220228
const condition = `ghec or fpt or ghes >=${supported.at(-1)} or some-feature`
221-
const allFeatures = {
229+
const allFeatures: AllFeatures = {
222230
'some-feature': {
223231
versions: {
224232
ghes: `>${supported.at(-1)}`,

src/content-render/tests/render-content.js renamed to src/content-render/tests/render-content.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { EOL } from 'os'
66

77
// Use platform-specific line endings for realistic tests when templates have
88
// been loaded from disk
9-
const nl = (str) => str.replace(/\n/g, EOL)
9+
const nl = (str: string): string => str.replace(/\n/g, EOL)
1010

1111
describe('renderContent', () => {
1212
test('takes a template and a context and returns a string (async)', async () => {
@@ -44,7 +44,7 @@ describe('renderContent', () => {
4444

4545
const html = await renderContent(template)
4646
const $ = cheerio.load(html, { xmlMode: true })
47-
expect($('ul p').length, 0)
47+
expect($('ul p').length).toBe(0)
4848
})
4949

5050
test('renders text only', async () => {

src/content-render/unified/annotate.js renamed to src/content-render/unified/annotate.ts

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,35 @@ import { visit } from 'unist-util-visit'
3535
import { h } from 'hastscript'
3636
import { fromMarkdown } from 'mdast-util-from-markdown'
3737
import { toHast } from 'mdast-util-to-hast'
38+
import type { Root } from 'mdast'
3839
import { header } from './code-header'
3940
import findPage from '@/frame/lib/find-page'
4041

41-
const languages = yaml.load(fs.readFileSync('./data/code-languages.yml', 'utf8'))
42+
interface LanguageConfig {
43+
comment: 'number' | 'slash' | 'xml' | 'percent' | 'hyphen'
44+
[key: string]: any
45+
}
46+
47+
interface ElementNode {
48+
type: 'element'
49+
tagName: string
50+
properties: {
51+
className?: string[]
52+
[key: string]: any
53+
}
54+
children: any[]
55+
data?: {
56+
meta?: {
57+
annotate?: boolean
58+
[key: string]: any
59+
}
60+
}
61+
}
62+
63+
const languages = yaml.load(fs.readFileSync('./data/code-languages.yml', 'utf8')) as Record<
64+
string,
65+
LanguageConfig
66+
>
4267

4368
const commentRegexes = {
4469
// Also known has hash or sharp; but the unicode name is "number sign".
@@ -64,18 +89,25 @@ const commentRegexes = {
6489
hyphen: /^\s*--\s*/,
6590
}
6691

67-
const matcher = (node) =>
68-
node.type === 'element' && node.tagName === 'pre' && getPreMeta(node).annotate
92+
// Using 'any' for node because unist-util-visit requires broad type compatibility
93+
const matcher = (node: any): node is ElementNode =>
94+
node.type === 'element' && node.tagName === 'pre' && Boolean(getPreMeta(node).annotate)
6995

70-
export default function annotate(context) {
71-
return (tree) => {
72-
visit(tree, matcher, (node, index, parent) => {
73-
parent.children[index] = createAnnotatedNode(node, context)
96+
// Using 'any' for context because unified plugins receive different context types depending on processor configuration
97+
export default function annotate(context: any) {
98+
// Using 'any' for tree because unified's AST types are complex and vary between processors
99+
return (tree: any) => {
100+
// Using 'any' for parent because unist-util-visit's callback typing doesn't provide specific parent types
101+
visit(tree, matcher, (node: ElementNode, index: number | undefined, parent: any) => {
102+
if (index !== undefined && parent) {
103+
parent.children[index] = createAnnotatedNode(node, context)
104+
}
74105
})
75106
}
76107
}
77108

78-
function createAnnotatedNode(node, context) {
109+
// Using 'any' for context to match the plugin signature, and return type because hastscript returns complex hast types
110+
function createAnnotatedNode(node: ElementNode, context: any): any {
79111
const lang = node.children[0].properties.className[0].replace('language-', '')
80112
const code = node.children[0].children[0].value
81113

@@ -102,7 +134,7 @@ function createAnnotatedNode(node, context) {
102134
return template({ lang, code, rows, context })
103135
}
104136

105-
function validate(lang, code) {
137+
function validate(lang: string, code: string): void {
106138
if (!lang) {
107139
throw new Error('No language specific for annotate info string.')
108140
}
@@ -128,33 +160,34 @@ function validate(lang, code) {
128160
}
129161
}
130162

131-
function getRegexp(lang) {
163+
function getRegexp(lang: string): RegExp {
132164
return commentRegexes[languages[lang].comment]
133165
}
134166

135-
function hasChar(line) {
167+
function hasChar(line: string): boolean {
136168
return Boolean(line.trim())
137169
}
138170

139-
function chunkBy(arr, predicate) {
140-
const groups = [[]]
171+
function chunkBy(arr: string[], predicate: (item: string) => boolean): string[][] {
172+
const groups: string[][] = [[]]
141173
let on = predicate(arr[0])
142174
for (const item of arr) {
143175
if ((!on && predicate(item)) || (on && !predicate(item))) {
144176
on = !on
145177
groups.push([])
146178
}
147-
last(groups).push(item)
179+
last(groups)!.push(item)
148180
}
149181
return groups
150182
}
151183

152-
function matchComment(lang) {
184+
function matchComment(lang: string): (line: string) => boolean {
153185
const regex = getRegexp(lang)
154186
return (line) => regex.test(line)
155187
}
156188

157-
function getSubnav() {
189+
// Using 'any' return type because hastscript's h() function returns complex hast element types
190+
function getSubnav(): any {
158191
const besideBtn = h(
159192
'button',
160193
{
@@ -179,7 +212,18 @@ function getSubnav() {
179212
return h('div', { className: 'annotate-toggle' }, [besideBtn, inlineBtn])
180213
}
181214

182-
function template({ lang, code, rows, context }) {
215+
// Using 'any' for context and return type due to hastscript's complex type definitions
216+
function template({
217+
lang,
218+
code,
219+
rows,
220+
context,
221+
}: {
222+
lang: string
223+
code: string
224+
rows: string[][][]
225+
context: any
226+
}): any {
183227
return h(
184228
'div',
185229
{ class: 'annotate beside' },
@@ -210,20 +254,20 @@ function template({ lang, code, rows, context }) {
210254
)
211255
}
212256

213-
function mdToHast(text, context) {
214-
const mdast = fromMarkdown(text)
257+
// Using 'any' for context and return type to maintain compatibility with mdast-util-to-hast complex types
258+
function mdToHast(text: string, context: any): any {
259+
const mdast: Root = fromMarkdown(text)
215260

216-
// Process AUTOTITLE links if context is available
217-
if (context) {
218-
processAutotitleInMdast(mdast, context)
219-
}
261+
// Process AUTOTITLE links
262+
processAutotitleInMdast(mdast, context)
220263

221264
return toHast(mdast)
222265
}
223266

224267
// Helper method to process AUTOTITLE links in MDAST
225268
// This can be reused for other MDAST processing that needs AUTOTITLE support
226-
function processAutotitleInMdast(mdast, context) {
269+
// Using 'any' for context because it may or may not have pages/redirects properties depending on usage
270+
function processAutotitleInMdast(mdast: Root, context: any): void {
227271
visit(mdast, 'link', (node) => {
228272
if (node.url && node.url.startsWith('/')) {
229273
for (const child of node.children) {
@@ -236,7 +280,10 @@ function processAutotitleInMdast(mdast, context) {
236280
child.value = page.rawTitle || 'AUTOTITLE'
237281
} catch (error) {
238282
// Keep AUTOTITLE if we can't get the title
239-
console.warn(`Could not resolve AUTOTITLE for ${node.url}:`, error.message)
283+
console.warn(
284+
`Could not resolve AUTOTITLE for ${node.url}:`,
285+
error instanceof Error ? error.message : String(error),
286+
)
240287
}
241288
}
242289
}
@@ -245,12 +292,12 @@ function processAutotitleInMdast(mdast, context) {
245292
})
246293
}
247294

248-
function removeComment(lang) {
295+
function removeComment(lang: string): (line: string) => string {
249296
const regex = getRegexp(lang)
250297
return (line) => line.replace(regex, '')
251298
}
252299

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

0 commit comments

Comments
 (0)