├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── Vagrantfile ├── configs └── vagrant │ ├── home │ ├── .config │ │ └── geany │ │ │ └── geany.conf │ └── .profile │ └── provision.sh ├── index.js ├── package.json └── test └── escape-regex-string.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "mocha": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "rules": { 9 | "indent": [ 10 | "error", 11 | 4 12 | ], 13 | "linebreak-style": [ 14 | "error", 15 | "unix" 16 | ], 17 | "max-len": [ 18 | "error", 19 | { 20 | "code": 120 21 | } 22 | ], 23 | "no-multi-spaces": "error", 24 | "quotes": [ 25 | "error", 26 | "single" 27 | ], 28 | "semi": [ 29 | "error", 30 | "always" 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Prevent Vagrant provisioning files from being used to determine GitHub repo language type. 2 | # Without this rule, GitHub labels the repo as predominantly "shell", where it should be "JavaScript". 3 | # https://github.com/github/linguist#overrides 4 | configs/** linguist-detectable=false 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Local Vagrant state files 6 | .vagrant 7 | 8 | # Ignore docs directory as it is generated at will by running jsdoc task 9 | docs 10 | 11 | # Dependency directory 12 | node_modules 13 | 14 | # npm package lock file which is unnecessary in this context. 15 | package-lock.json 16 | 17 | # npm-pack output archives 18 | **/*.tgz 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Some files, such as the node_modules directory, are always ignored. 2 | # https://docs.npmjs.com/files/package.json#files 3 | 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Local Vagrant state files 9 | .vagrant 10 | 11 | # Config files 12 | .eslintrc.json 13 | .git* 14 | .jscsrc 15 | .npmignore 16 | .travis.yml 17 | 18 | # Dev directories 19 | # Ignore docs directory as it is generated at will by running jsdoc task 20 | docs 21 | test 22 | 23 | # Misc 24 | **/*.tgz 25 | configs 26 | Makefile 27 | Vagrantfile 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - "lts/*" 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 monotonee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN=$(shell npm bin) 2 | DOC_DEST=./docs 3 | MODULE=./index.js 4 | TESTS=$(wildcard ./test/*.js) 5 | ALL_SRC=$(MODULE) $(TESTS) 6 | 7 | .PHONY: all clean docs lint tests 8 | 9 | all: lint tests 10 | 11 | clean: 12 | rm -Rf $(DOC_DEST) 13 | 14 | docs: $(BIN)/jsdoc $(ALL_SRC) 15 | $< $(ALL_SRC) --verbose --destination $(DOC_DEST) 16 | 17 | lint: $(BIN)/eslint $(ALL_SRC) 18 | $< $(ALL_SRC) --no-color 19 | 20 | tests: $(BIN)/mocha $(TESTS) 21 | $< $(TESTS) --no-colors --check-leaks 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # escape-regex-string [![Build Status](https://travis-ci.org/monotonee/escape-regex-string.svg?branch=master)](https://travis-ci.org/monotonee/escape-regex-string) [![npm version](https://badge.fury.io/js/escape-regex-string.svg)](https://www.npmjs.com/package/escape-regex-string) 2 | 3 | Escapes a string literal for use as an argument in the standard RegExp constructor. 4 | 5 | ## Interface 6 | 7 | #### escape-regex-string 8 | 9 | ```javascript 10 | (require('escape-regex-string'))(unescapedString[, escapeCharsRegex]) 11 | ``` 12 | * unescapedString [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) 13 | * The regular expression pattern string in which all special characters need to be escaped. 14 | * escapeCharsRegex [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) 15 | * Defaults to value of member escape-regex-string.defaultEscapeCharsRegex (see below) 16 | 17 | Returns the passed unescapedString with all RegExp special characters escaped. 18 | 19 | #### escape-regex-string.defaultEscapeCharsRegex 20 | 21 | ```javascript 22 | (require('escape-regex-string')).defaultEscapeCharsRegex 23 | ``` 24 | A read-only RegExp instance containing the default pattern used to escape passed strings. If a RegExp instance is 25 | manually passed into a function call to this module, the passed RegExp value will be used instead of this default value. 26 | 27 | ## Example Usage 28 | ```javascript 29 | let escapeRegexString = require('escape-regex-string'); 30 | let regexPatternString = '$&*()awsd'; 31 | let escapedRegexPatternString = escapeRegexString(regexPatternString); 32 | console.log(escapedRegexPatternString); // '\\$&\\*\\(\\)awsd' 33 | let regExpObject = new RegExp(escapedRegexPatternString); 34 | console.log(regExpObject); // /\$&\*\(\)awsd/ 35 | ``` 36 | 37 | ## Explanation 38 | The built-in JavaScript [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) 39 | object's constructor accepts a regular expression pattern in the form of another RegExp instance **or a string.** And, 40 | as we know, the JavaScript regular expression syntax includes a set of characters with special meaning when interpreted 41 | by the regex engine, such as the caret (^) and the asterisk (*). A problem is introduced when one attempts to create a 42 | regular expression pattern in a *string* (*not* a 43 | [RegExp literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Description)), 44 | for use in the RegExp constructor, that contains special regular expression characters *to be matched literally.* 45 | Consider the following extra-verbose example: 46 | 47 | A developer wants to use a RegExp to match caret characters in a given string: 48 | ```javascript 49 | let inputStr = 'a^2'; 50 | ``` 51 | For whatever reason, the dev is unwilling or unable to use the RegExp literal syntax and therefore attempts to define a 52 | regular expression pattern *in a string* to be passed to the RegExp constructor: 53 | ```javascript 54 | let firstPattern = '^'; 55 | let firstRegExp = new RegExp(firstPattern); 56 | ``` 57 | When the expression is evaluated, the results are incorrect because the caret is a regular expression special character 58 | representing the [beginning of the input](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#special-caret). 59 | The beginning of the subject string will therefore be the only match: 60 | ```javascript 61 | let firstResult = firstRegExp.exec(inputStr); 62 | console.log(firstResult); // [ '', index: 0, input: 'a^2' ] 63 | ``` 64 | The developer realizes he needs to escape the special caret character and therefore redefines his pattern with the 65 | standard backslash escape character: 66 | ```javascript 67 | let secondPattern = '\^'; 68 | let secondRegExp = new RegExp(secondPattern); 69 | let secondResult = secondRegExp.exec(inputStr); 70 | console.log(secondResult); // [ '', index: 0, input: 'a^2' ] 71 | ``` 72 | When the developer evaluates the second expression, however, the results are the same. This is because JavaScript *will 73 | first evaluate the backslash escape character in the pattern string,* before it ever reaches the RegExp constructor. 74 | When the developer eexamines the second pattern string, it is identical to the first despite the added backslash. 75 | ```javascript 76 | console.log(firstPattern === secondPattern); // true 77 | ``` 78 | Finally, the developer adds a second backslash to the pattern string, causing the JavaScript interpreter to preserve a 79 | single backslash character in the string stored in memory. This single backslash is successfully passed to the RegExp 80 | constructor, the expression therefore interprets the caret character literally, and the caret is correctly matched 81 | inside the input string: 82 | ```javascript 83 | let finalPattern = '\\^'; 84 | let finalRegExp = new RegExp(finalPattern); 85 | let finalResult = finalRegExp.exec(inputStr); 86 | console.log(finalResult); // [ '^', index: 1, input: 'a^2' ] 87 | ``` 88 | This is essentially a simple case of double-escaping. This module simply saves developers the trouble of determining the 89 | set of JavaScript's regular expression special characters and writing a function to escape them. 90 | 91 | ## Development 92 | 93 | To set up an optional development environment, a Vagrantfile is included. Install [Vagrant](https://www.vagrantup.com) 94 | and run: 95 | ```sh 96 | vagrant up 97 | ``` 98 | Once Vagrant has completed provisioning, `vagrant ssh` into the box and run the tests with: 99 | ```sh 100 | make 101 | ``` 102 | 103 | ## Feedback 104 | 105 | I wrote this miniature module to practice with a few of the tools, libraries, and workflows available to JS developers. 106 | I welcome constructive criticism and advice. 107 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure("2") do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | # Every Vagrant development environment requires a box. You can search for 14 | # boxes at https://atlas.hashicorp.com/search. 15 | config.vm.box = "bugyt/archlinux" 16 | 17 | # Disable automatic box update checking. If you disable this, then 18 | # boxes will only be checked for updates when the user runs 19 | # `vagrant box outdated`. This is not recommended. 20 | # config.vm.box_check_update = false 21 | 22 | # Create a forwarded port mapping which allows access to a specific port 23 | # within the machine from a port on the host machine. In the example below, 24 | # accessing "localhost:8080" will access port 80 on the guest machine. 25 | # config.vm.network "forwarded_port", guest: 80, host_ip: '0.0.0.0', host: 56789, auto_correct: true 26 | 27 | # Create a private network, which allows host-only access to the machine 28 | # using a specific IP. 29 | # config.vm.network "private_network", ip: "192.168.33.10" 30 | 31 | # Create a public network, which generally matched to bridged network. 32 | # Bridged networks make the machine appear as another physical device on 33 | # your network. 34 | # config.vm.network "public_network" 35 | 36 | # Share an additional folder to the guest VM. The first argument is 37 | # the path on the host to the actual folder. The second argument is 38 | # the path on the guest to mount the folder. And the optional third 39 | # argument is a set of non-required options. 40 | # config.vm.synced_folder "../data", "/vagrant_data" 41 | 42 | # Provider-specific configuration so you can fine-tune various 43 | # backing providers for Vagrant. These expose provider-specific options. 44 | # Example for VirtualBox: 45 | # 46 | # config.vm.provider "virtualbox" do |vb| 47 | # # Display the VirtualBox GUI when booting the machine 48 | # vb.gui = true 49 | # 50 | # # Customize the amount of memory on the VM: 51 | # vb.memory = "1024" 52 | # end 53 | # 54 | # View the documentation for the provider you are using for more 55 | # information on available options. 56 | 57 | # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies 58 | # such as FTP and Heroku are also available. See the documentation at 59 | # https://docs.vagrantup.com/v2/push/atlas.html for more information. 60 | # config.push.define "atlas" do |push| 61 | # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" 62 | # end 63 | 64 | # Enable provisioning with a shell script. Additional provisioners such as 65 | # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the 66 | # documentation for more information about their specific syntax and use. 67 | # Disabled Ansible provisioning in favor of shell. 68 | # config.vm.provision "ansible" do |ansible| 69 | # ansible.host_vars = { 70 | # 'default' => {'ansible_python_interpreter' => 'python2'} 71 | # } 72 | # ansible.playbook = 'provision/ansible/playbook.yml' 73 | # end 74 | 75 | # As of 2016-07, the Docker provisioner capability is not available for Arch. 76 | # config.vm.provision 'docker' do |docker| 77 | # docker.pull_images 78 | # end 79 | 80 | # X11Forwarding still needs to be set to "yes" in sshd_config. 81 | # This is done in the provisioner shell script. 82 | config.ssh.forward_x11 = true 83 | 84 | # Copy config files directly to destinations or to staging to be moved with shell provisioner to 85 | # directories that require elevated privileges to write. 86 | config.vm.provision 'file', source: 'configs/vagrant/home/.profile', destination: '.profile' 87 | config.vm.provision 'file', source: 'configs/vagrant/home/.config/geany/geany.conf', destination: '.config/geany/geany.conf' 88 | 89 | # Shell provisioning is used because Ansible gave me nothing but trouble. I don't think it's 90 | # ready for production use. Chef and Puppet are possible alternatives. 91 | config.vm.provision 'shell', path: 'configs/vagrant/provision.sh' 92 | end 93 | -------------------------------------------------------------------------------- /configs/vagrant/home/.config/geany/geany.conf: -------------------------------------------------------------------------------- 1 | [geany] 2 | default_open_path= 3 | cmdline_new_files=true 4 | notebook_double_click_hides_widgets=false 5 | tab_close_switch_to_mru=false 6 | tab_pos_sidebar=2 7 | sidebar_pos=0 8 | msgwin_orientation=1 9 | highlighting_invert_all=false 10 | pref_main_search_use_current_word=true 11 | check_detect_indent=false 12 | detect_indent_width=false 13 | use_tab_to_indent=true 14 | pref_editor_tab_width=4 15 | indent_mode=2 16 | indent_type=0 17 | virtualspace=1 18 | autocomplete_doc_words=false 19 | completion_drops_rest_of_word=false 20 | autocompletion_max_entries=30 21 | autocompletion_update_freq=250 22 | color_scheme= 23 | mru_length=10 24 | disk_check_timeout=30 25 | show_editor_scrollbars=true 26 | brace_match_ltgt=false 27 | use_gtk_word_boundaries=true 28 | complete_snippets_whilst_editing=false 29 | use_atomic_file_saving=false 30 | gio_unsafe_save_backup=false 31 | use_gio_unsafe_file_saving=true 32 | indent_hard_tab_width=8 33 | find_selection_type=0 34 | extract_filetype_regex=-\\*-\\s*([^\\s]+)\\s*-\\*- 35 | show_symbol_list_expanders=true 36 | compiler_tab_autoscroll=true 37 | allow_always_save=false 38 | statusbar_template=line: %l / %L col: %c sel: %s %w %t %mmode: %M encoding: %e filetype: %f scope: %S 39 | new_document_after_close=false 40 | msgwin_status_visible=true 41 | msgwin_compiler_visible=true 42 | msgwin_messages_visible=true 43 | msgwin_scribble_visible=true 44 | documents_show_paths=true 45 | sidebar_page=1 46 | pref_main_load_session=true 47 | pref_main_project_session=true 48 | pref_main_project_file_in_basedir=false 49 | pref_main_save_winpos=true 50 | pref_main_confirm_exit=false 51 | pref_main_suppress_status_messages=false 52 | switch_msgwin_pages=false 53 | beep_on_errors=true 54 | auto_focus=false 55 | sidebar_symbol_visible=false 56 | sidebar_openfiles_visible=true 57 | editor_font=Monospace 9 58 | tagbar_font=Sans 8 59 | msgwin_font=Sans 8 60 | show_notebook_tabs=true 61 | show_tab_cross=true 62 | tab_order_ltr=true 63 | tab_order_beside=false 64 | tab_pos_editor=2 65 | tab_pos_msgwin=0 66 | use_native_windows_dialogs=false 67 | show_indent_guide=false 68 | show_white_space=true 69 | show_line_endings=false 70 | show_markers_margin=true 71 | show_linenumber_margin=true 72 | long_line_enabled=true 73 | long_line_type=0 74 | long_line_column=120 75 | long_line_color=#C2EBC2 76 | symbolcompletion_max_height=10 77 | symbolcompletion_min_chars=4 78 | use_folding=true 79 | unfold_all_children=false 80 | use_indicators=true 81 | line_wrapping=false 82 | auto_close_xml_tags=true 83 | complete_snippets=true 84 | auto_complete_symbols=false 85 | pref_editor_disable_dnd=false 86 | pref_editor_smart_home_key=true 87 | pref_editor_newline_strip=true 88 | line_break_column=120 89 | auto_continue_multiline=true 90 | comment_toggle_mark= 91 | scroll_stop_at_last_line=true 92 | autoclose_chars=0 93 | pref_editor_default_new_encoding=UTF-8 94 | pref_editor_default_open_encoding=None 95 | default_eol_character=2 96 | pref_editor_new_line=true 97 | pref_editor_ensure_convert_line_endings=true 98 | pref_editor_replace_tabs=true 99 | pref_editor_trail_space=true 100 | pref_toolbar_show=false 101 | pref_toolbar_append_to_menu=false 102 | pref_toolbar_use_gtk_default_style=true 103 | pref_toolbar_use_gtk_default_icon=true 104 | pref_toolbar_icon_style=0 105 | pref_toolbar_icon_size=0 106 | pref_template_developer=Unknown 107 | pref_template_company= 108 | pref_template_mail=U 109 | pref_template_initial=U 110 | pref_template_version=1.0 111 | pref_template_year=%Y 112 | pref_template_date=%Y-%m-%d 113 | pref_template_datetime=%d.%m.%Y %H:%M:%S %Z 114 | context_action_cmd= 115 | sidebar_visible=true 116 | statusbar_visible=true 117 | msgwindow_visible=true 118 | fullscreen=false 119 | scribble_text=Type here what you want, use it as a notice/scratch board 120 | scribble_pos=57 121 | treeview_position=112 122 | msgwindow_position=932 123 | custom_date_format= 124 | keep_edit_history_on_reload_125=false 125 | replace_and_find_by_default=true 126 | keep_edit_history_on_reload=true 127 | show_keep_edit_history_on_reload_msg=false 128 | symbols_sort_mode=0 129 | scroll_lines_around_cursor=0 130 | 131 | [build-menu] 132 | number_ft_menu_items=0 133 | number_non_ft_menu_items=0 134 | number_exec_menu_items=0 135 | 136 | [search] 137 | pref_search_hide_find_dialog=false 138 | pref_search_always_wrap=false 139 | pref_search_current_file_dir=true 140 | find_all_expanded=true 141 | replace_all_expanded=true 142 | position_find_x=711 143 | position_find_y=519 144 | position_replace_x=1047 145 | position_replace_y=241 146 | position_fif_x=-1 147 | position_fif_y=-1 148 | fif_regexp=false 149 | fif_case_sensitive=true 150 | fif_match_whole_word=false 151 | fif_invert_results=false 152 | fif_recursive=false 153 | fif_extra_options= 154 | fif_use_extra_options=false 155 | fif_files= 156 | fif_files_mode=0 157 | find_regexp=false 158 | find_case_sensitive=false 159 | find_escape_sequences=false 160 | find_match_whole_word=false 161 | find_match_word_start=false 162 | find_close_dialog=true 163 | replace_regexp=false 164 | replace_case_sensitive=false 165 | replace_escape_sequences=false 166 | replace_match_whole_word=false 167 | replace_match_word_start=false 168 | replace_search_backwards=false 169 | replace_close_dialog=true 170 | find_regexp_multiline=false 171 | replace_regexp_multiline=false 172 | 173 | [plugins] 174 | load_plugins=true 175 | custom_plugin_path= 176 | active_plugins=; 177 | 178 | [tools] 179 | grep_cmd=grep 180 | 181 | [printing] 182 | print_cmd= 183 | use_gtk_printing=true 184 | print_line_numbers=true 185 | print_page_numbers=true 186 | print_page_header=true 187 | page_header_basename=false 188 | page_header_datefmt=%c 189 | 190 | [VTE] 191 | load_vte=true 192 | send_cmd_prefix= 193 | send_selection_unsafe=false 194 | 195 | [project] 196 | session_file= 197 | project_file_path= 198 | -------------------------------------------------------------------------------- /configs/vagrant/home/.profile: -------------------------------------------------------------------------------- 1 | [[ $PATH =~ '/home/vagrant/.local/bin:' ]] || PATH=/home/vagrant/.local/bin:$PATH 2 | -------------------------------------------------------------------------------- /configs/vagrant/provision.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Arch Linux Development Environment 4 | # This provisioning is designed for a virtualized development machine. The 5 | # machine not only provides the development environment and services, but also 6 | # the dev tools such as SQL editors and IDEs. Use the following variables to 7 | # specify extra packages to install alongside those of this Vagrantfile's 8 | # minimal configuration. AUR packages specified below will be downloaded into 9 | # the default user's ~/src/abs directory, built, and installed. If AUR 10 | # dependencies require user interaction beyond a simple confirmation of yes or 11 | # no (such as the "java-runtime" virtual package), one may explcitly include 12 | # them here. 13 | extra_pkgs=( geany libxtst nodejs npm ttf-dejavu xorg-xauth ) 14 | aur_pkgs=() 15 | 16 | # This script is executed on the guest machine via Vagrant's shell provisioner. 17 | # Remember that the Vagrant shell provisioner transfers this file to the guest 18 | # and executes it there as the root user, NOT vagrant. The initial PWD 19 | # is the vagrant user's home directory, however. All commands in this file 20 | # should be idempotent. 21 | default_user='vagrant' 22 | home_dir=/home/${default_user} 23 | src_dir=/vagrant 24 | 25 | echo 'TASK: Set timezone' 26 | timedatectl set-timezone UTC 27 | 28 | echo 'TASK: Synchronize package databases' 29 | pacman -Syy --noconfirm --quiet 30 | 31 | echo 'TASK: Update Arch keyring' 32 | pacman -S archlinux-keyring --noconfirm --quiet 33 | 34 | # Upgrade the system. 35 | # Sometimes kernel upgrades require initial ramdisk rebuild to detect devices. 36 | # See: https://www.archlinux.org/news/ca-certificates-utils-20170307-1-upgrade-requires-manual-intervention/ 37 | echo 'TASK: Full system upgrade' 38 | pacman -Syuw --noconfirm --quiet 39 | rm /etc/ssl/certs/ca-certificates.crt 40 | pacman -Su --noconfirm --quiet 41 | mkinitcpio -p linux 42 | 43 | # Install necessary packages. 44 | # WARNING: This command, in its current form, will reinstall ALL packages if one 45 | # or more of them is not already installed. pacman will return exit status > 0 46 | # if one or more package in query was not found. 47 | # As of 216-03-11, Linux headers are necessary for virtualbox-guest-dkms package 48 | # in order to build kernel modules for VirtualBox guest additions. 49 | # See: https://www.archlinux.org/packages/community/x86_64/virtualbox-guest-dkms/ 50 | # This box is designed for X11 forwarding. libxtst is used for squirrel-sql. 51 | echo 'TASK: Installing explicit packages' 52 | packages=( git linux-headers tree ${extra_pkgs[@]} ) 53 | pacman -Qiq ${packages[@]} 1> /dev/null || pacman -S ${packages[@]} --noconfirm --quiet --needed 54 | 55 | # Configure git 56 | su vagrant -c 'git config --global core.editor nano' 57 | 58 | # Enable SSH X11 forwarding. 59 | sed -i 's/#X11Forwarding no/X11Forwarding yes/' /etc/ssh/sshd_config 60 | 61 | # Source .profile from .bash_profile. 62 | echo 'TASK: Source .profile from .bash_profile' 63 | source_profile='[[ -f ~/.profile ]] && . ~/.profile' 64 | grep -Fxq "${source_profile}" .bash_profile || echo ${source_profile} >> .bash_profile 65 | 66 | # Add alias to .bashrc. .bashrc is always present in current Vagrant base image 67 | # so no need to check its existence. 68 | echo 'TASK: Add bash aliases' 69 | alias_line_la="alias la='LC_COLLATE=C ls -Alh --color --group-directories-first'" 70 | grep -q "${alias_line_la}" .bashrc || \ 71 | sed -i "/alias ls='ls --color=auto'/a ${alias_line_la}" .bashrc 72 | 73 | # Change to project directory on any new interactive terminal session. 74 | echo 'TASK: Set PWD to project directory' 75 | cd_cmd="cd ${src_dir}" 76 | grep -Fxq "${cd_cmd}" .bashrc || echo ${cd_cmd} >> .bashrc 77 | 78 | # Prepare to download and install AUR packages. 79 | # Example: Import mysql-build@oss.oracle.com PGP key for JDBC driver. 80 | echo 'TASK: Prepare to download AUR packages' 81 | 82 | # Download AUR resources. Due to complexity of some manual installs, makepkg 83 | # will not automatically be run. The user will need to install them after login. 84 | # This is naive and brittle. Upgrade this to actual AUR helper tool. 85 | # makepkg output is redirected to /dev/null since download progress cannot 86 | # be silenced and it blasts display with disjointed characters under su. 87 | echo 'TASK: Download AUR packages' 88 | abs_dir=${home_dir}/src/abs 89 | su ${default_user} -c 'mkdir -p '${abs_dir} 90 | cd ${abs_dir} 91 | for pkg in ${aur_pkgs[@]}; do 92 | if [[ -d ${pkg} ]]; then 93 | cd ${pkg} 94 | git pull --quiet origin #| sed 's/^/ /' 95 | else 96 | su ${default_user} -c 'git clone https://aur.archlinux.org/'${pkg}'.git' 97 | cd ${pkg} 98 | fi 99 | echo 'Running makepkg silently' 100 | su ${default_user} -c 'makepkg -crs --noconfirm --noprogressbar --needed > /dev/null 2>&1' 101 | pacman -U *.pkg.tar.xz --noconfirm --needed 102 | cd ${abs_dir} 103 | done 104 | 105 | # Project-specific tasks 106 | # The daemon.json file was uploaded into machine from host with the Vagrant "file" provisioner. 107 | # See: https://docs.docker.com/engine/reference/commandline/dockerd/#linux-configuration-file 108 | echo 'TASK: Install package dependencies.' 109 | cd ${src_dir} 110 | su ${default_user} -c 'npm install --no-package-lock --no-save' 111 | 112 | # Reboot system. 113 | # Actual reboot removed for now since rebooting outside of Vagrant's control 114 | # seems to prevent the working directory from being mounted to the guest's 115 | # /vagrant path. 116 | echo 'MANUAL TASK: Set git user.name and user.email.' 117 | echo 'WARNING: "vagrant reload" may be required to apply software and configuration updates.' 118 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Exports a simple function that will escape a string literal for use as an argument in the standard JS RegExp 3 | * constructor. 4 | * @module escape-regex-string 5 | * @author monotonee 6 | * @license MIT 7 | */ 8 | 9 | 'use strict'; 10 | 11 | // This is temporarily declared with "var" instead of "const" to maintain the absolute broadest compatibility. 12 | var defaultEscapeCharsRegex = /[-|\\{}()[\]^$+*?.]/g; 13 | 14 | /** 15 | * Escape a string literal for use as an argument in the standard RegExp constructor. 16 | * @alias module:escape-regex-string 17 | * @param {string} unescapedString - The string containing a regex pattern to be escaped. 18 | * @param {RegExp} [escapeCharsRegex] - An optional RegEx pattern containing a set of characters to escape. If not 19 | * passed, value will be set to default. 20 | * @return {string} - The escaped regex pattern string. 21 | * @throws {TypeError} - Arguments must be correct type. 22 | * @property {RegExp} defaultEscapeCharsRegex - A read-only property that contains the default escape character RegExp 23 | * instance. The value of this property is the value used when the optional second argument is omitted in a call to 24 | * {@link module:escape-regex-string}. 25 | */ 26 | function escapeRegexString(unescapedString, escapeCharsRegex) { 27 | // Validate arguments. 28 | if (Object.prototype.toString.call(unescapedString) !== '[object String]') { 29 | throw new TypeError('Argument 1 should be a string.'); 30 | } 31 | if (escapeCharsRegex === undefined) { 32 | escapeCharsRegex = defaultEscapeCharsRegex; 33 | } else if (Object.prototype.toString.call(escapeCharsRegex) !== '[object RegExp]') { 34 | throw new TypeError('Argument 2 should be a RegExp object.'); 35 | } 36 | 37 | // Escape the string. 38 | return unescapedString.replace(escapeCharsRegex, '\\$&'); 39 | } 40 | 41 | /*** 42 | * JSDoc STILL fails to parse this properly due to the use of Object.defineProperty. It has been documented as a 43 | * property of escapeRegexString. Note the three asterisks at the beginning of this comment to disable JSDoc parsing. 44 | * @readonly 45 | * @static 46 | * @type {RegExp} 47 | */ 48 | Object.defineProperty( 49 | escapeRegexString, 50 | 'defaultEscapeCharsRegex', 51 | { 52 | configurable: false, 53 | enumerable: true, 54 | value: defaultEscapeCharsRegex, 55 | writable: false 56 | } 57 | ); 58 | 59 | module.exports = escapeRegexString; 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "escape-regex-string", 3 | "version": "1.0.6", 4 | "description": "Escapes a string literal for use as an argument in the standard RegExp constructor.", 5 | "keywords": [ 6 | "regex", 7 | "RegExp", 8 | "escape", 9 | "string" 10 | ], 11 | "homepage": "https://github.com/monotonee/escape-regex-string/", 12 | "bugs": { 13 | "url": "https://github.com/monotonee/escape-regex-string/issues" 14 | }, 15 | "license": "MIT", 16 | "author": "monotonee ", 17 | "main": "index.js", 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/monotonee/escape-regex-string.git" 21 | }, 22 | "dependencies": {}, 23 | "devDependencies": { 24 | "eslint": "~4", 25 | "jsdoc": "~3", 26 | "mocha": "~5" 27 | }, 28 | "scripts": { 29 | "test": "make" 30 | }, 31 | "engines": { 32 | "node": ">=0.10" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/escape-regex-string.js: -------------------------------------------------------------------------------- 1 | var dependencies = { 2 | assert: require('assert'), 3 | escapeRegexString: require('../index') 4 | }; 5 | 6 | describe('escape-regex-string', function() { 7 | 8 | it('should escape regular expression tokens within a string literal', function() { 9 | dependencies.assert.strictEqual( 10 | dependencies.escapeRegexString('- | \\ { } ( ) [ ] ^ $ + * ? .'), 11 | '\\- \\| \\\\ \\{ \\} \\( \\) \\[ \\] \\^ \\$ \\+ \\* \\? \\.' 12 | ); 13 | dependencies.assert.strictEqual( 14 | dependencies.escapeRegexString('(Phobetron pithecium)'), 15 | '\\(Phobetron pithecium\\)' 16 | ); 17 | }); 18 | 19 | it('should use optional RegExp argument when passed instead of default', function() { 20 | // Remove the hyphen character from the default regex pattern. 21 | dependencies.assert.strictEqual( 22 | dependencies.escapeRegexString('- | \\ { } ( ) [ ] ^ $ + * ? .', /[|\\{}()[\]^$+*?.]/g), 23 | '- \\| \\\\ \\{ \\} \\( \\) \\[ \\] \\^ \\$ \\+ \\* \\? \\.' 24 | ); 25 | }); 26 | 27 | it('should not accept invalid arguments', function() { 28 | dependencies.assert.throws(dependencies.escapeRegexString.bind(42), TypeError); 29 | dependencies.assert.throws(dependencies.escapeRegexString.bind('VFA-103', 42), TypeError); 30 | }); 31 | 32 | describe('.defaultEscapeCharsRegex', function() { 33 | 34 | it('should be a non-configurable property', function() { 35 | dependencies.escapeRegexString.defaultEscapeCharsRegex = 3.14; 36 | dependencies.assert.notStrictEqual(dependencies.escapeRegexString.defaultEscapeCharsRegex, 3.14); 37 | }); 38 | 39 | it('should contain a readable RegExp object', function() { 40 | dependencies.assert.strictEqual( 41 | Object.prototype.toString.call(dependencies.escapeRegexString.defaultEscapeCharsRegex), 42 | '[object RegExp]' 43 | ); 44 | }); 45 | 46 | }); 47 | 48 | }); 49 | --------------------------------------------------------------------------------