Socket
Socket
Sign inDemoInstall

@yarnpkg/shell

Package Overview
Dependencies
Maintainers
6
Versions
122
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@yarnpkg/shell - npm Package Compare versions

Comparing version 3.0.0-rc.2 to 3.0.0-rc.3

2

lib/cli.js

@@ -6,3 +6,3 @@ #!/usr/bin/env node

const clipanion_1 = require("clipanion");
const entry_1 = (0, tslib_1.__importDefault)(require("./commands/entry"));
const entry_1 = tslib_1.__importDefault(require("./commands/entry"));
const cli = new clipanion_1.Cli({

@@ -9,0 +9,0 @@ binaryLabel: `Yarn Shell`,

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

: this.commandName;
return await (0, index_1.execute)(command, [], {
return await index_1.execute(command, [], {
cwd: fslib_1.npath.toPortablePath(this.cwd),

@@ -25,0 +25,0 @@ stdin: this.context.stdin,

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

const fslib_1 = require("@yarnpkg/fslib");
const fast_glob_1 = (0, tslib_1.__importDefault)(require("fast-glob"));
const fs_1 = (0, tslib_1.__importDefault)(require("fs"));
const micromatch_1 = (0, tslib_1.__importDefault)(require("micromatch"));
const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
const fs_1 = tslib_1.__importDefault(require("fs"));
const micromatch_1 = tslib_1.__importDefault(require("micromatch"));
exports.micromatchOptions = {

@@ -38,6 +38,6 @@ // This is required because we don't want ")/*" to be a valid shell glob pattern.

function match(pattern, { cwd, baseFs }) {
return (0, fast_glob_1.default)(pattern, {
return fast_glob_1.default(pattern, {
...exports.fastGlobOptions,
cwd: fslib_1.npath.fromPortablePath(cwd),
fs: (0, fslib_1.extendFs)(fs_1.default, new fslib_1.PosixFS(baseFs)),
fs: fslib_1.extendFs(fs_1.default, new fslib_1.PosixFS(baseFs)),
});

@@ -44,0 +44,0 @@ }

@@ -51,3 +51,5 @@ /// <reference types="node" />

};
nextBackgroundJobIndex: number;
backgroundJobs: Array<Promise<unknown>>;
};
export declare function execute(command: string, args?: Array<string>, { baseFs, builtins, cwd, env, stdin, stdout, stderr, variables, glob, }?: Partial<UserOptions>): Promise<number>;

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

const parsers_1 = require("@yarnpkg/parsers");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const os_1 = require("os");
const stream_1 = require("stream");
const util_1 = require("util");
const errors_1 = require("./errors");
Object.defineProperty(exports, "ShellError", { enumerable: true, get: function () { return errors_1.ShellError; } });
const globUtils = (0, tslib_1.__importStar)(require("./globUtils"));
const globUtils = tslib_1.__importStar(require("./globUtils"));
exports.globUtils = globUtils;
const pipe_1 = require("./pipe");
const pipe_2 = require("./pipe");
const setTimeoutPromise = util_1.promisify(setTimeout);
var StreamType;

@@ -64,3 +67,3 @@ (function (StreamType) {

const BUILTINS = new Map([
[`cd`, async ([target = (0, os_1.homedir)(), ...rest], opts, state) => {
[`cd`, async ([target = os_1.homedir(), ...rest], opts, state) => {
const resolvedTarget = fslib_1.ppath.resolve(state.cwd, fslib_1.npath.toPortablePath(target));

@@ -97,5 +100,18 @@ const stat = await opts.baseFs.statPromise(resolvedTarget);

}],
[`sleep`, async ([time], opts, state) => {
if (typeof time === `undefined`) {
state.stderr.write(`sleep: missing operand\n`);
return 1;
}
// TODO: make it support unit suffixes
const seconds = Number(time);
if (Number.isNaN(seconds)) {
state.stderr.write(`sleep: invalid time interval '${time}'\n`);
return 1;
}
return await setTimeoutPromise(1000 * seconds, 0);
}],
[`__ysh_run_procedure`, async (args, opts, state) => {
const procedure = state.procedures[args[0]];
const exitCode = await (0, pipe_2.start)(procedure, {
const exitCode = await pipe_2.start(procedure, {
stdin: new pipe_2.ProtectedStream(state.stdin),

@@ -197,3 +213,3 @@ stdout: new pipe_2.ProtectedStream(state.stdout),

}
const exitCode = await (0, pipe_2.start)(makeCommandAction(args.slice(t + 1), opts, state), {
const exitCode = await pipe_2.start(makeCommandAction(args.slice(t + 1), opts, state), {
stdin: new pipe_2.ProtectedStream(stdin),

@@ -206,3 +222,6 @@ stdout: new pipe_2.ProtectedStream(stdout),

// Wait until the output got flushed to the disk
return new Promise(resolve => {
return new Promise((resolve, reject) => {
output.on(`error`, error => {
reject(error);
});
output.on(`close`, () => {

@@ -473,3 +492,3 @@ resolve();

if (name === `command`) {
return (0, pipe_1.makeProcess)(rest[0], rest.slice(1), opts, {
return pipe_1.makeProcess(rest[0], rest.slice(1), opts, {
cwd: nativeCwd,

@@ -482,3 +501,3 @@ env,

throw new Error(`Assertion failed: A builtin should exist for "${name}"`);
return (0, pipe_1.makeBuiltin)(async ({ stdin, stdout, stderr }) => {
return pipe_1.makeBuiltin(async ({ stdin, stdout, stderr }) => {
state.stdin = stdin;

@@ -518,3 +537,3 @@ state.stdout = stdout;

}
async function executeCommandChain(node, opts, state) {
async function executeCommandChainImpl(node, opts, state) {
let current = node;

@@ -569,3 +588,3 @@ let pipeType = null;

// new execution pipeline
execution = (0, pipe_2.start)(action, {
execution = pipe_2.start(action, {
stdin: new pipe_2.ProtectedStream(activeState.stdin),

@@ -606,2 +625,25 @@ stdout: new pipe_2.ProtectedStream(activeState.stdout),

}
async function executeCommandChain(node, opts, state, { background = false } = {}) {
function getColorizer(index) {
const colors = [`#2E86AB`, `#A23B72`, `#F18F01`, `#C73E1D`, `#CCE2A3`];
const colorName = colors[index % colors.length];
return chalk_1.default.hex(colorName);
}
if (background) {
const index = state.nextBackgroundJobIndex++;
const colorizer = getColorizer(index);
const rawPrefix = `[${index}]`;
const prefix = colorizer(rawPrefix);
const { stdout, stderr } = pipe_1.createOutputStreamsWithPrefix(state, { prefix });
state.backgroundJobs.push(executeCommandChainImpl(node, opts, cloneState(state, { stdout, stderr }))
.catch(error => stderr.write(`${error.message}\n`))
.finally(() => {
if (state.stdout.isTTY) {
state.stdout.write(`Job ${prefix}, '${colorizer(parsers_1.stringifyCommandChain(node))}' has ended\n`);
}
}));
return 0;
}
return await executeCommandChainImpl(node, opts, state);
}
/**

@@ -611,3 +653,3 @@ * Execute a command line. A command line is a list of command shells linked

*/
async function executeCommandLine(node, opts, state) {
async function executeCommandLine(node, opts, state, { background = false } = {}) {
let code;

@@ -620,5 +662,5 @@ const setCode = (newCode) => {

};
const executeChain = async (chain) => {
const executeChain = async (line) => {
try {
return await executeCommandChain(chain, opts, state);
return await executeCommandChain(line.chain, opts, state, { background: background && typeof line.then === `undefined` });
}

@@ -632,3 +674,3 @@ catch (error) {

};
setCode(await executeChain(node.chain));
setCode(await executeChain(node));
// We use a loop because we must make sure that we respect

@@ -646,3 +688,3 @@ // the left associativity of lists, as per the bash spec.

if (code === 0) {
setCode(await executeChain(node.then.line.chain));
setCode(await executeChain(node.then.line));
}

@@ -654,3 +696,3 @@ }

if (code !== 0) {
setCode(await executeChain(node.then.line.chain));
setCode(await executeChain(node.then.line));
}

@@ -670,5 +712,7 @@ }

async function executeShellLine(node, opts, state) {
const originalBackgroundJobs = state.backgroundJobs;
state.backgroundJobs = [];
let rightMostExitCode = 0;
for (const command of node) {
rightMostExitCode = await executeCommandLine(command, opts, state);
for (const { command, type } of node) {
rightMostExitCode = await executeCommandLine(command, opts, state, { background: type === `&` });
// If the execution aborted (usually through "exit"), we must bailout

@@ -681,2 +725,4 @@ if (state.exitCode !== null)

}
await Promise.all(state.backgroundJobs);
state.backgroundJobs = originalBackgroundJobs;
return rightMostExitCode;

@@ -741,3 +787,3 @@ }

function locateArgsVariable(node) {
return node.some(command => {
return node.some(({ command }) => {
while (command) {

@@ -789,7 +835,7 @@ let chain = command.chain;

}
const ast = (0, parsers_1.parseShell)(command, glob);
const ast = parsers_1.parseShell(command, glob);
// If the shell line doesn't use the args, inject it at the end of the
// right-most command
if (!locateArgsVariable(ast) && ast.length > 0 && args.length > 0) {
let command = ast[ast.length - 1];
let { command } = ast[ast.length - 1];
while (command.then)

@@ -831,4 +877,6 @@ command = command.then.line;

}),
nextBackgroundJobIndex: 1,
backgroundJobs: [],
});
}
exports.execute = execute;
/// <reference types="node" />
import { Readable, Writable } from 'stream';
import { ShellOptions } from './index';
import { PassThrough, Readable, Writable } from 'stream';
import { ShellOptions, ShellState } from './index';
export declare enum Pipe {

@@ -49,2 +49,8 @@ STDIN = 0,

export declare function start(p: ProcessImplementation, opts: StartOptions): Handle;
export declare function createOutputStreamsWithPrefix(state: ShellState, { prefix }: {
prefix: string | null;
}): {
stdout: PassThrough;
stderr: PassThrough;
};
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.start = exports.Handle = exports.ProtectedStream = exports.makeBuiltin = exports.makeProcess = exports.Pipe = void 0;
exports.createOutputStreamsWithPrefix = exports.start = exports.Handle = exports.ProtectedStream = exports.makeBuiltin = exports.makeProcess = exports.Pipe = void 0;
const tslib_1 = require("tslib");
const cross_spawn_1 = (0, tslib_1.__importDefault)(require("cross-spawn"));
const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
const stream_1 = require("stream");
const string_decoder_1 = require("string_decoder");
var Pipe;

@@ -34,3 +35,3 @@ (function (Pipe) {

: stdio[2];
const child = (0, cross_spawn_1.default)(name, args, { ...spawnOpts, stdio: [
const child = cross_spawn_1.default(name, args, { ...spawnOpts, stdio: [
stdin,

@@ -239,1 +240,44 @@ stdout,

exports.start = start;
function createStreamReporter(reportFn, prefix = null) {
const stream = new stream_1.PassThrough();
const decoder = new string_decoder_1.StringDecoder();
let buffer = ``;
stream.on(`data`, chunk => {
let chunkStr = decoder.write(chunk);
let lineIndex;
do {
lineIndex = chunkStr.indexOf(`\n`);
if (lineIndex !== -1) {
const line = buffer + chunkStr.substr(0, lineIndex);
chunkStr = chunkStr.substr(lineIndex + 1);
buffer = ``;
if (prefix !== null) {
reportFn(`${prefix} ${line}`);
}
else {
reportFn(line);
}
}
} while (lineIndex !== -1);
buffer += chunkStr;
});
stream.on(`end`, () => {
const last = decoder.end();
if (last !== ``) {
if (prefix !== null) {
reportFn(`${prefix} ${last}`);
}
else {
reportFn(last);
}
}
});
return stream;
}
function createOutputStreamsWithPrefix(state, { prefix }) {
return {
stdout: createStreamReporter(text => state.stdout.write(`${text}\n`), state.stdout.isTTY ? prefix : null),
stderr: createStreamReporter(text => state.stderr.write(`${text}\n`), state.stderr.isTTY ? prefix : null),
};
}
exports.createOutputStreamsWithPrefix = createOutputStreamsWithPrefix;
{
"name": "@yarnpkg/shell",
"version": "3.0.0-rc.2",
"version": "3.0.0-rc.3",
"license": "BSD-2-Clause",

@@ -8,4 +8,5 @@ "main": "./lib/index.js",

"dependencies": {
"@yarnpkg/fslib": "^2.5.0-rc.2",
"@yarnpkg/parsers": "^2.3.1-rc.2",
"@yarnpkg/fslib": "^2.5.0-rc.3",
"@yarnpkg/parsers": "^2.4.0-rc.1",
"chalk": "^3.0.0",
"clipanion": "^3.0.0-rc.10",

@@ -21,3 +22,4 @@ "cross-spawn": "7.0.3",

"@types/micromatch": "^4.0.1",
"@yarnpkg/monorepo": "0.0.0"
"@yarnpkg/monorepo": "0.0.0",
"strip-ansi": "^6.0.0"
},

@@ -44,3 +46,3 @@ "scripts": {

"engines": {
"node": ">=10.19.0"
"node": ">=12 <14 || 14.2 - 14.9 || >14.10.0"
},

@@ -47,0 +49,0 @@ "stableVersion": "2.4.1",

@@ -10,3 +10,3 @@ # `@yarnpkg/shell`

process.exitCode = await execute(`ls "$1" | wc -l`, [process.cwd()]);
process.exitCode = await execute(`ls "$0" | wc -l`, [process.cwd()]);
```

@@ -26,2 +26,3 @@

- Supports argc/argv
- Supports background jobs with color-coded output
- Supports the most classic builtins

@@ -28,0 +29,0 @@ - Doesn't necessarily need to access the fs

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