Skip to content

Commit a79730e

Browse files
authored
Migrate 10 JavaScript files to TypeScript (#57971)
1 parent 0cf4aab commit a79730e

File tree

10 files changed

+238
-112
lines changed

10 files changed

+238
-112
lines changed

src/content-linter/lib/linting-rules/frontmatter-validation.js renamed to src/content-linter/lib/linting-rules/frontmatter-validation.ts

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
1+
// @ts-ignore - no types available for markdownlint-rule-helpers
12
import { addError } from 'markdownlint-rule-helpers'
23
import { getFrontmatter } from '@/content-linter/lib/helpers/utils'
34

5+
import type { RuleParams, RuleErrorCallback } from '@/content-linter/types'
6+
7+
interface PropertyLimits {
8+
max: number
9+
recommended: number
10+
required?: boolean
11+
}
12+
13+
interface ContentRules {
14+
title: PropertyLimits
15+
shortTitle: PropertyLimits
16+
intro: PropertyLimits
17+
requiredProperties: string[]
18+
}
19+
20+
type ContentType = 'category' | 'mapTopic' | 'article' | null
21+
422
// Strip liquid tags from text for character counting purposes
5-
function stripLiquidTags(text) {
6-
if (typeof text !== 'string') return text
23+
function stripLiquidTags(text: unknown): string {
24+
if (typeof text !== 'string') return text as string
725
// Remove both {% %} and {{ }} liquid tags
826
return text.replace(/\{%.*?%\}/g, '').replace(/\{\{.*?\}\}/g, '')
927
}
@@ -13,15 +31,15 @@ export const frontmatterValidation = {
1331
description:
1432
'Frontmatter properties must meet character limits and required property requirements',
1533
tags: ['frontmatter', 'character-limits', 'required-properties'],
16-
function: (params, onError) => {
17-
const fm = getFrontmatter(params.lines)
34+
function: (params: RuleParams, onError: RuleErrorCallback) => {
35+
const fm = getFrontmatter(params.lines as string[])
1836
if (!fm) return
1937

2038
// Detect content type based on frontmatter properties and file path
2139
const contentType = detectContentType(fm, params.name)
2240

2341
// Define character limits and requirements for different content types
24-
const contentRules = {
42+
const contentRules: Record<string, ContentRules> = {
2543
category: {
2644
title: { max: 70, recommended: 67 },
2745
shortTitle: { max: 30, recommended: 27 },
@@ -42,7 +60,7 @@ export const frontmatterValidation = {
4260
},
4361
}
4462

45-
const rules = contentRules[contentType]
63+
const rules = contentType ? contentRules[contentType] : null
4664
if (!rules) return
4765

4866
// Check required properties
@@ -61,14 +79,21 @@ export const frontmatterValidation = {
6179

6280
// Check title length
6381
if (fm.title) {
64-
validatePropertyLength(onError, params.lines, 'title', fm.title, rules.title, 'Title')
82+
validatePropertyLength(
83+
onError,
84+
params.lines as string[],
85+
'title',
86+
fm.title,
87+
rules.title,
88+
'Title',
89+
)
6590
}
6691

6792
// Check shortTitle length
6893
if (fm.shortTitle) {
6994
validatePropertyLength(
7095
onError,
71-
params.lines,
96+
params.lines as string[],
7297
'shortTitle',
7398
fm.shortTitle,
7499
rules.shortTitle,
@@ -78,17 +103,24 @@ export const frontmatterValidation = {
78103

79104
// Check intro length if it exists
80105
if (fm.intro && rules.intro) {
81-
validatePropertyLength(onError, params.lines, 'intro', fm.intro, rules.intro, 'Intro')
106+
validatePropertyLength(
107+
onError,
108+
params.lines as string[],
109+
'intro',
110+
fm.intro,
111+
rules.intro,
112+
'Intro',
113+
)
82114
}
83115

84116
// Cross-property validation: if title is longer than shortTitle limit, shortTitle must exist
85117
const strippedTitle = stripLiquidTags(fm.title)
86-
if (fm.title && strippedTitle.length > rules.shortTitle.max && !fm.shortTitle) {
87-
const titleLine = findPropertyLine(params.lines, 'title')
118+
if (fm.title && (strippedTitle as string).length > rules.shortTitle.max && !fm.shortTitle) {
119+
const titleLine = findPropertyLine(params.lines as string[], 'title')
88120
addError(
89121
onError,
90122
titleLine,
91-
`Title is ${strippedTitle.length} characters, which exceeds the shortTitle limit of ${rules.shortTitle.max} characters. A shortTitle must be provided.`,
123+
`Title is ${(strippedTitle as string).length} characters, which exceeds the shortTitle limit of ${rules.shortTitle.max} characters. A shortTitle must be provided.`,
92124
fm.title,
93125
null,
94126
null,
@@ -98,10 +130,10 @@ export const frontmatterValidation = {
98130
// Special validation for articles: should have at least one topic
99131
if (contentType === 'article' && fm.topics) {
100132
if (!Array.isArray(fm.topics)) {
101-
const topicsLine = findPropertyLine(params.lines, 'topics')
133+
const topicsLine = findPropertyLine(params.lines as string[], 'topics')
102134
addError(onError, topicsLine, 'Topics must be an array', String(fm.topics), null, null)
103135
} else if (fm.topics.length === 0) {
104-
const topicsLine = findPropertyLine(params.lines, 'topics')
136+
const topicsLine = findPropertyLine(params.lines as string[], 'topics')
105137
addError(
106138
onError,
107139
topicsLine,
@@ -115,9 +147,16 @@ export const frontmatterValidation = {
115147
},
116148
}
117149

118-
function validatePropertyLength(onError, lines, propertyName, propertyValue, limits, displayName) {
150+
function validatePropertyLength(
151+
onError: RuleErrorCallback,
152+
lines: string[],
153+
propertyName: string,
154+
propertyValue: string,
155+
limits: PropertyLimits,
156+
displayName: string,
157+
): void {
119158
const strippedValue = stripLiquidTags(propertyValue)
120-
const propertyLength = strippedValue.length
159+
const propertyLength = (strippedValue as string).length
121160
const propertyLine = findPropertyLine(lines, propertyName)
122161

123162
// Only report the most severe error - maximum takes precedence over recommended
@@ -142,7 +181,8 @@ function validatePropertyLength(onError, lines, propertyName, propertyValue, lim
142181
}
143182
}
144183

145-
function detectContentType(frontmatter, filePath) {
184+
// frontmatter object structure varies based on YAML content, using any for flexibility
185+
function detectContentType(frontmatter: any, filePath: string): ContentType {
146186
// Only apply validation to markdown files
147187
if (!filePath || !filePath.endsWith('.md')) {
148188
return null
@@ -168,7 +208,7 @@ function detectContentType(frontmatter, filePath) {
168208
return 'article'
169209
}
170210

171-
function findPropertyLine(lines, property) {
211+
function findPropertyLine(lines: string[], property: string): number {
172212
const line = lines.find((line) => line.trim().startsWith(`${property}:`))
173213
return line ? lines.indexOf(line) + 1 : 1
174214
}

src/content-linter/scripts/pretty-print-results.js renamed to src/content-linter/scripts/pretty-print-results.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
11
import chalk from 'chalk'
22

3-
function isNumber(value) {
3+
interface LintResult {
4+
ruleDescription: string
5+
ruleNames: string[]
6+
lineNumber: number
7+
columnNumber?: number
8+
severity: string
9+
errorDetail?: string
10+
errorContext?: string
11+
context?: string
12+
fixable?: boolean
13+
}
14+
15+
type LintResults = Record<string, LintResult[]>
16+
17+
function isNumber(value: unknown): value is number {
418
return typeof value === 'number' && !isNaN(value)
519
}
620

7-
function shorten(text, length = 70) {
21+
function shorten(text: string, length = 70): string {
822
if (text.length <= length) return text
923
return `${text.slice(0, length - 3)}…`
1024
}
1125

12-
export function prettyPrintResults(results, { fixed = false } = {}) {
26+
export function prettyPrintResults(
27+
results: LintResults,
28+
{ fixed = false }: { fixed?: boolean } = {},
29+
): void {
1330
const PREFIX_PADDING = ' '.repeat(4)
1431
const columnPadding = 'Description'.length // The longest column header word
1532

16-
function label(text, padding = columnPadding) {
33+
function label(text: string, padding = columnPadding): string {
1734
if (padding < text.length) throw new Error('Padding must be greater than text length')
1835
return `${PREFIX_PADDING}${chalk.dim(text.padEnd(padding))}`
1936
}
@@ -114,7 +131,8 @@ export function prettyPrintResults(results, { fixed = false } = {}) {
114131
}
115132
}
116133

117-
function chalkFunColors(text) {
134+
function chalkFunColors(text: string): string {
135+
// Valid chalk color method names for terminal output
118136
const colors = [
119137
'red',
120138
'yellow',
@@ -126,19 +144,21 @@ function chalkFunColors(text) {
126144
'greenBright',
127145
'magentaBright',
128146
'cyanBright',
129-
].sort(() => Math.random() - 0.5)
147+
] as const
148+
const shuffledColors = [...colors].sort(() => Math.random() - 0.5)
130149
let colorIndex = 0
131150
return text
132151
.split('')
133152
.map((char) => {
134-
const color = colors[colorIndex]
135-
colorIndex = (colorIndex + 1) % colors.length
136-
return chalk[color](char)
153+
const color = shuffledColors[colorIndex]
154+
colorIndex = (colorIndex + 1) % shuffledColors.length
155+
// Chalk's TypeScript types don't support dynamic property access, but these are valid color methods
156+
return (chalk as any)[color](char)
137157
})
138158
.join('')
139159
}
140160

141-
function indentWrappedString(str, startingIndent) {
161+
function indentWrappedString(str: string, startingIndent: number): string {
142162
const NEW_LINE_PADDING = ' '.repeat(16)
143163
const width = process.stdout.columns || 80 // Use terminal width, default to 80 if not available
144164
let indentedString = ''

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest'
22
import cheerio from 'cheerio'
33

44
import { renderContent } from '@/content-render/index'
5+
import type { Context } from '@/types'
56

67
const example = `
78
\`\`\`yaml annotate
@@ -131,7 +132,7 @@ on: [push]
131132
`
132133

133134
// Create a mock context with pages for AUTOTITLE resolution
134-
const mockPages = {
135+
const mockPages: Record<string, { href: string; rawTitle: string }> = {
135136
'/get-started/start-your-journey/hello-world': {
136137
href: '/get-started/start-your-journey/hello-world',
137138
rawTitle: 'Hello World',
@@ -147,7 +148,8 @@ on: [push]
147148
currentVersion: 'free-pro-team@latest',
148149
pages: mockPages,
149150
redirects: {},
150-
}
151+
// Mock test object doesn't need all Context properties, using 'as unknown as' to bypass strict type checking
152+
} as unknown as Context
151153

152154
const res = await renderContent(example, mockContext)
153155
const $ = cheerio.load(res)

0 commit comments

Comments
 (0)