Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@yarnpkg/shell

Package Overview
Dependencies
Maintainers
5
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 2.1.0 to 2.2.0

322

lib/index.js

@@ -8,2 +8,3 @@ "use strict";

const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
const os_1 = require("os");
const stream_1 = require("stream");

@@ -19,3 +20,3 @@ const pipe_1 = require("./pipe");

const BUILTINS = new Map([
[`cd`, async ([target, ...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));

@@ -43,3 +44,3 @@ const stat = await fslib_1.xfs.statPromise(resolvedTarget);

[`exit`, async ([code, ...rest], opts, state) => {
return state.exitCode = parseInt(code, 10);
return state.exitCode = parseInt(code !== null && code !== void 0 ? code : state.variables[`?`], 10);
}],

@@ -167,2 +168,106 @@ [`echo`, async (args, opts, state) => {

}
function split(raw) {
return raw.match(/[^ \r\n\t]+/g) || [];
}
async function evaluateVariable(segment, opts, state, push, pushAndClose = push) {
switch (segment.name) {
case `#`:
{
push(String(opts.args.length));
}
break;
case `@`:
{
if (segment.quoted) {
for (const raw of opts.args) {
pushAndClose(raw);
}
}
else {
for (const raw of opts.args) {
const parts = split(raw);
for (let t = 0; t < parts.length - 1; ++t)
pushAndClose(parts[t]);
push(parts[parts.length - 1]);
}
}
}
break;
case `*`:
{
const raw = opts.args.join(` `);
if (segment.quoted) {
push(raw);
}
else {
for (const part of split(raw)) {
pushAndClose(part);
}
}
}
break;
case `RANDOM`:
{
push(String(Math.floor(Math.random() * 32768)));
}
break;
default:
{
const argIndex = parseInt(segment.name, 10);
if (Number.isFinite(argIndex)) {
if (!(argIndex >= 0 && argIndex < opts.args.length)) {
throw new Error(`Unbound argument #${argIndex}`);
}
else {
push(opts.args[argIndex]);
}
}
else {
if (Object.prototype.hasOwnProperty.call(state.variables, segment.name)) {
push(state.variables[segment.name]);
}
else if (Object.prototype.hasOwnProperty.call(state.environment, segment.name)) {
push(state.environment[segment.name]);
}
else if (segment.defaultValue) {
push((await interpolateArguments(segment.defaultValue, opts, state)).join(` `));
}
else {
throw new Error(`Unbound variable "${segment.name}"`);
}
}
}
break;
}
}
const operators = {
addition: (left, right) => left + right,
subtraction: (left, right) => left - right,
multiplication: (left, right) => left * right,
division: (left, right) => Math.trunc(left / right),
};
async function evaluateArithmetic(arithmetic, opts, state) {
if (arithmetic.type === `number`) {
if (!Number.isInteger(arithmetic.value)) {
throw new Error(`Invalid number: "${arithmetic.value}", only integers are allowed`);
}
else {
return arithmetic.value;
}
}
else if (arithmetic.type === `variable`) {
const parts = [];
await evaluateVariable({ ...arithmetic, quoted: true }, opts, state, result => parts.push(result));
const number = Number(parts.join(` `));
if (Number.isNaN(number)) {
return evaluateArithmetic({ type: `variable`, name: parts.join(` `) }, opts, state);
}
else {
return evaluateArithmetic({ type: `number`, value: number }, opts, state);
}
}
else {
return operators[arithmetic.type](await evaluateArithmetic(arithmetic.left, opts, state), await evaluateArithmetic(arithmetic.right, opts, state));
}
}
async function interpolateArguments(commandArgs, opts, state) {

@@ -172,5 +277,2 @@ const redirections = new Map();

let interpolatedSegments = [];
const split = (raw) => {
return raw.match(/[^ \r\n\t]+/g) || [];
};
const push = (segment) => {

@@ -239,68 +341,10 @@ interpolatedSegments.push(segment);

{
switch (segment.name) {
case `#`:
{
push(String(opts.args.length));
}
break;
case `@`:
{
if (segment.quoted) {
for (const raw of opts.args) {
pushAndClose(raw);
}
}
else {
for (const raw of opts.args) {
const parts = split(raw);
for (let t = 0; t < parts.length - 1; ++t)
pushAndClose(parts[t]);
push(parts[parts.length - 1]);
}
}
}
break;
case `*`:
{
const raw = opts.args.join(` `);
if (segment.quoted) {
push(raw);
}
else {
for (const part of split(raw)) {
pushAndClose(part);
}
}
}
break;
default:
{
const argIndex = parseInt(segment.name, 10);
if (Number.isFinite(argIndex)) {
if (!(argIndex >= 0 && argIndex < opts.args.length)) {
throw new Error(`Unbound argument #${argIndex}`);
}
else {
push(opts.args[argIndex]);
}
}
else {
if (Object.prototype.hasOwnProperty.call(state.variables, segment.name)) {
push(state.variables[segment.name]);
}
else if (Object.prototype.hasOwnProperty.call(state.environment, segment.name)) {
push(state.environment[segment.name]);
}
else if (segment.defaultValue) {
push((await interpolateArguments(segment.defaultValue, opts, state)).join(` `));
}
else {
throw new Error(`Unbound variable "${segment.name}"`);
}
}
}
break;
}
await evaluateVariable(segment, opts, state, push, pushAndClose);
}
break;
case `arithmetic`:
{
push(String(await evaluateArithmetic(segment.arithmetic, opts, state)));
}
break;
}

@@ -358,2 +402,23 @@ }

}
function makeGroupAction(ast, opts, state) {
return (stdio) => {
const stdin = new stream_1.PassThrough();
const promise = executeShellLine(ast, opts, state);
return { stdin, promise };
};
}
function makeActionFromProcedure(procedure, args, opts, activeState) {
if (args.length === 0) {
return procedure;
}
else {
let key;
do {
key = String(Math.random());
} while (Object.prototype.hasOwnProperty.call(activeState.procedures, key));
activeState.procedures = { ...activeState.procedures };
activeState.procedures[key] = procedure;
return makeCommandAction([...args, `__ysh_run_procedure`, key], opts, activeState);
}
}
async function executeCommandChain(node, opts, state) {

@@ -386,16 +451,12 @@ let current = node;

const procedure = makeSubshellAction(current.subshell, opts, activeState);
if (args.length === 0) {
action = procedure;
}
else {
let key;
do {
key = String(Math.random());
} while (Object.prototype.hasOwnProperty.call(activeState.procedures, key));
activeState.procedures = { ...activeState.procedures };
activeState.procedures[key] = procedure;
action = makeCommandAction([...args, `__ysh_run_procedure`, key], opts, activeState);
}
action = makeActionFromProcedure(procedure, args, opts, activeState);
}
break;
case `group`:
{
const args = await interpolateArguments(current.args, opts, state);
const procedure = makeGroupAction(current.group, opts, activeState);
action = makeActionFromProcedure(procedure, args, opts, activeState);
}
break;
case `envs`:

@@ -428,3 +489,3 @@ {

{
execution = execution.pipeTo(action);
execution = execution.pipeTo(action, pipe_2.Pipe.STDOUT);
}

@@ -434,3 +495,3 @@ break;

{
execution = execution.pipeTo(action);
execution = execution.pipeTo(action, pipe_2.Pipe.STDOUT | pipe_2.Pipe.STDERR);
}

@@ -457,38 +518,42 @@ break;

async function executeCommandLine(node, opts, state) {
if (!node.then)
return await executeCommandChain(node.chain, opts, state);
const code = await executeCommandChain(node.chain, opts, state);
// If the execution aborted (usually through "exit"), we must bailout
if (state.exitCode !== null)
return state.exitCode;
// We must update $?, which always contains the exit code from
// the right-most command
state.variables[`?`] = String(code);
switch (node.then.type) {
case `&&`:
{
if (code === 0) {
return await executeCommandLine(node.then.line, opts, state);
let code;
const setCode = (newCode) => {
code = newCode;
// We must update $?, which always contains the exit code from
// the right-most command
state.variables[`?`] = String(newCode);
};
setCode(await executeCommandChain(node.chain, opts, state));
// We use a loop because we must make sure that we respect
// the left associativity of lists, as per the bash spec.
// (e.g. `inexistent && echo yes || echo no` must be
// the same as `{inexistent && echo yes} || echo no`)
while (node.then) {
// If the execution aborted (usually through "exit"), we must bailout
if (state.exitCode !== null)
return state.exitCode;
switch (node.then.type) {
case `&&`:
{
if (code === 0) {
setCode(await executeCommandChain(node.then.line.chain, opts, state));
}
}
else {
return code;
break;
case `||`:
{
if (code !== 0) {
setCode(await executeCommandChain(node.then.line.chain, opts, state));
}
}
}
break;
case `||`:
{
if (code !== 0) {
return await executeCommandLine(node.then.line, opts, state);
break;
default:
{
throw new Error(`Unsupported command type: "${node.then.type}"`);
}
else {
return code;
}
}
break;
default:
{
throw new Error(`Unsupported command type: "${node.then.type}"`);
}
break;
break;
}
node = node.then.line;
}
return code;
}

@@ -512,5 +577,10 @@ async function executeShellLine(node, opts, state) {

{
return segment.name === `@` || segment.name === `#` || segment.name === `*` || Number.isFinite(parseInt(segment.name, 10)) || (!!segment.defaultValue && segment.defaultValue.some(arg => locateArgsVariableInArgument(arg)));
return segment.name === `@` || segment.name === `#` || segment.name === `*` || Number.isFinite(parseInt(segment.name, 10)) || (`defaultValue` in segment && !!segment.defaultValue && segment.defaultValue.some(arg => locateArgsVariableInArgument(arg)));
}
break;
case `arithmetic`:
{
return locateArgsVariableInArithmetic(segment.arithmetic);
}
break;
case `shell`:

@@ -544,2 +614,18 @@ {

}
function locateArgsVariableInArithmetic(arg) {
switch (arg.type) {
case `variable`:
{
return locateArgsVariableInSegment(arg);
}
break;
case `number`:
{
return false;
}
break;
default:
return locateArgsVariableInArithmetic(arg.left) || locateArgsVariableInArithmetic(arg.right);
}
}
function locateArgsVariable(node) {

@@ -584,3 +670,3 @@ return node.some(command => {

cwd: fslib_1.npath.fromPortablePath(cwd),
// @ts-ignore: `fs` is wrapped in `PosixFS`
// @ts-expect-error: `fs` is wrapped in `PosixFS`
fs: new fslib_1.PosixFS(fs),

@@ -638,3 +724,3 @@ }),

stderr,
variables: Object.assign(Object.create(variables), {
variables: Object.assign({}, variables, {
[`?`]: 0,

@@ -641,0 +727,0 @@ }),

/// <reference types="node" />
import { Readable, Writable } from 'stream';
import { ShellOptions } from './index';
declare enum Pipe {
export declare enum Pipe {
STDOUT = 1,

@@ -6,0 +6,0 @@ STDERR = 2

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.start = exports.Handle = exports.ProtectedStream = exports.makeBuiltin = exports.makeProcess = void 0;
exports.start = exports.Handle = exports.ProtectedStream = exports.makeBuiltin = exports.makeProcess = exports.Pipe = void 0;
const tslib_1 = require("tslib");

@@ -11,3 +11,3 @@ const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));

Pipe[Pipe["STDERR"] = 2] = "STDERR";
})(Pipe || (Pipe = {}));
})(Pipe = exports.Pipe || (exports.Pipe = {}));
function sigintHandler() {

@@ -51,3 +51,3 @@ // We don't want SIGINT to kill our process; we want it to kill the

process.off(`SIGINT`, sigintHandler);
// @ts-ignore
// @ts-expect-error
switch (error.code) {

@@ -54,0 +54,0 @@ case `ENOENT`:

{
"name": "@yarnpkg/shell",
"version": "2.1.0",
"version": "2.2.0",
"license": "BSD-2-Clause",

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

"dependencies": {
"@yarnpkg/fslib": "^2.1.0",
"@yarnpkg/parsers": "^2.1.0",
"clipanion": "^2.4.2",
"@yarnpkg/fslib": "^2.2.0",
"@yarnpkg/parsers": "^2.2.0",
"clipanion": "^2.4.4",
"cross-spawn": "7.0.3",

@@ -13,0 +13,0 @@ "fast-glob": "^3.2.2",

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