Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 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
50 changes: 36 additions & 14 deletions lib/build.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/**
* @import {AppHash, BuildResult} from './types/build';
* @import {ApplicationElmJson} from './types/content';
* @import {ApplicationElmJson, ElmJson} from './types/content';
* @import {VersionString} from './types/version';
* @import {Options, Template} from './types/options';
* @import {Path} from './types/path';
* @import {CompileOptions} from '../vendor/types/node-elm-compiler';
* @import {CompileOptions, Sources} from '../vendor/types/node-elm-compiler';
*/
const path = require('node:path');
const crypto = require('node:crypto');
Expand Down 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 Expand Up @@ -333,6 +330,11 @@ async function createTemplateProject(
Benchmark.end(options, 'Create template project');
}

/**
* @param {Options} options
* @param {string} userSrc
* @param {ApplicationElmJson} elmJson
*/
function updateSourceDirectories(options, userSrc, elmJson) {
let sourceDirectories = [
...elmJson['source-directories'].map((directory) =>
Expand All @@ -355,13 +357,22 @@ function updateSourceDirectories(options, userSrc, elmJson) {
};
}

/**
* @param {Options} options
* @param {string} dest
* @param {string} elmModulePath
Comment on lines +362 to +363
Copy link
Owner

@jfmengels jfmengels Nov 4, 2024

Choose a reason for hiding this comment

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

I think this would be more accurate:

 * @param {Path} dest
 * @param {Path} elmModulePath

Same for elmBinary below and other places in this file.

* @param {Sources} compileTargets
* @param {string} elmBinary
* @param {boolean} isReviewApp
* @returns {Promise<string | null>}
*/
async function compileElmProject(
options,
dest,
elmModulePath,
compileTargets,
elmBinary,
isReviewAppApp
isReviewApp
) {
/** @type {CompileOptions} */
const compileOptions = {
Expand All @@ -379,6 +390,7 @@ async function compileElmProject(
}
};

/** @type {string | null} */
const resolvedElmModulePath = await new Promise((resolve) => {
const compileProcess = elmCompiler.compile(compileTargets, compileOptions);

Expand Down Expand Up @@ -437,13 +449,13 @@ async function compileElmProject(
}
});
});
return await OptimizeJs.optimize(
options,
resolvedElmModulePath,
isReviewAppApp
);
return await OptimizeJs.optimize(options, resolvedElmModulePath, isReviewApp);
}

/**
* @param {Options} options
* @param {string} stderr
*/
function compilationError(options, stderr) {
if (stderr.includes('DEBUG REMNANTS')) {
return {
Expand All @@ -457,7 +469,7 @@ function compilationError(options, stderr) {
return {
title: 'MODULE NOT FOUND',
// prettier-ignore
message: `A module is missing in your configuration. Maybe you forgot to add some dependencies that contain the rules you wished to enable? If so, run ${chalk.magenta('elm install')} with the package name from inside ${chalk.yellow(options.userSrc(null))}.`
message: `A module is missing in your configuration. Maybe you forgot to add some dependencies that contain the rules you wished to enable? If so, run ${chalk.magenta('elm install')} with the package name from inside ${chalk.yellow(options.userSrc())}.`
};
}

Expand All @@ -480,6 +492,11 @@ function compilationError(options, stderr) {
};
}

/**
* @param {Options} options
* @param {Path} reviewElmJsonPath
* @param {ElmJson} reviewElmJson
*/
function validateElmReviewVersion(options, reviewElmJsonPath, reviewElmJson) {
if (options.localElmReviewSrc) {
return;
Expand Down Expand Up @@ -533,6 +550,11 @@ of ${chalk.yellow(path.dirname(reviewElmJsonPath))}.`
MinVersion.validate(options, reviewElmJsonPath, elmReviewVersion);
}

/**
* @param {Options} options
* @param {ApplicationElmJson} reviewElmJson
* @returns {Promise<void>}
*/
async function buildElmParser(options, reviewElmJson) {
const elmSyntaxVersion =
reviewElmJson.dependencies.direct['stil4m/elm-syntax'] ||
Expand Down Expand Up @@ -566,7 +588,7 @@ async function buildElmParser(options, reviewElmJson) {
})
]);

return await compileElmProject(
await compileElmProject(
options,
buildFolder,
elmParserPath,
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
21 changes: 18 additions & 3 deletions lib/optimize-js.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
/**
* @import {Options} from './types/options';
* @import {Optimization} from './types/optimize-js';
*/

const Benchmark = require('./benchmark');
const FS = require('./fs-wrapper');

async function optimize(options, elmModulePath, isReviewAppApp) {
/**
* @param {Options} options
* @param {string | null} elmModulePath
* @param {boolean} isReviewApp
* @returns {Promise<string | null>}
*/
async function optimize(options, elmModulePath, isReviewApp) {
if (options.debug || !elmModulePath) {
return elmModulePath;
}

const timerId = isReviewAppApp
const timerId = isReviewApp
? 'optimizing review application'
: 'optimizing parser application';
Benchmark.start(options, timerId);
const originalSource = await FS.readFile(elmModulePath);
const replacements = isReviewAppApp
const replacements = isReviewApp
? [
...performanceReplacements,
...cacheReplacements(options.localElmReviewSrc)
Expand Down Expand Up @@ -411,6 +422,10 @@ const performanceReplacements = [
}
];

/**
* @param {string | undefined} localElmReviewSrc
* @returns {Optimization[]}
*/
function cacheReplacements(localElmReviewSrc) {
const packageName = localElmReviewSrc
? '$author$project'
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
Loading