elm-tooling
Advanced tools
Comparing version 0.1.6 to 0.2.0
@@ -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"; |
39
index.js
@@ -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"] | ||
} |
101
README.md
@@ -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)** |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
14
1333
7
51054
5