Stricter rules for JSDoc documentation blocks (#11881)

This commit is contained in:
Álvaro Mondéjar Rubio 2024-09-29 16:28:34 +02:00 committed by GitHub
parent 1a5a37cc2d
commit 5183e3c06b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 150 additions and 136 deletions

View File

@ -2,7 +2,7 @@
"prettier": true,
"space": 2,
"plugins": ["import"],
"extends": ["plugin:jsdoc/recommended"],
"extends": ["plugin:jsdoc/recommended-error"],
"rules": {
"sort-imports": [
"error",
@ -29,7 +29,21 @@
}
],
"no-console": ["error", {"allow": ["warn", "error"]}],
"jsdoc/require-file-overview": "error"
"no-warning-comments": [
"warn",
{
"terms": ["fixme", "xxx"]
}
],
"jsdoc/require-file-overview": "error",
"jsdoc/require-description": "error",
"jsdoc/no-bad-blocks": "error",
"jsdoc/no-blank-blocks": "error",
"jsdoc/no-blank-block-descriptions": "error",
"jsdoc/check-syntax": "error",
"jsdoc/require-asterisk-prefix": "error",
"jsdoc/require-description-complete-sentence": "error",
"jsdoc/require-hyphen-before-param-description": ["error", "never"]
},
"overrides": [
{

View File

@ -91,7 +91,7 @@
"editorconfig-checker": "5.1.5",
"esbuild": "0.20.2",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "48.2.8",
"eslint-plugin-jsdoc": "50.3.0",
"fake-diff": "1.0.0",
"fast-fuzzy": "1.12.0",
"get-relative-luminance": "1.0.0",

View File

@ -41,8 +41,9 @@ const licenseTypes =
);
/**
* @param {string} input URL input
* @returns {Promise<boolean|string>} Whether the input is a valid URL
* Whether an input is a valid URL.
* @param {string} input URL input.
* @returns {Promise<boolean|string>} Whether the input is a valid URL.
*/
const isValidURL = async (input) => {
const regex = await urlRegex();
@ -50,15 +51,17 @@ const isValidURL = async (input) => {
};
/**
* @param {string} input Hex color
* @returns {boolean|string} Whether the input is a valid hex color
* Whether an input is a valid hex color.
* @param {string} input Hex color.
* @returns {boolean|string} Whether the input is a valid hex color.
*/
const isValidHexColor = (input) =>
HEX_REGEX.test(input) || 'Must be a valid hex code.';
/**
* @param {string} input New icon input
* @returns {boolean} Whether the icon is new
* Whether an icon is not already in the dataset.
* @param {string} input New icon input.
* @returns {boolean} Whether the icon is new.
*/
const isNewIcon = (input) =>
!iconsData.icons.some(
@ -67,8 +70,9 @@ const isNewIcon = (input) =>
);
/**
* @param {string} input Color input
* @returns {string} Preview of the color
* Compute a preview of a color to use in prompt background.
* @param {string} input Color input.
* @returns {string} Preview of the color.
*/
const previewHexColor = (input) => {
const color = normalizeColor(input);

View File

@ -13,6 +13,11 @@ const __dirname = getDirnameFromImportMeta(import.meta.url);
const rootDirectory = path.resolve(__dirname, '..', '..');
const files = ['index.js', 'index.mjs', 'index.d.ts', 'sdk.js'];
/**
* Check if a file exists.
* @param {string} fpath File path to check.
* @returns {Promise<boolean>} True if the file exists, false otherwise.
*/
const fileExists = async (fpath) => {
try {
await fs.access(fpath);

View File

@ -53,18 +53,20 @@ const icons = await getIconsData();
const iconObjectTemplate = await fs.readFile(iconObjectTemplateFile, UTF8);
/**
* @param {string} value The value to escape
* @returns {string} The escaped value
* Escape a string for use in a JavaScript string.
* @param {string} value The value to escape.
* @returns {string} The escaped value.
*/
const escape = (value) => {
return value.replaceAll(/(?<!\\)'/g, "\\'");
};
/**
* @param {License} license The license object or URL
* @returns {License} The license object with a URL
* Converts a license object to a URL if the URL is not defined.
* @param {License} license The license object or URL.
* @returns {License} The license object with a URL.
*/
const licenseToObject = (license) => {
const licenseToString = (license) => {
if (license.url === undefined) {
license.url = `https://spdx.org/licenses/${license.type}`;
}
@ -74,8 +76,8 @@ const licenseToObject = (license) => {
/**
* Converts an icon object to a JavaScript object.
* @param {IconDataAndObject} icon The icon object
* @returns {string} The JavaScript object
* @param {IconDataAndObject} icon The icon object.
* @returns {string} The JavaScript object.
*/
const iconToJsObject = (icon) => {
return format(
@ -89,14 +91,15 @@ const iconToJsObject = (icon) => {
icon.guidelines ? `\n guidelines: '${escape(icon.guidelines)}',` : '',
icon.license === undefined
? ''
: `\n license: ${JSON.stringify(licenseToObject(icon.license))},`,
: `\n license: ${JSON.stringify(licenseToString(icon.license))},`,
);
};
/**
* @param {string} filepath The path to the file to write
* @param {string} rawJavaScript The raw JavaScript content to write to the file
* @param {EsBuildTransformOptions | null} options The options to pass to esbuild
* Write JavaScript content to a file.
* @param {string} filepath The path to the file to write.
* @param {string} rawJavaScript The raw JavaScript content to write to the file.
* @param {EsBuildTransformOptions | null} options The options to pass to esbuild.
*/
const writeJs = async (filepath, rawJavaScript, options = null) => {
options = options === null ? {minify: true} : options;
@ -105,8 +108,9 @@ const writeJs = async (filepath, rawJavaScript, options = null) => {
};
/**
* @param {string} filepath The path to the file to write
* @param {string} rawTypeScript The raw TypeScript content to write to the file
* Write TypeScript content to a file.
* @param {string} filepath The path to the file to write.
* @param {string} rawTypeScript The raw TypeScript content to write to the file.
*/
const writeTs = async (filepath, rawTypeScript) => {
await fs.writeFile(filepath, rawTypeScript);

View File

@ -1,8 +1,7 @@
#!/usr/bin/env node
/**
* @file
* Linters for the package that can't easily be implemented in the existing
* linters (e.g. jsonlint/svglint).
* Linters for the package that can't easily be implemented in the existing ones.
*/
/**
@ -22,18 +21,18 @@ import {collator, getIconsDataString, normalizeNewlines} from '../../sdk.mjs';
*/
const TESTS = {
/**
* Tests whether our icons are in alphabetical order
* @param {{icons: IconsData}} data Icons data
* @returns {string|undefined} Error message or undefined
* Tests whether our icons are in alphabetical order.
* @param {{icons: IconsData}} data Icons data.
* @returns {string|undefined} Error message or undefined.
*/
alphabetical(data) {
/**
* Collects invalid alphabet ordered icons
* @param {IconData[]} invalidEntries Invalid icons reference
* @param {IconData} icon Icon to check
* @param {number} index Index of the icon
* @param {IconData[]} array Array of icons
* @returns {IconData[]} Invalid icons
* Collects invalid alphabet ordered icons.
* @param {IconData[]} invalidEntries Invalid icons reference.
* @param {IconData} icon Icon to check.
* @param {number} index Index of the icon.
* @param {IconData[]} array Array of icons.
* @returns {IconData[]} Invalid icons.
*/
const collector = (invalidEntries, icon, index, array) => {
if (index > 0) {
@ -54,9 +53,9 @@ const TESTS = {
};
/**
* Format an icon for display in the error message
* @param {IconData} icon Icon to format
* @returns {string} Formatted icon
* Format an icon for display in the error message.
* @param {IconData} icon Icon to format.
* @returns {string} Formatted icon.
*/
const format = (icon) => {
if (icon.slug) {
@ -89,32 +88,32 @@ const TESTS = {
checkUrl(data) {
/**
* Check if an URL has a redundant trailing slash.
* @param {URL} $url URL instance
* @param {string} url Original URL string
* @returns {boolean} Whether the URL has a redundant trailing slash
* @param {URL} $url URL instance.
* @param {string} url Original URL string.
* @returns {boolean} Whether the URL has a redundant trailing slash.
*/
const hasRedundantTrailingSlash = ($url, url) => url === $url.origin + '/';
/**
* Check if an URL is static wikimedia asset URL.
* @param {URL} $url URL instance
* @returns {boolean} Whether the URL is static wikimedia asset URL
* @param {URL} $url URL instance.
* @returns {boolean} Whether the URL is static wikimedia asset URL.
*/
const isStaticWikimediaAssetUrl = ($url) =>
$url.hostname === 'upload.wikimedia.org';
/**
* Check if an URL is raw GitHub asset URL.
* @param {URL} $url URL instance
* @returns {boolean} Whether the URL is raw GitHub asset URL
* @param {URL} $url URL instance.
* @returns {boolean} Whether the URL is raw GitHub asset URL.
*/
const isRawGithubAssetUrl = ($url) =>
$url.hostname === 'raw.githubusercontent.com';
/**
* Check if an URL is a GitHub URL.
* @param {URL} $url URL instance
* @returns {boolean} Whether the URL is a GitHub URL
* @param {URL} $url URL instance.
* @returns {boolean} Whether the URL is a GitHub URL.
*/
const isGitHubUrl = ($url) => $url.hostname === 'github.com';
@ -135,8 +134,8 @@ const TESTS = {
/**
* Check if an URL is a permanent GitHub URL for a file.
* @param {string} url URL string
* @returns {boolean} Whether the URL is a GitHub URL for a file
* @param {string} url URL string.
* @returns {boolean} Whether the URL is a GitHub URL for a file.
*/
const isPermalinkGitHubFileUrl = (url) => permalinkGitHubRegex.test(url);
@ -154,7 +153,6 @@ const TESTS = {
if (icon.license !== undefined && Object.hasOwn(icon.license, 'url')) {
allUrlFields.push([
false,
// eslint-disable-next-line no-warning-comments
// TODO: `hasOwn` is not currently supported by TS.
// See https://github.com/microsoft/TypeScript/issues/44253
/** @type {string} */

View File

@ -19,7 +19,7 @@ const disclaimerFile = path.resolve(rootDirectory, 'DISCLAIMER.md');
/**
* Reformat a file.
* @param {string} filePath Path to the file
* @param {string} filePath Path to the file.
*/
const reformat = async (filePath) => {
const fileContent = await readFile(filePath, 'utf8');

View File

@ -17,6 +17,7 @@ const packageJsonFile = path.resolve(rootDirectory, 'package.json');
const readmeFile = path.resolve(rootDirectory, 'README.md');
/**
* Get the major version number from a semantic version string.
* @param {string} semVersion A semantic version string.
* @returns {number} The major version number.
*/
@ -35,6 +36,7 @@ const getManifest = async () => {
};
/**
* Update the version number in the README.md.
* @param {number} majorVersion The major version number.
*/
const updateVersionInReadmeIfNecessary = async (majorVersion) => {

View File

@ -56,9 +56,9 @@ const generateSdkMts = async () => {
/**
* We must remove the duplicated export types that tsc generates from
* JSDoc `typedef` comments.
* See {@link https://github.com/microsoft/TypeScript/issues/46011}
* @param {string} content Content of the file
* @returns {string} The content without duplicated export types
* See {@link https://github.com/microsoft/TypeScript/issues/46011}.
* @param {string} content Content of the file.
* @returns {string} The content without duplicated export types.
*/
const removeDuplicatedExportTypes = (content) => {
const newContent = [];

69
sdk.mjs
View File

@ -42,16 +42,16 @@ export const SVG_PATH_REGEX = /^m[-mzlhvcsqtae\d,. ]+$/i;
/**
* Get the directory name where this file is located from `import.meta.url`,
* equivalent to the `__dirname` global variable in CommonJS.
* @param {string} importMetaUrl import.meta.url
* @returns {string} Directory name in which this file is located
* @param {string} importMetaUrl Relative `import.meta.url` value of the caller.
* @returns {string} Directory name in which this file is located.
*/
export const getDirnameFromImportMeta = (importMetaUrl) =>
path.dirname(fileURLToPath(importMetaUrl));
/**
* Build a regex to validate HTTPs URLs.
* @param {string} jsonschemaPath Path to the *.jsonschema.json* file
* @returns {Promise<RegExp>} Regex to validate HTTPs URLs
* @param {string} jsonschemaPath Path to the *.jsonschema.json* file.
* @returns {Promise<RegExp>} Regex to validate HTTPs URLs.
*/
export const urlRegex = async (
jsonschemaPath = path.join(
@ -68,22 +68,22 @@ export const urlRegex = async (
/**
* Get the slug/filename for an icon.
* @param {IconData} icon The icon data as it appears in *_data/simple-icons.json*
* @returns {string} The slug/filename for the icon
* @param {IconData} icon The icon data as it appears in *_data/simple-icons.json*.
* @returns {string} The slug/filename for the icon.
*/
export const getIconSlug = (icon) => icon.slug || titleToSlug(icon.title);
/**
* Extract the path from an icon SVG content.
* @param {string} svg The icon SVG content
* @returns {string} The path from the icon SVG content
* @param {string} svg The icon SVG content.
* @returns {string} The path from the icon SVG content.
*/
export const svgToPath = (svg) => svg.split('"', 8)[7];
/**
* Converts a brand title into a slug/filename.
* @param {string} title The title to convert
* @returns {string} The slug/filename for the title
* @param {string} title The title to convert.
* @returns {string} The slug/filename for the title.
*/
export const titleToSlug = (title) =>
title
@ -97,8 +97,8 @@ export const titleToSlug = (title) =>
/**
* Converts a slug into a variable name that can be exported.
* @param {string} slug The slug to convert
* @returns {string} The variable name for the slug
* @param {string} slug The slug to convert.
* @returns {string} The variable name for the slug.
*/
export const slugToVariableName = (slug) => {
const slugFirstLetter = slug[0].toUpperCase();
@ -108,8 +108,8 @@ export const slugToVariableName = (slug) => {
/**
* Converts a brand title as defined in *_data/simple-icons.json* into a brand
* title in HTML/SVG friendly format.
* @param {string} brandTitle The title to convert
* @returns {string} The brand title in HTML/SVG friendly format
* @param {string} brandTitle The title to convert.
* @returns {string} The brand title in HTML/SVG friendly format.
*/
export const titleToHtmlFriendly = (brandTitle) =>
brandTitle
@ -126,9 +126,9 @@ export const titleToHtmlFriendly = (brandTitle) =>
/**
* Converts a brand title in HTML/SVG friendly format into a brand title (as
* it is seen in *_data/simple-icons.json*)
* @param {string} htmlFriendlyTitle The title to convert
* @returns {string} The brand title in HTML/SVG friendly format
* it is seen in *_data/simple-icons.json*).
* @param {string} htmlFriendlyTitle The title to convert.
* @returns {string} The brand title in HTML/SVG friendly format.
*/
export const htmlFriendlyToTitle = (htmlFriendlyTitle) =>
htmlFriendlyTitle
@ -138,17 +138,18 @@ export const htmlFriendlyToTitle = (htmlFriendlyTitle) =>
.replaceAll(
/&(quot|amp|lt|gt);/g,
/**
* @param {string} _ Full match
* @param {'quot' | 'amp' | 'lt' | 'gt'} reference Reference to replace
* @returns {string} Replacement for the reference
* Replace HTML entity references with their respective decoded characters.
* @param {string} _ Full match.
* @param {'quot' | 'amp' | 'lt' | 'gt'} reference Reference to replace.
* @returns {string} Replacement for the reference.
*/
(_, reference) => ({quot: '"', amp: '&', lt: '<', gt: '>'})[reference],
);
/**
* Get path of *_data/simple-icons.json*.
* @param {string} rootDirectory Path to the root directory of the project
* @returns {string} Path of *_data/simple-icons.json*
* @param {string} rootDirectory Path to the root directory of the project.
* @returns {string} Path of *_data/simple-icons.json*.
*/
export const getIconDataPath = (
rootDirectory = getDirnameFromImportMeta(import.meta.url),
@ -158,8 +159,8 @@ export const getIconDataPath = (
/**
* Get contents of *_data/simple-icons.json*.
* @param {string} rootDirectory Path to the root directory of the project
* @returns {Promise<string>} Content of *_data/simple-icons.json*
* @param {string} rootDirectory Path to the root directory of the project.
* @returns {Promise<string>} Content of *_data/simple-icons.json*.
*/
export const getIconsDataString = (
rootDirectory = getDirnameFromImportMeta(import.meta.url),
@ -169,8 +170,8 @@ export const getIconsDataString = (
/**
* Get icons data as object from *_data/simple-icons.json*.
* @param {string} rootDirectory Path to the root directory of the project
* @returns {Promise<IconData[]>} Icons data as array from *_data/simple-icons.json*
* @param {string} rootDirectory Path to the root directory of the project.
* @returns {Promise<IconData[]>} Icons data as array from *_data/simple-icons.json*.
*/
export const getIconsData = async (
rootDirectory = getDirnameFromImportMeta(import.meta.url),
@ -181,8 +182,8 @@ export const getIconsData = async (
/**
* Replace Windows newline characters by Unix ones.
* @param {string} text The text to replace
* @returns {string} The text with Windows newline characters replaced by Unix ones
* @param {string} text The text to replace.
* @returns {string} The text with Windows newline characters replaced by Unix ones.
*/
export const normalizeNewlines = (text) => {
return text.replaceAll('\r\n', '\n');
@ -190,8 +191,8 @@ export const normalizeNewlines = (text) => {
/**
* Convert non-6-digit hex color to 6-digit with the character `#` stripped.
* @param {string} text The color text
* @returns {string} The color text in 6-digit hex format
* @param {string} text The color text.
* @returns {string} The color text in 6-digit hex format.
*/
export const normalizeColor = (text) => {
let color = text.replace('#', '').toUpperCase();
@ -207,8 +208,8 @@ export const normalizeColor = (text) => {
/**
* Get information about third party extensions from the README table.
* @param {string} readmePath Path to the README file
* @returns {Promise<ThirdPartyExtension[]>} Information about third party extensions
* @param {string} readmePath Path to the README file.
* @returns {Promise<ThirdPartyExtension[]>} Information about third party extensions.
*/
export const getThirdPartyExtensions = async (
readmePath = path.join(
@ -258,8 +259,8 @@ export const getThirdPartyExtensions = async (
/**
* Get information about third party libraries from the README table.
* @param {string} readmePath Path to the README file
* @returns {Promise<ThirdPartyExtension[]>} Information about third party libraries
* @param {string} readmePath Path to the README file.
* @returns {Promise<ThirdPartyExtension[]>} Information about third party libraries.
*/
export const getThirdPartyLibraries = async (
readmePath = path.join(

View File

@ -51,8 +51,9 @@ const ignoreFile = './.svglint-ignored.json';
const iconIgnored = updateIgnoreFile ? {} : svglintIgnores;
/**
* @param {{ [key: string]: any }} object Object to sort by key
* @returns {{ [key: string]: any }} Object sorted by key
* Sort an object alphabetically by key converting it to an array.
* @param {{ [key: string]: any }} object Object to sort by key.
* @returns {{ [key: string]: any }} Object sorted by key.
*/
const sortObjectByKey = (object) => {
return Object.fromEntries(
@ -63,8 +64,9 @@ const sortObjectByKey = (object) => {
};
/**
* @param {{ [key: string]: any }} object Object to sort by value
* @returns {{ [key: string]: any }} Object sorted by value
* Sort an object alphabetically by value converting it to an array.
* @param {{ [key: string]: any }} object Object to sort by value.
* @returns {{ [key: string]: any }} Object sorted by value.
*/
const sortObjectByValue = (object) => {
return Object.fromEntries(
@ -222,7 +224,7 @@ if (updateIgnoreFile) {
* Check if an icon is ignored by a linter rule.
* @param {string} linterRule The name of the linter rule.
* @param {string} path SVG path of the icon.
* @returns {boolean} Whether the icon is ignored by the linter rule
* @returns {boolean} Whether the icon is ignored by the linter rule.
*/
const isIgnored = (linterRule, path) => {
return (
@ -234,7 +236,7 @@ const isIgnored = (linterRule, path) => {
* Ignore an icon for a linter rule.
* @param {string} linterRule The name of the linter rule.
* @param {string} path SVG path of the icon.
* @param {Cheerio} $ The SVG object
* @param {Cheerio} $ The SVG object.
*/
const ignoreIcon = (linterRule, path, $) => {
iconIgnored[linterRule] ||= {};
@ -520,11 +522,14 @@ const config = {
const segments = getIconPathSegments(iconPath);
/** @type {import('svg-path-segments').Segment[]} */
// eslint-disable-next-line no-warning-comments
// TODO: svgpath does not includes the `segments` property on the interface,
// see https://github.com/fontello/svgpath/pull/67/files
// @ts-ignore
const absSegments = svgpath(iconPath).abs().unshort().segments;
//
/** @typedef {[string, ...number[]]} Segment */
/** @type {Segment[]} */
const absSegments =
// @ts-ignore
svgpath(iconPath).abs().unshort().segments;
const lowerMovementCommands = ['m', 'l'];
const lowerDirectionCommands = ['h', 'v'];
@ -608,8 +613,11 @@ const config = {
].reverse();
// If the previous command was a direction one,
// we need to iterate back until we find the missing coordinates
// @ts-ignore
if (upperDirectionCommands.includes(xPreviousCoord)) {
// @ts-ignore
xPreviousCoord = undefined;
// @ts-ignore
yPreviousCoord = undefined;
let index_ = index;
while (
@ -624,12 +632,14 @@ const config = {
// we need to consider the single coordinate as x
if (upperHorDirectionCommand === xPreviousCoordDeep) {
xPreviousCoordDeep = yPreviousCoordDeep;
// @ts-ignore
yPreviousCoordDeep = undefined;
}
// If the previous command was a vertical movement,
// we need to consider the single coordinate as y
if (upperVersionDirectionCommand === xPreviousCoordDeep) {
// @ts-ignore
xPreviousCoordDeep = undefined;
}
@ -791,10 +801,8 @@ const config = {
// Next switch cases have been ordered by frequency
// of occurrence in the SVG paths of the icons
case 'M': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[2];
// SVG 1.1:
@ -808,10 +816,8 @@ const config = {
}
case 'm': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[2];
if (seg.chain === undefined || seg.chain.start === seg.start) {
@ -822,48 +828,40 @@ const config = {
}
case 'H': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[1];
break;
}
case 'h': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[1];
break;
}
case 'V': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[1];
break;
}
case 'v': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[1];
break;
}
case 'L': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[2];
break;
}
case 'l': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[2];
break;
@ -871,108 +869,88 @@ const config = {
case 'Z':
case 'z': {
// eslint-disable-next-line no-warning-comments
// TODO: Overlapping in Z should be handled in another rule
// @ts-ignore
currentAbsCoord = [startPoint[0], startPoint[1]];
_resetStartPoint = true;
break;
}
case 'C': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[5];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[6];
break;
}
case 'c': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[5];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[6];
break;
}
case 'A': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[6];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[7];
break;
}
case 'a': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[6];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[7];
break;
}
case 's': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[2];
break;
}
case 'S': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[2];
break;
}
case 't': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[2];
break;
}
case 'T': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[1];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[2];
break;
}
case 'Q': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = parms[3];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = parms[4];
break;
}
case 'q': {
/** @type {number} */
// @ts-ignore
currentAbsCoord[0] = (currentAbsCoord[0] || 0) + parms[3];
/** @type {number} */
// @ts-ignore
currentAbsCoord[1] = (currentAbsCoord[1] || 0) + parms[4];
break;
@ -990,6 +968,7 @@ const config = {
_resetStartPoint = false;
}
// @ts-ignore
_nextInStraightLine = straightLineCommands.includes(nextCmd);
const _exitingStraightLine =
_inStraightLine && !_nextInStraightLine;
@ -1006,6 +985,7 @@ const config = {
// Get collinear coordinates
for (let p = 1; p < currentLine.length - 1; p++) {
const _collinearCoord = collinear(
// @ts-ignore
currentLine[p - 1][0],
currentLine[p - 1][1],
currentLine[p][0],

View File

@ -2,7 +2,7 @@
* @file Custom mocha reporter.
*
* Serves to clear the console after the test run is finished.
* See {@link https://github.com/mochajs/mocha/issues/2312}
* See {@link https://github.com/mochajs/mocha/issues/2312}.
*/
const {reporters, Runner} = require('mocha');
@ -11,11 +11,16 @@ const {EVENT_RUN_END} = Runner.constants;
class EvenMoreMin extends reporters.Base {
/**
* @param {import('mocha').Runner} runner Mocha test runner
* Construct a new `EvenMoreMin` reporter.
* @param {import('mocha').Runner} runner Mocha test runner.
*/
constructor(runner) {
super(runner);
runner.once(EVENT_RUN_END, () => this.epilogue());
runner.once(EVENT_RUN_END, () => {
// TODO: mocha's base reporters are not typed
// @ts-ignore
return this.epilogue();
});
}
}

View File

@ -20,9 +20,10 @@ const iconsDirectory = path.resolve(
/**
* Checks if icon data matches a subject icon.
* @param {import('../sdk.d.ts').IconData} icon Icon data
* @param {import('../types.d.ts').SimpleIcon} subject Icon object to check against icon data
* @param {string} slug Icon data slug
* @param {import('../sdk.d.ts').IconData} icon Icon data.
* @param {import('../types.d.ts').SimpleIcon} subject
* Icon object to check against icon data.
* @param {string} slug Icon data slug.
*/
export const testIcon = (icon, subject, slug) => {
const svgPath = path.resolve(iconsDirectory, `${slug}.svg`);