diff --git a/.eslintrc.js b/.eslintrc.js index 3ff503ba6..3c496dd5d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -128,7 +128,9 @@ module.exports = { 'no-unused-expressions': 'off', // This rule is replaced with the TSESlint version. '@typescript-eslint/no-unused-expressions': 'error', // Support TS stuff. '@typescript-eslint/no-throw-literal': 'error', // Recommended in v8 (w/rename to `only-throw-error`) - '@typescript-eslint/prefer-namespace-keyword': 'error', // Recommended in v8 + '@typescript-eslint/prefer-find': 'error', // Recommended in v8 + '@typescript-eslint/prefer-includes': 'error', // Recommended in v8 + '@typescript-eslint/prefer-regexp-exec': 'error', // Recommended in v8 // Unsafe '@typescript-eslint/no-unsafe-assignment': 'off', // Blocked on typescript-eslint/typescript-eslint#1682. diff --git a/lib/anonymize.js b/lib/anonymize.js index 03b599730..65fd2f4ef 100644 --- a/lib/anonymize.js +++ b/lib/anonymize.js @@ -1,5 +1,5 @@ /** - * This module aims to make the paths and versions used in the CLI generic + * @file This module aims to make the paths and versions used in the CLI generic, * so that the CLI tests (in the `test/` folder) have the same output on different * machines, and also the same output when only the CLI version changes. */ diff --git a/lib/app-wrapper.js b/lib/app-wrapper.js index 2e089e08d..8835f667a 100644 --- a/lib/app-wrapper.js +++ b/lib/app-wrapper.js @@ -81,6 +81,7 @@ function initWithWorker(elmModulePath, flags) { /** * @param {string | symbol} port + * @returns {Listened} */ function send(port) { return (/** @type {unknown} */ data) => { @@ -137,6 +138,7 @@ function initializeListeners() { /** * @param {string} elmModulePath * @param {Flags} flags + * @returns {ReviewApp} */ function initWithoutWorker(elmModulePath, flags) { const elmModule = loadCompiledElmApp(elmModulePath); @@ -146,6 +148,9 @@ function initWithoutWorker(elmModulePath, flags) { return app; } +/** + * @returns {void} + */ function stop() { if (worker) { worker.terminate(); diff --git a/lib/autofix.js b/lib/autofix.js index 84b838255..f1b540231 100644 --- a/lib/autofix.js +++ b/lib/autofix.js @@ -27,6 +27,7 @@ const StyledMessage = require('./styled-message'); * @param {Options} options * @param {ReviewApp} app * @param {VersionString} elmVersion + * @returns {void} */ function subscribe(options, app, elmVersion) { AppState.subscribe( diff --git a/lib/build.js b/lib/build.js index cda241d9d..7d3b13cb4 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,10 +1,11 @@ /** + * @import {CompileOptions, Sources} from '../vendor/types/node-elm-compiler'; * @import {AppHash, BuildResult} from './types/build'; * @import {ApplicationElmJson, ElmJson} from './types/content'; - * @import {VersionString} from './types/version'; + * @import {ErrorMessageInfo} from './types/error-message'; * @import {Options, Template} from './types/options'; * @import {Path} from './types/path'; - * @import {CompileOptions, Sources} from '../vendor/types/node-elm-compiler'; + * @import {VersionString} from './types/version'; */ const path = require('node:path'); const crypto = require('node:crypto'); @@ -334,6 +335,7 @@ async function createTemplateProject( * @param {Options} options * @param {string} userSrc * @param {ApplicationElmJson} elmJson + * @returns {ApplicationElmJson} */ function updateSourceDirectories(options, userSrc, elmJson) { let sourceDirectories = [ @@ -359,10 +361,10 @@ function updateSourceDirectories(options, userSrc, elmJson) { /** * @param {Options} options - * @param {string} dest - * @param {string} elmModulePath + * @param {Path} dest + * @param {Path} elmModulePath * @param {Sources} compileTargets - * @param {string} elmBinary + * @param {Path} elmBinary * @param {boolean} isReviewApp * @returns {Promise} */ @@ -455,6 +457,7 @@ async function compileElmProject( /** * @param {Options} options * @param {string} stderr + * @returns {ErrorMessageInfo} */ function compilationError(options, stderr) { if (stderr.includes('DEBUG REMNANTS')) { @@ -496,6 +499,7 @@ function compilationError(options, stderr) { * @param {Options} options * @param {Path} reviewElmJsonPath * @param {ElmJson} reviewElmJson + * @returns {void} */ function validateElmReviewVersion(options, reviewElmJsonPath, reviewElmJson) { if (options.localElmReviewSrc) { diff --git a/lib/debug.js b/lib/debug.js index 275384965..d9a832d9c 100644 --- a/lib/debug.js +++ b/lib/debug.js @@ -4,6 +4,7 @@ const options = AppState.getOptions(); /** * @param {string} message + * @returns {void} */ function log(message) { if (options.debug) { diff --git a/lib/elm-files.js b/lib/elm-files.js index c1948cbf3..d39112613 100644 --- a/lib/elm-files.js +++ b/lib/elm-files.js @@ -1,5 +1,5 @@ /** - * @import {ElmFile, Source, Readme, ElmJson, ElmJsonData, SourceDirectories, Ast} from './types/content'; + * @import {Ast, ElmFile, ElmJson, ProjectFiles, Readme, Source, SourceDirectories} from './types/content'; * @import {ReviewOptions} from './types/options'; * @import {Path} from './types/path'; */ @@ -19,14 +19,6 @@ const AppState = require('./state'); const defaultGlob = '**/*.elm$'; -/** - * @typedef {object} ProjectFiles - * @property {ElmJsonData} elmJsonData - * @property {Readme | null} readme - * @property {ElmFile[]} elmFiles - * @property {Path[]} sourceDirectories - */ - /** * Get all files from the project. * diff --git a/lib/error-message.js b/lib/error-message.js index 77c8378b5..27b6efa85 100644 --- a/lib/error-message.js +++ b/lib/error-message.js @@ -97,7 +97,7 @@ function stacktrace(debug, error) { * @param {boolean} debug * @param {CustomError} error * @param {Path} [defaultPath] - * @returns {unknown} + * @returns {{type: string; title: string; path: string | undefined; message: string[]; stack: string | undefined}} */ function formatJson(debug, error, defaultPath) { return { diff --git a/lib/fs-wrapper.js b/lib/fs-wrapper.js index 3a8332a26..e2444b8c1 100644 --- a/lib/fs-wrapper.js +++ b/lib/fs-wrapper.js @@ -9,7 +9,7 @@ const fsp = fs.promises; * Read a JSON file. * * @param {Path} file - * @param {Reviver | undefined} [reviver=undefined] + * @param {Reviver} [reviver] * @returns {Promise} */ async function readJsonFile(file, reviver) { @@ -19,10 +19,9 @@ async function readJsonFile(file, reviver) { } /** - * * @param {string} data * @param {Path} file - * @param {Reviver | undefined} reviver + * @param {Reviver} [reviver] * @returns {unknown} */ function parseJsonFromFile(data, file, reviver) { @@ -46,8 +45,8 @@ function readJsonFileSync(file) { /** * Read a file using Promises. * - * @param {string} file - * @param {fs.BaseEncodingOptions & { flag?: fs.OpenMode | undefined }} [options={encoding: 'utf8'}] + * @param {Path} file + * @param {fs.BaseEncodingOptions & { flag?: fs.OpenMode | undefined }} [options] * @returns {Promise} */ async function readFile(file, options) { @@ -58,10 +57,10 @@ async function readFile(file, options) { /** * Write a JSON file. * - * @param {string} file + * @param {Path} file * @param {unknown} content - * @param {string | number | undefined} [space=undefined] - * @param {Replacer | undefined} [replacer=undefined] + * @param {string | number | undefined} [space] + * @param {Replacer} [replacer] * @returns {Promise} */ async function writeJson(file, content, space, replacer) { @@ -85,7 +84,8 @@ function mkdirpSync(dir) { } /** - * @param {fs.PathLike} file + * @param {Path} file + * @returns {Promise} */ async function remove(file) { await fsp.rm( diff --git a/lib/help.js b/lib/help.js index f46d83bf3..7749c0691 100644 --- a/lib/help.js +++ b/lib/help.js @@ -56,6 +56,9 @@ ${Flags.buildFlags('fix', null)} ); } +/** + * @returns {void} + */ function suppress() { const orange = chalk.keyword('orange'); @@ -97,6 +100,9 @@ ${Flags.buildFlags('suppress', 'suppress')} ); } +/** + * @returns {void} + */ function init() { console.log( // prettier-ignore @@ -117,6 +123,9 @@ ${Flags.buildFlags('init', 'init')} ); } +/** + * @returns {void} + */ function newPackage() { console.log( // prettier-ignore @@ -138,6 +147,9 @@ ${Flags.buildFlags('new-package', 'new-package')} ); } +/** + * @returns {void} + */ function newRule() { console.log(`The new-rule command adds an empty rule to your review configuration or review package. @@ -161,6 +173,9 @@ ${Flags.buildFlags('new-rule', 'new-rule')} `); } +/** + * @returns {void} + */ function prepareOffline() { console.log(`The prepare-offline command allows the tool to run in offline mode using the ${chalk.cyan('--offline')} flag. diff --git a/lib/init.js b/lib/init.js index 2d49f2ba3..f173d1f6c 100644 --- a/lib/init.js +++ b/lib/init.js @@ -52,6 +52,7 @@ async function promptAndCreate(options) { * @param {Options} options * @param {Template} template * @param {string} directory + * @returns {Promise} */ async function createFromTemplate(options, template, directory) { const configDirectory = path.join(directory, 'src'); @@ -91,6 +92,7 @@ async function createFromTemplate(options, template, directory) { /** * @param {Options} options * @param {Path} directory + * @returns {void} */ function logInit(options, directory) { const message = options.template @@ -118,6 +120,7 @@ ${options.template ? templateRecommendation : ''}` /** * @param {Options} options * @param {Path} directory + * @returns {string} */ function regularInitMessage(options, directory) { return `You can now define your review configuration by editing ${chalk.green( @@ -130,6 +133,7 @@ const orange = chalk.keyword('orange'); /** * @param {Options} options * @param {Path} directory + * @returns {string} */ function templateInitMessage(options, directory) { return `You chose to use someone's review configuration which can be great to get started @@ -155,6 +159,7 @@ I recommend you use a mix of the following approaches: * @param {Options} options * @param {Path} directory * @param {string} template + * @returns {Promise} */ async function create(options, directory, template) { const configDirectory = path.join(directory, 'src'); @@ -170,6 +175,7 @@ async function create(options, directory, template) { /** * @param {Options} options * @param {Path} directory + * @returns {Promise} */ async function createElmJson(options, directory) { const elmBinary = await getElmBinary(options); @@ -188,6 +194,7 @@ async function createElmJson(options, directory) { /** * @param {Path} directory * @param {string} template + * @returns {void} */ function createReviewConfig(directory, template) { fsExtra.copyFileSync( diff --git a/lib/main.js b/lib/main.js index 9df6afef5..6a82f7f3d 100644 --- a/lib/main.js +++ b/lib/main.js @@ -67,6 +67,9 @@ function errorHandler(err) { exit(1); } +/** + * @returns {Promise} + */ async function runElmReview() { const {elmModulePath, reviewElmJson, appHash} = await Builder.build(options); @@ -142,6 +145,9 @@ async function runElmReviewInWatchMode() { } } +/** + * @returns {Promise} + */ async function prepareOffline() { const elmBinary = await ElmBinary.getElmBinary(options); ElmBinary.downloadDependenciesOfElmJson( diff --git a/lib/min-version.js b/lib/min-version.js index c134f3137..974b3907e 100644 --- a/lib/min-version.js +++ b/lib/min-version.js @@ -50,7 +50,7 @@ function updateToAtLeastMinimalVersion(version) { * @param {Options} options * @param {Path} elmJsonPath - path to an elm.json file * @param {VersionString} version - version string, e.g. "1.0" - * @returns void + * @returns {void} */ function validate(options, elmJsonPath, version) { const [major, minor] = version.split('.'); diff --git a/lib/module-cache.js b/lib/module-cache.js index 57a71f4d5..21ee2d739 100644 --- a/lib/module-cache.js +++ b/lib/module-cache.js @@ -11,6 +11,7 @@ const Cache = require('./cache'); /** * @param {Options} options * @param {ReviewApp} app + * @returns {void} */ function subscribe(options, app) { AppState.subscribe(app.ports.cacheFile, async ({source, ast}) => @@ -25,6 +26,7 @@ function subscribe(options, app) { * @param {Options} options * @param {string} fileHash * @param {Ast} ast + * @returns {Promise} */ async function cacheFile(options, fileHash, ast) { await Cache.cacheJsonFile( diff --git a/lib/new-package.js b/lib/new-package.js index 66fdab604..8fef31728 100644 --- a/lib/new-package.js +++ b/lib/new-package.js @@ -1,5 +1,6 @@ /** - * @import {ApplicationElmJson} from './types/content'; + * @import {PackageJSON} from '@package-json/types' with {"resolution-mode": "import"}; + * @import {ApplicationElmJson, PackageElmJson} from './types/content'; * @import {PackageTitle} from './types/new-package'; * @import {Options, RuleType} from './types/options'; * @import {Path} from './types/path'; @@ -19,6 +20,7 @@ const Spinner = require('./spinner'); /** * @param {Options} options + * @returns {Promise} */ async function create(options) { const onCancelOptions = /** @satisfies {prompts.Options} */ ({ @@ -132,6 +134,9 @@ function validatePackageName(packageName) { } } +/** + * @returns {Promise} + */ async function askForPackageName() { let canceled = false; @@ -162,6 +167,9 @@ async function askForPackageName() { return await askForPackageName(); } +/** + * An up-to-date `elm-tooling.json` file. + */ const elmToolingJson = { tools: { elm: '0.19.1', @@ -187,6 +195,7 @@ async function writeFile(dir, fileName, content) { * @param {string} ruleName * @param {RuleType} ruleType * @param {string} license + * @returns {Promise} */ async function createProject( options, @@ -363,6 +372,7 @@ ElmjutsuDumMyM0DuL3.elm * @param {PackageTitle} packageName * @param {string} ruleName * @param {string} license + * @returns {PackageElmJson} */ function elmJson(authorName, packageName, ruleName, license) { return { @@ -388,6 +398,7 @@ function elmJson(authorName, packageName, ruleName, license) { * @param {string} authorName * @param {PackageTitle} packageName * @param {string} ruleName + * @returns {string} */ function readme(authorName, packageName, ruleName) { return `# ${packageName} @@ -425,6 +436,7 @@ elm-review --template ${authorName}/${packageName}/example /** * @param {Options} options * @param {PackageTitle} packageName + * @returns {PackageJSON} */ function packageJson(options, packageName) { return { diff --git a/lib/new-rule.js b/lib/new-rule.js index 8afcfdd52..4a0be5d4c 100644 --- a/lib/new-rule.js +++ b/lib/new-rule.js @@ -15,6 +15,7 @@ const packageNameRegex = /.+\/(elm-)?review-.+/; /** * @param {ReviewOptions} options + * @returns {Promise} */ async function create(options) { const elmJson = readElmJson(options); @@ -81,6 +82,9 @@ function validateRuleName(ruleName) { return ruleName; } +/** + * @returns {Promise} + */ async function askForRuleName() { let canceled = false; /** @type {{ruleName: string}} */ @@ -157,17 +161,18 @@ async function askForRuleType() { * @param {string} dir * @param {string} fileName * @param {string} content + * @returns {void} */ function writeFile(dir, fileName, content) { fs.writeFileSync(path.join(dir, fileName), content); } /** - * * @param {ReviewOptions} options * @param {PackageElmJson} elmJson * @param {string} ruleName * @param {RuleType} ruleType + * @returns {Promise} */ async function addRule(options, elmJson, ruleName, ruleType) { const ruleNameFolder = ruleName.split('.').slice(0, -1).join('/'); @@ -248,6 +253,7 @@ async function addRule(options, elmJson, ruleName, ruleType) { * @param {string} dir * @param {PackageElmJson} elmJson * @param {string} ruleName + * @returns {void} */ function injectRuleInPreview(dir, elmJson, ruleName) { try { @@ -272,6 +278,7 @@ function injectRuleInPreview(dir, elmJson, ruleName) { * @param {PackageElmJson} elmJson * @param {string} ruleName * @param {string} content + * @returns {void} */ function injectRuleInReadme(dir, elmJson, ruleName, content) { const lines = content.split('\n'); @@ -283,10 +290,13 @@ function injectRuleInReadme(dir, elmJson, ruleName, content) { const ruleSectionRegex = /^#+.*rules/i; /** + * @remarks + * Mutates `lines`! + * * @param {PackageElmJson} elmJson * @param {string} ruleName * @param {string[]} lines - * @description - Mutates `lines`! + * @returns {void} */ function insertRuleDescription(elmJson, ruleName, lines) { const rulesSectionIndex = lines.findIndex((line) => @@ -315,6 +325,7 @@ function insertRuleDescription(elmJson, ruleName, lines) { * @param {string} ruleName * @param {number} rulesSectionIndex * @param {string[]} lines + * @returns {boolean} */ function alreadyHasRuleDescription(ruleName, rulesSectionIndex, lines) { const nextSectionIndex = findNextSectionIndex(rulesSectionIndex, lines); @@ -329,6 +340,7 @@ function alreadyHasRuleDescription(ruleName, rulesSectionIndex, lines) { /** * @param {number} previousSectionIndex * @param {string[]} lines + * @returns {number} */ function findNextSectionIndex(previousSectionIndex, lines) { const nextSectionIndex = lines @@ -343,12 +355,14 @@ function findNextSectionIndex(previousSectionIndex, lines) { } /** - * @remarks Mutates `lines`! + * @remarks + * Mutates `lines`! * * @param {string} configurationPath * @param {PackageElmJson} elmJson * @param {string} ruleName * @param {string[]} lines + * @returns {void} */ function insertRuleInConfiguration( configurationPath, @@ -370,6 +384,7 @@ function insertRuleInConfiguration( * @param {string} configurationPath * @param {string} ruleName * @param {string[]} lines + * @returns {void} */ function insertImport(configurationPath, ruleName, lines) { const firstImportIndex = lines.findIndex((line) => line.startsWith('import')); @@ -402,6 +417,7 @@ function insertImport(configurationPath, ruleName, lines) { * @param {string} ruleName * @param {string} someOtherRule * @param {string[]} lines + * @returns {void} */ function insertRuleInConfigList(ruleName, someOtherRule, lines) { const indexOfOtherRuleExample = lines.findIndex((line) => @@ -429,6 +445,7 @@ function insertRuleInConfigList(ruleName, someOtherRule, lines) { * @param {string} fullPackageName * @param {string} ruleName * @param {RuleType} ruleType + * @returns {string} */ function newSourceFile(fullPackageName, ruleName, ruleType) { return `module ${ruleName} exposing (rule) @@ -520,8 +537,8 @@ expressionVisitor node context = /** * @param {string} ruleName * @returns {string} - * @todo Create a branded `ElmSource` type. */ +// TODO(@lishaduck): Create a branded `ElmSource` type. function projectRuleTemplate(ruleName) { return `rule : Rule rule = diff --git a/lib/npx.js b/lib/npx.js index 9956e933e..ea6b476bf 100644 --- a/lib/npx.js +++ b/lib/npx.js @@ -1,5 +1,9 @@ /** - * A fast `npx` alternative. + * @file A fast `npx` alternative. + */ + +/** + * @import {Path} from './types/path'; */ const path = require('node:path'); @@ -56,6 +60,8 @@ const pathKey = getPathKey(); * That’s an odd use case, but was supported due to the `npx` approach. * * This can be removed in a major version. + * + * @returns {Path} */ function backwardsCompatiblePath() { return [ diff --git a/lib/options.js b/lib/options.js index e94aa38bf..542514766 100644 --- a/lib/options.js +++ b/lib/options.js @@ -101,6 +101,9 @@ function compute(processArgv) { } } + /** + * @returns {Path} + */ function projectToReview() { if (!elmJsonPath) { throw new ErrorMessage.CustomError( @@ -142,6 +145,9 @@ try re-running it with ${chalk.cyan('--elmjson ')}.`, const namespace = args.namespace || 'cli'; + /** + * @returns {Path} + */ function elmStuffFolder() { return path.join( projectToReview(), @@ -154,12 +160,16 @@ try re-running it with ${chalk.cyan('--elmjson ')}.`, ); } + /** + * @returns {Path} + */ function userSrc() { return args.config ? path.resolve(process.cwd(), args.config) : path.join(projectToReview(), 'review'); } + /** @returns {Path} */ function suppressedErrorsFolder() { return path.join(userSrc(), 'suppressed'); } @@ -518,7 +528,11 @@ function suggestions(flagName) { distance: levenshtein.distance(flagName, f.name) })) .sort( - /** @returns {-1 | 0 | 1} */ + /** + * @param {Flag & {distance: number}} a + * @param {Flag & {distance: number}} b + * @returns {-1 | 0 | 1} + */ (a, b) => { if (a.distance < b.distance) { return -1; @@ -542,7 +556,10 @@ function suggestions(flagName) { */ function checkForMissingArgs(subcommand, args) { for (const flag of Flags.flags.filter( - /** @returns {flag is Flag & Multi} */ + /** + * @param {Flag} flag + * @returns {flag is Flag & Multi} + */ (flag) => flag.boolean === false )) { if (typeof args[flag.name] === 'boolean') { diff --git a/lib/parse-elm.js b/lib/parse-elm.js index 1cc71ccb9..f21514855 100644 --- a/lib/parse-elm.js +++ b/lib/parse-elm.js @@ -1,24 +1,18 @@ /** + * @file Parse Elm files in parallel using worker threads. + * * This code was very much inspired by * . */ /** - * @import {Source, ElmFile, Ast} from './types/content'; - * @import {ParseJob} from './types/parse-elm'; + * @import {Ast, ElmFile, Source} from './types/content'; + * @import {CustomWorker, ParseJob} from './types/parse-elm'; * @import {Path} from './types/path'; */ const os = require('node:os'); const path = require('node:path'); -/** - * A worker and the information whether it is currently busy. - * - * @typedef {object} CustomWorker - * @property {Worker} worker - * @property {boolean} busy - */ - // We want to have as many worker threads as CPUs on the user's machine. // Since the main thread is already one, we spawn (numberOfCpus - 1) workers. const numberOfThreads = Math.max(1, os.cpus().length - 1); @@ -49,6 +43,9 @@ function prepareWorkers(Worker) { }; } +/** + * @returns {void} + */ function terminateWorkers() { for (const {worker} of workers) worker.terminate(); } @@ -109,25 +106,34 @@ function findInactiveWorker() { function runWorker(availableWorker, queueItem) { availableWorker.busy = true; - /** @param {ElmFile} result */ + /** + * @param {ElmFile} result + * @returns {void} + */ const messageCallback = (result) => { queueItem.callback(undefined, result); cleanUp(); }; - /** @param {Error} error */ + /** + * @param {Error} error + * @returns {void} + */ function errorCallback(error) { queueItem.callback(error); cleanUp(); } + /** + * @returns {void} + */ function cleanUp() { availableWorker.worker.removeAllListeners('message'); availableWorker.worker.removeAllListeners('error'); availableWorker.busy = false; const nextJob = queue.pop(); if (nextJob === undefined) { - return null; + return; } runWorker(availableWorker, nextJob); diff --git a/lib/project-dependencies.js b/lib/project-dependencies.js index f1b0917fe..c6d69201a 100644 --- a/lib/project-dependencies.js +++ b/lib/project-dependencies.js @@ -1,5 +1,5 @@ /** - * @import {ElmJson} from './types/content'; + * @import {Dependencies, ElmJson, PackageElmJson, PackageName} from './types/content'; * @import {Options} from './types/options'; * @import {VersionString} from './types/version'; */ @@ -10,6 +10,7 @@ const ProjectJsonFiles = require('./project-json-files'); * @param {Options} options * @param {ElmJson} elmJson * @param {VersionString} elmVersion + * @returns {Promise} */ async function collect(options, elmJson, elmVersion) { const dependenciesEntries = @@ -29,7 +30,8 @@ async function collect(options, elmJson, elmVersion) { let hasDependenciesThatCouldNotBeDownloaded = false; const projectDepsPromises = Object.entries(dependenciesEntries).map( - async ([name, constraint]) => { + async ([pkgname, constraint]) => { + const name = /** @type {PackageName} */ (pkgname); const packageVersion = /** @type {VersionString} */ ( constraint.split(' ')[0] ); @@ -80,8 +82,9 @@ I will try to review the project anyway, but you might get unexpected results… } /** - * @param {string} name + * @param {PackageName} name * @param {VersionString} packageVersion + * @returns {PackageElmJson} */ function defaultElmJson(name, packageVersion) { return { diff --git a/lib/project-json-files.js b/lib/project-json-files.js index a53036a3e..d8f1dd5e2 100644 --- a/lib/project-json-files.js +++ b/lib/project-json-files.js @@ -2,7 +2,7 @@ * @import {Path} from './types/path'; * @import {VersionString} from './types/version'; * @import {Options} from './types/options'; - * @import {PackageElmJson} from './types/content'; + * @import {PackageElmJson, PackageName} from './types/content'; */ const os = require('node:os'); const path = require('node:path'); @@ -17,12 +17,12 @@ const elmRoot = ); /** - * Get the elm.json file for a dependency. + * Get the `elm.json` file for a dependency. * * @param {Options} options * @param {VersionString} elmVersion - * @param {string} name - * @param {string} packageVersion + * @param {PackageName} name + * @param {VersionString} packageVersion * @returns {Promise} */ async function getElmJson(options, elmVersion, name, packageVersion) { @@ -117,7 +117,7 @@ function getPackagePathInElmHome(elmVersion, name) { * * @param {Options} options * @param {VersionString} elmVersion - * @param {string} name + * @param {PackageName} name * @param {VersionString} packageVersion * @returns {Promise} */ diff --git a/lib/promisify-port.js b/lib/promisify-port.js index b7d6bb97e..56acb7681 100644 --- a/lib/promisify-port.js +++ b/lib/promisify-port.js @@ -1,5 +1,5 @@ /** - * @import { PortsToPromise } from './types/promisify-port'; + * @import {PortsToPromise} from './types/promisify-port'; */ module.exports = promisifyPort; @@ -16,7 +16,7 @@ function promisifyPort({subscribeTo, sendThrough, data}) { return new Promise((resolve) => { /** * @param {DataOut} result - * @returns void + * @returns {void} */ const handler = (result) => { subscribeTo.unsubscribe(handler); diff --git a/lib/remote-template.js b/lib/remote-template.js index 040d7c28f..b5e760c51 100644 --- a/lib/remote-template.js +++ b/lib/remote-template.js @@ -1,5 +1,6 @@ /** * @import {OptionsOfJSONResponseBody} from 'got'; + * @import {ErrorMessageInfo} from './types/error-message'; * @import {Options, Template} from './types/options'; * @import {ApplicationElmJson} from './types/content'; * @import {Path} from './types/path'; @@ -168,6 +169,7 @@ ${error.message}` } } +/** @type {ErrorMessageInfo} */ const rateLimitErrorMessage = { title: 'GITHUB RATE LIMIT EXCEEDED', message: `It looks like you exceeded the GitHub rate limit by using "--template" too many @@ -185,6 +187,7 @@ elm-review in your project: /** * @param {string} repoName + * @returns {ErrorMessageInfo} */ function repoNotFoundErrorMessage(repoName) { return { @@ -198,8 +201,9 @@ with private ones at the moment.` } /** - * @param {unknown} repoName - * @param {unknown} reference + * @param {string} repoName + * @param {string} reference + * @returns {ErrorMessageInfo} */ function commitNotFoundErrorMessage(repoName, reference) { return { @@ -220,6 +224,7 @@ Check the spelling and make sure it has been pushed.` * @param {string} commit * @param {string} basePath * @param {ApplicationElmJson} reviewElmJson + * @returns {Promise} */ async function downloadSourceDirectories( options, @@ -228,7 +233,7 @@ async function downloadSourceDirectories( basePath, reviewElmJson ) { - return await Promise.all( + await Promise.all( reviewElmJson['source-directories'].map(async (sourceDirectory) => { await downloadDirectory( options, @@ -247,6 +252,7 @@ async function downloadSourceDirectories( * @param {string} commit * @param {string} basePath * @param {string} directory + * @returns {Promise} */ async function downloadDirectory( options, @@ -300,7 +306,7 @@ async function downloadDirectory( * Returns a promise that resolves to null if the download was successful, or an error if it failed. * * @param {string} url - * @param {string} dest + * @param {Path} dest * @returns {Promise} */ async function downloadFile(url, dest) { @@ -315,16 +321,12 @@ async function downloadFile(url, dest) { }); } -/** - * @typedef {{message: string}} JsonResponse - */ - /** * Make a request to the GitHub API. * * @param {Options} options * @param {string} url - * @param {((arg: JsonResponse) => {title: string, message: string})} [handleNotFound] + * @param {((errorBody: {message: string}) => ErrorMessageInfo)} [handleNotFound] * @returns {Promise} */ async function makeGitHubApiRequest(options, url, handleNotFound) { diff --git a/lib/report.js b/lib/report.js index cea73f9de..3cc0aad2d 100644 --- a/lib/report.js +++ b/lib/report.js @@ -1,14 +1,14 @@ /** - * @import { Options } from './types/options'; - * @import { StyledMessage as StyledMsg } from './types/styled-message'; - * @import { SuppressedErrorsFile } from './types/suppressed'; + * @import {Options} from './types/options'; + * @import {Report} from './types/report'; */ const Benchmark = require('./benchmark'); const StyledMessage = require('./styled-message'); /** * @param {Options} options - * @param {{ errors?: { errors: unknown[]; path: unknown; }[] & StyledMsg; extracts?: unknown; suppressedErrors?: SuppressedErrorsFile[] }} result + * @param {Report} result + * @returns {Promise} */ async function report(options, result) { Benchmark.start(options, 'Writing error report'); @@ -25,27 +25,24 @@ async function report(options, result) { /** * @param {Options} options - * @param {{ errors?: { errors: unknown[]; path: unknown; }[]; extracts?: unknown; }} json + * @param {Report} json + * @returns {Promise} */ async function print(options, json) { if (options.reportOnOneLine) { if ((json.errors?.length ?? 0) > 0) { await safeConsoleLog( json.errors - ?.map( - ( - /** @type {{ errors: unknown[]; path: unknown; }} */ errorForFile - ) => { - return errorForFile.errors - .map((error) => { - return JSON.stringify({ - path: errorForFile.path, - .../** @type {object} */ (error) - }); - }) - .join('\n'); - } - ) + ?.map((errorForFile) => { + return errorForFile.errors + .map((error) => { + return JSON.stringify({ + path: errorForFile.path, + ...error + }); + }) + .join('\n'); + }) .join('\n') ?? '' ); } @@ -63,15 +60,16 @@ async function print(options, json) { /** * Prints a message in a way that will not be cut off. * + * @remarks * Printing large outputs to stdout is not recommended because at times * console.log is asynchronous and returns before ensuring that the whole * output has been printed. Check out these links for more details: * - * - https://nodejs.org/api/process.html#process_process_exit_code - * - https://github.com/nodejs/node/issues/6456 - * - https://github.com/nodejs/node/issues/19218 + * - + * - nodejs/node#6456 + * - nodejs/node#19218 * - * Using process.stdout.write and passing a function ensures that + * Using {@linkcode process.stdout.write} and passing a function ensures that * the whole output has been written. * * @param {string} message - Message to print. diff --git a/lib/result-cache-json.js b/lib/result-cache-json.js index 01ff6cafd..c15d8d15d 100644 --- a/lib/result-cache-json.js +++ b/lib/result-cache-json.js @@ -1,7 +1,7 @@ // @ts-expect-error(TS6133): There's a bug in noUnusedLocals (microsoft/TypeScript#58368). /** @import {Replacer, Reviver} from './types/json'; */ // @ts-expect-error(TS6133): There's a bug in noUnusedLocals (microsoft/TypeScript#58368). -/** @import {Value, ValueStruct} from './types/elm-internals'; */ +/** @import {ElmArray, Value, ValueStruct} from './types/elm-internals'; */ /** @type {Replacer} */ function replacer(_key, value_) { @@ -57,6 +57,7 @@ function replacer(_key, value_) { /** * @param {ValueStruct} xs + * @returns {ElmArray[] | null} */ function prudentListToArray(xs) { const out = []; @@ -113,7 +114,8 @@ function reviver(_, value_) { const _ListNilPROD = {$: 0}; /** - * @param {string | string[]} array + * @param {ElmArray} array + * @returns {ValueStruct} */ function _ListFromArrayPROD(array) { let out = _ListNilPROD; diff --git a/lib/result-cache-worker.js b/lib/result-cache-worker.js index c560d7c11..5c87a11ef 100644 --- a/lib/result-cache-worker.js +++ b/lib/result-cache-worker.js @@ -12,6 +12,7 @@ if (parentPort) { /** * @param {MessagePort} parentPort + * @returns {void} */ function subscribe(parentPort) { parentPort.on('message', ({filePath, cacheEntry, cacheKey}) => { diff --git a/lib/result-cache.js b/lib/result-cache.js index c602f5c4a..f53e132fe 100644 --- a/lib/result-cache.js +++ b/lib/result-cache.js @@ -124,7 +124,6 @@ async function load(options, ignoredDirs, ignoredFiles, cacheFolder) { } /** - * * @param {RuleName} ruleName * @param {RuleId} ruleId * @returns {CacheKey} diff --git a/lib/review-dependencies.js b/lib/review-dependencies.js index 3f05a1f2e..68a4dca53 100644 --- a/lib/review-dependencies.js +++ b/lib/review-dependencies.js @@ -8,6 +8,7 @@ const ProjectJsonFiles = require('./project-json-files'); /** * @param {ApplicationDependencyList} reviewDirectDependencies * @param {VersionString} elmVersion + * @returns {Promise>} */ async function collectRuleLinks(reviewDirectDependencies, elmVersion) { const elmJsonForReviewDependenciesPromises = Object.entries( @@ -36,6 +37,7 @@ async function collectRuleLinks(reviewDirectDependencies, elmVersion) { /** * @param {ApplicationDependencyList} reviewDirectDependencies * @param {PackageElmJson[]} elmJsonForReviewDependencies + * @returns {Record} */ function computeLinksToRuleDocs( reviewDirectDependencies, @@ -76,6 +78,7 @@ function computeLinksToRuleDocs( * @param {PackageName} dependencyName * @param {VersionString} packageVersion * @param {string} moduleName + * @returns {string} */ function linkToModule(dependencyName, packageVersion, moduleName) { const urlModuleName = moduleName.split('.').join('-'); diff --git a/lib/run-review.js b/lib/run-review.js index 129096537..0111c2499 100644 --- a/lib/run-review.js +++ b/lib/run-review.js @@ -66,6 +66,7 @@ let isVeryFirstRun = true; /** * @param {Options} options * @param {ReviewApp} app + * @returns {void} */ function startReview(options, app) { if (options.report !== 'json' && !isVeryFirstRun) { @@ -79,6 +80,7 @@ function startReview(options, app) { /** * @param {Options} options * @param {ReviewApp} app + * @returns {void} */ function requestReview(options, app) { if (AppState.requestReview()) { diff --git a/lib/runner.js b/lib/runner.js index 22351a3e0..0b5478014 100755 --- a/lib/runner.js +++ b/lib/runner.js @@ -1,12 +1,14 @@ #!/usr/bin/env node /** - * @import {Options} from './types/options'; * @import {ReviewApp, FileReceipt} from './types/app'; - * @import {ElmFile, Readme, ElmJsonData, Dependencies, LinksToRuleDocs, NonElmFiles, ExtraFileRequest, ApplicationElmJson} from './types/content' - * @import {SuppressedErrorsFile} from './types/suppressed'; * @import {AppHash} from './types/build'; + * @import {ApplicationElmJson, Dependencies, ElmFile, ElmJsonData, ExtraFileRequest, LinksToRuleDocs, NonElmFiles, Readme} from './types/content'; * @import {FixMode} from './types/fix'; + * @import {Options} from './types/options'; + * @import {ReportedError} from './types/report'; + * @import {RunOptions} from'./types/runner'; + * @import {SuppressedErrorsFile} from './types/suppressed'; */ const exit = require('../vendor/exit'); const AppWrapper = require('./app-wrapper'); @@ -104,6 +106,7 @@ async function sendProjectContent( * @param {string} elmModulePath * @param {ApplicationElmJson} reviewElmJson * @param {AppHash} appHash + * @returns {Promise} */ async function initializeApp(options, elmModulePath, reviewElmJson, appHash) { const app = AppWrapper.init(options, elmModulePath, { @@ -131,7 +134,10 @@ async function initializeApp(options, elmModulePath, reviewElmJson, appHash) { }); AppState.subscribe( app.ports.abortForConfigurationErrors, - /** @returns {never} */ + /** + * @param {ReportedError[]} errors + * @returns {never} + */ (errors) => { Report.report(options, {errors}); exit(1); @@ -245,6 +251,7 @@ function fixMode(options) { /** * @param {string} message + * @returns {void} */ function throwOnError(message) { throw new ErrorMessage.CustomError( diff --git a/lib/spinner.js b/lib/spinner.js index 00c8a5de3..bcef9dba8 100644 --- a/lib/spinner.js +++ b/lib/spinner.js @@ -74,6 +74,7 @@ function fail(text) { /** * @template {(v: string) => void} T * @param {T} func + * @returns {(T | (() => void))} */ function exportFunc(func) { return options.report === 'json' ? () => {} : func; diff --git a/lib/state.js b/lib/state.js index 416ab20db..71c4fe823 100644 --- a/lib/state.js +++ b/lib/state.js @@ -217,6 +217,9 @@ function getFileFromMemoryCache(filePath) { return model.elmFilesCacheForWatch.get(filePath); } +/** + * @returns {FilesProposedByCurrentFix} + */ function filesProposedByCurrentFix() { return model.filesProposedByCurrentFix; } diff --git a/lib/styled-message.js b/lib/styled-message.js index aa95dd485..3cbb1c427 100644 --- a/lib/styled-message.js +++ b/lib/styled-message.js @@ -14,6 +14,7 @@ const wrap = require('wrap-ansi'); * @param {Options} options * @param {StyledMessage} message * @param {boolean} clearFixLine + * @returns {void} */ function clearAndLog(options, message, clearFixLine) { if (options.watch && !options.debug && options.report !== 'json') { @@ -29,6 +30,7 @@ function clearAndLog(options, message, clearFixLine) { /** * @param {Options} options * @param {StyledMessage} message + * @returns {void} */ function log(options, message) { const colorEnabled = options.color !== false && options.report === null; @@ -40,7 +42,7 @@ function log(options, message) { /** * @param {boolean} colorEnabled * @param {StyledMessage} message - * @returns + * @returns {string} */ function styleMessage(colorEnabled, message) { return message @@ -102,6 +104,9 @@ function wrapLinesForTerminal(message) { // CLEARING CONSOLE +/** + * @returns {void} + */ function clearConsole() { process.stdout.write( process.platform === 'win32' diff --git a/lib/template-dependencies.js b/lib/template-dependencies.js index 2a4b8c1cc..4222ab156 100644 --- a/lib/template-dependencies.js +++ b/lib/template-dependencies.js @@ -335,6 +335,9 @@ function update(options, elmJson) { return elmJson; } +/** + * @returns {void} + */ function teardownDependenciesProvider() { if (dependencyProvider) { dependencyProvider.tearDown(); diff --git a/lib/types/app.ts b/lib/types/app.ts index 54a9a1078..066c4414b 100644 --- a/lib/types/app.ts +++ b/lib/types/app.ts @@ -8,10 +8,12 @@ import type { Readme, Source } from './content.ts'; -import type {ElmNamespace, ElmApp} from './elm-js.js'; +import type {ElmNamespace, ElmApp} from './elm-js.ts'; +import type {ErrorMessageInfo} from './error-message.ts'; import type {Flags} from './flags.ts'; import type {Path} from './path.ts'; import type {SendPort, SubscribePort} from './promisify-port.ts'; +import type {ReportedError} from './report.ts'; import type {FilesProposedByCurrentFix} from './state.ts'; import type {StyledMessage} from './styled-message.ts'; import type {SuppressedErrorsFile} from './suppressed.ts'; @@ -52,10 +54,8 @@ export type Ports = { fixConfirmationStatus: SubscribePort; askForFixConfirmationStatus: SendPort; abort: SubscribePort; - abortWithDetails: SubscribePort<{title: string; message: string}>; - abortForConfigurationErrors: SubscribePort< - {errors: unknown[]; path: unknown}[] & StyledMessage - >; + abortWithDetails: SubscribePort; + abortForConfigurationErrors: SubscribePort; }; export type FileReceipt = { diff --git a/lib/types/content.ts b/lib/types/content.ts index 11b53d666..a1fcaedb5 100644 --- a/lib/types/content.ts +++ b/lib/types/content.ts @@ -67,12 +67,23 @@ export type ExtraFileRequest = { excludedDirectories: string[]; }; +export type ProjectFiles = { + elmJsonData: ElmJsonData; + readme: Readme | null; + elmFiles: ElmFile[]; + sourceDirectories: Path[]; +}; + export type Dependencies = Dependency[]; -export type Dependency = unknown; +export type Dependency = { + name: PackageName; + docsJson: unknown; + elmJson: PackageElmJson; +}; export type LinksToRuleDocs = Record; -export type Source = string; +export type Source = Path; export type Ast = Record; diff --git a/lib/types/elm-internals.ts b/lib/types/elm-internals.ts index b503d55fe..5f4cae514 100644 --- a/lib/types/elm-internals.ts +++ b/lib/types/elm-internals.ts @@ -1,7 +1,8 @@ export type Value = null | ValueStruct | number | string; export type ValueStruct = { - readonly $: 1 | -1 | 0 | `$L`; - readonly a?: string[] | string; + readonly $: 1 | -1 | 0 | '$L'; + readonly a?: ElmArray; readonly b?: ValueStruct; readonly c?: unknown; }; +export type ElmArray = string[] | string; diff --git a/lib/types/error-message.ts b/lib/types/error-message.ts new file mode 100644 index 000000000..8c1a0563c --- /dev/null +++ b/lib/types/error-message.ts @@ -0,0 +1,4 @@ +export type ErrorMessageInfo = { + title: string; + message: string; +}; diff --git a/lib/types/parse-elm.ts b/lib/types/parse-elm.ts index 99d1617f9..1d461250d 100644 --- a/lib/types/parse-elm.ts +++ b/lib/types/parse-elm.ts @@ -1,7 +1,8 @@ -import type {ElmApp, ElmNamespace} from './elm-js.js'; +import type {ElmApp, ElmNamespace} from './elm-js.ts'; import type {Ast, ElmFile, Source} from './content.ts'; import type {Path} from './path.ts'; import type {SendPort, SubscribePort} from './promisify-port.ts'; +import type {Worker} from 'node:worker_threads'; export type ParseJob = { elmParserPath: Path; @@ -21,3 +22,11 @@ type ParserPorts = { requestParsing: SendPort; parseResult: SubscribePort; }; + +/** + * A worker thread and whether it is currently busy. + */ +export type CustomWorker = { + worker: Worker; + busy: boolean; +}; diff --git a/lib/types/report.ts b/lib/types/report.ts new file mode 100644 index 000000000..a699d12ec --- /dev/null +++ b/lib/types/report.ts @@ -0,0 +1,14 @@ +import type {StyledMessagePart} from './styled-message.ts'; +import type {SuppressedErrorsFile} from './suppressed.ts'; + +export type ReportedError = StyledMessagePart & { + errors: object[]; + path: unknown; + extracts?: unknown; +}; + +export type Report = { + errors?: ReportedError[]; + extracts?: unknown; + suppressedErrors?: SuppressedErrorsFile[]; +}; diff --git a/lib/types/runner.ts b/lib/types/runner.ts new file mode 100644 index 000000000..caef57ec2 --- /dev/null +++ b/lib/types/runner.ts @@ -0,0 +1,12 @@ +import type {ReviewApp} from './app.ts'; +import type {ElmFile, ElmJsonData, ExtraFileRequest} from './content.ts'; +import type {VersionString} from './version.js'; + +export type RunOptions = { + app: ReviewApp; + elmVersion: VersionString; + elmJsonData: ElmJsonData; + elmFiles: ElmFile[]; + sourceDirectories: string[]; + requestedExtraFiles: ExtraFileRequest[]; +}; diff --git a/lib/types/version.ts b/lib/types/version.ts index 9ccf209fe..733046d10 100644 --- a/lib/types/version.ts +++ b/lib/types/version.ts @@ -1,9 +1,9 @@ /** - * A major.minor version string, e.g. "1.0.0" + * A "major.minor.patch" version string, e.g. `1.0.0`. */ export type VersionString = `${number}.${number}.${number}`; /** - * A dependency support version, e.g. "1.0.0 <= v < 2.0.0" + * A dependency support version, e.g. `1.0.0 <= v < 2.0.0`. */ export type VersionRange = `${VersionString} <= v < ${VersionString}`; diff --git a/lib/types/watch.ts b/lib/types/watch.ts index ba3051606..26cf733c0 100644 --- a/lib/types/watch.ts +++ b/lib/types/watch.ts @@ -1,18 +1,8 @@ -import type {ReviewApp} from './app.ts'; -import type { - ApplicationElmJson, - ElmFile, - ElmJsonData, - ExtraFileRequest -} from './content.ts'; +import type {ApplicationElmJson} from './content.ts'; import type {Path} from './path.ts'; +import type {RunOptions} from './runner.ts'; -export type WatchOptions = { - app: ReviewApp; - elmJsonData: ElmJsonData; - elmFiles: ElmFile[]; - sourceDirectories: Path[]; +export type WatchOptions = RunOptions & { reviewElmJson: ApplicationElmJson; reviewElmJsonPath: Path | null; - requestedExtraFiles: ExtraFileRequest[]; }; diff --git a/lib/utils.js b/lib/utils.js index f0ed6f087..fd49ab6d5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -14,6 +14,7 @@ function unique(array) { * Otherwise, wrap it in a generic error. * * @param {unknown} error + * @returns {Error} */ function intoError(error) { return error instanceof Error ? error : new Error(String(error)); diff --git a/lib/watch.js b/lib/watch.js index d254f0e86..eb665f746 100644 --- a/lib/watch.js +++ b/lib/watch.js @@ -438,6 +438,9 @@ function createExtraFilesWatcher(options, app, runReview, onError, request) { * @returns {FSWatcher} */ function createSuppressedFilesWatcher(options, app, onError) { + /** + * @returns {void} + */ function updateSuppressedErrors() { // TODO(@jfmengels): Write last save time for each of these in appstate, // and compare with the last update time that is given as argument to @@ -468,6 +471,9 @@ function createSuppressedFilesWatcher(options, app, onError) { .on('error', onError); } +/** + * @returns {void} + */ function clearConsole() { process.stdout.write( process.platform === 'win32' diff --git a/new-package/elm-review-package-tests/check-previews-compile.js b/new-package/elm-review-package-tests/check-previews-compile.js index 7df56f84e..13699cdc5 100644 --- a/new-package/elm-review-package-tests/check-previews-compile.js +++ b/new-package/elm-review-package-tests/check-previews-compile.js @@ -16,6 +16,7 @@ for (const example of findPreviewConfigurations()) { /** * @param {string} exampleConfiguration + * @returns {void} */ function checkThatExampleCompiles(exampleConfiguration) { const exampleConfigurationElmJson = require(`${exampleConfiguration}/elm.json`); @@ -67,6 +68,7 @@ and make the necessary changes to make it compile.` /** * @param {string} config + * @returns {void} */ function success(config) { console.log(`${Ansi.green('✔')} ${path.relative(root, config)}/ compiles`); @@ -75,6 +77,7 @@ function success(config) { /** * @param {string} exampleConfiguration * @param {Record} previewDependencies + * @returns {void} */ function checkDepsAreCompatible(exampleConfiguration, previewDependencies) { for (const [depName, constraint] of Object.entries(packageDependencies)) { @@ -109,6 +112,7 @@ function checkDepsAreCompatible(exampleConfiguration, previewDependencies) { * @param {string} depName * @param {string} constraint * @param {string} version + * @returns {void} */ function checkConstraint(exampleConfiguration, depName, constraint, version) { const [minVersion] = constraint.split(' <= v < ').map(splitVersion); @@ -128,6 +132,7 @@ function checkConstraint(exampleConfiguration, depName, constraint, version) { /** * @param {string} version + * @returns {number[]} */ function splitVersion(version) { return version.split('.').map((n) => Number.parseInt(n, 10)); diff --git a/new-package/elm-review-package-tests/helpers/ansi.js b/new-package/elm-review-package-tests/helpers/ansi.js index 5eaa78f5a..24eb0148b 100644 --- a/new-package/elm-review-package-tests/helpers/ansi.js +++ b/new-package/elm-review-package-tests/helpers/ansi.js @@ -1,5 +1,6 @@ /** * @param {string} text + * @returns {string} */ function red(text) { return `\u001B[31m${text}\u001B[39m`; @@ -7,6 +8,7 @@ function red(text) { /** * @param {string} text + * @returns {string} */ function green(text) { return `\u001B[32m${text}\u001B[39m`; @@ -14,6 +16,7 @@ function green(text) { /** * @param {string} text + * @returns {string} */ function yellow(text) { return `\u001B[33m${text}\u001B[39m`; diff --git a/new-package/maintenance/update-examples-from-preview.js b/new-package/maintenance/update-examples-from-preview.js index bd82369e8..7c229ef0c 100755 --- a/new-package/maintenance/update-examples-from-preview.js +++ b/new-package/maintenance/update-examples-from-preview.js @@ -28,6 +28,9 @@ if (require.main === module) { * @property {Record} indirect */ +/** + * @returns {void} + */ function copyPreviewsToExamples() { const previewFolders = findPreviewConfigurations(); for (const folder of previewFolders) { @@ -37,6 +40,7 @@ function copyPreviewsToExamples() { /** * @param {string} pathToPreviewFolder + * @returns {void} */ function copyPreviewToExample(pathToPreviewFolder) { const pathToExampleFolder = `${pathToPreviewFolder}/`.replace( diff --git a/package-lock.json b/package-lock.json index 18379a50a..5bdb2c2ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1", + "@package-json/types": "^0.0.11", "@types/cross-spawn": "~6.0.6", "@types/folder-hash": "~3.3.0", "@types/fs-extra": "~9.0.13", @@ -1717,6 +1718,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@package-json/types": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@package-json/types/-/types-0.0.11.tgz", + "integrity": "sha512-allOTUn4Xi2bQMs+mthzHWekgjRBVno+DLOcXk9+6haG5oFu5rlz0pszT3sh1OAkQVFLYrAS4V5CSxWyVwUf7g==", + "dev": true + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -12074,6 +12081,12 @@ } } }, + "@package-json/types": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@package-json/types/-/types-0.0.11.tgz", + "integrity": "sha512-allOTUn4Xi2bQMs+mthzHWekgjRBVno+DLOcXk9+6haG5oFu5rlz0pszT3sh1OAkQVFLYrAS4V5CSxWyVwUf7g==", + "dev": true + }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", diff --git a/package.json b/package.json index 9f30f108f..3fbcc3719 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1", + "@package-json/types": "^0.0.11", "@types/cross-spawn": "~6.0.6", "@types/folder-hash": "~3.3.0", "@types/fs-extra": "~9.0.13", diff --git a/test/jest-helpers/cli.js b/test/jest-helpers/cli.js index 53f8cf1d5..d1b0fd241 100644 --- a/test/jest-helpers/cli.js +++ b/test/jest-helpers/cli.js @@ -12,7 +12,8 @@ expect.extend({toMatchFile}); /** * @param {string} args - * @param {Options} [options=undefined] + * @param {Options} [options] + * @returns */ async function run(args, options) { return await internalExec(`--FOR-TESTS ${args}`, options); @@ -20,7 +21,7 @@ async function run(args, options) { /** * @param {string} args - * @param {Options | undefined} [options=undefined] + * @param {Options | undefined} [options] * @returns {Promise} */ async function runAndExpectError(args, options) { @@ -36,7 +37,8 @@ async function runAndExpectError(args, options) { /** * @param {string} args - * @param {Options | undefined} [options=undefined] + * @param {Options | undefined} [options] + * @returns */ async function runWithoutTestMode(args, options) { return await internalExec(args, options); @@ -44,7 +46,8 @@ async function runWithoutTestMode(args, options) { /** * @param {string} args - * @param {Options} [options=undefined] + * @param {Options} [options] + * @returns */ async function internalExec(args, options = {}) { // Overriding FORCE_COLOR because Jest forcefully adds it as well, @@ -67,6 +70,7 @@ async function internalExec(args, options = {}) { /** * @param {Options} options + * @returns */ function cwdFromOptions(options) { if (options.project) { @@ -78,6 +82,7 @@ function cwdFromOptions(options) { /** * @param {Options} options + * @returns */ function reportMode(options) { if (!options.report) { @@ -89,6 +94,7 @@ function reportMode(options) { /** * @param {Options} options + * @returns */ function colors(options) { if (options.colors) { diff --git a/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/check-previews-compile.js b/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/check-previews-compile.js index a577b2c98..dcafe0169 100644 --- a/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/check-previews-compile.js +++ b/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/check-previews-compile.js @@ -15,6 +15,7 @@ for (const example of findPreviewConfigurations()) { /** * @param {string} exampleConfiguration + * @returns {void} */ function checkThatExampleCompiles(exampleConfiguration) { const exampleConfigurationElmJson = require(`${exampleConfiguration}/elm.json`); @@ -66,6 +67,7 @@ and make the necessary changes to make it compile.` /** * @param {string} config + * @returns {void} */ function success(config) { console.log(`${Ansi.green('✔')} ${path.relative(root, config)}/ compiles`); @@ -74,6 +76,7 @@ function success(config) { /** * @param {string} exampleConfiguration * @param {Record} previewDependencies + * @returns {void} */ function checkDepsAreCompatible(exampleConfiguration, previewDependencies) { for (const [depName, constraint] of Object.entries(packageDependencies)) { @@ -108,6 +111,7 @@ function checkDepsAreCompatible(exampleConfiguration, previewDependencies) { * @param {string} depName * @param {string} constraint * @param {string} version + * @returns {void} */ function checkConstraint(exampleConfiguration, depName, constraint, version) { const [minVersion] = constraint.split(' <= v < ').map(splitVersion); @@ -127,6 +131,7 @@ function checkConstraint(exampleConfiguration, depName, constraint, version) { /** * @param {string} version + * @returns {number[]} */ function splitVersion(version) { return version.split('.').map((n) => Number.parseInt(n, 10)); diff --git a/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/helpers/ansi.js b/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/helpers/ansi.js index 5eaa78f5a..24eb0148b 100644 --- a/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/helpers/ansi.js +++ b/test/run-snapshots/elm-review-something-for-new-rule/elm-review-package-tests/helpers/ansi.js @@ -1,5 +1,6 @@ /** * @param {string} text + * @returns {string} */ function red(text) { return `\u001B[31m${text}\u001B[39m`; @@ -7,6 +8,7 @@ function red(text) { /** * @param {string} text + * @returns {string} */ function green(text) { return `\u001B[32m${text}\u001B[39m`; @@ -14,6 +16,7 @@ function green(text) { /** * @param {string} text + * @returns {string} */ function yellow(text) { return `\u001B[33m${text}\u001B[39m`; diff --git a/test/run-snapshots/elm-review-something-for-new-rule/maintenance/update-examples-from-preview.js b/test/run-snapshots/elm-review-something-for-new-rule/maintenance/update-examples-from-preview.js index bd82369e8..7c229ef0c 100755 --- a/test/run-snapshots/elm-review-something-for-new-rule/maintenance/update-examples-from-preview.js +++ b/test/run-snapshots/elm-review-something-for-new-rule/maintenance/update-examples-from-preview.js @@ -28,6 +28,9 @@ if (require.main === module) { * @property {Record} indirect */ +/** + * @returns {void} + */ function copyPreviewsToExamples() { const previewFolders = findPreviewConfigurations(); for (const folder of previewFolders) { @@ -37,6 +40,7 @@ function copyPreviewsToExamples() { /** * @param {string} pathToPreviewFolder + * @returns {void} */ function copyPreviewToExample(pathToPreviewFolder) { const pathToExampleFolder = `${pathToPreviewFolder}/`.replace( diff --git a/test/run-snapshots/elm-review-something/elm-review-package-tests/check-previews-compile.js b/test/run-snapshots/elm-review-something/elm-review-package-tests/check-previews-compile.js index a577b2c98..dcafe0169 100644 --- a/test/run-snapshots/elm-review-something/elm-review-package-tests/check-previews-compile.js +++ b/test/run-snapshots/elm-review-something/elm-review-package-tests/check-previews-compile.js @@ -15,6 +15,7 @@ for (const example of findPreviewConfigurations()) { /** * @param {string} exampleConfiguration + * @returns {void} */ function checkThatExampleCompiles(exampleConfiguration) { const exampleConfigurationElmJson = require(`${exampleConfiguration}/elm.json`); @@ -66,6 +67,7 @@ and make the necessary changes to make it compile.` /** * @param {string} config + * @returns {void} */ function success(config) { console.log(`${Ansi.green('✔')} ${path.relative(root, config)}/ compiles`); @@ -74,6 +76,7 @@ function success(config) { /** * @param {string} exampleConfiguration * @param {Record} previewDependencies + * @returns {void} */ function checkDepsAreCompatible(exampleConfiguration, previewDependencies) { for (const [depName, constraint] of Object.entries(packageDependencies)) { @@ -108,6 +111,7 @@ function checkDepsAreCompatible(exampleConfiguration, previewDependencies) { * @param {string} depName * @param {string} constraint * @param {string} version + * @returns {void} */ function checkConstraint(exampleConfiguration, depName, constraint, version) { const [minVersion] = constraint.split(' <= v < ').map(splitVersion); @@ -127,6 +131,7 @@ function checkConstraint(exampleConfiguration, depName, constraint, version) { /** * @param {string} version + * @returns {number[]} */ function splitVersion(version) { return version.split('.').map((n) => Number.parseInt(n, 10)); diff --git a/test/run-snapshots/elm-review-something/elm-review-package-tests/helpers/ansi.js b/test/run-snapshots/elm-review-something/elm-review-package-tests/helpers/ansi.js index 5eaa78f5a..24eb0148b 100644 --- a/test/run-snapshots/elm-review-something/elm-review-package-tests/helpers/ansi.js +++ b/test/run-snapshots/elm-review-something/elm-review-package-tests/helpers/ansi.js @@ -1,5 +1,6 @@ /** * @param {string} text + * @returns {string} */ function red(text) { return `\u001B[31m${text}\u001B[39m`; @@ -7,6 +8,7 @@ function red(text) { /** * @param {string} text + * @returns {string} */ function green(text) { return `\u001B[32m${text}\u001B[39m`; @@ -14,6 +16,7 @@ function green(text) { /** * @param {string} text + * @returns {string} */ function yellow(text) { return `\u001B[33m${text}\u001B[39m`; diff --git a/test/run-snapshots/elm-review-something/maintenance/update-examples-from-preview.js b/test/run-snapshots/elm-review-something/maintenance/update-examples-from-preview.js index bd82369e8..7c229ef0c 100755 --- a/test/run-snapshots/elm-review-something/maintenance/update-examples-from-preview.js +++ b/test/run-snapshots/elm-review-something/maintenance/update-examples-from-preview.js @@ -28,6 +28,9 @@ if (require.main === module) { * @property {Record} indirect */ +/** + * @returns {void} + */ function copyPreviewsToExamples() { const previewFolders = findPreviewConfigurations(); for (const folder of previewFolders) { @@ -37,6 +40,7 @@ function copyPreviewsToExamples() { /** * @param {string} pathToPreviewFolder + * @returns {void} */ function copyPreviewToExample(pathToPreviewFolder) { const pathToExampleFolder = `${pathToPreviewFolder}/`.replace( diff --git a/vendor/types/node-elm-compiler.ts b/vendor/types/node-elm-compiler.ts index e5bd98e33..8ce80923d 100644 --- a/vendor/types/node-elm-compiler.ts +++ b/vendor/types/node-elm-compiler.ts @@ -1,17 +1,19 @@ import type {ChildProcess, SpawnOptions} from 'node:child_process'; import type {ReportMode} from '../../lib/types/options'; +import type {Path} from '../../lib/types/path'; +import type {Source} from '../../lib/types/content'; export type CompileOptions = { spawn?: Spawner; - cwd: string; - output: string; + cwd: Path; + output: Path; debug: boolean; optimize: boolean; verbose: boolean; warn: boolean; report: ReportMode; - pathToElm: string; + pathToElm: Path; help?: undefined; docs?: undefined; processOpts: ProcessOptions; @@ -23,9 +25,9 @@ export interface ProcessOptions { } export type Spawner = ( - pathToElm: string, + pathToElm: Path, processArgs: SpawnOptions, processOpts: ProcessOptions ) => ChildProcess; -export type Sources = string | string[]; +export type Sources = Source | Source[];