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

bash-parser

Package Overview
Dependencies
Maintainers
4
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bash-parser - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

src/modes/word-expansion/built-grammar.js

10

package.json
{
"name": "bash-parser",
"version": "0.4.0",
"version": "0.5.0",
"main": "src/index.js",

@@ -11,5 +11,5 @@ "description": "Standard compliant bash parser",

"doc": "doctoc",
"test": "ava --no-babel && xo --ignore **/built-grammar.js --ignore 'packages/**/*'",
"build": "mgb ./src/modes posix && mgb ./src/modes bash",
"cover-test": "nyc ava --no-babel && xo --ignore **/built-grammar.js --ignore 'packages/**/*'",
"test": "ava && xo --ignore **/built-grammar.js",
"build": "mgb ./src/modes posix && mgb ./src/modes bash && mgb ./src/modes word-expansion",
"cover-test": "nyc ava && xo --ignore **/built-grammar.js",
"cover-publish": "nyc report --reporter=text-lcov | coveralls"

@@ -26,3 +26,3 @@ },

"json5": "^0.5.0",
"mode-grammar-builder": "0.0.0",
"mode-grammar-builder": "^0.6.0",
"nyc": "^7.0.0",

@@ -29,0 +29,0 @@ "xo": "^0.16.0"

# bash-parser
> See [repo root readme](https://github.com/vorpaljs/bash-parser)
Parses bash source code to produce an AST
[![Travis Build Status](https://img.shields.io/travis/vorpaljs/bash-parser/master.svg)](http://travis-ci.org/vorpaljs/bash-parser)
[![Coveralls](https://img.shields.io/coveralls/vorpaljs/bash-parser.svg?maxAge=2592000)](https://coveralls.io/github/vorpaljs/bash-parser)
[![NPM module](https://img.shields.io/npm/v/bash-parser.svg)](https://npmjs.org/package/bash-parser)
[![NPM downloads](https://img.shields.io/npm/dt/bash-parser.svg)](https://npmjs.org/package/bash-parser)
[![Try online](https://img.shields.io/badge/try_it-online!-yellow.svg)](https://vorpaljs.github.io/bash-parser-playground/)
# Installation
```bash
npm install --save bash-parser
```
# Usage
```js
const parse = require('bash-parser');
const ast = parse('echo ciao');
```
`ast` result is:
```js
{
type: "Script",
commands: [
{
type: "SimpleCommand",
name: {
text: "echo",
type: "Word"
},
suffix: [
{
text: "ciao",
type: "Word"
}
]
}
]
}
```
# Related projects
* [cash](https://github.com/dthree/cash) - This parser should become the parser used by `cash` (and also [vorpal](https://github.com/dthree/vorpal))
* [nsh](https://github.com/piranna/nsh) - This parser should become the parser used by `nsh`
* [js-shell-parse](https://github.com/grncdr/js-shell-parse) - bash-parser was born as a fork of `js-shell-parse`, but was rewritten to use a `jison` grammar
* [jison](https://github.com/zaach/jison) - Bison in JavaScript.
# Documentation
Look in [documents folder](https://github.com/vorpaljs/bash-parser/tree/master/documents)
# License
The MIT License (MIT)
Copyright (c) 2016 vorpaljs

@@ -122,2 +122,5 @@ /* parser generated by jison 0.4.17 */

break;
case 16:
this.$ = yy.addRedirections($$[$0-1], $$[$0])
break;
case 25:

@@ -184,3 +187,3 @@ this.$ = yy.subshell($$[$0-1], $$[$0-2].loc, $$[$0].loc);

case 55:
this.$ = yy.patternAppend(pattern, $$[$0]);
this.$ = yy.patternAppend($$[$0-2], $$[$0]);
break;

@@ -211,2 +214,8 @@ case 56:

break;
case 64:
this.$ = [$$[$0], null];
break;
case 65:
this.$ = [$$[$0-1], $$[$0]];
break;
case 67:

@@ -255,3 +264,3 @@ this.$ = yy.braceGroup($$[$0-1], $$[$0-2].loc, $$[$0].loc);

case 85:
this.$ = [$$[$0-1].concat($$[$0])];
this.$ = $$[$0-1].concat($$[$0]);
break;

@@ -258,0 +267,0 @@ case 87:

@@ -5,2 +5,121 @@ 'use strict';

const name = '[a-zA-Z_][a-zA-Z0-9_]*';
const parameterOperators = {
// This is referred to as Substring Expansion.
// It expands to up to length characters of the value
// of parameter starting at the character specified by offset.
[`^(${name}):([^:]*):?([^:]*)$`]: {
op: 'substring',
parameter: m => m[1],
offset: m => parseInt(m[2], 10),
length: m => parseInt(m[3], 10) || undefined
},
// Expands to the names of variables whose names begin with prefix,
// separated by the first character of the IFS special variable.
// When ‘@’ is used and the expansion appears within double quotes,
// each variable name expands to a separate word.
// TODO: @ case may need some investigation, maybe it's not actually possible
[`^!(${name})(\\*|@)$`]: {
op: 'prefix',
prefix: m => m[1],
expandWords: m => m[2] === '@',
parameter: () => undefined
},
// If name is an array variable, expands to the list of array indices
// (keys) assigned in name. If name is not an array, expands to 0 if
// name is set and null otherwise. When ‘@’ is used and the expansion
// appears within double quotes, each key expands to a separate word.
// TODO: @ case may need some investigation, maybe it's not actually possible
[`^!(${name})(\\[\\*\\]|\\[@\\])$`]: {
op: 'arrayIndices',
parameter: m => m[1],
expandWords: m => m[2] === '[@]'
},
// Parameter is expanded and the longest match of pattern against its
// value is replaced with string. If pattern begins with ‘/’, all matches
// of pattern are replaced with string.
[`^(${name})\\/(\\/)?([^\\/])+\\/(.*)$`]: {
op: 'stringReplace',
parameter: m => m[1],
substitute: m => m[3],
replace: m => m[4],
globally: m => m[2] === '/'
},
// This expansion modifies the case of alphabetic characters in parameter.
// The pattern is expanded to produce a pattern just as in filename expansion.
// Each character in the expanded value of parameter is tested against pattern,
// and, if it matches the pattern, its case is converted. The pattern should
// not attempt to match more than one character. The ‘^’ operator converts
// lowercase letters matching pattern to uppercase; the ‘,’ operator converts
// matching uppercase letters to lowercase. The ‘^^’ and ‘,,’ expansions convert
// each matched character in the expanded value; the ‘^’ and ‘,’ expansions match
// and convert only the first character in the expanded value. If pattern is omitted,
// it is treated like a ‘?’, which matches every character. If parameter is ‘@’
// or ‘*’, the case modification operation is applied to each positional parameter
// in turn, and the expansion is the resultant list. If parameter is an array variable
// subscripted with ‘@’ or ‘*’, the case modification operation is applied to each
// member of the array in turn, and the expansion is the resultant list.
[`^(${name})(\\^\\^|\\^|,,|,)(.*)$`]: {
op: 'caseChange',
parameter: m => m[1],
pattern: m => m[3] || '?',
case: m => m[2][0] === ',' ? 'lower' : 'upper',
globally: m => m[2].length === 2
},
// The expansion is either a transformation of the value of parameter or information about
// parameter itself, depending on the value of operator. Each operator is a single letter:
//
// Q - The expansion is a string that is the value of parameter quoted in a format that can
// be reused as input.
// E - The expansion is a string that is the value of parameter with backslash escape
// sequences expanded as with the $'…' quoting mechansim.
// P - The expansion is a string that is the result of expanding the value of parameter
// as if it were a prompt string (see Controlling the Prompt).
// A - The expansion is a string in the form of an assignment statement or declare command
// that, if evaluated, will recreate parameter with its attributes and value.
// a - The expansion is a string consisting of flag values representing parameter’s attributes.
//
// If parameter is ‘@’ or ‘*’, the operation is applied to each positional parameter in turn,
// and the expansion is the resultant list. If parameter is an array variable subscripted
// with ‘@’ or ‘*’, the operation is applied to each member of the array in turn, and the
// expansion is the resultant list.
// The result of the expansion is subject to word splitting and pathname expansion as
// described below.
[`^(${name})@([Q|E|P|A|a])$`]: {
op: 'transformation',
parameter: m => m[1],
kind: m => {
switch (m[2]) {
case 'Q': return 'quoted';
case 'E': return 'escape';
case 'P': return 'prompt';
case 'A': return 'assignment';
case 'a': return 'flags';
default: return 'unknown';
}
}
},
// If the first character of parameter is an exclamation point (!), and parameter is not
// a nameref, it introduces a level of variable indirection. Bash uses the value of the
// variable formed from the rest of parameter as the name of the variable; this variable
// is then expanded and that value is used in the rest of the substitution, rather than
// the value of parameter itself. This is known as indirect expansion. If parameter is a
// nameref, this expands to the name of the variable referenced by parameter instead of
// performing the complete indirect expansion. The exceptions to this are the expansions
// of ${!prefix*} and ${!name[@]} described below. The exclamation point must immediately
// follow the left brace in order to introduce indirection.
[`^!(.+)$`]: {
op: 'indirection',
word: m => m[1],
parameter: () => undefined
}
};
module.exports = {

@@ -21,4 +140,19 @@ inherits: 'posix',

return Object.assign({}, posixMode, {phaseCatalog, lexerPhases});
const bashOperators = Object.assign(
parameterOperators,
posixMode.enums.parameterOperators
);
const enums = Object.assign(
{},
posixMode.enums,
{parameterOperators: bashOperators}
);
return Object.assign(
{},
posixMode,
{phaseCatalog, lexerPhases, enums}
);
}
};

@@ -82,2 +82,11 @@ 'use strict';

builder.addRedirections = (compoundCommand, redirectList) => {
compoundCommand.redirections = redirectList;
if (options.insertLOC) {
const lastRedirect = redirectList[redirectList.length - 1];
setLocEnd(compoundCommand.loc, lastRedirect.loc);
}
return compoundCommand;
};
builder.term = logicalExpression => {

@@ -172,5 +181,14 @@ const node = {type: 'CompoundList', commands: [logicalExpression]};

builder.functionDefinition = (name, body) => {
const node = {type: 'Function', name, body};
const node = {type: 'Function', name};
node.body = body[0];
if (body[1]) {
node.redirections = body[1];
}
const endLoc = body[1] || body[0];
if (options.insertLOC) {
node.loc = setLocEnd(setLocStart({}, name.loc), body.loc);
node.loc = setLocEnd(setLocStart({}, name.loc), endLoc.loc);
}

@@ -224,7 +242,10 @@ return node;

builder.commandAssignment = function commandAssignment(prefix) {
return builder.command(prefix, {text: '', type: 'Word'});
return builder.command(prefix);
};
builder.command = function command(prefix, command, suffix) {
const node = {type: 'Command', name: command};
const node = {type: 'Command'};
if (command) {
node.name = command;
}

@@ -243,4 +264,7 @@ if (options.insertLOC) {

node.loc.end = lastSuffix.loc.end;
} else if (command) {
node.loc.end = command.loc.end;
} else {
node.loc.end = command.loc.end;
const lastPrefix = prefix[prefix.length - 1];
node.loc.end = lastPrefix.loc.end;
}

@@ -247,0 +271,0 @@ }

@@ -122,2 +122,5 @@ /* parser generated by jison 0.4.17 */

break;
case 16:
this.$ = yy.addRedirections($$[$0-1], $$[$0])
break;
case 25:

@@ -184,3 +187,3 @@ this.$ = yy.subshell($$[$0-1], $$[$0-2].loc, $$[$0].loc);

case 55:
this.$ = yy.patternAppend(pattern, $$[$0]);
this.$ = yy.patternAppend($$[$0-2], $$[$0]);
break;

@@ -211,2 +214,8 @@ case 56:

break;
case 64:
this.$ = [$$[$0], null];
break;
case 65:
this.$ = [$$[$0-1], $$[$0]];
break;
case 67:

@@ -255,3 +264,3 @@ this.$ = yy.braceGroup($$[$0-1], $$[$0-2].loc, $$[$0].loc);

case 85:
this.$ = [$$[$0-1].concat($$[$0])];
this.$ = $$[$0-1].concat($$[$0]);
break;

@@ -258,0 +267,0 @@ case 87:

@@ -71,3 +71,6 @@ /* eslint-disable max-lines */

'compound_command',
'compound_command redirect_list',
[
'compound_command redirect_list',
'$$ = yy.addRedirections($compound_command, $redirect_list)'
],
'function_definition'

@@ -223,3 +226,3 @@ ],

'pattern PIPE WORD',
'$$ = yy.patternAppend(pattern, $WORD);'
'$$ = yy.patternAppend($pattern, $WORD);'
]

@@ -270,4 +273,10 @@ ],

function_body: [
'compound_command',
'compound_command redirect_list'
[
'compound_command',
'$$ = [$compound_command, null];'
],
[
'compound_command redirect_list',
'$$ = [$compound_command, $redirect_list];'
]
],

@@ -366,3 +375,3 @@ fname: [

'redirect_list io_redirect',
'$$ = [$redirect_list.concat($io_redirect)];'
'$$ = $redirect_list.concat($io_redirect);'
]

@@ -369,0 +378,0 @@ ],

'use strict';
const mapObj = require('map-obj');
const filter = require('filter-obj');
const map = require('map-iterable');

@@ -12,3 +13,4 @@ const pairs = require('object-pairs');

if (typeof v === 'function') {
return [k, v(match)];
const val = v(match);
return [k, val];
}

@@ -47,6 +49,6 @@

return Object.assign(
return filter(Object.assign(
xp,
opProps
);
), (k, v) => v !== undefined);
}

@@ -53,0 +55,0 @@ }

@@ -7,3 +7,3 @@ 'use strict';

let replaced = false;
let result = text.replace(/^~[^\/]*\//, (match, p1) => {
let result = text.replace(/^~([^\/]*)\//, (match, p1) => {
replaced = true;

@@ -14,3 +14,3 @@ return resolveHomeUser(p1 || null) + '/';

if (!replaced) {
result = text.replace(/^~.*$/, (match, p1) => {
result = text.replace(/^~(.*)$/, (match, p1) => {
return resolveHomeUser(p1 || null);

@@ -17,0 +17,0 @@ });

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