2018-02-28 19:13:49 +00:00
|
|
|
const SPECIAL_CHARACTERS = [
|
|
|
|
"'", '"',
|
|
|
|
'<', '>',
|
|
|
|
'{', '}',
|
|
|
|
'\\[', '\\]',
|
|
|
|
'(', ')',
|
|
|
|
'`', '$',
|
2018-03-01 00:29:42 +00:00
|
|
|
'|', '&', ';',
|
2018-02-28 19:13:49 +00:00
|
|
|
'\\',
|
|
|
|
'\\s',
|
|
|
|
'#',
|
|
|
|
];
|
|
|
|
|
2017-07-14 19:28:54 +00:00
|
|
|
module.exports = grammar({
|
|
|
|
name: 'bash',
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
inline: $ => [
|
2017-07-16 05:23:38 +00:00
|
|
|
$._statement,
|
|
|
|
$._terminator,
|
|
|
|
$._expression,
|
2018-02-27 18:54:40 +00:00
|
|
|
$._primary_expression,
|
2018-02-27 18:54:40 +00:00
|
|
|
$._simple_variable_name,
|
2018-02-28 19:13:49 +00:00
|
|
|
$._special_variable_name,
|
2017-07-16 05:13:55 +00:00
|
|
|
],
|
2017-07-14 19:28:54 +00:00
|
|
|
|
2017-07-14 20:54:05 +00:00
|
|
|
externals: $ => [
|
2017-07-14 21:27:13 +00:00
|
|
|
$._simple_heredoc,
|
|
|
|
$._heredoc_beginning,
|
|
|
|
$._heredoc_middle,
|
2017-07-15 00:14:23 +00:00
|
|
|
$._heredoc_end,
|
2017-07-15 00:41:14 +00:00
|
|
|
$.file_descriptor,
|
2017-07-16 06:12:22 +00:00
|
|
|
$._empty_value,
|
2017-07-17 17:19:35 +00:00
|
|
|
$._concat,
|
2018-02-27 18:54:40 +00:00
|
|
|
$.variable_name, // Variable name followed by an operator like '=' or '+='
|
2018-02-27 18:54:40 +00:00
|
|
|
'}',
|
2018-02-28 19:13:49 +00:00
|
|
|
']',
|
|
|
|
'\n',
|
2017-07-14 20:54:05 +00:00
|
|
|
],
|
|
|
|
|
2017-07-14 21:34:49 +00:00
|
|
|
extras: $ => [
|
|
|
|
$.comment,
|
2017-07-14 21:39:28 +00:00
|
|
|
token(choice(/\s/, '\\\n')),
|
2017-07-14 21:34:49 +00:00
|
|
|
],
|
|
|
|
|
2017-07-14 19:28:54 +00:00
|
|
|
rules: {
|
2017-07-14 23:11:35 +00:00
|
|
|
program: $ => repeat($._terminated_statement),
|
2017-07-14 19:28:54 +00:00
|
|
|
|
2017-07-14 23:11:35 +00:00
|
|
|
_terminated_statement: $ => seq(
|
2017-07-16 05:23:38 +00:00
|
|
|
$._statement,
|
|
|
|
$._terminator
|
2017-07-14 23:11:35 +00:00
|
|
|
),
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
// Statements
|
|
|
|
|
2017-07-16 05:23:38 +00:00
|
|
|
_statement: $ => choice(
|
2018-02-27 21:22:28 +00:00
|
|
|
$.variable_assignment,
|
2017-07-14 23:11:35 +00:00
|
|
|
$.command,
|
2018-02-27 21:22:28 +00:00
|
|
|
$.declaration_command,
|
2018-03-01 18:12:10 +00:00
|
|
|
$.unset_command,
|
2018-03-01 06:46:47 +00:00
|
|
|
$.bracket_command,
|
2017-07-15 00:51:06 +00:00
|
|
|
$.for_statement,
|
2017-07-14 23:11:35 +00:00
|
|
|
$.while_statement,
|
2017-07-14 23:18:46 +00:00
|
|
|
$.if_statement,
|
2017-07-14 23:29:28 +00:00
|
|
|
$.case_statement,
|
2017-07-14 23:11:35 +00:00
|
|
|
$.pipeline,
|
2017-07-15 00:32:55 +00:00
|
|
|
$.list,
|
2017-07-15 00:35:51 +00:00
|
|
|
$.subshell,
|
|
|
|
$.function_definition
|
2017-07-14 23:11:35 +00:00
|
|
|
),
|
|
|
|
|
2017-07-15 00:51:06 +00:00
|
|
|
for_statement: $ => seq(
|
|
|
|
'for',
|
2018-02-27 18:54:40 +00:00
|
|
|
$._simple_variable_name,
|
2018-03-02 18:18:12 +00:00
|
|
|
optional(seq(
|
|
|
|
'in',
|
|
|
|
repeat1($._expression)
|
|
|
|
)),
|
2017-07-17 17:19:35 +00:00
|
|
|
$._terminator,
|
2017-07-15 00:51:06 +00:00
|
|
|
$.do_group
|
|
|
|
),
|
|
|
|
|
2017-07-14 23:11:35 +00:00
|
|
|
while_statement: $ => seq(
|
|
|
|
'while',
|
|
|
|
$._terminated_statement,
|
2018-03-01 00:28:30 +00:00
|
|
|
$.do_group,
|
|
|
|
repeat(choice(
|
|
|
|
$.file_redirect,
|
|
|
|
$.heredoc_redirect,
|
|
|
|
$.herestring_redirect
|
|
|
|
))
|
2017-07-14 23:11:35 +00:00
|
|
|
),
|
|
|
|
|
2017-07-14 23:29:28 +00:00
|
|
|
do_group: $ => seq(
|
|
|
|
'do',
|
|
|
|
repeat($._terminated_statement),
|
|
|
|
'done'
|
|
|
|
),
|
|
|
|
|
2017-07-14 23:18:46 +00:00
|
|
|
if_statement: $ => seq(
|
|
|
|
'if',
|
|
|
|
$._terminated_statement,
|
|
|
|
'then',
|
|
|
|
repeat($._terminated_statement),
|
|
|
|
repeat($.elif_clause),
|
|
|
|
optional($.else_clause),
|
|
|
|
'fi'
|
|
|
|
),
|
|
|
|
|
|
|
|
elif_clause: $ => seq(
|
|
|
|
'elif',
|
|
|
|
$._terminated_statement,
|
|
|
|
'then',
|
|
|
|
repeat($._terminated_statement)
|
|
|
|
),
|
|
|
|
|
|
|
|
else_clause: $ => seq(
|
|
|
|
'else',
|
|
|
|
repeat($._terminated_statement)
|
|
|
|
),
|
|
|
|
|
2017-07-14 23:29:28 +00:00
|
|
|
case_statement: $ => seq(
|
|
|
|
'case',
|
2017-07-16 05:23:38 +00:00
|
|
|
$._expression,
|
|
|
|
optional($._terminator),
|
2017-07-14 23:29:28 +00:00
|
|
|
'in',
|
2017-07-16 05:23:38 +00:00
|
|
|
$._terminator,
|
2018-03-01 00:29:42 +00:00
|
|
|
optional(seq(
|
|
|
|
repeat($.case_item),
|
|
|
|
alias($.last_case_item, $.case_item),
|
|
|
|
)),
|
2017-07-14 23:29:28 +00:00
|
|
|
'esac'
|
|
|
|
),
|
|
|
|
|
|
|
|
case_item: $ => seq(
|
2017-07-16 05:23:38 +00:00
|
|
|
$._expression,
|
2017-07-17 17:19:35 +00:00
|
|
|
repeat(seq('|', $._expression)),
|
2017-07-14 23:29:28 +00:00
|
|
|
')',
|
2018-03-01 22:04:29 +00:00
|
|
|
optional(seq(
|
|
|
|
repeat($._terminated_statement),
|
|
|
|
optional($._statement)
|
|
|
|
)),
|
|
|
|
prec(1, ';;')
|
2017-07-14 19:28:54 +00:00
|
|
|
),
|
|
|
|
|
2018-03-01 00:29:42 +00:00
|
|
|
last_case_item: $ => seq(
|
|
|
|
$._expression,
|
|
|
|
repeat(seq('|', $._expression)),
|
|
|
|
')',
|
2018-03-01 22:04:29 +00:00
|
|
|
optional(seq(
|
|
|
|
repeat($._terminated_statement),
|
|
|
|
optional($._statement)
|
|
|
|
)),
|
|
|
|
optional(prec(1, ';;'))
|
2018-03-01 00:29:42 +00:00
|
|
|
),
|
|
|
|
|
2017-07-15 00:35:51 +00:00
|
|
|
function_definition: $ => seq(
|
2018-02-27 18:54:20 +00:00
|
|
|
choice(
|
2018-02-28 19:13:49 +00:00
|
|
|
seq('function', $.word, optional(seq('(', ')'))),
|
|
|
|
seq($.word, '(', ')')
|
2018-02-27 18:54:20 +00:00
|
|
|
),
|
2017-12-26 22:27:05 +00:00
|
|
|
$.compound_statement,
|
|
|
|
optional($.file_redirect)
|
2017-07-15 00:35:51 +00:00
|
|
|
),
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
compound_statement: $ => seq(
|
2017-07-15 00:35:51 +00:00
|
|
|
'{',
|
|
|
|
repeat($._terminated_statement),
|
|
|
|
'}'
|
|
|
|
),
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
subshell: $ => seq(
|
|
|
|
'(',
|
|
|
|
repeat($._terminated_statement),
|
2017-07-17 17:19:35 +00:00
|
|
|
$._statement,
|
|
|
|
optional($._terminator),
|
2017-07-16 05:13:55 +00:00
|
|
|
')'
|
|
|
|
),
|
|
|
|
|
|
|
|
pipeline: $ => prec.left(1, seq(
|
2017-07-16 05:23:38 +00:00
|
|
|
$._statement,
|
2017-07-16 05:13:55 +00:00
|
|
|
choice('|', '|&'),
|
2017-07-16 05:23:38 +00:00
|
|
|
$._statement
|
2017-07-16 05:13:55 +00:00
|
|
|
)),
|
|
|
|
|
2017-07-16 05:41:56 +00:00
|
|
|
list: $ => prec.left(-1, seq(
|
2017-07-16 05:23:38 +00:00
|
|
|
$._statement,
|
2017-07-16 05:13:55 +00:00
|
|
|
choice('&&', '||'),
|
2017-07-16 05:23:38 +00:00
|
|
|
$._statement
|
2017-07-16 05:13:55 +00:00
|
|
|
)),
|
|
|
|
|
|
|
|
// Commands
|
|
|
|
|
|
|
|
command: $ => prec.left(seq(
|
2017-07-14 19:43:42 +00:00
|
|
|
repeat(choice(
|
2018-02-27 21:22:28 +00:00
|
|
|
$.variable_assignment,
|
2017-07-14 19:43:42 +00:00
|
|
|
$.file_redirect
|
|
|
|
)),
|
2017-07-17 17:19:35 +00:00
|
|
|
$.command_name,
|
2018-03-01 18:42:20 +00:00
|
|
|
repeat(choice(
|
|
|
|
$._expression,
|
2018-03-01 22:15:29 +00:00
|
|
|
seq(
|
|
|
|
choice('=~', '=='),
|
|
|
|
choice($.regex, $._expression)
|
|
|
|
)
|
2018-03-01 18:42:20 +00:00
|
|
|
)),
|
2017-07-14 20:54:05 +00:00
|
|
|
repeat(choice(
|
|
|
|
$.file_redirect,
|
2018-02-28 19:13:49 +00:00
|
|
|
$.heredoc_redirect,
|
|
|
|
$.herestring_redirect
|
2017-07-14 20:54:05 +00:00
|
|
|
))
|
2017-07-14 19:28:54 +00:00
|
|
|
)),
|
|
|
|
|
2017-07-17 17:19:35 +00:00
|
|
|
command_name: $ => $._expression,
|
|
|
|
|
2018-03-01 18:42:20 +00:00
|
|
|
bracket_command: $ => {
|
|
|
|
const args = repeat1(choice(
|
|
|
|
$._expression,
|
2018-03-01 22:15:29 +00:00
|
|
|
seq(
|
|
|
|
choice('=~', '=='),
|
|
|
|
choice($.regex, $._expression)
|
|
|
|
)
|
2018-03-01 18:42:20 +00:00
|
|
|
))
|
|
|
|
|
|
|
|
return seq(
|
|
|
|
choice(
|
|
|
|
seq('[', args, ']'),
|
|
|
|
seq('[[', args, ']]')
|
|
|
|
),
|
|
|
|
repeat(choice(
|
|
|
|
$.file_redirect,
|
|
|
|
$.heredoc_redirect,
|
|
|
|
$.herestring_redirect
|
|
|
|
))
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
2018-02-27 21:22:28 +00:00
|
|
|
variable_assignment: $ => seq(
|
2017-07-17 17:19:35 +00:00
|
|
|
choice(
|
|
|
|
$.variable_name,
|
|
|
|
$.subscript
|
|
|
|
),
|
2018-02-24 23:02:24 +00:00
|
|
|
$._assignment
|
|
|
|
),
|
|
|
|
|
2018-03-01 01:32:48 +00:00
|
|
|
declaration_command: $ => prec.left(seq(
|
2018-02-27 21:22:28 +00:00
|
|
|
choice('declare', 'typeset', 'export', 'readonly', 'local'),
|
|
|
|
repeat(choice(
|
2018-03-01 01:32:48 +00:00
|
|
|
$._expression,
|
2018-02-27 18:54:40 +00:00
|
|
|
$._simple_variable_name,
|
2018-02-27 21:22:28 +00:00
|
|
|
$.variable_assignment
|
|
|
|
))
|
2018-03-01 01:32:48 +00:00
|
|
|
)),
|
2018-02-24 23:02:24 +00:00
|
|
|
|
2018-03-01 18:12:10 +00:00
|
|
|
unset_command: $ => prec.left(seq(
|
|
|
|
choice('unset', 'unsetenv'),
|
|
|
|
repeat(choice(
|
|
|
|
$._expression,
|
|
|
|
$._simple_variable_name
|
|
|
|
))
|
|
|
|
)),
|
|
|
|
|
2018-02-24 23:02:24 +00:00
|
|
|
_assignment: $ => seq(
|
2017-12-26 22:55:37 +00:00
|
|
|
choice(
|
|
|
|
'=',
|
|
|
|
'+='
|
|
|
|
),
|
2017-07-15 00:41:14 +00:00
|
|
|
choice(
|
2017-07-16 05:23:38 +00:00
|
|
|
$._expression,
|
2017-07-17 17:19:35 +00:00
|
|
|
$.array,
|
2017-07-15 00:41:14 +00:00
|
|
|
$._empty_value
|
|
|
|
)
|
2017-07-14 23:47:25 +00:00
|
|
|
),
|
|
|
|
|
2017-07-17 17:19:35 +00:00
|
|
|
subscript: $ => seq(
|
|
|
|
$.variable_name,
|
|
|
|
'[',
|
|
|
|
$._expression,
|
2018-02-28 19:13:49 +00:00
|
|
|
optional($._concat),
|
|
|
|
']',
|
|
|
|
optional($._concat)
|
2017-07-17 17:19:35 +00:00
|
|
|
),
|
|
|
|
|
|
|
|
file_redirect: $ => prec.left(seq(
|
2017-07-16 05:13:55 +00:00
|
|
|
optional($.file_descriptor),
|
|
|
|
choice('<', '>', '>>', '&>', '&>>', '<&', '>&'),
|
2017-07-16 05:23:38 +00:00
|
|
|
$._expression
|
2017-07-17 17:19:35 +00:00
|
|
|
)),
|
2017-07-16 05:13:55 +00:00
|
|
|
|
|
|
|
heredoc_redirect: $ => seq(
|
|
|
|
choice('<<', '<<-'),
|
|
|
|
$.heredoc
|
|
|
|
),
|
|
|
|
|
|
|
|
heredoc: $ => choice(
|
|
|
|
$._simple_heredoc,
|
|
|
|
seq(
|
|
|
|
$._heredoc_beginning,
|
|
|
|
repeat(choice(
|
|
|
|
$.expansion,
|
|
|
|
$.simple_expansion,
|
|
|
|
$._heredoc_middle
|
|
|
|
)),
|
|
|
|
$._heredoc_end
|
|
|
|
)
|
|
|
|
),
|
|
|
|
|
2018-02-28 19:13:49 +00:00
|
|
|
herestring_redirect: $ => seq(
|
|
|
|
'<<<',
|
|
|
|
$._expression
|
|
|
|
),
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
// Expressions
|
|
|
|
|
2017-07-16 05:23:38 +00:00
|
|
|
_expression: $ => choice(
|
2018-02-27 18:54:40 +00:00
|
|
|
$.concatenation,
|
2018-02-28 19:13:49 +00:00
|
|
|
$._primary_expression,
|
|
|
|
alias(prec(-2, $._special_characters), $.word)
|
2018-02-27 18:54:40 +00:00
|
|
|
),
|
|
|
|
|
|
|
|
_primary_expression: $ => choice(
|
2017-07-16 05:13:55 +00:00
|
|
|
$.word,
|
|
|
|
$.string,
|
|
|
|
$.raw_string,
|
2017-07-14 23:47:25 +00:00
|
|
|
$.expansion,
|
2017-07-16 05:13:55 +00:00
|
|
|
$.simple_expansion,
|
2018-03-01 17:54:08 +00:00
|
|
|
$.string_expansion,
|
2017-07-16 05:22:38 +00:00
|
|
|
$.command_substitution,
|
2018-02-27 18:54:40 +00:00
|
|
|
$.process_substitution
|
2017-07-14 19:28:54 +00:00
|
|
|
),
|
|
|
|
|
2017-07-17 17:19:35 +00:00
|
|
|
concatenation: $ => prec(-1, seq(
|
2018-02-28 19:13:49 +00:00
|
|
|
choice(
|
|
|
|
$._primary_expression,
|
|
|
|
$._special_characters,
|
|
|
|
),
|
|
|
|
repeat1(prec(-1, seq(
|
|
|
|
$._concat,
|
|
|
|
choice(
|
|
|
|
$._primary_expression,
|
|
|
|
$._special_characters,
|
|
|
|
)
|
|
|
|
))),
|
2017-07-17 17:19:35 +00:00
|
|
|
)),
|
|
|
|
|
2018-02-28 19:13:49 +00:00
|
|
|
_special_characters: $ => token(prec(-1, repeat1(choice('{', '}', '[', ']')))),
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
string: $ => seq(
|
2017-07-14 23:47:25 +00:00
|
|
|
'"',
|
2018-02-28 19:13:49 +00:00
|
|
|
repeat(seq(
|
|
|
|
choice(
|
2018-03-01 17:54:08 +00:00
|
|
|
seq(optional('$'), $._string_content),
|
2018-02-28 19:13:49 +00:00
|
|
|
$.expansion,
|
|
|
|
$.simple_expansion,
|
|
|
|
$.command_substitution
|
|
|
|
),
|
|
|
|
optional($._concat)
|
2017-07-14 23:47:25 +00:00
|
|
|
)),
|
|
|
|
'"'
|
|
|
|
),
|
|
|
|
|
2018-03-01 17:54:08 +00:00
|
|
|
_string_content: $ => token(prec(-1, /([^"`$]|\\.)+/)),
|
2018-02-27 18:54:40 +00:00
|
|
|
|
2017-07-16 05:41:56 +00:00
|
|
|
array: $ => seq(
|
|
|
|
'(',
|
2017-12-26 22:55:37 +00:00
|
|
|
repeat($._expression),
|
2017-07-16 05:41:56 +00:00
|
|
|
')'
|
|
|
|
),
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
raw_string: $ => /'[^']*'/,
|
2017-07-14 23:47:25 +00:00
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
simple_expansion: $ => seq(
|
2017-07-14 20:00:41 +00:00
|
|
|
'$',
|
2018-03-01 01:32:48 +00:00
|
|
|
choice(
|
|
|
|
$._simple_variable_name,
|
|
|
|
$._special_variable_name,
|
2018-03-01 17:54:08 +00:00
|
|
|
alias('#', $.special_variable_name)
|
2018-03-01 01:32:48 +00:00
|
|
|
)
|
2017-07-14 20:00:41 +00:00
|
|
|
),
|
|
|
|
|
2018-03-01 22:15:15 +00:00
|
|
|
string_expansion: $ => seq('$', choice($.string, $.raw_string)),
|
2018-03-01 17:54:08 +00:00
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
expansion: $ => seq(
|
2017-07-14 20:00:41 +00:00
|
|
|
'${',
|
2018-02-28 19:13:49 +00:00
|
|
|
optional('#'),
|
2017-07-16 06:12:22 +00:00
|
|
|
choice(
|
|
|
|
seq(
|
2018-02-28 19:13:49 +00:00
|
|
|
$.variable_name,
|
|
|
|
'=',
|
2018-03-01 00:28:55 +00:00
|
|
|
optional($._expression)
|
2018-02-28 19:13:49 +00:00
|
|
|
),
|
|
|
|
seq(
|
|
|
|
choice(
|
|
|
|
$.subscript,
|
|
|
|
$._simple_variable_name,
|
|
|
|
$._special_variable_name
|
|
|
|
),
|
2018-03-01 18:41:16 +00:00
|
|
|
optional(seq(
|
|
|
|
token(prec(1, '/')),
|
|
|
|
alias($.regex_without_right_brace, $.regex)
|
|
|
|
)),
|
2018-03-01 00:28:55 +00:00
|
|
|
repeat(choice(
|
|
|
|
$._expression,
|
2018-03-01 18:41:16 +00:00
|
|
|
':', ':?', '=', ':-', '%', '-', '#'
|
2018-02-28 19:13:49 +00:00
|
|
|
))
|
|
|
|
),
|
2017-07-16 06:12:22 +00:00
|
|
|
),
|
2017-07-14 20:00:41 +00:00
|
|
|
'}'
|
|
|
|
),
|
|
|
|
|
2017-07-16 05:13:55 +00:00
|
|
|
command_substitution: $ => choice(
|
2017-07-16 05:41:56 +00:00
|
|
|
seq('$(', $._statement, ')'),
|
|
|
|
prec(1, seq('`', $._statement, '`'))
|
2017-07-14 19:43:42 +00:00
|
|
|
),
|
|
|
|
|
2017-07-16 05:22:38 +00:00
|
|
|
process_substitution: $ => seq(
|
2017-07-17 17:19:35 +00:00
|
|
|
choice('<(', '>('),
|
2017-07-16 05:23:38 +00:00
|
|
|
$._statement,
|
2017-07-16 05:22:38 +00:00
|
|
|
')'
|
|
|
|
),
|
|
|
|
|
2018-03-01 17:54:08 +00:00
|
|
|
comment: $ => token(prec(-10, /#.*/)),
|
2017-07-14 19:28:54 +00:00
|
|
|
|
2018-02-28 19:13:49 +00:00
|
|
|
_simple_variable_name: $ => alias(/\w+/, $.variable_name),
|
2018-02-27 18:54:40 +00:00
|
|
|
|
2018-02-28 19:13:49 +00:00
|
|
|
_special_variable_name: $ => alias(choice('*', '@', '?', '-', '$', '0', '_'), $.special_variable_name),
|
2017-07-14 21:34:49 +00:00
|
|
|
|
2018-02-28 19:13:49 +00:00
|
|
|
word: $ => token(repeat1(choice(
|
|
|
|
noneOf(...SPECIAL_CHARACTERS),
|
|
|
|
seq('\\', noneOf('\\s'))
|
|
|
|
))),
|
2017-07-14 23:29:28 +00:00
|
|
|
|
2018-03-01 22:15:29 +00:00
|
|
|
regex: $ => /([^"\s]|\\.)([^\s]|\\.)*/,
|
|
|
|
regex_without_right_brace: $ => /([^"\s}]|\\.)([^\s}]|\\.)*/,
|
2018-03-01 17:53:10 +00:00
|
|
|
|
2017-07-17 17:19:35 +00:00
|
|
|
_terminator: $ => choice(';', ';;', '\n', '&')
|
2017-07-14 19:28:54 +00:00
|
|
|
}
|
|
|
|
});
|
2018-02-28 19:13:49 +00:00
|
|
|
|
|
|
|
function noneOf(...characters) {
|
|
|
|
const negatedString = characters.map(c => c == '\\' ? '\\\\' : c).join('')
|
|
|
|
return new RegExp('[^' + negatedString + ']')
|
|
|
|
}
|