Repository: VerbalExpressions/JSVerbalExpressions Branch: master Commit: 34a9dddc1813 Files: 34 Total size: 94.1 KB Directory structure: gitextract_ziqoi740/ ├── .editorconfig ├── .eslintrc ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── automerge.yml │ ├── codeql-analysis.yml │ ├── gh-pages.yml │ └── test.yml ├── .gitignore ├── .mdlintrc.json ├── Gruntfile.js ├── LICENSE ├── README.md ├── VerbalExpressions.js ├── bower.json ├── dist/ │ └── verbalexpressions.js ├── docs/ │ ├── 404.md │ ├── Gemfile │ ├── VerEx.md │ ├── VerbalExpression/ │ │ ├── capture-groups.md │ │ ├── constructor.md │ │ ├── index.md │ │ ├── loops.md │ │ ├── miscellaneous.md │ │ ├── modifiers.md │ │ ├── rules.md │ │ ├── special-characters.md │ │ └── utilities.md │ ├── _config.yml │ ├── _layouts/ │ │ └── default.html │ ├── assets/ │ │ └── css/ │ │ └── style.scss │ └── index.md ├── package.json ├── test/ │ └── tests.js └── typings/ └── VerbalExpressions.d.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 charset = utf8 [{package.json, package-lock.json}] indent_size = 2 ================================================ FILE: .eslintrc ================================================ { "extends": "airbnb", "rules": { "indent": [2, 4], "no-underscore-dangle": [2, { "allowAfterThis": true }], "no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"], "newline-per-chained-call": "off", "max-len": [2, 255, 4], "no-param-reassign": 0, "spaced-comment": [2, "always", { "markers": ["/", "!"] }], "no-plusplus": 0, "operator-linebreak":"off" }, "env": { "amd": true, "node": true, "commonjs": true, "es6": true, "browser": true }, "globals": { "VerEx": true } } ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: npm directory: "/" schedule: interval: daily open-pull-requests-limit: 1000000 - package-ecosystem: bundler directory: "/docs" schedule: interval: daily open-pull-requests-limit: 1000000 ================================================ FILE: .github/workflows/automerge.yml ================================================ name: Dependabot auto-merge on: pull_request permissions: pull-requests: write contents: write jobs: dependabot: runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' }} steps: - name: Enable auto-merge for Dependabot PRs env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} run: | function get_pending_jobs() { gh pr view "$PR_URL" --json statusCheckRollup --jq '.statusCheckRollup | map(select(.name != "dependabot")) | map(select(.status != "COMPLETED")).[]' } function get_failed_jobs() { gh pr view "$PR_URL" --json statusCheckRollup --jq '.statusCheckRollup | map(select(.name != "dependabot")) | map(select(.conclusion != "SUCCESS")).[]' } function wait_until_completed() { while [[ $(get_pending_jobs) ]] do sleep 5 done } function fail_if_unsuccessful() { if [[ $(get_failed_jobs) ]]; then echo "Some jobs failed, unable to automerge" exit 1 fi } function auto_merge() { gh pr merge --auto --rebase "$PR_URL" } wait_until_completed && \ fail_if_unsuccessful && \ auto_merge ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ # For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: 'CodeQL' on: push: branches: [master] pull_request: # The branches below must be a subset of the branches above branches: [master] schedule: - cron: '33 0 * * 1' jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: ['javascript'] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository uses: actions/checkout@v2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 ================================================ FILE: .github/workflows/gh-pages.yml ================================================ name: Build docs/ folder on: pull_request jobs: test: name: Build docs/ folder runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-ruby@v1 - run: | cd docs gem install bundler --version '~> 1' bundle install bundle exec jekyll build - run: | git add -A # Make sure new files are accounted git diff --exit-code --cached # Expect no changes in git ================================================ FILE: .github/workflows/test.yml ================================================ name: Run tests on: pull_request jobs: test: name: Run tests on Node.js ${{ matrix.node-version }} runs-on: ubuntu-latest strategy: matrix: node-version: ["16", "15", "14", "13", "12"] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - run: npm ci - run: npm run test:verbose ================================================ FILE: .gitignore ================================================ node_modules .DS_Store .idea/ .vscode/ .nyc_output docs/_site docs/.sass-cache docs/.jekyll-metadata ================================================ FILE: .mdlintrc.json ================================================ { "heading-increment": true, "first-heading-h1": { "level": 1 }, "heading-style": { "style": "atx" }, "ul-style": { "style": "dash" }, "list-indent": true, "ul-start-left": true, "ul-indent": { "indent": 4 }, "no-trailing-spaces": true, "no-hard-tabs": true, "no-reversed-links": true, "no-multiple-blanks": { "maximum": 1 }, "line-length": false, "commands-show-output": true, "no-missing-space-atx": true, "no-multiple-space-atx": true, "no-missing-space-closed-atx": true, "no-multiple-space-closed-atx": true, "blanks-around-headings": true, "heading-start-left": true, "no-duplicate-heading": true, "single-h1": false, "no-trailing-punctuation": true, "ol-prefix": { "style": "ordered" }, "list-marker-space": 1, "blanks-around-fences": true, "blanks-around-lists": true, "no-inline-html": false, "no-bare-urls": true, "hr-style": { "style": "___" }, "no-emphasis-as-heading": true, "no-space-in-emphasis": true, "no-space-in-code": false, "no-space-in-links": true, "fenced-code-language": false, "first-line-h1": true, "no-empty-links": true, "no-alt-text": true } ================================================ FILE: Gruntfile.js ================================================ module.exports = function gruntConfig(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), eslint: { target: ['VerbalExpressions.js', 'test/tests.js', 'Gruntfile.js'], }, ava: { test: ['test/tests.js'], options: { nyc: true, }, verbose: { test: ['test/tests.js'], options: { verbose: true, nyc: true, }, }, }, babel: { options: { sourceMap: true, presets: [['@babel/preset-env', { modules: false }]], plugins: [ ['transform-builtin-extend', { globals: ['RegExp'] }], ], }, dist: { files: { 'dist/verbalexpressions.js': 'VerbalExpressions.js', }, }, }, umd: { all: { options: { src: 'dist/verbalexpressions.js', objectToExport: 'VerEx', amdModuleId: 'VerEx', globalAlias: 'VerEx', }, }, }, uglify: { options: { banner: '/*!\n' + '* <%= pkg.name %> JavaScript Library v<%= pkg.version %>\n' + '* <%= pkg.homepage %>\n' + '*\n' + '* Released under the <%= pkg.license %> license\n' + '*/\n', sourceMap: true, }, dist: { files: { 'dist/verbalexpressions.min.js': [ 'dist/verbalexpressions.js', ], }, }, }, sourcemap_localize: { options: { localize_to: '..', }, build: { files: { src: ['dist/*.min.js.map'], }, }, }, markdownlint: { options: { config: grunt.file.readJSON('.mdlintrc.json'), }, src: ['README.md', 'docs/*.md', 'docs/VerbalExpression/*.md'], }, }); grunt.loadNpmTasks('grunt-eslint'); grunt.loadNpmTasks('grunt-ava'); grunt.loadNpmTasks('grunt-babel'); grunt.loadNpmTasks('grunt-umd'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-sourcemap-localize'); grunt.loadNpmTasks('grunt-markdownlint'); grunt.registerTask('default', ['test']); grunt.registerTask('test', [ 'compile', 'eslint', 'markdownlint', 'ava:test', ]); grunt.registerTask('test:verbose', ['compile', 'eslint', 'ava:verbose']); grunt.registerTask('compile', ['babel', 'umd:all']); grunt.registerTask('build', [ 'compile', 'ava:test', 'uglify', 'sourcemap_localize', ]); }; ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2017 jehna Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # VerbalExpressions [![Build Status](https://travis-ci.org/VerbalExpressions/JSVerbalExpressions.svg)](https://travis-ci.org/VerbalExpressions/JSVerbalExpressions) [![Latest Version](https://img.shields.io/npm/v/verbal-expressions.svg)](https://www.npmjs.com/package/verbal-expressions) [![jsDelivr](https://img.shields.io/badge/dynamic/json.svg?label=jsDelivr&url=https%3A%2F%2Fdata.jsdelivr.com%2Fv1%2Fpackage%2Fnpm%2Fverbal-expressions&query=%24..tags.latest&colorB=blue&prefix=v)](https://www.jsdelivr.com/package/npm/verbal-expressions) [![License](https://img.shields.io/github/license/VerbalExpressions/JSVerbalExpressions.svg)](LICENSE) ## JavaScript Regular Expressions made easy VerbalExpressions is a JavaScript library that helps construct difficult regular expressions. ## How to get started ### In the browser ```html ``` Or use the [jsDelivr CDN](https://www.jsdelivr.com/package/npm/verbal-expressions). ### On the server (node.js) Install: ```sh npm install verbal-expressions ``` Require: ```js const VerEx = require('verbal-expressions'); ``` Or use ES6's `import`: ```js import VerEx from 'verbal-expressions'; ``` ## Running tests ```sh npm test ``` (or) ```sh npm run test:verbose ``` ## Creating a minified version ```sh npm run build ``` This will run [Babel](https://babeljs.io) on `VerbalExpressions.js` and output the result to `dist/verbalexpressions.js`. A minified version of the same will also be written to `dist/verbalexpressions.min.js`. A source map will also be created in `dist`, so you can use the original "un-babelified", unminified source file for debugging purposes. ## Building the docs/ folder The `docs/` folder uses Jekyll for building the static HTML and is hosted at gh-pages. To install the Ruby dependencies, run: ``` cd docs/ bundle install ``` This installs all needed Ruby dependencies locally After you've installed dependencies, you can run: ``` bundle exec jekyll build ``` This builds all static files to `docs/_site/` folder. If you want to develop the files locally, you can run: ``` bundle exec jekyll serve ``` This starts a local development web server and starts watching your files for changes. ## API documentation You can find the API documentation at [verbalexpressions.github.io/JSVerbalExpressions](https://verbalexpressions.github.io/JSVerbalExpressions). You can find the source code for the docs in [`docs`](docs/). ## Examples Here are some simple examples to give an idea of how VerbalExpressions works: ### Testing if we have a valid URL ```js // Create an example of how to test for correctly formed URLs const tester = VerEx() .startOfLine() .then('http') .maybe('s') .then('://') .maybe('www.') .anythingBut(' ') .endOfLine(); // Create an example URL const testMe = 'https://www.google.com'; // Use RegExp object's native test() function if (tester.test(testMe)) { alert('We have a correct URL'); // This output will fire } else { alert('The URL is incorrect'); } console.log(tester); // Outputs the actual expression used: /^(http)(s)?(\:\/\/)(www\.)?([^\ ]*)$/ ``` ### Replacing strings ```js // Create a test string const replaceMe = 'Replace bird with a duck'; // Create an expression that seeks for word "bird" const expression = VerEx().find('bird'); // Execute the expression like a normal RegExp object const result = expression.replace(replaceMe, 'duck'); // Outputs "Replace duck with a duck" alert(result); ``` ### Shorthand for string replace ```js const result = VerEx().find('red').replace('We have a red house', 'blue'); // Outputs "We have a blue house" alert(result); ``` ## Contributions Pull requests are warmly welcome! Clone the repo and fork: ```sh git clone https://github.com/VerbalExpressions/JSVerbalExpressions.git ``` ### Style guide The [Airbnb](https://github.com/airbnb/javascript) style guide is loosely used as a basis for creating clean and readable JavaScript code. Check [`.eslintrc`](.eslintrc). Check out these slide decks for handy Github & git tips: - [Git and Github Secrets](https://zachholman.com/talk/git-github-secrets/) - [More Git and Github Secrets](https://zachholman.com/talk/more-git-and-github-secrets/) ## Tools - - it's a wrapper of JSVerbalExpressions; users can write down the code and compile to regex - - JSBin Playground ## Other Implementations You can see an up to date list of all ports on [VerbalExpressions.github.io](https://VerbalExpressions.github.io). - [Ruby](https://github.com/ryan-endacott/verbal_expressions) - [C#](https://github.com/VerbalExpressions/CSharpVerbalExpressions) - [Python](https://github.com/VerbalExpressions/PythonVerbalExpressions) - [Java](https://github.com/VerbalExpressions/JavaVerbalExpressions) - [Groovy](https://github.com/VerbalExpressions/GroovyVerbalExpressions) - [PHP](https://github.com/VerbalExpressions/PHPVerbalExpressions) - [Haskell](https://github.com/VerbalExpressions/HaskellVerbalExpressions) - [Haxe](https://github.com/VerbalExpressions/HaxeVerbalExpressions) - [C++](https://github.com/VerbalExpressions/CppVerbalExpressions) - [Objective-C](https://github.com/VerbalExpressions/ObjectiveCVerbalExpressions) - [Perl](https://github.com/VerbalExpressions/PerlVerbalExpressions) - [Swift](https://github.com/VerbalExpressions/SwiftVerbalExpressions) If you would like to contribute another port (which would be awesome!), please [open an issue](https://github.com/VerbalExpressions/implementation/issues/new) specifying the language in the [VerbalExpressions/implementation repo](https://github.com/VerbalExpressions/implementation/issues). Please don't open PRs for other languages against this repo. ### Similar projects Here's a list of other similar projects that implement regular expression builders: - https://github.com/MaxArt2501/re-build - https://github.com/mathiasbynens/regenerate ================================================ FILE: VerbalExpressions.js ================================================ /** * @file VerbalExpressions JavaScript Library * @version 0.3.0 * @license MIT * * @see https://github.com/VerbalExpressions/JSVerbalExpressions */ /** * Define the VerbalExpression class * * @class VerbalExpression * @extends {RegExp} */ class VerbalExpression extends RegExp { /** * Creates an instance of VerbalExpression. * @constructor * @alias VerEx * @memberof VerbalExpression */ constructor() { // Call the `RegExp` constructor so that `this` can be used super('', 'gm'); // Variables to hold the expression construction in order this._prefixes = ''; this._source = ''; this._suffixes = ''; this._modifiers = 'gm'; // 'global, multiline' matching by default } // Utility // /** * Escape meta-characters in the parameter and make it safe for adding to the expression * @static * @param {(string|RegExp|number)} value object to sanitize * @returns {string} sanitized value * @memberof VerbalExpression */ static sanitize(value) { if (value instanceof RegExp) { return value.source; } if (typeof value === 'number') { return value; } if (typeof value !== 'string') { return ''; } // Regular expression to match meta characters // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp const toEscape = /([\].|*?+(){}^$\\:=[])/g; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastMatch const lastMatch = '$&'; // Escape meta characters return value.replace(toEscape, `\\${lastMatch}`); } /** * Add stuff to the expression and compile the new expression so it's ready to be used. * @param {(string|number)} [value=''] stuff to add * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ add(value = '') { this._source += value; const pattern = this._prefixes + this._source + this._suffixes; this.compile(pattern, this._modifiers); return this; } // Rules // /** * Control start-of-line matching * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ startOfLine(enable = true) { this._prefixes = enable ? '^' : ''; return this.add(); } /** * Control end-of-line matching * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ endOfLine(enable = true) { this._suffixes = enable ? '$' : ''; return this.add(); } /** * Look for the value passed * @param {(string|RegExp|number)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ then(value) { value = VerbalExpression.sanitize(value); return this.add(`(?:${value})`); } /** * Alias for then() to allow for readable syntax when then() is the first method in the chain. * @param {(string|RegExp|numer)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ find(value) { return this.then(value); } /** * Add optional values * @param {(string|RegExp|number)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ maybe(value) { value = VerbalExpression.sanitize(value); return this.add(`(?:${value})?`); } /** * Add alternative expressions * @param {(string|RegExp|number)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ or(value) { this._prefixes += '(?:'; this._suffixes = `)${this._suffixes}`; this.add(')|(?:'); if (value) { this.then(value); } return this; } /** * Any character any number of times * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ anything() { return this.add('(?:.*)'); } /** * Anything but these characters * @param {(string|number|string[]|number[])} value characters to not match * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ anythingBut(value) { if (Array.isArray(value)) { value = value.join(''); } value = VerbalExpression.sanitize(value); return this.add(`(?:[^${value}]*)`); } /** * Any character(s) at least once * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ something() { return this.add('(?:.+)'); } /** * Any character at least one time except for these characters * @param {(string|number|string[]|number[])} value characters to not match * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ somethingBut(value) { if (Array.isArray(value)) { value = value.join(''); } value = VerbalExpression.sanitize(value); return this.add(`(?:[^${value}]+)`); } /** * Match any of the given characters * @param {(string|number|string[]|number[])} value characters to match * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ anyOf(value) { if (Array.isArray(value)) { value = value.join(''); } value = VerbalExpression.sanitize(value); return this.add(`[${value}]`); } /** * Shorthand for anyOf(value) * @param {string|number} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ any(value) { return this.anyOf(value); } /** * Ensure that the parameter does not follow * @param {string|number} value * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ not(value) { value = VerbalExpression.sanitize(value); this.add(`(?!${value})`); return this; } /** * Matching any character within a range of characters * Usage: .range( from, to [, from, to ... ] ) * @param {...string} ranges characters denoting beginning and ending of ranges * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ range(...ranges) { let value = ''; for (let i = 1; i < ranges.length; i += 2) { const from = VerbalExpression.sanitize(ranges[i - 1]); const to = VerbalExpression.sanitize(ranges[i]); value += `${from}-${to}`; } return this.add(`[${value}]`); } // Special characters // /** * Match a Line break * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ lineBreak() { return this.add('(?:\\r\\n|\\r|\\n)'); // Unix(LF) + Windows(CRLF) } /** * A shorthand for lineBreak() for html-minded users * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ br() { return this.lineBreak(); } /** * Match a tab character * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ tab() { return this.add('\\t'); } /** * Match any alphanumeric * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ word() { return this.add('\\w+'); } /** * Match a single digit * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ digit() { return this.add('\\d'); } /** * Match a single whitespace * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ whitespace() { return this.add('\\s'); } // Modifiers // /** * Add a regex modifier/flag * @param {string} modifier modifier to add * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ addModifier(modifier) { if (!this._modifiers.includes(modifier)) { this._modifiers += modifier; } return this.add(); } /** * Remove modifier * @param {string} modifier modifier to remove * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ removeModifier(modifier) { this._modifiers = this._modifiers.replace(modifier, ''); return this.add(); } /** * Control case-insensitive matching * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ withAnyCase(enable = true) { return enable ? this.addModifier('i') : this.removeModifier('i'); } /** * Default behaviour is with "g" modifier, so we can turn this another way around than other modifiers * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ stopAtFirst(enable = true) { return enable ? this.removeModifier('g') : this.addModifier('g'); } /** * Control the multiline modifier * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ searchOneLine(enable = true) { return enable ? this.removeModifier('m') : this.addModifier('m'); } // Loops // /** * Repeat the previous item exactly n times or between n and m times * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ repeatPrevious(...quantity) { const isInteger = /\d+/; const values = quantity.filter((argument) => isInteger.test(argument)); if (values.length === 0 || values.length > 2) { return this; } this.add(`{${values.join(',')}}`); return this; } /** * Repeat the previous at least once * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ oneOrMore() { return this.add('+'); } /** * Match the value zero or more times * @param {string} value value to find * @param {integer} [lower] minimum number of times the value should be repeated * @param {integer} [upper] maximum number of times the value should be repeated * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ multiple(value, lower, upper) { if (value !== undefined) { value = VerbalExpression.sanitize(value); this.add(`(?:${value})`); } if (lower === undefined && upper === undefined) { this.add('*'); // Any number of times } else if (lower !== undefined && upper === undefined) { this.add(`{${lower},}`); } else if (lower !== undefined && upper !== undefined) { this.add(`{${lower},${upper}}`); } return this; } // Capture groups // /** * Starts a capturing group * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ beginCapture() { // Add the end of the capture group to the suffixes temporarily so that compilation continues to work this._suffixes += ')'; return this.add('('); } /** * Ends a capturing group * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ endCapture() { // Remove the last parenthesis from the _suffixes and add it to the regex this._suffixes = this._suffixes.slice(0, -1); return this.add(')'); } // Miscellaneous // /** * Shorthand function for the string.replace function to allow for a more logical flow * @param {string} source string to search for * @param {string} value value to replace with * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ replace(source, value) { source = source.toString(); return source.replace(this, value); } /** * Convert to RegExp object * @returns {RegExp} equivalent RegExp instance * @memberof VerbalExpression */ toRegExp() { const components = this.toString().match(/\/(.*)\/([gimuy]+)?/); const pattern = components[1]; const flags = components[2]; return new RegExp(pattern, flags); } } /** * Return a new instance of `VerbalExpression` * @export * @returns {VerbalExpression} new instance */ function VerEx() { // eslint-disable-line no-unused-vars const instance = new VerbalExpression(); instance.sanitize = VerbalExpression.sanitize; return instance; } ================================================ FILE: bower.json ================================================ { "name": "verbal-expressions", "description": "JavaScript Regular expressions made easy", "keywords": [ "regular expressions", "regex" ], "main": "dist/verbalexpressions.js", "license": "MIT", "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests", "Gruntfile.js", "package.json", "bower.json" ] } ================================================ FILE: dist/verbalexpressions.js ================================================ (function (root, factory) { if (root === undefined && window !== undefined) root = window; if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module unless amdModuleId is set define('VerEx', [], function () { return (root['VerEx'] = factory()); }); } else if (typeof module === 'object' && module.exports) { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(); } else { root['VerEx'] = factory(); } }(this, function () { var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _extendableBuiltin(cls) { function ExtendableBuiltin() { var instance = Reflect.construct(cls, Array.from(arguments)); Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); return instance; } ExtendableBuiltin.prototype = Object.create(cls.prototype, { constructor: { value: cls, enumerable: false, writable: true, configurable: true } }); if (Object.setPrototypeOf) { Object.setPrototypeOf(ExtendableBuiltin, cls); } else { ExtendableBuiltin.__proto__ = cls; } return ExtendableBuiltin; } /** * @file VerbalExpressions JavaScript Library * @version 0.3.0 * @license MIT * * @see https://github.com/VerbalExpressions/JSVerbalExpressions */ /** * Define the VerbalExpression class * * @class VerbalExpression * @extends {RegExp} */ var VerbalExpression = function (_extendableBuiltin2) { _inherits(VerbalExpression, _extendableBuiltin2); /** * Creates an instance of VerbalExpression. * @constructor * @alias VerEx * @memberof VerbalExpression */ function VerbalExpression() { _classCallCheck(this, VerbalExpression); // Variables to hold the expression construction in order var _this = _possibleConstructorReturn(this, (VerbalExpression.__proto__ || Object.getPrototypeOf(VerbalExpression)).call(this, '', 'gm')); // Call the `RegExp` constructor so that `this` can be used _this._prefixes = ''; _this._source = ''; _this._suffixes = ''; _this._modifiers = 'gm'; // 'global, multiline' matching by default return _this; } // Utility // /** * Escape meta-characters in the parameter and make it safe for adding to the expression * @static * @param {(string|RegExp|number)} value object to sanitize * @returns {string} sanitized value * @memberof VerbalExpression */ _createClass(VerbalExpression, [{ key: 'add', /** * Add stuff to the expression and compile the new expression so it's ready to be used. * @param {(string|number)} [value=''] stuff to add * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ value: function add() { var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; this._source += value; var pattern = this._prefixes + this._source + this._suffixes; this.compile(pattern, this._modifiers); return this; } // Rules // /** * Control start-of-line matching * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'startOfLine', value: function startOfLine() { var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; this._prefixes = enable ? '^' : ''; return this.add(); } /** * Control end-of-line matching * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'endOfLine', value: function endOfLine() { var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; this._suffixes = enable ? '$' : ''; return this.add(); } /** * Look for the value passed * @param {(string|RegExp|number)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'then', value: function then(value) { value = VerbalExpression.sanitize(value); return this.add('(?:' + value + ')'); } /** * Alias for then() to allow for readable syntax when then() is the first method in the chain. * @param {(string|RegExp|numer)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'find', value: function find(value) { return this.then(value); } /** * Add optional values * @param {(string|RegExp|number)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'maybe', value: function maybe(value) { value = VerbalExpression.sanitize(value); return this.add('(?:' + value + ')?'); } /** * Add alternative expressions * @param {(string|RegExp|number)} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'or', value: function or(value) { this._prefixes += '(?:'; this._suffixes = ')' + this._suffixes; this.add(')|(?:'); if (value) { this.then(value); } return this; } /** * Any character any number of times * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'anything', value: function anything() { return this.add('(?:.*)'); } /** * Anything but these characters * @param {(string|number|string[]|number[])} value characters to not match * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'anythingBut', value: function anythingBut(value) { if (Array.isArray(value)) { value = value.join(''); } value = VerbalExpression.sanitize(value); return this.add('(?:[^' + value + ']*)'); } /** * Any character(s) at least once * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'something', value: function something() { return this.add('(?:.+)'); } /** * Any character at least one time except for these characters * @param {(string|number|string[]|number[])} value characters to not match * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'somethingBut', value: function somethingBut(value) { if (Array.isArray(value)) { value = value.join(''); } value = VerbalExpression.sanitize(value); return this.add('(?:[^' + value + ']+)'); } /** * Match any of the given characters * @param {(string|number|string[]|number[])} value characters to match * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'anyOf', value: function anyOf(value) { if (Array.isArray(value)) { value = value.join(''); } value = VerbalExpression.sanitize(value); return this.add('[' + value + ']'); } /** * Shorthand for anyOf(value) * @param {string|number} value value to find * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'any', value: function any(value) { return this.anyOf(value); } /** * Ensure that the parameter does not follow * @param {string|number} value * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'not', value: function not(value) { value = VerbalExpression.sanitize(value); this.add('(?!' + value + ')'); return this; } /** * Matching any character within a range of characters * Usage: .range( from, to [, from, to ... ] ) * @param {...string} ranges characters denoting beginning and ending of ranges * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'range', value: function range() { var value = ''; for (var i = 1; i < arguments.length; i += 2) { var from = VerbalExpression.sanitize(arguments.length <= i - 1 ? undefined : arguments[i - 1]); var to = VerbalExpression.sanitize(arguments.length <= i ? undefined : arguments[i]); value += from + '-' + to; } return this.add('[' + value + ']'); } // Special characters // /** * Match a Line break * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'lineBreak', value: function lineBreak() { return this.add('(?:\\r\\n|\\r|\\n)'); // Unix(LF) + Windows(CRLF) } /** * A shorthand for lineBreak() for html-minded users * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'br', value: function br() { return this.lineBreak(); } /** * Match a tab character * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'tab', value: function tab() { return this.add('\\t'); } /** * Match any alphanumeric * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'word', value: function word() { return this.add('\\w+'); } /** * Match a single digit * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'digit', value: function digit() { return this.add('\\d'); } /** * Match a single whitespace * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'whitespace', value: function whitespace() { return this.add('\\s'); } // Modifiers // /** * Add a regex modifier/flag * @param {string} modifier modifier to add * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'addModifier', value: function addModifier(modifier) { if (!this._modifiers.includes(modifier)) { this._modifiers += modifier; } return this.add(); } /** * Remove modifier * @param {string} modifier modifier to remove * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'removeModifier', value: function removeModifier(modifier) { this._modifiers = this._modifiers.replace(modifier, ''); return this.add(); } /** * Control case-insensitive matching * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'withAnyCase', value: function withAnyCase() { var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; return enable ? this.addModifier('i') : this.removeModifier('i'); } /** * Default behaviour is with "g" modifier, so we can turn this another way around than other modifiers * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'stopAtFirst', value: function stopAtFirst() { var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; return enable ? this.removeModifier('g') : this.addModifier('g'); } /** * Control the multiline modifier * @param {boolean} [enable=true] whether to enable this behaviour * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'searchOneLine', value: function searchOneLine() { var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; return enable ? this.removeModifier('m') : this.addModifier('m'); } // Loops // /** * Repeat the previous item exactly n times or between n and m times * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'repeatPrevious', value: function repeatPrevious() { var isInteger = /\d+/; for (var _len = arguments.length, quantity = Array(_len), _key = 0; _key < _len; _key++) { quantity[_key] = arguments[_key]; } var values = quantity.filter(function (argument) { return isInteger.test(argument); }); if (values.length === 0 || values.length > 2) { return this; } this.add('{' + values.join(',') + '}'); return this; } /** * Repeat the previous at least once * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'oneOrMore', value: function oneOrMore() { return this.add('+'); } /** * Match the value zero or more times * @param {string} value value to find * @param {integer} [lower] minimum number of times the value should be repeated * @param {integer} [upper] maximum number of times the value should be repeated * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'multiple', value: function multiple(value, lower, upper) { if (value !== undefined) { value = VerbalExpression.sanitize(value); this.add('(?:' + value + ')'); } if (lower === undefined && upper === undefined) { this.add('*'); // Any number of times } else if (lower !== undefined && upper === undefined) { this.add('{' + lower + ',}'); } else if (lower !== undefined && upper !== undefined) { this.add('{' + lower + ',' + upper + '}'); } return this; } // Capture groups // /** * Starts a capturing group * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'beginCapture', value: function beginCapture() { // Add the end of the capture group to the suffixes temporarily so that compilation continues to work this._suffixes += ')'; return this.add('('); } /** * Ends a capturing group * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'endCapture', value: function endCapture() { // Remove the last parenthesis from the _suffixes and add it to the regex this._suffixes = this._suffixes.slice(0, -1); return this.add(')'); } // Miscellaneous // /** * Shorthand function for the string.replace function to allow for a more logical flow * @param {string} source string to search for * @param {string} value value to replace with * @returns {VerbalExpression} recompiled instance of VerbalExpression * @memberof VerbalExpression */ }, { key: 'replace', value: function replace(source, value) { source = source.toString(); return source.replace(this, value); } /** * Convert to RegExp object * @returns {RegExp} equivalent RegExp instance * @memberof VerbalExpression */ }, { key: 'toRegExp', value: function toRegExp() { var components = this.toString().match(/\/(.*)\/([gimuy]+)?/); var pattern = components[1]; var flags = components[2]; return new RegExp(pattern, flags); } }], [{ key: 'sanitize', value: function sanitize(value) { if (value instanceof RegExp) { return value.source; } if (typeof value === 'number') { return value; } if (typeof value !== 'string') { return ''; } // Regular expression to match meta characters // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp var toEscape = /([\].|*?+(){}^$\\:=[])/g; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastMatch var lastMatch = '$&'; // Escape meta characters return value.replace(toEscape, '\\' + lastMatch); } }]); return VerbalExpression; }(_extendableBuiltin(RegExp)); /** * Return a new instance of `VerbalExpression` * @export * @returns {VerbalExpression} new instance */ function VerEx() { // eslint-disable-line no-unused-vars var instance = new VerbalExpression(); instance.sanitize = VerbalExpression.sanitize; return instance; } //# sourceMappingURL=verbalexpressions.js.map return VerEx; })); ================================================ FILE: docs/404.md ================================================ # Page not found Perhaps you wish to go to the [home page](/) instead? ================================================ FILE: docs/Gemfile ================================================ source "https://rubygems.org" gem "github-pages", group: :jekyll_plugins ================================================ FILE: docs/VerEx.md ================================================ # `VerEx` Return a new instance of [`VerbalExpression`](VerbalExpression). This is the function that is exported from within `VerbalExpressions.js` and is to be the first method in chains that describe verbal expressions. ================================================ FILE: docs/VerbalExpression/capture-groups.md ================================================ # Capture Groups Capture groups are used to extract data from within the regular expression match for further processing. ## `beginCapture` Begin a capture group. ## `endCapture` End a capture group. ___ ```js const phoneNumber = VerEx() .find('+') .beginCapture() .digit().repeatPrevious(2) .endCapture() .then('-') .digit().repeatPrevious(10); const [, countryCode] = phoneNumber.exec('+91-2223387510'); console.log(countryCode); // => '91' ``` ================================================ FILE: docs/VerbalExpression/constructor.md ================================================ # Constructor ## `constructor` Construct and return a new instance of [`VerbalExpression`](#verbalexpression). Used to support the `new VerbalExpression()` syntax in ES6 classes as mandated by [the spec](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor). You usually wouldn't need to call `VerEx().constructor()`. ================================================ FILE: docs/VerbalExpression/index.md ================================================ --- title: VerbalExpression --- # `VerbalExpression` A class that extends [`RegExp`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) and wraps all VerbalExpressions functionality. ## Table of Contents - [Constructor](../VerbalExpression/constructor) - [`constructor`](../VerbalExpression/constructor#constructor) - [Utilities](../VerbalExpression/utilities) - [`static sanitize`](../VerbalExpression/utilities#static) - [`add`](../VerbalExpression/utilities#add) - [Rules](../VerbalExpression/rules) - [`startOfLine`](../VerbalExpression/rules#startOfLine) - [`endOfLine`](../VerbalExpression/rules#endOfLine) - [`then`](../VerbalExpression/rules#then) - [`find`](../VerbalExpression/rules#find) - [`maybe`](../VerbalExpression/rules#maybe) - [`or`](../VerbalExpression/rules#or) - [`anything`](../VerbalExpression/rules#anything) - [`anythingBut`](../VerbalExpression/rules#anythingBut) - [`something`](../VerbalExpression/rules#something) - [`somethingBut`](../VerbalExpression/rules#somethingBut) - [`anyOf`](../VerbalExpression/rules#anyOf) - [`any`](../VerbalExpression/rules#any) - [`not`](../VerbalExpression/rules#not) - [`range`](../VerbalExpression/rules#range) - [Special Characters](../VerbalExpression/special-characters) - [`lineBreak`](../VerbalExpression/special-characters#lineBreak) - [`br`](../VerbalExpression/special-characters#br) - [`tab`](../VerbalExpression/special-characters#tab) - [`word`](../VerbalExpression/special-characters#word) - [`digit`](../VerbalExpression/special-characters#digit) - [`whitespace`](../VerbalExpression/special-characters#whitespace) - [Modifiers](../VerbalExpression/modifiers) - [`addModifier`](../VerbalExpression/modifiers#addModifier) - [`removeModifier`](../VerbalExpression/modifiers#removeModifier) - [`withAnyCase`](../VerbalExpression/modifiers#withAnyCase) - [`stopAtFirst`](../VerbalExpression/modifiers#stopAtFirst) - [`searchOneLine`](../VerbalExpression/modifiers#searchOneLine) - [`repeatPrevious`](../VerbalExpression/modifiers#repeatPrevious) - [Loops](../VerbalExpression/loops) - [`oneOrMore`](../VerbalExpression/loops#oneOrMore) - [`multiple`](../VerbalExpression/loops#multiple) - [Capture Groups](../VerbalExpression/capture-groups) - [`beginCapture`](../VerbalExpression/capture-groups#beginCapture) - [`endCapture`](../VerbalExpression/capture-groups#endCapture) - [Miscellaneous](../VerbalExpression/miscellaneous) - [`replace`](../VerbalExpression/miscellaneous#replace) - [`toRegExp`](../VerbalExpression/miscellaneous#toRegExp) ================================================ FILE: docs/VerbalExpression/loops.md ================================================ # Loops ## `oneOrMore` Match the previous stuff one or more times. ```js const integer = VerEx().digit().oneOrMore(); console.log(integer.exec('foo 12345')[0]); // => '12345' ``` ## `multiple` ### Usage 1 Match the previous group any number of times. ```js const expr = VerEx().startOfLine().find(' ').multiple().endOfLine(); console.log(expr.test(' ')); // => true ``` ### Usage 2 Match something zero or more times. Parameter | Expected type | Description ----------|---------------|-------------- `value` | `String` | Item to match ```js const expr = VerEx() .find('what').multiple('?') .endOfLine(); console.log(expr.test('what')); // => true expr.lastIndex = 0; console.log(expr.test('what???'));// => true ``` ### Usage 3 Match something greater than or equal to `min` number of times. Parameter | Expected type | Description ----------|---------------|--------------------------------------------- `value` | `String` | Item to match `min` | `Number` | Minimum number of times it should be present ```js const expr = VerEx() .find('hurray').then('!').multiple(1) .endOfLine(); console.log(expr.test('hurray')); // => false expr.lastIndex = 0; console.log(expr.test('hurray!!')); // => true ``` ### Usage 4 Match something between `min` and `max` (inclusive) number of times. Parameter | Expected type | Description ----------|---------------|--------------------------------------------- `value` | `String` | Item to match `min` | `Number` | Minimum number of times it should be present `max` | `Number` | Maximum number of times it should be present ```js const expr = VerEx() .find('h').then('i').multiple(1, 3) .endOfLine(); console.log(expr.test('hiii')); // => true expr.lastIndex = 0; console.log(expr.test('hiiii')); // => false ``` ================================================ FILE: docs/VerbalExpression/miscellaneous.md ================================================ # Miscellaneous ## `replace` Replace characters matching the VerbalExpression in a string with another string. Parameter | Expected type | Description ----------|---------------|------------------------------- `source` | `String` | String to look for matches in `value` | `String` | String to replace matches with Return type: [`String`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) ```js const spaces = VerEx().find(' '); const fileName = 'a file name.txt'; // => 'a_file_name.txt' console.log(spaces.replace(fileName, '_')); ``` ## `toRegExp` Convert the class to a [`RegExp`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) object. Return type: [`RegExp`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) ```js const expr = VerEx().find('foo'); console.log(expr.toRegExp()); // => /(?:foo)/gm ``` ================================================ FILE: docs/VerbalExpression/modifiers.md ================================================ # Modifiers ## `addModifier` Manually add a regex modifier (flag). Parameter | Expected type | Description ----------|---------------|---------------- `value` | `String` | Modifier to add ```js let expr = VerEx() console.log(expr.flags); // => 'gm' expr = expr.addModifier('i'); console.log(expr.flags); // => 'gim' ``` ## `removeModifier` Manually remove a regex modifier (flag). Parameter | Expected type | Description ----------|---------------|------------------- `value` | `String` | Modifier to remove ```js let expr = VerEx(); console.log(expr.flags); // => 'gm' expr = expr.removeModifier('m'); console.log(expr.flags); // => 'g' ``` ## `withAnyCase` Control case-insensitive matching. Equivalent to adding or removing the `i` modifier. Parameter | Expected type | Description ----------|---------------|------------ `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior ```js const hexColorCode = VerEx() .find('#') .range('0', '9', 'a', 'f') .repeatPrevious(6) .withAnyCase(); console.log(hexColorCode.test('#93afee')); // => true hexColorCode.lastIndex = 0; console.log(hexColorCode.test('#93AFEE')); // => true ``` ## `stopAtFirst` Control global matching. Enabling would cause the expression to not look for matches beyond the first match. Equivalent to removing or adding the `g` modifier. Global matching is enabled by default. Parameter | Expected type | Description ----------|---------------|------------ `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior ```js ``` ## `searchOneLine` Control multi-line matching. Enabling would cause the expression to not look for matches beyond the first line. Equivalent to removing or adding the `m` modifier. Multi-line matching is enabled by default. Parameter | Expected type | Description ----------|---------------|------------ `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior ```js let findFoo = VerEx().startOfLine().find('foo').endOfLine(); console.log(findFoo.test('foo\nfoo\nfoo')); // => true findFoo = findFoo.searchOneLine(); console.log(findFoo.test('foo\nfoo\nfoo')); // => false ``` ## `repeatPrevious` ### Usage 1 Repeat the previous item exactly `count` times. Parameter | Expected type | Description ----------|---------------|------------ `count` | `Number` | Number of times to repeat the previous item ```js const expr = VerEx() .startOfLine() .find('foo') .repeatPrevious(2) .endOfLine(); console.log(expr.test('foofoo')); // => true expr.lastIndex = 0; console.log(expr.test('foofoofoo')); // => false ``` ### Usage 2 Repeat the previous item between `mix` and `max` (inclusive) times. Parameter | Expected type | Description ----------|---------------|------------ `min` | `Number` | Minimum number of times to repeat the previous item `max` | `Number` | Maximum number of times to repeat the previous item ```js const expr = VerEx() .startOfLine() .find('foo') .repeatPrevious(1, 3) .endOfLine(); console.log(expr.test('foo')); // => true expr.lastIndex = 0; console.log(expr.test('foofoo')); // => true expr.lastIndex = 0; console.log(expr.test('foofoofoo')); // => true expr.lastIndex = 0; console.log(expr.test('foofoofoofoo')); // => false ``` ================================================ FILE: docs/VerbalExpression/rules.md ================================================ # Rules ## `startOfLine` Control whether to match the expression only if it appears from the beginning of the line. Parameter | Expected type | Description ----------|---------------|------------ `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior ```js const expr1 = VerEx().find('apple'); console.log(expr1.test('pineapple')); // => true const expr2 = VerEx().startOfLine().find('apple'); console.log(expr2.test('pineapple')); // => false ``` ## `endOfLine` Control whether to match the expression only if it appears till the end of the line. Parameter | Expected type | Description ----------|---------------|------------ `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior ```js const expr1 = VerEx().find('apple'); console.log(expr1.test('apples')); // => true const expr2 = VerEx().find('apple').endOfLine(); console.log(expr2.test('apples')); // => false ``` ## `then` Match an expression. Parameter | Expected type | Description ----------|---------------|------------ `value` | `String`, `number`, `RegExp`, `VerbalExpression` | Expression to match ```js const expr = VerEx().then('foo'); console.log(expr.test('foo')); // => true ``` ## `find` Alias for [`then`](#then). Meant for semantics when used at the beginning of a verbal expression. For example, `VerEx().find('foo')` is more readable than `VerEx().then('foo')`. ## `maybe` Optionally match an expression. Parameter | Expected type | Description ----------|---------------|------------ `value` | `String`, `number`, `RegExp`, `VerbalExpression` | Expression to optionally match ```js const protocol = VerEx().find('http').maybe('s').then('://'); console.log(protocol.test('http://')); // => true protocol.lastIndex = 0; console.log(protocol.test('https://')); // => true ``` ## `or` Alternatively, match another expression. Parameter | Expected type | Description ----------|---------------|------------ `value` (optional) | `String`, `number`, `RegExp`, `VerbalExpression` | Expression to match instead If no parameters are passed into `or`, the alternate expression would be the one built after the call to `or`. ```js let fooOrBar = VerEx().find('foo').or('bar'); console.log(expr.test('foo')); // => true fooOrBar.lastIndex = 0 console.log(expr.test('bar')); // => true // alternate syntax fooOrBar = VerEx().find('foo').or().find('bar'); console.log(expr.test('foo')); // => true fooOrBar.lastIndex = 0 console.log(expr.test('bar')); // => true ``` ## `anything` Match any character(s) any (including zero) number of times. ```js const anything = VerEx().anything(); console.log(anything.test('')); // => true anything.lastIndex = 0; console.log(anything.test('x')); // => true ``` ## `anythingBut` Match any character(s) except these any (including zero) number of times. Parameter | Expected type | Description ----------|----------------------|------------------------ `value` | `String`, `[String]` | Characters to not match ```js const anythingButXyz = VerEx().anythingBut('xyz'); console.log(anythingButXyz.test('')); // => true anythingButXyz.lastIndex = 0; console.log(anythingButXyz.test('a')); // => true anythingButXyz.lastIndex = 0; console.log(anythingButXyz.test('x')); // => false ``` ## `something` Match any character(s) at least once. ```js const something = VerEx().something(); console.log(something.test('abc')); // => true something.lastIndex = 0; console.log(something.test('')); // => false ``` ## `somethingBut` Match any character(s) except these at least once. Parameter | Expected type | Description ----------|----------------------|------------------------ `value` | `String`, `[String]` | Characters to not match ```js const somethingButXyz = VerEx().somethingBut('xyz'); console.log(somethingButXyz.test('abc')); // => true somethingButXyz.lastIndex = 0; console.log(somethingButXyz.test('')); // => false somethingButXyz.lastIndex = 0; console.log(somethingButXyz.test('xyz')); // => false ``` ## `anyOf` Match any of these characters exactly once. Parameter | Expected type | Description ----------|-----------------------|-------------------- `value` | `String`, `[String]` | Characters to match ```js const expr = VerEx().anyOf('abc'); console.log(expr.test('c')); // => true expr.lastIndex = 0; console.log(expr.test('d')); // => false ``` ## `any` Alias for [`anyOf`](#anyof). ## `not` Ensure that the parameter does not follow. Parameter | Expected type | Description ----------|-----------------|--------------------------- `value` | `String|Number` | Value to ensure absence of ```js const notLeapDay = VerEx().startOfLine()not('FEB-29').something().endOfLine(); console.log(notLeapDay.test('FEB-29-2017')); // => false notLeapDay.lastIndex = 0; console.log(notLeapDay.test('FEB-28-2017')); // => true ``` ## `range` Match any character within the range defined by the parameters. Parameter | Expected type | Description -----------|---------------|-------------------- `...range` | `String[]` | Range of characters Arguments will be interpreted as pairs. For example, `.range('a', 'z', '0', '9')` will be interpreted to mean any character within the ranges `a–z` (ascii x–y) or `0–9` (ascii x–y). The method expects an even number of parameters; unpaired parameters are ignored. ```js const hex = VerEx().range('0', '9', 'a', 'f').oneOrMore(); console.log(hex.test('b39a3f')); // => true hex.lastIndex = 0; console.log(hex.test('b39aeg')); // => false ``` ================================================ FILE: docs/VerbalExpression/special-characters.md ================================================ # Special Characters ## `lineBreak` Match a line break (both [Unix style](//codepoints.net/U+000A) and [Windows style](//codepoints.net/U+000D)). ```js const expr = VerEx().find('foo').lineBreak().then('bar'); console.log(expr.test('foo\nbar')); ``` ## `br` An alias for [`lineBreak`](#linebreak). ## `tab` Match a [tab character](//codepoints.net/U+0009). ```js const tabs = VerEx().tab(); const code = '\tconsole.log("tabs vs spaces")'; // => ' console.log("tabs vs spaces")' console.log(tabs.replace(code, ' ')); ``` ## `word` Match a word—a string of word characters (a–z, A–Z, 0–9 or \_). ```js const word = VerEx().startOfLine().word().endOfLine(); console.log(word.test('foo')); // => true word.lastIndex = 0; console.log(word.test('foo-bar')); // => false ``` ## `digit` Match a digit (0–9). ```js const digit = VerEx().digit(); console.log(digit.test('2')); // => true ``` ## `whitespace` Match a whitespace character (one of [space](//codepoints.net/U+0020), [tab](//codepoints.net/U+0009), [carriage return](//codepoints.net/U+000D), [new line](//codepoints.net/U+000), [vertical tab](//codepoints.net/U+000B) and [form feed](//codepoints.net/U+000C)). ```js const expr = VerEx().word().whitespace().word(); console.log(expr.test('word\tword')); // => true ``` ================================================ FILE: docs/VerbalExpression/utilities.md ================================================ # Utilities ## `static sanitize` Escape characters expected special by regex engines (all of `.`, `|`, `*`, `?`, `+`, `(`, `)`, `{`, `}`, `^`, `$`, `\`, `:`, `=`, `[` and `]`). Parameter | Expected type | Description ----------|---------------|------------------- `value` | `String` | String to sanitize This method will not be accessible from outside the source file since `VerEx()` returns an instance of the class rather than the class itself. ```js const stringToEscape = '(http://example.com?arg=foo+bar)'; // => '\(http:\/\/example.com\?arg\=foo\+bar\)' console.log(VerbalExpression.sanitize(stringToEscape)); ``` `sanitize` is a static method on the `VerbalExpression` class. However, it is also exposed as `VerEx().sanitize`. ## `add` Append a literal expression to the object. Parameter | Expected type | Description ----------------------------|---------------|-------------------------------- `value` (defaults to `''`) | `String` | Expression to add to the object ```js const expr = VerEx(); expr.add('(foo)?(?:bar)*'); console.log(expr); // => /(foo)?(?:bar)*/gm ``` ================================================ FILE: docs/_config.yml ================================================ title: JSVerbalExpressions Docs description: API Documentation for JSVerbalExpressions. repository: VerbalExpressions/JSVerbalExpressions show_downloads: true theme: jekyll-theme-minimal exclude: - Gemfile - Gemfile.lock - .gitignore cdn_url: https://jsdelivr.com/package/npm/verbal-expressions npm_url: https://npmjs.com/package/verbal-expressions minified_url: https://cdn.jsdelivr.net/npm/verbal-expressions@latest/dist/verbalexpressions.min.js ================================================ FILE: docs/_layouts/default.html ================================================ {% seo %}

{{ site.title | default: site.github.repository_name }}

{{ site.description | default: site.github.project_tagline }}

{% if site.logo %} Logo {% endif %} {% if site.github.is_project_page %}

View the Project on GitHub
{{ site.github.repository_nwo }}

{% endif %} {% if site.github.is_user_page %}

View My GitHub Profile

{% endif %}
VerExVerbalExpression


{{ content }}
================================================ FILE: docs/assets/css/style.scss ================================================ --- --- @import "{{ site.theme }}"; .wrapper { width: 900px; } section { width: 540px; } ul { margin-bottom: 5px; list-style: none; padding-left: 2em; } hr { margin: 20px 0; } a:hover { font-weight: inherit; } a code { color: #267CB9; } a code:hover { color: #006699; } details { padding-bottom: 20px; } ================================================ FILE: docs/index.md ================================================ --- title: Home --- VerbalExpressions is a JavaScript library that helps to construct difficult regular expressions. For more details, refer to the [README](//github.com/VerbalExpressions/JSVerbalExpressions#readme). # Table Of Contents - [`VerEx`](VerEx) - [`VerbalExpression`](VerbalExpression) - [Constructor](VerbalExpression/constructor) - [Utilities](VerbalExpression/utilities) - [Rules](VerbalExpression/rules) - [Special Characters](VerbalExpression/special-characters) - [Modifiers](VerbalExpression/modifiers) - [Loops](VerbalExpression/loops) - [Capture Groups](VerbalExpression/capture-groups) - [Miscellaneous](VerbalExpression/miscellaneous) ___ Methods have a return type of [`VerbalExpression`](VerbalExpressions) except where mentioned otherwise. If there is no mention of a method's parameters, it is to be assumed that it has none. ================================================ FILE: package.json ================================================ { "name": "verbal-expressions", "description": "JavaScript Regular expressions made easy", "version": "1.0.2", "keywords": [ "regular expressions", "regex" ], "homepage": "https://github.com/VerbalExpressions/JSVerbalExpressions", "devDependencies": { "@babel/preset-env": "^7.12.1", "ava": "^3.13.0", "babel-core": "^6.26.3", "babel-plugin-transform-builtin-extend": "^1.1.2", "eslint": "^8.10.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.22.1", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.21.5", "grunt": "^1.3.0", "grunt-ava": "^0.19.0", "grunt-babel": "^8.0.0", "grunt-contrib-uglify": "^5.0.0", "grunt-eslint": "^24.0.0", "grunt-markdownlint": "^3.1.0", "grunt-sourcemap-localize": "^0.1.0", "grunt-umd": "^3.0.0", "nyc": "^15.1.0" }, "repository": { "type": "git", "url": "git://github.com/VerbalExpressions/JSVerbalExpressions.git" }, "bugs": { "url": "https://github.com/VerbalExpressions/JSVerbalExpressions/issues" }, "main": "dist/verbalexpressions.js", "license": "MIT", "scripts": { "test": "grunt test", "test:verbose": "grunt test:verbose", "compile": "grunt compile", "grunt": "grunt", "build": "grunt build" }, "types": "./typings/VerbalExpressions.d.ts", "engines": { "node": ">=9.2.0" }, "dependencies": {}, "prettier": { "singleQuote": true } } ================================================ FILE: test/tests.js ================================================ const test = require('ava'); const VerEx = require('../dist/verbalexpressions'); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#Using_test()_on_a_regex_with_the_global_flag function resetLastIndex(regex) { regex.lastIndex = 0; } test('constructor', (t) => { const testRegex = VerEx(); t.true(testRegex instanceof RegExp, 'Should extend RegExp'); t.is(testRegex.toString(), '/(?:)/gm', 'Should be empty regex with global, multiline matching'); }); // Utility // test('sanitize', (t) => { const testString = '$a^b\\c|d(e)f[g]h{i}j.k*l+m?n:o=p'; const escaped = '\\$a\\^b\\\\c\\|d\\(e\\)f\\[g\\]h\\{i\\}j\\.k\\*l\\+m\\?n\\:o\\=p'; t.is(VerEx().sanitize(testString), escaped, 'Special characters should be sanitized'); t.is(VerEx().sanitize(42), 42); t.is(VerEx().sanitize(/foo/), 'foo'); t.notThrows(() => VerEx().sanitize()); t.notThrows(() => VerEx().sanitize(NaN)); t.notThrows(() => VerEx().sanitize(null)); t.notThrows(() => VerEx().sanitize(true)); }); test('add', (t) => { let testRegex = VerEx().startOfLine().withAnyCase().endOfLine(); testRegex = testRegex.add('(?:foo)?'); t.true(testRegex.source.startsWith('^'), 'Should retain old prefixes'); t.true(testRegex.source.endsWith('$'), 'Should retain old suffixes'); t.true(testRegex.test('foo'), 'Should add new rules'); resetLastIndex(testRegex); t.true(testRegex.test(''), 'Should add new rules'); t.true(testRegex.flags.includes('i'), 'Should retain old modifiers'); }); // Rules // test('startOfLine', (t) => { let testRegex = VerEx().startOfLine().then('a'); let testString = 'a'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'ba'; t.false(testRegex.test(testString)); testRegex = testRegex.startOfLine(false); // start of line is no longer necessary testString = 'ba'; t.true(testRegex.test(testString)); }); test('endOfLine', (t) => { let testRegex = VerEx().find('a').endOfLine(); let testString = 'a'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'ab'; t.false(testRegex.test(testString)); testRegex = testRegex.endOfLine(false); // end of line is no longer necessary testString = 'ab'; t.true(testRegex.test(testString)); }); function then(name, t) { let testRegex = VerEx()[name]('a'); let testString = 'a'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'b'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = ''; t.false(testRegex.test(testString)); testRegex = VerEx()[name]('a')[name]('b'); testString = 'ab'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'ac'; t.false(testRegex.test(testString)); } test('then', (t) => { then('then', t); }); test('find', (t) => { then('find', t); }); test('maybe', (t) => { const testRegex = VerEx().startOfLine().then('a').maybe('b'); let testString = 'acb'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'abc'; t.true(testRegex.test(testString)); }); test('or', (t) => { let testRegex = VerEx().startOfLine().then('abc').or('def'); let testString = 'defzzz'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'abczzz'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'xyzabc'; t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().then('abc').or().then('def'); testString = 'defzzz'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'abczzz'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'xyzabc'; t.false(testRegex.test(testString)); }); test('anything', (t) => { const testRegex = VerEx().startOfLine().anything(); let testString = 'foo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = ''; t.true(testRegex.test(testString), 'Should be able to match zero characters'); }); test('anythingBut', (t) => { let testRegex = VerEx().startOfLine().anythingBut('br').endOfLine(); let testString = 'foobar'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foo_a_'; t.true(testRegex.test(testString)); testRegex = VerEx().startOfLine().anythingBut('br'); testString = 'bar'; t.true(testRegex.test(testString), 'Should be able to match zero characters'); testRegex = VerEx().startOfLine().anythingBut(['b', 'r']).endOfLine(); testString = 'foobar'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foo_a_'; t.true(testRegex.test(testString)); testRegex = VerEx().startOfLine().anythingBut(['b', 'r']); testString = 'bar'; t.true(testRegex.test(testString), 'Should be able to match zero characters'); }); test('something', (t) => { const testRegex = VerEx().something(); let testString = ''; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'a'; t.true(testRegex.test(testString)); }); test('somethingBut', (t) => { let testRegex = VerEx().startOfLine().somethingBut('abc').endOfLine(); let testString = ''; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'fab'; t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().somethingBut(['a', 'b', 'c']).endOfLine(); testString = ''; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'fab'; t.false(testRegex.test(testString)); }); function anyOf(name, t) { let testRegex = VerEx().startOfLine().then('a')[name]('xyz'); let testString = 'ay'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'ab'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'a'; t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().then('a')[name](['x', 'y', 'z']); testString = 'ay'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'ab'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'a'; t.false(testRegex.test(testString)); } test('anyOf', (t) => { anyOf('anyOf', t); }); test('any', (t) => { anyOf('any', t); }); test('not', (t) => { const testRegex = VerEx().startOfLine().not('foo').anything().endOfLine(); let testString = 'foobar'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'bar'; t.true(testRegex.test(testString)); }); test('range', (t) => { let testRegex = VerEx().startOfLine().range('a', 'z', '0', '9').oneOrMore().endOfLine(); let testString = 'foobarbaz123'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'fooBarBaz_123'; t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().range('a', 'z', '0').oneOrMore().endOfLine(); testString = 'foobarbaz'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foobarbaz123'; t.false(testRegex.test(testString), 'Should ignore extra parameters'); }); // Special characters // function lineBreak(name, t) { const testRegex = VerEx().startOfLine().then('abc')[name]().then('def'); let testString = 'abc\r\ndef'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'abc\ndef'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'abc\rdef'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'abc\r\n\ndef'; t.false(testRegex.test(testString)); } test('lineBreak', (t) => { lineBreak('lineBreak', t); }); test('br', (t) => { lineBreak('br', t); }); test('tab', (t) => { const testRegex = VerEx().startOfLine().tab().then('abc'); let testString = '\tabc'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'abc'; t.false(testRegex.test(testString)); }); test('word', (t) => { let testRegex = VerEx().startOfLine().word().endOfLine(); let testString = 'azertyuiopqsdfghjklmwxcvbn0123456789_'; t.true(testRegex.test(testString)); testRegex = VerEx().word(); testString = '. @[]|,&~-'; t.false(testRegex.test(testString)); }); test('digit', (t) => { let testRegex = VerEx().startOfLine().digit().oneOrMore().endOfLine(); let testString = '0123456789'; t.true(testRegex.test(testString)); testRegex = VerEx().digit(); testString = '-.azertyuiopqsdfghjklmwxcvbn @[]|,_&~'; t.false(testRegex.test(testString)); }); test('whitespace', (t) => { const testRegex = VerEx().startOfLine().whitespace().oneOrMore().searchOneLine().endOfLine(); let testString = ' \t\r\n\v\f'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'a z'; t.false(testRegex.test(testString)); }); // Modifiers // test('addModifier', (t) => { let testRegex = VerEx().addModifier('y'); t.true(testRegex.flags.includes('y')); t.notThrows(() => { testRegex = VerEx().addModifier('g'); }, 'Should not add extra modifier if it already exists'); }); test('removeModifier', (t) => { const testRegex = VerEx().removeModifier('g'); t.false(testRegex.flags.includes('g')); }); test('withAnyCase', (t) => { let testRegex = VerEx().startOfLine().then('a'); let testString = 'A'; t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().then('a').withAnyCase(); testString = 'A'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'a'; t.true(testRegex.test(testString)); testRegex = VerEx().startOfLine().then('a').withAnyCase(false); testString = 'A'; t.false(testRegex.test(testString)); }); test('stopAtFirst', (t) => { let testRegex = VerEx().find('foo'); const testString = 'foofoofoo'; t.is(testString.match(testRegex).length, 3, 'Should match all "foo"s'); testRegex = VerEx().find('foo').stopAtFirst(); t.is(testString.match(testRegex).length, 1, 'Should match one "foo"'); testRegex = VerEx().find('foo').stopAtFirst(false); t.is(testString.match(testRegex).length, 3, 'Should match all "foo"s'); }); test('searchOneLine', (t) => { let testRegex = VerEx().startOfLine().then('b').endOfLine(); const testString = 'a\nb\nc'; t.true(testRegex.test(testString)); testRegex = VerEx().startOfLine().then('b').endOfLine().searchOneLine(); t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().then('b').endOfLine().searchOneLine(false); t.true(testRegex.test(testString)); }); // Loops // test('repeatPrevious', (t) => { let testRegex = VerEx().startOfLine().find('foo').repeatPrevious(3).endOfLine(); let testString = 'foofoofoo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foofoo'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foofoofoofoo'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'bar'; t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().find('foo').repeatPrevious(1, 3).endOfLine(); for (let i = 0; i <= 4; i++) { resetLastIndex(testRegex); testString = 'foo'.repeat(i); if (i < 1 || i > 3) { t.false(testRegex.test(testString)); } else { t.true(testRegex.test(testString)); } } testRegex = VerEx().startOfLine().find('foo').repeatPrevious().endOfLine(); testString = 'foofoo'; t.false(testRegex.test(testString), 'Should silently fail on edge cases'); testRegex = VerEx().startOfLine().find('foo').repeatPrevious(1, 2, 3).endOfLine(); testString = 'foofoo'; t.false(testRegex.test(testString), 'Should silently fail on edge cases'); }); test('oneOrMore', (t) => { const testRegex = VerEx().startOfLine().then('foo').oneOrMore().endOfLine(); let testString = 'foo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foofoo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'bar'; t.false(testRegex.test(testString)); }); test('multiple', (t) => { let testRegex = VerEx().startOfLine().find(' ').multiple().endOfLine(); let testString = ' '; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = ' a '; t.false(testRegex.test(testString)); testRegex = VerEx().startOfLine().multiple('foo').endOfLine(); testString = 'foo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foofoofoo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = ''; t.true(testRegex.test(testString)); testRegex = VerEx().startOfLine().multiple('foo', 2).endOfLine(); testString = 'foo'; t.false(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foofoo'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); testString = 'foofoofoo'; t.true(testRegex.test(testString)); testRegex = VerEx().startOfLine().multiple('foo', 2, 5).endOfLine(); for (let i = 0; i <= 6; i++) { resetLastIndex(testRegex); testString = 'foo'.repeat(i); if (i < 2 || i > 5) { t.false(testRegex.test(testString)); } else { t.true(testRegex.test(testString)); } } }); // Capture groups // test('capture groups', (t) => { let testRegex = VerEx().find('foo').beginCapture().then('bar'); let testString = 'foobar'; t.true(testRegex.test(testString), 'Expressions with incomplete capture groups should work'); testRegex = testRegex.endCapture().then('baz'); testString = 'foobarbaz'; t.true(testRegex.test(testString)); resetLastIndex(testRegex); const matches = testRegex.exec(testString); t.is(matches[1], 'bar'); }); // Miscellaneous // test('replace', (t) => { const testRegex = VerEx().find(' '); const testString = 'foo bar baz'; t.is(testRegex.replace(testString, '_'), 'foo_bar_baz'); }); test('toRegExp', (t) => { const testRegex = VerEx().anything(); const converted = testRegex.toRegExp(); t.is(converted.toString(), testRegex.toString(), 'Converted regex should have same behaviour'); }); ================================================ FILE: typings/VerbalExpressions.d.ts ================================================ // Type definitions for JSVerbalExpressions // Project: https://github.com/VerbalExpressions/JSVerbalExpressions // Definitions by: Mihai Ionut Vilcu // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped type RegExpFlags = "g" | "i" | "m" | "u" | "y"; type Appendable = VerbalExpression | RegExp | string | number; interface VerbalExpression extends RegExp { // Utility // /** Sanitation function for adding anything safely to the expression */ sanitize(value: Appendable): VerbalExpression; /** Append literal expression to the object. Also refreshes the expression. */ add(value: string | number): VerbalExpression; // Rules // /** Mark the expression to end at the last character of the line. */ startOfLine(enable?: boolean): VerbalExpression; /** Mark the expression to start at the beginning of the line. */ endOfLine(enable?: boolean): VerbalExpression; /** Add a string to the expression */ then(value: Appendable): VerbalExpression; /** Add a string to the expression. Alias for then() */ find(value: Appendable): VerbalExpression; /** Add a string to the expression that might appear once (or not). */ maybe(value: Appendable): VerbalExpression; /** Add a alternative expression to be matched. */ or(value?: Appendable): VerbalExpression; /** Match any character(s) any (including zero) number of times. */ anything(): VerbalExpression; anythingBut(value: Appendable | string[]): VerbalExpression; /** Match any character(s) at least once. */ something(): VerbalExpression; somethingBut(value: Appendable | string[]): VerbalExpression; /** Match any of the provided values */ anyOf(value: Appendable | string[]): VerbalExpression; /** Match any of the provided values. Alias for anyOf() */ any(value: Appendable | string[]): VerbalExpression; /** Ensure that the parameter does not follow. */ not(value: Appendable): VerbalExpression; /** Add expression to match a range (or multiply ranges) */ range(...values: string[]): VerbalExpression; // Special Characters /** Add universal line break expression */ lineBreak(): VerbalExpression; /** Add universal line break expression. Alias for lineBreak() */ br(): VerbalExpression; /** Add expression to match a tab character */ tab(): VerbalExpression; /** Add expression to match a word */ word(): VerbalExpression; /** Add expression to match a digit */ digit(): VerbalExpression; /** Add expression to match a whitespace character */ whitespace(): VerbalExpression; // Modifiers // /** Adds a modifier to the expression. */ addModifier(modifier: RegExpFlags): VerbalExpression; /** Removes a modifier to the expression. */ removeModifier(modifier: RegExpFlags): VerbalExpression; /** Makes the expression case insensitive */ withAnyCase(enable?: boolean): VerbalExpression; /** Removes the 'g' modifier. */ stopAtFirst(enable?: boolean): VerbalExpression; /** Removes the 'm' modifier. */ searchOneLine(enable?: boolean): VerbalExpression; // Loops // /** Repeat the previous item between mix and max (inclusive) times. */ repeatPrevious(min: number, max: number): VerbalExpression; /** Repeat the previous item exactly count times. */ repeatPrevious(count: number): VerbalExpression; /** Match the previous stuff one or more times. */ oneOrMore(): VerbalExpression; /** Match something greater than or equal to min number of times. Or of upper is set. Match something between min and max (inclusive) number of times. */ multiple(value: string, lower: number, upper?: number): VerbalExpression; /** Match something zero or more times. */ multiple(value: string): VerbalExpression; /** Match the previous group any number of times. */ multiple(): VerbalExpression; /** Starts a capturing group */ beginCapture(): VerbalExpression; /** Emds a capturing group */ endCapture(): VerbalExpression; // Miscellaneous replace(source: string, value: string): string; /** Converts the verbal expression to a RegExp object */ toRegExp(): RegExp; } interface VerbalExpressionConstructor { new(): VerbalExpression; (): VerbalExpression; prototype: VerbalExpression; } declare var VerEx: VerbalExpressionConstructor; export = VerEx;