Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
cf1ba92
chore: enable `noImplicitAny` on `elm-binary.js`
lishaduck Nov 4, 2024
78f3479
fix: type-level arithmetic!
lishaduck Nov 4, 2024
03479d3
chore: enable `noImplicitAny` on `template-dependencies.js`
lishaduck Nov 4, 2024
70aae3f
chore: add watch-strict script to ease `noImplicitAny` adoption
lishaduck Nov 4, 2024
a5faaca
chore: enable `noImplicitAny` on `result-cache-worker.js`
lishaduck Nov 4, 2024
860a198
refactor: define CacheRequest type
lishaduck Nov 4, 2024
d336723
fix: readAst returns an Ast, not an ElmFile
lishaduck Nov 4, 2024
f02acd1
fix: use unknown over object, which ts now treats as any
lishaduck Nov 4, 2024
834c54a
chore: enable `noImplicitAny` on `result-cache.js`
lishaduck Nov 4, 2024
8b76474
fix: more types
lishaduck Nov 4, 2024
28c23bf
fix: remove redundant annotation
lishaduck Nov 4, 2024
ad4f70a
chore: enable `noImplicitAny` on `review-dependencies.js`
lishaduck Nov 4, 2024
a06b3c7
chore: enable `noImplicitAny` on `project-dependencies.js`
lishaduck Nov 4, 2024
17644f0
chore: enable `noImplicitAny` on `runner.js`
lishaduck Nov 4, 2024
7f6e6a7
chore: enable `noImplicitAny` on `app-wrapper.js`
lishaduck Nov 4, 2024
b2c7e04
chore: enable `noImplicitAny` on `autofix.js`
lishaduck Nov 4, 2024
8acbcea
chore: enable `noImplicitAny` on `remote-template.js`
lishaduck Nov 4, 2024
a6fa97b
chore: enable `noImplicitAny` on `optimize-js.js`
lishaduck Nov 4, 2024
e7c5864
chore: update type imports to use ts extensions
lishaduck Nov 4, 2024
d0f19fc
chore: enable `noImplicitAny` on `build.js`
lishaduck Nov 4, 2024
da322ba
chore: enable `noImplicitAny` on `elm-app-worker.js`
lishaduck Nov 4, 2024
3552ccd
chore: enable `noImplicitAny` on `init.js`
lishaduck Nov 4, 2024
98a0279
chore: enable `noImplicitAny` on `new-package.js`
lishaduck Nov 4, 2024
a64d587
chore: enable `noImplicitAny` on `main.js`
lishaduck Nov 4, 2024
ffe85cc
chore: enable `noImplicitAny` on `module-cache.js`
lishaduck Nov 4, 2024
f68a16d
chore: enable `noImplicitAny` on `run-review.js`
lishaduck Nov 4, 2024
fd34ca9
chore: enable `noImplicitAny` on `watch.js`
lishaduck Nov 4, 2024
505261a
chore: enable `noImplicitAny` on `new-package/`
lishaduck Nov 4, 2024
4e91e56
chore: remove `tsconfig.no-implicit-any.json`
lishaduck Nov 4, 2024
fd4fd3a
chore: enable blanket strict mode
lishaduck Nov 4, 2024
c13b9ff
chore: make eslint depend on tsconfig
lishaduck Nov 4, 2024
d7b4155
chore: add offline testing script
lishaduck Nov 4, 2024
bdaa693
Update maintenance file snapshots
jfmengels Nov 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions lib/app-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,7 @@ function subscribe(port) {
function unsubscribe(port) {
// eslint-disable-next-line promise/prefer-await-to-callbacks -- Callbacks are still needed here.
return (callback) => {
listeners[port] = listeners[port].filter(
(/** @type {Listened<unknown>} */ fn) => fn === callback
);
listeners[port] = listeners[port].filter((fn) => fn === callback);
};
}

Expand Down
5 changes: 1 addition & 4 deletions lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,7 @@ I can help set you up with an initial configuration if you run ${chalk.magenta('
*/
async function buildFromGitHubTemplate(options, template) {
Spinner.setText('Fetching template information');
const commit = await RemoteTemplate.getRelevantCommit(
options,
options.template
);
const commit = await RemoteTemplate.getRelevantCommit(options, template);
const reviewElmJson = await RemoteTemplate.getRemoteElmJson(
options,
template,
Expand Down
4 changes: 2 additions & 2 deletions lib/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const FS = require('./fs-wrapper');
const AppState = require('./state');

/**
* @template {object} T
* @template T
* @param {Path} folder
* @param {string} key
* @param {() => Promise<T | null>} fn
Expand Down Expand Up @@ -39,7 +39,7 @@ const ensuredFolders = new Set();
* Cache a file on the filesystem.
*
* @param {string} filepath - Path to the file ending in ".json"
* @param {object} content
* @param {unknown} content
* @returns {Promise<void>}
*/
async function cacheJsonFile(filepath, content) {
Expand Down
6 changes: 3 additions & 3 deletions lib/elm-files.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @import {ElmFile, Source, Readme, ElmJson, ElmJsonData, SourceDirectories} from './types/content';
* @import {ElmFile, Source, Readme, ElmJson, ElmJsonData, SourceDirectories, Ast} from './types/content';
* @import {ReviewOptions} from './types/options';
* @import {Path} from './types/path';
*/
Expand Down Expand Up @@ -189,7 +189,7 @@ async function readFile(
path: OsHelpers.makePathOsAgnostic(relativeFilePath),
source,
lastUpdatedTime,
ast: cachedAst || (await readAst(options, elmParserPath, source))
ast: cachedAst ?? (await readAst(options, elmParserPath, source))
};
}

Expand All @@ -199,7 +199,7 @@ async function readFile(
* @param {ReviewOptions} options
* @param {Path} elmParserPath
* @param {Source} source
* @returns {Promise<ElmFile | null>}
* @returns {Promise<Ast | null>}
*/
async function readAst(options, elmParserPath, source) {
const hash = Hash.hash(source);
Expand Down
4 changes: 2 additions & 2 deletions lib/fs-wrapper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @import {Path} from './types/path';
* @import {Replacer, Reviver} from './types/json';
* @import {Path} from './types/path';
*/
const fs = require('graceful-fs');
const fsp = fs.promises;
Expand Down Expand Up @@ -51,7 +51,7 @@ async function readFile(file, options) {
* Write a JSON file.
*
* @param {string} file
* @param {object} content
* @param {unknown} content
* @param {string | number | undefined} [space=undefined]
* @param {Replacer | undefined} [replacer=undefined]
* @returns {Promise<void>}
Expand Down
11 changes: 8 additions & 3 deletions lib/min-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ const chalk = require('chalk');
const ErrorMessage = require('./error-message');
const PathHelpers = require('./path-helpers');

const minimalVersion = {major: 2, minor: 14};
// prettier-ignore
const supportedRange = `${minimalVersion.major}.${minimalVersion.minor}.0 <= v < ${minimalVersion.major + 1}.0.0`
const minimalVersion = /** @type {const} */ ({major: 2, minor: 14});

// TS can't do arithmetic, so make sure the cast is right when bumping the major.
const nextMajor = /** @type {3} */ (minimalVersion.major + 1);

const supportedRange = /** @type {const} */ (
`${minimalVersion.major}.${minimalVersion.minor}.0 <= v < ${nextMajor}.0.0`
);

/**
* If given an input version string smaller than the hardcoded `minimalVersion`,
Expand Down
12 changes: 10 additions & 2 deletions lib/new-rule.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,18 @@ async function addRule(options, elmJson, ruleName, ruleType) {

if (elmJson.type === 'package' && packageNameRegex.test(elmJson.name)) {
console.log('Exposing the rule in elm.json');
if (!elmJson['exposed-modules'].includes(ruleName)) {

const exposedModules = Array.isArray(elmJson['exposed-modules'])
? elmJson['exposed-modules']
: Object.values(elmJson['exposed-modules']).reduce((acc, items) => [
...acc,
...items
]);

if (!exposedModules.includes(ruleName)) {
const newElmJson = {
...elmJson,
'exposed-modules': [...elmJson['exposed-modules'], ruleName].sort()
'exposed-modules': [...exposedModules, ruleName].sort()
};

writeFile(dir, 'elm.json', JSON.stringify(newElmJson, null, 4));
Expand Down
6 changes: 4 additions & 2 deletions lib/parse-elm.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

/**
* @import {Source, ElmFile} from './types/content';
* @import {Source, ElmFile, Ast} from './types/content';
* @import {ParseJob} from './types/parse-elm';
* @import {Path} from './types/path';
*/
Expand Down Expand Up @@ -58,15 +58,17 @@ function terminateWorkers() {
/**
* @param {Path} elmParserPath
* @param {Source} source
* @returns {Promise<ElmFile>}
* @returns {Promise<Ast>}
*/
async function parse(elmParserPath, source) {
return await new Promise((resolve, reject) => {
const availableWorker = findInactiveWorker();

/** @type {ParseJob} */
const queueItem = {
source,
elmParserPath,

callback: (/** @type {Error | undefined} */ error, result) => {
if (error === undefined) {
resolve(result);
Expand Down
19 changes: 18 additions & 1 deletion lib/project-dependencies.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
/**
* @import {ElmJson} from './types/content';
* @import {Options} from './types/options';
* @import {VersionString} from './types/version';
*/

const ProjectJsonFiles = require('./project-json-files');

/**
* @param {Options} options
* @param {ElmJson} elmJson
* @param {VersionString} elmVersion
*/
async function collect(options, elmJson, elmVersion) {
const dependenciesEntries =
elmJson.type === 'application'
Expand All @@ -19,7 +30,9 @@ async function collect(options, elmJson, elmVersion) {

const projectDepsPromises = Object.entries(dependenciesEntries).map(
async ([name, constraint]) => {
const packageVersion = constraint.split(' ')[0];
const packageVersion = /** @type {VersionString} */ (
constraint.split(' ')[0]
);

const [docsJson, dependencyElmJson] = await Promise.all([
ProjectJsonFiles.getDocsJson(
Expand Down Expand Up @@ -66,6 +79,10 @@ I will try to review the project anyway, but you might get unexpected results…
return projectDeps;
}

/**
* @param {string} name
* @param {VersionString} packageVersion
*/
function defaultElmJson(name, packageVersion) {
return {
type: 'package',
Expand Down
2 changes: 1 addition & 1 deletion lib/project-json-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ function getPackagePathInElmHome(elmVersion, name) {
* @param {Options} options
* @param {VersionString} elmVersion
* @param {string} name
* @param {string} packageVersion
* @param {VersionString} packageVersion
* @returns {Promise<unknown>}
*/
async function getDocsJson(options, elmVersion, name, packageVersion) {
Expand Down
81 changes: 60 additions & 21 deletions lib/remote-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const TemplateDependencies = require('./template-dependencies');
// GET LATEST INFORMATION ABOUT REPOSITORY

/**
* @param {Options} options
* @param {Template} template
* @returns {Promise<string>}
*/
async function getRelevantCommit(options, template) {
Expand All @@ -36,33 +38,42 @@ async function getRelevantCommit(options, template) {

/**
* @returns {Promise<string>}
* @param {Options} options
* @param {Template} template
*/
async function findDefaultBranch(options, template) {
Debug.log('Fetching default branch');
const body = await makeGitHubApiRequest(
options,
`https://api.github.com/repos/${template.repoName}`,
() => repoNotFoundErrorMessage(template.repoName)
const body = /** @type {{default_branch: string}} */ (
await makeGitHubApiRequest(
options,
`https://api.github.com/repos/${template.repoName}`,
() => repoNotFoundErrorMessage(template.repoName)
)
);
return body.default_branch;
}

/**
* @returns {Promise<string>}
* @param {Options} options
* @param {Template} template
* @param {string} reference
*/
async function getLatestCommitForReference(options, template, reference) {
Debug.log(`Fetching commit ${reference}`);
const body = await makeGitHubApiRequest(
options,
`https://api.github.com/repos/${template.repoName}/commits/${reference}`,
(responseBody) => {
if (responseBody.message === 'Not Found') {
// This error means that the repo itself was not found
return repoNotFoundErrorMessage(template.repoName);
}
const body = /** @type {{sha: string}} */ (
await makeGitHubApiRequest(
options,
`https://api.github.com/repos/${template.repoName}/commits/${reference}`,
(responseBody) => {
if (responseBody.message === 'Not Found') {
// This error means that the repo itself was not found
return repoNotFoundErrorMessage(template.repoName);
}

return commitNotFoundErrorMessage(template.repoName, reference);
}
return commitNotFoundErrorMessage(template.repoName, reference);
}
)
);
return body.sha;
}
Expand Down Expand Up @@ -108,6 +119,10 @@ async function getRemoteElmJson(
return TemplateDependencies.update(options, elmJson);
}

/**
* @param {Template} template
* @param {string} commit
*/
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not a return type annotation? (Same of other functions in this file)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They should, but I used the IDE inferer to get started, which skips them, unfortunately, and I didn't realize it until I was done.
TS infers them though, so I think it can be left for a follow-up.

async function downloadTemplateElmJson(template, commit) {
const {repoName, pathToFolder} = template;
const pathToFolderAsUrl = pathToFolder ? `/${pathToFolder}` : '';
Expand Down Expand Up @@ -165,6 +180,9 @@ elm-review in your project:
elm-review init --template <some-configuration>`
};

/**
* @param {string} repoName
*/
function repoNotFoundErrorMessage(repoName) {
return {
title: 'REPOSITORY NOT FOUND',
Expand All @@ -176,6 +194,10 @@ with private ones at the moment.`
};
}

/**
* @param {unknown} repoName
* @param {unknown} reference
*/
function commitNotFoundErrorMessage(repoName, reference) {
return {
title: 'BRANCH OR COMMIT NOT FOUND',
Expand All @@ -189,6 +211,13 @@ Check the spelling and make sure it has been pushed.`

// DOWNLOAD TEMPLATE FILES

/**
* @param {Options} options
* @param {Template} template
* @param {string} commit
* @param {string} basePath
* @param {ApplicationElmJson} reviewElmJson
*/
async function downloadSourceDirectories(
options,
template,
Expand All @@ -209,6 +238,13 @@ async function downloadSourceDirectories(
);
}

/**
* @param {Options} options
* @param {Template} template
* @param {string} commit
* @param {string} basePath
* @param {string} directory
*/
async function downloadDirectory(
options,
template,
Expand All @@ -220,12 +256,15 @@ async function downloadDirectory(
const destinationDirectory = directory.split('..').join('parent');

await FS.mkdirp(path.join(basePath, destinationDirectory));
const fileListing = await makeGitHubApiRequest(
options,
`https://api.github.com/repos/${repoName}/contents${pathToFolder}/${directory}?ref=${commit}`
.split('//')
.join('/')
);
const fileListing =
/** @type {({ type: string; name: string; download_url: string; })[]} */ (
await makeGitHubApiRequest(
options,
`https://api.github.com/repos/${repoName}/contents${pathToFolder}/${directory}?ref=${commit}`
.split('//')
.join('/')
)
);

await Promise.all(
fileListing.map(async (fileOrDir) => {
Expand Down Expand Up @@ -283,7 +322,7 @@ async function downloadFile(url, dest) {
* @param {Options} options
* @param {string} url
* @param {((arg: JsonResponse) => {title: string, message: string})} [handleNotFound]
* @returns {Promise<object>}
* @returns {Promise<unknown>}
*/
async function makeGitHubApiRequest(options, url, handleNotFound) {
/** @type {OptionsOfJSONResponseBody}} */
Expand Down
10 changes: 9 additions & 1 deletion lib/result-cache-worker.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* @import {MessagePort} from 'node:worker_threads';
*/
const path = require('node:path');
const {parentPort} = require('node:worker_threads');
const fs = require('graceful-fs');
Expand All @@ -7,6 +10,9 @@ if (parentPort) {
subscribe(parentPort);
}

/**
* @param {MessagePort} parentPort
*/
function subscribe(parentPort) {
parentPort.on('message', ({filePath, cacheEntry, cacheKey}) => {
try {
Expand All @@ -17,7 +23,9 @@ function subscribe(parentPort) {
filePath,
JSON.stringify(cacheEntry, ResultCacheJson.replacer, 0),
'utf8',
() => parentPort?.postMessage(cacheKey)
() => {
parentPort?.postMessage(cacheKey);
}
);
});
}
Loading