elm-review
Version:
Run elm-review from Node.js
106 lines (95 loc) • 2.73 kB
JavaScript
/**
* @import {Options} from './types/options';
* @import {Path} from './types/path';
* @import {VersionString} from './types/version';
*/
const path = require('node:path');
const chalk = require('chalk');
const spawn = require('cross-spawn');
const which = require('which');
const ErrorMessage = require('./error-message');
const {backwardsCompatiblePath} = require('./npx');
/**
* Get the path to the Elm binary
*
* @param {Options} options
* @returns {Promise<Path>}
*/
async function getElmBinary(options) {
try {
const elmBinaryPath = await which(options.compiler ?? 'elm', {
path: backwardsCompatiblePath(options.compiler)
});
return path.resolve(elmBinaryPath);
} catch {
throw new ErrorMessage.CustomError(
'ELM NOT FOUND',
options.compiler === undefined
? // prettier-ignore
`I could not find the executable for the ${chalk.magentaBright('elm')} compiler.
A few options:
- Install it globally
- Specify the path using ${chalk.cyan('--compiler <path-to-elm>')}`
: // prettier-ignore
`I could not find the executable for the ${chalk.magentaBright('elm')} compiler at the location you specified:
${options.compiler}`,
options.elmJsonPath
);
}
}
/**
* Get the version of the Elm compiler
*
* @param {Path} elmBinary
* @returns {VersionString}
*/
function getElmVersion(elmBinary) {
const result = spawn.sync(elmBinary, ['--version'], {
// @ts-expect-error(TS2769): The types are outdated.
silent: true,
env: process.env
});
if (result.status !== 0) {
return '0.19.1';
}
return trimVersion(result.stdout.toString());
}
/**
* Download the dependencies of the project to analyze.
*
* @param {Path} elmBinary
* @param {Path} elmJsonPath
* @returns {void}
*/
function downloadDependenciesOfElmJson(elmBinary, elmJsonPath) {
const result = spawn.sync(elmBinary, ['make', '--report=json'], {
cwd: path.dirname(elmJsonPath),
// @ts-expect-error(TS2769): The types are outdated.
silent: false,
env: process.env
});
if (result.status !== 0) {
const error = JSON.parse(result.stderr.toString());
// TODO(@jfmengels): Check for other kinds of errors.
if (error.title !== 'NO INPUT') {
// TODO(@jfmengels): Print the error nicely.
throw new Error(error);
}
}
}
/**
* @param {string} version
* @returns {VersionString}
*/
function trimVersion(version) {
const index = version.indexOf('-');
if (index === -1) {
return /** @type {VersionString} */ (version.trim());
}
return /** @type {VersionString} */ (version.slice(0, index).trim());
}
module.exports = {
getElmBinary,
getElmVersion,
downloadDependenciesOfElmJson
};