Socket
Socket
Sign inDemoInstall

elm-tooling

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

elm-tooling - npm Package Compare versions

Comparing version 0.1.6 to 0.2.0

helpers/known-tools.js

10

commands/download.js

@@ -12,5 +12,5 @@ "use strict";

const EMPTY_STDERR = mixed_1.dim("(empty stderr)");
async function download(cwd, logger) {
async function download(cwd, env, logger) {
var _a;
const parseResult = parse_1.findReadAndParseElmToolingJson(cwd);
const parseResult = parse_1.findReadAndParseElmToolingJson(cwd, env);
switch (parseResult.tag) {

@@ -303,5 +303,5 @@ case "ElmToolingJsonNotFound":

// If the caller runs `.destroy()` after we’ve already run `cleanup`,
// don’t run the cleanup process again: If the cleanup succeeded there’s
// nothing to clean; if it failed, running it again will just fail
// again.
// don’t run the cleanup procedure again: If the cleanup succeeded
// there’s nothing to clean; if it failed, running it again will just
// fail again.
cleanup = () => undefined;

@@ -308,0 +308,0 @@ try {

@@ -5,3 +5,3 @@ "use strict";

const parse_1 = require("../helpers/parse");
function help(cwd) {
function help(cwd, env) {
return `

@@ -16,3 +16,3 @@ ${mixed_1.bold("elm-tooling init")}

Download the tools in the closest elm-tooling.json to:
${mixed_1.dim(parse_1.elmToolingInstallPath(cwd))}
${mixed_1.dim(parse_1.elmToolingInstallPath(cwd, env))}

@@ -19,0 +19,0 @@ ${mixed_1.bold("elm-tooling postinstall")}

@@ -6,3 +6,3 @@ "use strict";

const readline = require("readline");
const known_tools_1 = require("../helpers/known_tools");
const known_tools_1 = require("../helpers/known-tools");
const mixed_1 = require("../helpers/mixed");

@@ -23,2 +23,3 @@ const parse_1 = require("../helpers/parse");

const relative = path.relative(path.dirname(absolutePath), file);
/* istanbul ignore next */
const normalized = parse_1.isWindows ? relative.replace(/\\/g, "/") : relative;

@@ -28,3 +29,3 @@ return `./${normalized}`;

const tools = parse_1.getOSName() instanceof Error
? undefined
? /* istanbul ignore next */ undefined
: Object.fromEntries(Object.keys(known_tools_1.KNOWN_TOOLS)

@@ -57,3 +58,5 @@ .sort()

.map((entry) => path.join(directory, entry.name)));
const results = await Promise.all(files.map((file) => isMainFile(file).then((isMain) => (isMain ? file : new Error(`${file} is not a main file.`)), (error) => error)));
const results = await Promise.all(files.map((file) => isMainFile(file).then((isMain) => (isMain ? file : new Error(`${file} is not a main file.`)),
/* istanbul ignore next */
(error) => error)));
const entrypoints = results

@@ -60,0 +63,0 @@ .flatMap((result) => (result instanceof Error ? [] : result))

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makePs1Script = exports.makeCmdScript = exports.makeShScript = void 0;
const fs = require("fs");

@@ -8,7 +9,7 @@ const path = require("path");

const download_1 = require("./download");
async function postinstall(cwd, logger) {
if ("NO_ELM_TOOLING_POSTINSTALL" in process.env) {
async function postinstall(cwd, env, logger) {
if ("NO_ELM_TOOLING_POSTINSTALL" in env) {
return 0;
}
const result = await download_1.default(cwd, logger);
const result = await download_1.default(cwd, env, logger);
switch (result.tag) {

@@ -24,2 +25,3 @@ case "Exit":

const nodeModulesPath = mixed_1.findClosest("node_modules", cwd);
/* istanbul ignore if */
if (nodeModulesPath === undefined) {

@@ -36,2 +38,3 @@ logger.error("No node_modules/ folder found. Install your npm dependencies before running this script.");

logger.error(`Failed to create ${nodeModulesBinPath}:\n${error.message}`);
return 1;
}

@@ -43,5 +46,6 @@ for (const tool of tools) {

// the `elm` npm package, or links from previous runs of this script.
const linkPathPresentationString = parse_1.isWindows
? symlinkShimWindows(tool, linkPath)
: symlink(tool, linkPath);
const [linkPathPresentationString, what] = parse_1.isWindows
? // istanbul ignore next
[symlinkShimWindows(tool, linkPath), "shims"]
: [symlink(tool, linkPath), "link"];
if (linkPathPresentationString instanceof Error) {

@@ -51,3 +55,2 @@ logger.error(linkPathPresentationString.message);

}
const what = parse_1.isWindows ? "shims" : "link";
logger.log(`${mixed_1.bold(`${tool.name} ${tool.version}`)} ${what} created: ${mixed_1.dim(`${linkPathPresentationString} -> ${tool.absolutePath}`)}`);

@@ -70,3 +73,3 @@ }

}
catch (errorAny) {
catch (errorAny) /* istanbul ignore next */ {
const error = errorAny;

@@ -77,3 +80,3 @@ return new Error(`Failed to create link for ${tool.name} at ${linkPath}:\n${error.message}`);

}
// Inspired by: https://github.com/npm/cmd-shim/blob/92c0a16d3c8a8c53ade76b5eae8efae01dd7f41f/index.js
// istanbul ignore next
function symlinkShimWindows(tool, linkPath) {

@@ -95,3 +98,3 @@ const shLinkPath = linkPath;

if (error.code !== "ENOENT") {
return new Error(`Failed to remove old links for ${tool.name} at ${linkPathPresentationString}:\n${error.message}`);
return new Error(`Failed to remove old shims for ${tool.name} at ${linkPathPresentationString}:\n${error.message}`);
}

@@ -109,3 +112,3 @@ }

const error = errorAny;
return new Error(`Failed to create links for ${tool.name} at ${linkPathPresentationString}:\n${error.message}`);
return new Error(`Failed to create shims for ${tool.name} at ${linkPathPresentationString}:\n${error.message}`);
}

@@ -118,5 +121,9 @@ return linkPathPresentationString;

#!/bin/sh
'${toolAbsolutePath.replace(/'/g, "'\\''")}' "$@"
${toolAbsolutePath
.split(/(')/)
.map((segment) => segment === "" ? "" : segment === "'" ? "\\'" : `'${segment}'`)
.join("")} "$@"
`);
}
exports.makeShScript = makeShScript;
// Note: Paths on Windows cannot contain `"`.

@@ -129,2 +136,3 @@ function makeCmdScript(toolAbsolutePath) {

}
exports.makeCmdScript = makeCmdScript;
// The shebang is for PowerShell on unix: https://github.com/npm/cmd-shim/pull/34

@@ -137,2 +145,3 @@ function makePs1Script(toolAbsolutePath) {

}
exports.makePs1Script = makePs1Script;
function lf(string) {

@@ -139,0 +148,0 @@ return `${string.trim()}\n`;

@@ -6,4 +6,4 @@ "use strict";

const parse_1 = require("../helpers/parse");
function validate(cwd, logger) {
const parseResult = parse_1.findReadAndParseElmToolingJson(cwd);
function validate(cwd, env, logger) {
const parseResult = parse_1.findReadAndParseElmToolingJson(cwd, env);
switch (parseResult.tag) {

@@ -37,3 +37,3 @@ case "ElmToolingJsonNotFound":

path: [field],
message: `Unknown field`,
message: `Unknown field\nKnown fields: ${mixed_1.KNOWN_FIELDS.join(", ")}`,
})),

@@ -54,3 +54,3 @@ ...entrypointsErrors,

logger.error("");
logger.error(`${mixed_1.dim("To download missing tools:")}\n${mixed_1.indent("elm-tooling download")}`);
logger.error(missingToolsText);
}

@@ -65,2 +65,10 @@ logger.error("");

exports.default = validate;
const missingToolsText = `
${mixed_1.dim("To download missing tools:")}
${mixed_1.indent(`
elm-tooling download
${mixed_1.dim("or:")}
elm-tooling postinstall
`.trim())}
`.trim();
function getEntrypointsErrors(fieldResult) {

@@ -67,0 +75,0 @@ switch (fieldResult.tag) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.logger = void 0;
/* eslint-disable no-console */
exports.makeLogger = void 0;
const readline = require("readline");
let previousProgress = undefined;
exports.logger = {
log: (message) => {
previousProgress = undefined;
console.log(message);
},
error: (message) => {
previousProgress = undefined;
console.error(message);
},
progress: (message) => {
if (previousProgress !== undefined) {
readline.moveCursor(process.stderr, 0, -previousProgress);
}
previousProgress = message.split("\n").length;
console.log(message);
},
};
function makeLogger({ env, stdout, stderr, }) {
const NO_COLOR = "NO_COLOR" in env;
const handleColor = (string) =>
// eslint-disable-next-line no-control-regex
NO_COLOR ? string.replace(/\x1B\[\dm/g, "") : string;
return {
log(message) {
previousProgress = undefined;
stdout.write(handleColor(message) + "\n");
},
error(message) {
previousProgress = undefined;
stderr.write(handleColor(message) + "\n");
},
/* istanbul ignore next */
progress(passedMessage) {
const message = handleColor(passedMessage);
if (previousProgress !== undefined) {
readline.moveCursor(stdout, 0, -previousProgress);
}
previousProgress = message.split("\n").length;
stdout.write(message + "\n");
},
};
}
exports.makeLogger = makeLogger;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.printNumErrors = exports.elmToolingJsonDocumentationLink = exports.indent = exports.dim = exports.bold = exports.EXECUTABLE = exports.partitionMap = exports.findClosest = exports.isRecord = void 0;
exports.printNumErrors = exports.elmToolingJsonDocumentationLink = exports.indent = exports.dim = exports.bold = exports.EXECUTABLE = exports.partitionMap = exports.findClosest = exports.isRecord = exports.KNOWN_FIELDS = void 0;
const fs = require("fs");
const path = require("path");
exports.KNOWN_FIELDS = ["entrypoints", "tools"];
function isRecord(value) {

@@ -23,3 +24,3 @@ return typeof value === "object" && value !== null && !Array.isArray(value);

for (const [index, item] of items.entries()) {
const either = f(item, index);
const either = f(item, index, left, right);
switch (either.tag) {

@@ -38,10 +39,9 @@ case "Left":

exports.EXECUTABLE = "755";
const NO_COLOR = "NO_COLOR" in process.env;
const RESET_COLOR = "\x1B[0m";
function bold(string) {
return NO_COLOR ? string : `${RESET_COLOR}\x1B[1m${string}${RESET_COLOR}`;
return `${RESET_COLOR}\x1B[1m${string}${RESET_COLOR}`;
}
exports.bold = bold;
function dim(string) {
return NO_COLOR ? string : `${RESET_COLOR}\x1B[2m${string}${RESET_COLOR}`;
return `${RESET_COLOR}\x1B[2m${string}${RESET_COLOR}`;
}

@@ -48,0 +48,0 @@ exports.dim = dim;

@@ -7,9 +7,10 @@ "use strict";

const path = require("path");
const known_tools_1 = require("./known_tools");
const known_tools_1 = require("./known-tools");
const mixed_1 = require("./mixed");
exports.isWindows = process.platform === "win32";
function elmToolingInstallPath(cwd) {
const elmHome = process.env.ELM_HOME ||
exports.isWindows = os.platform() === "win32";
function elmToolingInstallPath(cwd, env) {
/* istanbul ignore next */
const elmHome = env.ELM_HOME ||
(exports.isWindows
? path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "elm")
? path.join(env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "elm")
: path.join(os.homedir(), ".elm"));

@@ -19,3 +20,3 @@ return path.join(path.resolve(cwd, elmHome), "elm-tooling");

exports.elmToolingInstallPath = elmToolingInstallPath;
function findReadAndParseElmToolingJson(cwd) {
function findReadAndParseElmToolingJson(cwd, env) {
const elmToolingJsonPath = mixed_1.findClosest("elm-tooling.json", cwd);

@@ -60,9 +61,10 @@ if (elmToolingJsonPath === undefined) {

result.tools = prefixFieldResult("tools", osName instanceof Error
? {
tag: "Error",
errors: [
{ path: [], message: osName.message },
],
}
: parseTools(cwd, osName, value));
? /* istanbul ignore next */
{
tag: "Error",
errors: [
{ path: [], message: osName.message },
],
}
: parseTools(cwd, env, osName, value));
break;

@@ -79,3 +81,4 @@ }

function getOSName() {
switch (process.platform) {
/* istanbul ignore next */
switch (os.platform()) {
case "linux":

@@ -88,3 +91,3 @@ return "linux";

default:
return new Error(`Sorry, your platform (${process.platform}) is not supported yet :(`);
return new Error(`Sorry, your platform (${os.platform()}) is not supported yet :(`);
}

@@ -116,2 +119,3 @@ }

const error = errorAny;
/* istanbul ignore else */
if (error.code === "ENOENT") {

@@ -123,6 +127,8 @@ return {

}
return {
tag: "Error",
message: `File error for ${fullPath}: ${error.message}`,
};
else {
return {
tag: "Error",
message: `File error for ${fullPath}: ${error.message}`,
};
}
}

@@ -155,3 +161,3 @@ return { tag: "Exists" };

}
const [errors, entrypoints] = mixed_1.partitionMap(json, (entrypoint, index) => {
const [errors, entrypoints] = mixed_1.partitionMap(json, (entrypoint, index, _, entrypointsSoFar) => {
if (typeof entrypoint !== "string") {

@@ -183,2 +189,11 @@ return {

}
if (entrypointsSoFar.some((otherEntrypoint) => otherEntrypoint.absolutePath === absolutePath)) {
return {
tag: "Left",
value: {
path: [index],
message: `Duplicate entrypoint: ${absolutePath}`,
},
};
}
return {

@@ -200,3 +215,3 @@ tag: "Right",

}
function parseTools(cwd, osName, json) {
function parseTools(cwd, env, osName, json) {
if (!mixed_1.isRecord(json)) {

@@ -229,3 +244,6 @@ return {

tag: "Left",
value: { path: [name], message: `Unknown tool` },
value: {
path: [name],
message: `Unknown tool\nKnown tools: ${Object.keys(known_tools_1.KNOWN_TOOLS).join(", ")}`,
},
};

@@ -239,3 +257,6 @@ }

tag: "Left",
value: { path: [name], message: `Unknown version: ${version}` },
value: {
path: [name],
message: `Unknown version: ${version}\nKnown versions: ${Object.keys(versions).join(", ")}`,
},
};

@@ -247,3 +268,3 @@ }

version,
absolutePath: getToolAbsolutePath(elmToolingInstallPath(cwd), name, version, asset.fileName),
absolutePath: getToolAbsolutePath(elmToolingInstallPath(cwd, env), name, version, asset.fileName),
asset,

@@ -293,2 +314,3 @@ };

function joinPath(errorPath) {
/* istanbul ignore if */
if (errorPath.length === 0) {

@@ -295,0 +317,0 @@ return "General";

@@ -10,7 +10,7 @@ #!/usr/bin/env node

const logger_1 = require("./helpers/logger");
async function run(argv, cwd, logger) {
async function run(argv, cwd, env, logger) {
// So far no command takes any further arguments.
// Let each command handle this when needed.
if (argv.length > 1) {
logger.error(`Expected no extra arguments but got: ${argv.slice(1).join(" ")}`);
logger.error(`Expected a single argument but got: ${argv.slice(1).join(" ")}`);
return 1;

@@ -24,3 +24,3 @@ }

case "help":
logger.log(help_1.default(cwd));
logger.log(help_1.default(cwd, env));
return 0;

@@ -30,5 +30,5 @@ case "init":

case "validate":
return validate_1.default(cwd, logger);
return validate_1.default(cwd, env, logger);
case "download": {
const result = await download_1.default(cwd, logger);
const result = await download_1.default(cwd, env, logger);
switch (result.tag) {

@@ -42,3 +42,3 @@ case "Exit":

case "postinstall":
return await postinstall_1.default(cwd, logger);
return await postinstall_1.default(cwd, env, logger);
default:

@@ -49,7 +49,22 @@ logger.error(`Unknown command: ${argv[0]}`);

}
run(process.argv.slice(2), process.cwd(), logger_1.logger).then((exitCode) => {
process.exit(exitCode);
}, (error) => {
logger_1.logger.error(`Unexpected error:\n${error.stack || error.message}`);
process.exit(1);
});
function elmToolingCli(args,
/* istanbul ignore next */
{ cwd, env, stdout, stderr } = {
cwd: process.cwd(),
env: process.env,
stdin: process.stdin,
stdout: process.stdout,
stderr: process.stderr,
}) {
return run(args, cwd, env, logger_1.makeLogger({ env, stdout, stderr }));
}
module.exports = elmToolingCli;
/* istanbul ignore if */
if (require.main === module) {
elmToolingCli(process.argv.slice(2)).then((exitCode) => {
process.exit(exitCode);
}, (error) => {
process.stderr.write(`Unexpected error:\n${error.stack || error.message}\n`);
process.exit(1);
});
}
{
"name": "elm-tooling",
"version": "0.1.6",
"version": "0.2.0",
"author": "Simon Lydell",

@@ -9,5 +9,5 @@ "license": "MIT",

"type": "commonjs",
"exports": {},
"exports": "./index.js",
"bin": "./index.js",
"keywords": ["elm", "elm-format", "elm-tooling", "elm-tooling.json"]
}

@@ -5,101 +5,2 @@ # elm-tooling CLI

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Installation](#installation)
- [Commands](#commands)
- [elm-tooling init](#elm-tooling-init)
- [elm-tooling validate](#elm-tooling-validate)
- [elm-tooling download](#elm-tooling-download)
- [elm-tooling postinstall](#elm-tooling-postinstall)
- [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Installation
```
npm install --save-dev elm-tooling
```
```
npx elm-tooling --help
```
## Commands
### elm-tooling init
Create a sample `elm-tooling.json` in the current directory. It tries to guess some values based on your project to help you get started.
### elm-tooling validate
Validate the closest `elm-tooling.json`. If you’re having trouble with some program not reading your `elm-tooling.json` correctly, try `elm-tooling validate` to check if you’ve made any mistakes.
### elm-tooling download
Download the [tools] in the closest `elm-tooling.json`.
This command just downloads stuff from the Internet and shoves it into a folder (basically, `~/.elm/elm-tooling/`). It does not provide you with an easy way to run the tools or anything. It’s up to other programs to support the shared location of binaries. But you can use `elm-tooling postinstall` to piggy-back on the well-supported `npm` ecosystem.
As mentioned in [tools], you can set `ELM_HOME` environment variable to customize where tools will be downloaded. The Elm compiler uses this variable too for where to store packages.
### elm-tooling postinstall
Download the [tools] in the closest `elm-tooling.json` and create links to them in `node_modules/.bin/`.
This is basically a drop-in replacement for installing `elm` and `elm-format` with `npm`. This lets you use the [tools] field of `elm-tooling.json` without your editor and build tools having to support it.
`package.json`:
```diff
{
"name": "my-package",
"devDependencies": {
- "elm": "0.19.1",
- "elm-format": "0.8.3"
+ "elm-tooling": "0.1.6"
},
"scripts": {
+ "postinstall": "elm-tooling postinstall"
}
}
```
elm-tooling.json:
```diff
+{
+ "tools": {
+ "elm": "0.19.1",
+ "elm-format": "0.8.3"
+ }
+}
```
Thanks to the [postinstall] script shown in `package.json` above, `elm` and `elm-format` will be automatically installed whenever you run `npm install` (just like you’re used to if you already install `elm` and `elm-format` using `npm`).
`elm-tooling postinstall` does two things:
1. Runs `elm-tooling download`. This makes sure your [tools] are available on disk as required by the `elm-tooling.json` spec.
2. Creates links in your local `node_modules/.bin/` folder to the downloaded tools, just like the `elm` and `elm-format` npm packages do. This allows you to run things like `npx elm make src/Main.elm`, and your editor and build tools to automatically find them.
The difference compared to installing the regular `elm` and `elm-format` packages are:
- Faster initial installs. `elm-tooling` downloads all tools in parallel, while the binary downloads for the regular `elm` and `elm-format` packages are serial.
- Faster subsequent installs. Once you’ve downloaded one version of a tool once you never need to download it again. This works by saving the binaries in a shared location rather than locally in each project.
- Less disk usage. Again, storing the binaries in a shared location saves tens of megabytes per project.
- Less npm dependencies. The `elm` and `elm-format` npm packages depend on megabytes of dependencies. `elm-tooling` has no npm dependencies at all.
Note: If you’re using `npm`’s [ignore-scripts] setting or the `--ignore-scripts` flag, that also means your _own_ `postinstall` script won’t run. Which means that you’ll have to remember to run `npm run postinstall` or `npx elm-tooling postinstall` yourself. `npm` tends to keep stuff in `node_modules/.bin/` even when running `npm ci` (which claims to remove `node_modules/` before installation), so it should hopefully not be too much of a hassle.
Similarly, you can set the `NO_ELM_TOOLING_POSTINSTALL` environment variable to turn `elm-tooling postinstall` into a no-op. This is useful if you need to `npm install` without running `elm-tooling postinstall`, but `npm install --ignore-scripts` disables too many scripts (such as those of dependencies).
## License
[MIT](LICENSE).
[elm-tooling.json]: https://github.com/lydell/elm-tooling.json
[ignore-scripts]: https://docs.npmjs.com/using-npm/config#ignore-scripts
[postinstall]: https://docs.npmjs.com/misc/scripts
[tools]: https://github.com/lydell/elm-tooling.json#tools
**[➡️ Full readme](https://github.com/lydell/elm-tooling.json/tree/master/cli)**
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc