Skip to content

Commit 7beb9fc

Browse files
committed
Address new TypeScript warnings in core files, improve type definitions.
1 parent bd02390 commit 7beb9fc

32 files changed

+354
-170
lines changed

eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export default [
5454
"multiline-comment-style": [ "error", "separate-lines" ],
5555
"no-empty-function": "off",
5656
"no-implicit-coercion": "off",
57+
"no-inline-comments": [ "error", { "ignorePattern": " @type \\{.+\\} " } ],
5758
"no-magic-numbers": "off",
5859
"no-param-reassign": "off",
5960
"no-plusplus": "off",

example/typescript/type-check.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function assertLintResults(results: LintResults) {
3030
assert.equal(results["string"][0].lineNumber, 1);
3131
assert.deepEqual(results["string"][0].ruleNames, [ "MD047", "single-trailing-newline" ]);
3232
assert.equal(results["string"][0].ruleDescription, "Files should end with a single newline character");
33-
assert.equal(results["string"][0].ruleInformation.replace(/v\d+\.\d+\.\d+/, "v0.0.0"), "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md047.md");
33+
assert.equal(results["string"][0].ruleInformation?.replace(/v\d+\.\d+\.\d+/, "v0.0.0"), "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md047.md");
3434
assert.equal(results["string"][0].errorDetail, null);
3535
assert.equal(results["string"][0].errorContext, null);
3636
assert.deepEqual(results["string"][0].errorRange, [ 9, 1 ]);

helpers/helpers.cjs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,11 @@ module.exports.cloneIfArray = cloneIfArray;
111111
/**
112112
* Clones the input if it is a URL.
113113
*
114-
* @param {Object} url Object of unknown type.
114+
* @param {Object | undefined} url Object of unknown type.
115115
* @returns {Object} Clone of obj iff obj is a URL.
116116
*/
117117
function cloneIfUrl(url) {
118+
// @ts-ignore
118119
return isUrl(url) ? new URL(url) : url;
119120
}
120121
module.exports.cloneIfUrl = cloneIfUrl;
@@ -139,7 +140,7 @@ module.exports.getHtmlAttributeRe = function getHtmlAttributeRe(name) {
139140
function isBlankLine(line) {
140141
const startComment = "<!--";
141142
const endComment = "-->";
142-
const removeComments = (s) => {
143+
const removeComments = (/** @type {string} */ s) => {
143144
while (true) {
144145
const start = s.indexOf(startComment);
145146
const end = s.indexOf(endComment);
@@ -177,8 +178,8 @@ const startsWithPipeRe = /^ *\|/;
177178
const notCrLfRe = /[^\r\n]/g;
178179
const notSpaceCrLfRe = /[^ \r\n]/g;
179180
const trailingSpaceRe = / +[\r\n]/g;
180-
const replaceTrailingSpace = (s) => s.replace(notCrLfRe, safeCommentCharacter);
181-
module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
181+
const replaceTrailingSpace = (/** @type {string} */ s) => s.replace(notCrLfRe, safeCommentCharacter);
182+
module.exports.clearHtmlCommentText = function clearHtmlCommentText(/** @type {string} */ text) {
182183
let i = 0;
183184
while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
184185
const j = text.indexOf(htmlCommentEnd, i + 2);
@@ -220,7 +221,7 @@ module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
220221
};
221222

222223
// Escapes a string for use in a RegExp
223-
module.exports.escapeForRegExp = function escapeForRegExp(str) {
224+
module.exports.escapeForRegExp = function escapeForRegExp(/** @type {string} */ str) {
224225
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
225226
};
226227

@@ -355,7 +356,7 @@ module.exports.hasOverlap = function hasOverlap(rangeA, rangeB) {
355356

356357
// Determines if the front matter includes a title
357358
module.exports.frontMatterHasTitle =
358-
function frontMatterHasTitle(frontMatterLines, frontMatterTitlePattern) {
359+
function frontMatterHasTitle(/** @type {readonly string[]} */ frontMatterLines, /** @type {string} */ frontMatterTitlePattern) {
359360
const ignoreFrontMatter =
360361
(frontMatterTitlePattern !== undefined) && !frontMatterTitlePattern;
361362
const frontMatterTitleRe =
@@ -367,18 +368,31 @@ module.exports.frontMatterHasTitle =
367368
frontMatterLines.some((line) => frontMatterTitleRe.test(line));
368369
};
369370

371+
/**
372+
* Result object for getReferenceLinkImageData.
373+
*
374+
* @typedef {Object} GetReferenceLinkImageDataResult
375+
* @property {Map<string, number[][]>} references References.
376+
* @property {Map<string, number[][]>} shortcuts Shortcuts.
377+
* @property {Map<string, [number, string]>} definitions Definitions.
378+
* @property {[string, number][]} duplicateDefinitions Duplicate definitions.
379+
* @property {number[]} definitionLineIndices Definition line indices.
380+
*/
381+
370382
/**
371383
* Returns an object with information about reference links and images.
372384
*
373385
* @param {MicromarkToken[]} tokens Micromark tokens.
374-
* @returns {Object} Reference link/image data.
386+
* @returns {GetReferenceLinkImageDataResult} Reference link/image data.
375387
*/
376388
function getReferenceLinkImageData(tokens) {
377-
const normalizeReference = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
378-
const getText = (t) => t?.children.filter((c) => c.type !== "blockQuotePrefix").map((c) => c.text).join("");
389+
const normalizeReference = (/** @type {string} */ s) => s.toLowerCase().trim().replace(/\s+/g, " ");
390+
const getText = (/** @type {MicromarkToken} */ t) => t?.children.filter((c) => c.type !== "blockQuotePrefix").map((c) => c.text).join("");
391+
/** @type {Map<string, number[][]>} */
379392
const references = new Map();
393+
/** @type {Map<string, number[][]>} */
380394
const shortcuts = new Map();
381-
const addReferenceToDictionary = (token, label, isShortcut) => {
395+
const addReferenceToDictionary = (/** @type {MicromarkToken} */ token, /** @type {string} */ label, /** @type {boolean} */ isShortcut) => {
382396
const referenceDatum = [
383397
token.startLine - 1,
384398
token.startColumn - 1,
@@ -390,8 +404,11 @@ function getReferenceLinkImageData(tokens) {
390404
referenceData.push(referenceDatum);
391405
dictionary.set(reference, referenceData);
392406
};
407+
/** @type {Map<string, [number, string]>} */
393408
const definitions = new Map();
409+
/** @type {number[]} */
394410
const definitionLineIndices = [];
411+
/** @type {[string, number][]} */
395412
const duplicateDefinitions = [];
396413
const filteredTokens =
397414
micromark.filterByTypes(
@@ -433,7 +450,7 @@ function getReferenceLinkImageData(tokens) {
433450
micromark.getDescendantsByType(parent, [ "definitionDestination", "definitionDestinationRaw", "definitionDestinationString" ])[0]?.text;
434451
definitions.set(
435452
reference,
436-
[ token.startLine - 1, destinationString ]
453+
[ token.startLine - 1, destinationString || "" ]
437454
);
438455
}
439456
}
@@ -490,7 +507,7 @@ module.exports.getReferenceLinkImageData = getReferenceLinkImageData;
490507
* Gets the most common line ending, falling back to the platform default.
491508
*
492509
* @param {string} input Markdown content to analyze.
493-
* @param {Object} [os] Node.js "os" module.
510+
* @param {{EOL: string}} [os] Node.js "os" module.
494511
* @returns {string} Preferred line ending.
495512
*/
496513
function getPreferredLineEnding(input, os) {
@@ -530,7 +547,7 @@ module.exports.getPreferredLineEnding = getPreferredLineEnding;
530547
* Expands a path with a tilde to an absolute path.
531548
*
532549
* @param {string} file Path that may begin with a tilde.
533-
* @param {Object} os Node.js "os" module.
550+
* @param {{homedir: () => string}} os Node.js "os" module.
534551
* @returns {string} Absolute path (or original path).
535552
*/
536553
function expandTildePath(file, os) {
@@ -591,6 +608,7 @@ function convertLintErrorsVersion2To1(errors) {
591608
* @returns {LintErrors} Lint errors (v0).
592609
*/
593610
function convertLintErrorsVersion2To0(errors) {
611+
/** @type {Object.<string, number[]>} */
594612
const dictionary = {};
595613
for (const error of errors) {
596614
const ruleName = error.ruleNames[0];
@@ -606,10 +624,11 @@ function convertLintErrorsVersion2To0(errors) {
606624
* Copies and transforms lint results from resultVersion 3 to ?.
607625
*
608626
* @param {LintResults} results Lint results (v3).
609-
* @param {(LintErrors) => LintErrors} transform Lint errors (v?).
627+
* @param {(errors: LintErrors) => LintErrors} transform Lint errors (v?).
610628
* @returns {LintResults} Lint results (v?).
611629
*/
612630
function copyAndTransformResults(results, transform) {
631+
/** @type {Object.<string, LintErrors>} */
613632
const newResults = {};
614633
Object.defineProperty(newResults, "toString", { "value": results.toString });
615634
for (const key of Object.keys(results)) {

helpers/micromark-helpers.cjs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const { flatTokensSymbol, htmlFlowSymbol, newLineRe } = require("./shared.cjs");
1717
* @returns {boolean} True iff the token is within an htmlFlow type.
1818
*/
1919
function inHtmlFlow(token) {
20+
// @ts-ignore
2021
return Boolean(token[htmlFlowSymbol]);
2122
}
2223

@@ -126,8 +127,11 @@ function filterByPredicate(tokens, allowed, transformChildren) {
126127
* @returns {Token[]} Filtered tokens.
127128
*/
128129
function filterByTypes(tokens, types, htmlFlow) {
129-
const predicate = (token) => types.includes(token.type) && (htmlFlow || !inHtmlFlow(token));
130-
const flatTokens = tokens[flatTokensSymbol];
130+
const predicate = (/** @type {Token} */ token) => types.includes(token.type) && (htmlFlow || !inHtmlFlow(token));
131+
/** @type {Token[]} */
132+
const flatTokens =
133+
// @ts-ignore
134+
tokens[flatTokensSymbol];
131135
if (flatTokens) {
132136
return flatTokens.filter(predicate);
133137
}
@@ -163,7 +167,7 @@ function getBlockQuotePrefixText(tokens, lineNumber, count = 1) {
163167
function getDescendantsByType(parent, typePath) {
164168
let tokens = Array.isArray(parent) ? parent : [ parent ];
165169
for (const type of typePath) {
166-
const predicate = (token) => Array.isArray(type) ? type.includes(token.type) : (type === token.type);
170+
const predicate = (/** @type {Token} */ token) => Array.isArray(type) ? type.includes(token.type) : (type === token.type);
167171
tokens = tokens.flatMap((t) => t.children.filter(predicate));
168172
}
169173
return tokens;

lib/cache.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { filterByTypes } from "../helpers/micromark-helpers.cjs";
66
/** @typedef {import("markdownlint").RuleParams} RuleParams */
77
/** @typedef {import("markdownlint").MicromarkToken} MicromarkToken */
88
/** @typedef {import("markdownlint").MicromarkTokenType} MicromarkTokenType */
9+
/** @typedef {import("../helpers/helpers.cjs").GetReferenceLinkImageDataResult} GetReferenceLinkImageDataResult */
910

1011
/** @type {Map<string, object>} */
1112
const map = new Map();
@@ -68,9 +69,10 @@ export function filterByTypesCached(types, htmlFlow) {
6869
/**
6970
* Gets a reference link and image data object.
7071
*
71-
* @returns {Object} Reference link and image data object.
72+
* @returns {GetReferenceLinkImageDataResult} Reference link and image data object.
7273
*/
7374
export function getReferenceLinkImageData() {
75+
// @ts-ignore
7476
return getCached(
7577
getReferenceLinkImageData.name,
7678
() => helpersGetReferenceLinkImageData(micromarkTokens())

lib/constants.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-check
22

3+
/** @type {string[]} */
34
export const deprecatedRuleNames = [];
45
export const fixableRuleNames = [
56
"MD004", "MD005", "MD007", "MD009", "MD010", "MD011",

lib/markdownit.cjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ function annotateAndFreezeTokens(tokens, lines) {
127127
}
128128
// Annotate children with lineNumber
129129
if (token.children) {
130+
/** @type {number[]} */
130131
const codeSpanExtraLines = [];
131132
if (token.children.some((child) => child.type === "code_inline")) {
132133
forEachInlineCodeSpan(token.content, (code) => {
@@ -140,7 +141,7 @@ function annotateAndFreezeTokens(tokens, lines) {
140141
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
141142
lineNumber++;
142143
} else if (child.type === "code_inline") {
143-
lineNumber += codeSpanExtraLines.shift();
144+
lineNumber += codeSpanExtraLines.shift() || 0;
144145
}
145146
}
146147
}

lib/markdownlint.d.mts

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,39 +26,38 @@ export function lintSync(options: Options | null): LintResults;
2626
* @param {Configuration} config Configuration object.
2727
* @param {string} file Configuration file name.
2828
* @param {ConfigurationParser[] | undefined} parsers Parsing function(s).
29-
* @param {Object} fs File system implementation.
29+
* @param {FsLike} fs File system implementation.
3030
* @returns {Promise<Configuration>} Configuration object.
3131
*/
32-
export function extendConfigPromise(config: Configuration, file: string, parsers: ConfigurationParser[] | undefined, fs: any): Promise<Configuration>;
32+
export function extendConfigPromise(config: Configuration, file: string, parsers: ConfigurationParser[] | undefined, fs: FsLike): Promise<Configuration>;
3333
/**
3434
* Read specified configuration file.
3535
*
3636
* @param {string} file Configuration file name.
37-
* @param {ConfigurationParser[] | ReadConfigCallback} [parsers] Parsing
38-
* function(s).
39-
* @param {Object} [fs] File system implementation.
37+
* @param {ConfigurationParser[] | ReadConfigCallback} [parsers] Parsing function(s).
38+
* @param {FsLike | ReadConfigCallback} [fs] File system implementation.
4039
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
4140
* @returns {void}
4241
*/
43-
export function readConfigAsync(file: string, parsers?: ConfigurationParser[] | ReadConfigCallback, fs?: any, callback?: ReadConfigCallback): void;
42+
export function readConfigAsync(file: string, parsers?: ConfigurationParser[] | ReadConfigCallback, fs?: FsLike | ReadConfigCallback, callback?: ReadConfigCallback): void;
4443
/**
4544
* Read specified configuration file.
4645
*
4746
* @param {string} file Configuration file name.
4847
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
49-
* @param {Object} [fs] File system implementation.
48+
* @param {FsLike} [fs] File system implementation.
5049
* @returns {Promise<Configuration>} Configuration object.
5150
*/
52-
export function readConfigPromise(file: string, parsers?: ConfigurationParser[], fs?: any): Promise<Configuration>;
51+
export function readConfigPromise(file: string, parsers?: ConfigurationParser[], fs?: FsLike): Promise<Configuration>;
5352
/**
5453
* Read specified configuration file.
5554
*
5655
* @param {string} file Configuration file name.
5756
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
58-
* @param {Object} [fs] File system implementation.
57+
* @param {FsLike} [fs] File system implementation.
5958
* @returns {Configuration} Configuration object.
6059
*/
61-
export function readConfigSync(file: string, parsers?: ConfigurationParser[], fs?: any): Configuration;
60+
export function readConfigSync(file: string, parsers?: ConfigurationParser[], fs?: FsLike): Configuration;
6261
/**
6362
* Applies the specified fix to a Markdown content line.
6463
*
@@ -82,6 +81,19 @@ export function applyFixes(input: string, errors: LintError[]): string;
8281
* @returns {string} SemVer string.
8382
*/
8483
export function getVersion(): string;
84+
/**
85+
* Result object for removeFrontMatter.
86+
*/
87+
export type RemoveFrontMatterResult = {
88+
/**
89+
* Markdown content.
90+
*/
91+
content: string;
92+
/**
93+
* Front matter lines.
94+
*/
95+
frontMatterLines: string[];
96+
};
8597
/**
8698
* Result object for getEffectiveConfig.
8799
*/
@@ -120,6 +132,27 @@ export type EnabledRulesPerLineNumberResult = {
120132
*/
121133
rulesSeverity: Map<string, "error" | "warning">;
122134
};
135+
/**
136+
* Node fs instance (or compatible object).
137+
*/
138+
export type FsLike = {
139+
/**
140+
* access method.
141+
*/
142+
access: (path: string, callback: (err: Error) => void) => void;
143+
/**
144+
* accessSync method.
145+
*/
146+
accessSync: (path: string) => void;
147+
/**
148+
* readFile method.
149+
*/
150+
readFile: (path: string, encoding: string, callback: (err: Error, data: string) => void) => void;
151+
/**
152+
* readFileSync method.
153+
*/
154+
readFileSync: (path: string, encoding: string) => string;
155+
};
123156
/**
124157
* Function to implement rule logic.
125158
*/
@@ -418,7 +451,7 @@ export type Options = {
418451
/**
419452
* File system implementation.
420453
*/
421-
fs?: any;
454+
fs?: FsLike;
422455
/**
423456
* True to catch exceptions.
424457
*/
@@ -467,15 +500,15 @@ export type LintError = {
467500
/**
468501
* Link to more information.
469502
*/
470-
ruleInformation: string;
503+
ruleInformation: string | null;
471504
/**
472505
* Detail about the error.
473506
*/
474-
errorDetail: string;
507+
errorDetail: string | null;
475508
/**
476509
* Context for the error.
477510
*/
478-
errorContext: string;
511+
errorContext: string | null;
479512
/**
480513
* Column number (1-based) and length.
481514
*/

0 commit comments

Comments
 (0)