├── .gitignore ├── .gitmodules ├── .npmignore ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── benchmark.js ├── package-lock.json ├── package.json ├── scripts ├── build.sh └── setup-emsdk.sh ├── spec ├── README.md ├── onig-reg-exp-spec.js ├── onig-scanner-spec.js ├── onig-string-spec.js └── test-scan.js ├── src ├── OnigRegExp.ts ├── OnigScanner.ts ├── OnigString.ts ├── index.ts ├── onigasm.cc └── onigasmH.ts ├── test └── index.js ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled stuff 33 | build/Release 34 | lib/ 35 | 36 | # Dependency directories 37 | node_modules/ 38 | jspm_packages/ 39 | 40 | # Optional npm cache directory 41 | .npm 42 | 43 | # Optional eslint cache 44 | .eslintcache 45 | 46 | # Optional REPL history 47 | .node_repl_history 48 | 49 | # Output of 'npm pack' 50 | *.tgz 51 | 52 | # Yarn Integrity file 53 | .yarn-integrity 54 | 55 | # dotenv environment variables file 56 | .env 57 | 58 | # next.js build output 59 | .next 60 | 61 | # cloned emsdk 62 | emsdk/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "oniguruma"] 2 | path = oniguruma 3 | url = https://github.com/kkos/oniguruma 4 | ignore = all 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | oniguruma 2 | spec 3 | test 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Benchmark", 11 | "program": "${workspaceFolder}/benchmark.js" 12 | }, 13 | { 14 | "type": "node", 15 | "request": "launch", 16 | "name": "Tests", 17 | "program": "${workspaceFolder}/test/index.js" 18 | } 19 | 20 | ] 21 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.sass": "sass", 4 | "stdio.h": "c", 5 | "onigposix.h": "c", 6 | "regint.h": "c", 7 | "cmath": "cpp", 8 | "cstddef": "cpp", 9 | "cstdint": "cpp", 10 | "cstdio": "cpp", 11 | "cstdlib": "cpp", 12 | "cstring": "cpp", 13 | "cwchar": "cpp", 14 | "exception": "cpp", 15 | "initializer_list": "cpp", 16 | "ios": "cpp", 17 | "iosfwd": "cpp", 18 | "istream": "cpp", 19 | "limits": "cpp", 20 | "new": "cpp", 21 | "ostream": "cpp", 22 | "stdexcept": "cpp", 23 | "streambuf": "cpp", 24 | "string": "cpp", 25 | "system_error": "cpp", 26 | "type_traits": "cpp", 27 | "typeinfo": "cpp", 28 | "utility": "cpp", 29 | "xfacet": "cpp", 30 | "xiosbase": "cpp", 31 | "xlocale": "cpp", 32 | "xlocinfo": "cpp", 33 | "xlocnum": "cpp", 34 | "xmemory0": "cpp", 35 | "xstddef": "cpp", 36 | "xstring": "cpp", 37 | "xtr1common": "cpp", 38 | "xutility": "cpp" 39 | } 40 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Neek Sandhu 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Onigasm (**Onig**uruma**ASM**) 2 | 3 | `WebAssembly` port of Oniguruma regex library. 4 | 5 | Usage/API/Behaviour 1:1 with [`node-oniguruma`](https://github.com/atom/node-oniguruma) port, tests are literally imported from `node-oniguruma` repository for maximum compliance. 6 | 7 | Of course, unlike `node-oniguruma`, this library can't hook into roots of `V8` and is therefore 2 times* slower than the former. 8 | 9 | ## Instructions for porting your app to web 10 | 11 | ### Install 12 | 13 | ```bash 14 | npm i onigasm 15 | ``` 16 | 17 | ### Light it up 18 | 19 | > WASM must be loaded before you use any other feature like `OnigRegExp` or `OnigScanner` 20 | 21 | ```javascript 22 | // index.js (entry point) 23 | 24 | import { loadWASM } from 'onigasm' 25 | import App from './App' 26 | 27 | (async () => { 28 | await loadWASM('path/to/onigasm.wasm') // You can also pass ArrayBuffer of onigasm.wasm file 29 | App.start() 30 | })() 31 | 32 | // `onigasm.wasm` file will be available at `onigasm/lib/onigasm.wasm` in `node_modules` of your project directory 33 | ``` 34 | 35 | > Once loaded `onigasm` is a drop-in replacement for `oniguruma` 36 | 37 | ```diff 38 | - import { OnigRegExp } from 'oniguruma' 39 | + import { OnigRegExp } from 'onigasm' 40 | ``` 41 | 42 | ### That's it! 43 | 44 | \* Tested under laboratory conditions using `benchmark.js` 45 | ___ 46 | 47 | ### License 48 | 49 | `onigasm` is licensed under MIT License. See `LICENSE` in the root of this project for more info. 50 | 51 | ### Contributors/Maintainers 52 | - [@neeksandhu](https://github.com/NeekSandhu) (Neek Sandhu) 53 | - [@aeschli](https://github.com/aeschli) (Martin Aeschlimann) 54 | 55 | -------------------------------------------------------------------------------- /benchmark.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const { 4 | loadWASM, 5 | OnigScanner, 6 | OnigString 7 | } = require('.'); 8 | 9 | const wasmBin = fs.readFileSync(path.join(__dirname, './lib/onigasm.wasm')).buffer 10 | 11 | const StopWatch = typeof performance === 'undefined' ? Date : performance 12 | const log = console.log 13 | 14 | loadWASM(wasmBin).then(() => { 15 | const str = fs.readFileSync('node_modules/typescript/lib/typescriptServices.js', 'utf8').repeat(2) 16 | const scanner = new OnigScanner(['searchTillTheEndButYouWontFindMe']) 17 | var T0 = StopWatch.now() 18 | 19 | log() 20 | const test = (charCount) => { 21 | let t0 = StopWatch.now() 22 | let stepCount = 50 23 | let stepFactor = charCount / 5 24 | for (let i = 0; i < 100; i++) { 25 | for (let j = 0; j < stepCount; j++) { 26 | scanner.findNextMatchSync(str.slice(0, j * stepFactor)) 27 | } 28 | } 29 | log(`Uncached strings < ${charCount} characters\n:`, StopWatch.now() - t0, 'ms') 30 | 31 | t0 = StopWatch.now() 32 | var onig_strs = Array(stepCount).fill(undefined).map((_, i) => new OnigString(str.slice(0, stepFactor * i))) 33 | for (let i = 0; i < 100; i++) { 34 | for(let j = 0; j < stepCount; j++) { 35 | scanner.findNextMatchSync(onig_strs[j]) 36 | } 37 | } 38 | log(`Cached strings < ${charCount} characters\n:`, StopWatch.now() - t0, 'ms') 39 | log() 40 | } 41 | 42 | [ 43 | 100, 44 | 1000, 45 | 10000, 46 | 50000, 47 | 100000, 48 | 1000000, 49 | 2000000, 50 | ].forEach(test) 51 | 52 | 53 | 54 | console.log('All tests took ', StopWatch.now() - T0, 'ms') 55 | }) 56 | .catch(console.log) -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "onigasm", 3 | "version": "2.2.5", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.5.5", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", 10 | "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", 11 | "requires": { 12 | "@babel/highlight": "^7.0.0" 13 | } 14 | }, 15 | "@babel/highlight": { 16 | "version": "7.5.0", 17 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", 18 | "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", 19 | "requires": { 20 | "chalk": "^2.0.0", 21 | "esutils": "^2.0.2", 22 | "js-tokens": "^4.0.0" 23 | } 24 | }, 25 | "@blakeembrey/deque": { 26 | "version": "1.0.5", 27 | "resolved": "https://registry.npmjs.org/@blakeembrey/deque/-/deque-1.0.5.tgz", 28 | "integrity": "sha512-6xnwtvp9DY1EINIKdTfvfeAtCYw4OqBZJhtiqkT3ivjnEfa25VQ3TsKvaFfKm8MyGIEfE95qLe+bNEt3nB0Ylg==", 29 | "dev": true 30 | }, 31 | "@types/lru-cache": { 32 | "version": "5.1.0", 33 | "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.0.tgz", 34 | "integrity": "sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w==", 35 | "dev": true 36 | }, 37 | "amdefine": { 38 | "version": "1.0.1", 39 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 40 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 41 | "dev": true 42 | }, 43 | "ansi-regex": { 44 | "version": "3.0.0", 45 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 46 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 47 | "dev": true 48 | }, 49 | "ansi-styles": { 50 | "version": "3.2.1", 51 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 52 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 53 | "requires": { 54 | "color-convert": "^1.9.0" 55 | } 56 | }, 57 | "anymatch": { 58 | "version": "3.1.1", 59 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 60 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 61 | "dev": true, 62 | "requires": { 63 | "normalize-path": "^3.0.0", 64 | "picomatch": "^2.0.4" 65 | } 66 | }, 67 | "argparse": { 68 | "version": "1.0.10", 69 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 70 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 71 | "requires": { 72 | "sprintf-js": "~1.0.2" 73 | } 74 | }, 75 | "arrify": { 76 | "version": "2.0.1", 77 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", 78 | "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", 79 | "dev": true 80 | }, 81 | "async": { 82 | "version": "1.5.2", 83 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 84 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 85 | "dev": true 86 | }, 87 | "balanced-match": { 88 | "version": "1.0.0", 89 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 90 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 91 | }, 92 | "binary-extensions": { 93 | "version": "2.0.0", 94 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", 95 | "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", 96 | "dev": true 97 | }, 98 | "brace-expansion": { 99 | "version": "1.1.11", 100 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 101 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 102 | "requires": { 103 | "balanced-match": "^1.0.0", 104 | "concat-map": "0.0.1" 105 | } 106 | }, 107 | "braces": { 108 | "version": "3.0.2", 109 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 110 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 111 | "dev": true, 112 | "requires": { 113 | "fill-range": "^7.0.1" 114 | } 115 | }, 116 | "builtin-modules": { 117 | "version": "1.1.1", 118 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 119 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" 120 | }, 121 | "camelcase": { 122 | "version": "5.3.1", 123 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 124 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 125 | "dev": true 126 | }, 127 | "chalk": { 128 | "version": "2.4.2", 129 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 130 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 131 | "requires": { 132 | "ansi-styles": "^3.2.1", 133 | "escape-string-regexp": "^1.0.5", 134 | "supports-color": "^5.3.0" 135 | }, 136 | "dependencies": { 137 | "supports-color": { 138 | "version": "5.5.0", 139 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 140 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 141 | "requires": { 142 | "has-flag": "^3.0.0" 143 | } 144 | } 145 | } 146 | }, 147 | "chokidar": { 148 | "version": "3.3.0", 149 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", 150 | "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", 151 | "dev": true, 152 | "requires": { 153 | "anymatch": "~3.1.1", 154 | "braces": "~3.0.2", 155 | "fsevents": "~2.1.1", 156 | "glob-parent": "~5.1.0", 157 | "is-binary-path": "~2.1.0", 158 | "is-glob": "~4.0.1", 159 | "normalize-path": "~3.0.0", 160 | "readdirp": "~3.2.0" 161 | } 162 | }, 163 | "cliui": { 164 | "version": "4.1.0", 165 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", 166 | "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", 167 | "dev": true, 168 | "requires": { 169 | "string-width": "^2.1.1", 170 | "strip-ansi": "^4.0.0", 171 | "wrap-ansi": "^2.0.0" 172 | } 173 | }, 174 | "code-point-at": { 175 | "version": "1.1.0", 176 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 177 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 178 | "dev": true 179 | }, 180 | "coffee-script": { 181 | "version": "1.12.7", 182 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", 183 | "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", 184 | "dev": true 185 | }, 186 | "coffeestack": { 187 | "version": "1.2.0", 188 | "resolved": "https://registry.npmjs.org/coffeestack/-/coffeestack-1.2.0.tgz", 189 | "integrity": "sha512-vXT7ZxSZ4lXHh/0A2cODyFqrVIl4Vb0Er5wcS2SrFN4jW8g1qIAmcMsRlRdUKvnvfmKixvENYspAyF/ihWbpyw==", 190 | "dev": true, 191 | "requires": { 192 | "coffee-script": "~1.8.0", 193 | "fs-plus": "^3.1.1", 194 | "source-map": "~0.1.43" 195 | }, 196 | "dependencies": { 197 | "coffee-script": { 198 | "version": "1.8.0", 199 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.8.0.tgz", 200 | "integrity": "sha1-nJ8dK0pSoADe0Vtll5FwNkgmPB0=", 201 | "dev": true, 202 | "requires": { 203 | "mkdirp": "~0.3.5" 204 | } 205 | } 206 | } 207 | }, 208 | "color-convert": { 209 | "version": "1.9.3", 210 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 211 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 212 | "requires": { 213 | "color-name": "1.1.3" 214 | } 215 | }, 216 | "color-name": { 217 | "version": "1.1.3", 218 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 219 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 220 | }, 221 | "commander": { 222 | "version": "2.20.3", 223 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 224 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" 225 | }, 226 | "concat-map": { 227 | "version": "0.0.1", 228 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 229 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 230 | }, 231 | "concurrently": { 232 | "version": "5.0.0", 233 | "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-5.0.0.tgz", 234 | "integrity": "sha512-1yDvK8mduTIdxIxV9C60KoiOySUl/lfekpdbI+U5GXaPrgdffEavFa9QZB3vh68oWOpbCC+TuvxXV9YRPMvUrA==", 235 | "dev": true, 236 | "requires": { 237 | "chalk": "^2.4.2", 238 | "date-fns": "^2.0.1", 239 | "lodash": "^4.17.15", 240 | "read-pkg": "^4.0.1", 241 | "rxjs": "^6.5.2", 242 | "spawn-command": "^0.0.2-1", 243 | "supports-color": "^4.5.0", 244 | "tree-kill": "^1.2.1", 245 | "yargs": "^12.0.5" 246 | } 247 | }, 248 | "cross-spawn": { 249 | "version": "6.0.5", 250 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 251 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 252 | "dev": true, 253 | "requires": { 254 | "nice-try": "^1.0.4", 255 | "path-key": "^2.0.1", 256 | "semver": "^5.5.0", 257 | "shebang-command": "^1.2.0", 258 | "which": "^1.2.9" 259 | } 260 | }, 261 | "date-fns": { 262 | "version": "2.7.0", 263 | "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.7.0.tgz", 264 | "integrity": "sha512-wxYp2PGoUDN5ZEACc61aOtYFvSsJUylIvCjpjDOqM1UDaKIIuMJ9fAnMYFHV3TQaDpfTVxhwNK/GiCaHKuemTA==", 265 | "dev": true 266 | }, 267 | "decamelize": { 268 | "version": "1.2.0", 269 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 270 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 271 | "dev": true 272 | }, 273 | "diff": { 274 | "version": "4.0.1", 275 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", 276 | "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==" 277 | }, 278 | "durations": { 279 | "version": "3.4.1", 280 | "resolved": "https://registry.npmjs.org/durations/-/durations-3.4.1.tgz", 281 | "integrity": "sha512-51GO9gUZrihYsslOAakc2Z21JiDDwHwTGRXsXtWt/LoIvKU1fSt8Lbd0X5zxBKCt87Fz2gschTyBNsYK8S4HMw==", 282 | "dev": true 283 | }, 284 | "end-of-stream": { 285 | "version": "1.4.4", 286 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 287 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 288 | "dev": true, 289 | "requires": { 290 | "once": "^1.4.0" 291 | } 292 | }, 293 | "error-ex": { 294 | "version": "1.3.2", 295 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 296 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 297 | "dev": true, 298 | "requires": { 299 | "is-arrayish": "^0.2.1" 300 | } 301 | }, 302 | "escape-string-regexp": { 303 | "version": "1.0.5", 304 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 305 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 306 | }, 307 | "esprima": { 308 | "version": "4.0.1", 309 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 310 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" 311 | }, 312 | "esutils": { 313 | "version": "2.0.3", 314 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 315 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" 316 | }, 317 | "execa": { 318 | "version": "1.0.0", 319 | "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", 320 | "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", 321 | "dev": true, 322 | "requires": { 323 | "cross-spawn": "^6.0.0", 324 | "get-stream": "^4.0.0", 325 | "is-stream": "^1.1.0", 326 | "npm-run-path": "^2.0.0", 327 | "p-finally": "^1.0.0", 328 | "signal-exit": "^3.0.0", 329 | "strip-eof": "^1.0.0" 330 | } 331 | }, 332 | "fileset": { 333 | "version": "0.1.8", 334 | "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.1.8.tgz", 335 | "integrity": "sha1-UGuRqTluqn4y+0KoQHfHoMc2t0E=", 336 | "dev": true, 337 | "requires": { 338 | "glob": "3.x", 339 | "minimatch": "0.x" 340 | }, 341 | "dependencies": { 342 | "glob": { 343 | "version": "3.2.11", 344 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", 345 | "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", 346 | "dev": true, 347 | "requires": { 348 | "inherits": "2", 349 | "minimatch": "0.3" 350 | }, 351 | "dependencies": { 352 | "minimatch": { 353 | "version": "0.3.0", 354 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 355 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 356 | "dev": true, 357 | "requires": { 358 | "lru-cache": "2", 359 | "sigmund": "~1.0.0" 360 | } 361 | } 362 | } 363 | }, 364 | "lru-cache": { 365 | "version": "2.7.3", 366 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 367 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 368 | "dev": true 369 | }, 370 | "minimatch": { 371 | "version": "0.4.0", 372 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.4.0.tgz", 373 | "integrity": "sha1-vSx9Bg0sjI/Xzefx8u0tWycP2xs=", 374 | "dev": true, 375 | "requires": { 376 | "lru-cache": "2", 377 | "sigmund": "~1.0.0" 378 | } 379 | } 380 | } 381 | }, 382 | "fill-range": { 383 | "version": "7.0.1", 384 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 385 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 386 | "dev": true, 387 | "requires": { 388 | "to-regex-range": "^5.0.1" 389 | } 390 | }, 391 | "find-up": { 392 | "version": "3.0.0", 393 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 394 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 395 | "dev": true, 396 | "requires": { 397 | "locate-path": "^3.0.0" 398 | } 399 | }, 400 | "fs-plus": { 401 | "version": "3.1.1", 402 | "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", 403 | "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", 404 | "dev": true, 405 | "requires": { 406 | "async": "^1.5.2", 407 | "mkdirp": "^0.5.1", 408 | "rimraf": "^2.5.2", 409 | "underscore-plus": "1.x" 410 | }, 411 | "dependencies": { 412 | "mkdirp": { 413 | "version": "0.5.1", 414 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 415 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 416 | "dev": true, 417 | "requires": { 418 | "minimist": "0.0.8" 419 | } 420 | }, 421 | "rimraf": { 422 | "version": "2.7.1", 423 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 424 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 425 | "dev": true, 426 | "requires": { 427 | "glob": "^7.1.3" 428 | } 429 | } 430 | } 431 | }, 432 | "fs.realpath": { 433 | "version": "1.0.0", 434 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 435 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 436 | }, 437 | "fsevents": { 438 | "version": "2.1.2", 439 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", 440 | "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", 441 | "dev": true, 442 | "optional": true 443 | }, 444 | "gaze": { 445 | "version": "0.3.4", 446 | "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.3.4.tgz", 447 | "integrity": "sha1-X5S92gr+U7xxCWm81vKCVI1gwnk=", 448 | "dev": true, 449 | "requires": { 450 | "fileset": "~0.1.5", 451 | "minimatch": "~0.2.9" 452 | }, 453 | "dependencies": { 454 | "lru-cache": { 455 | "version": "2.7.3", 456 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 457 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 458 | "dev": true 459 | }, 460 | "minimatch": { 461 | "version": "0.2.14", 462 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", 463 | "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", 464 | "dev": true, 465 | "requires": { 466 | "lru-cache": "2", 467 | "sigmund": "~1.0.0" 468 | } 469 | } 470 | } 471 | }, 472 | "get-caller-file": { 473 | "version": "1.0.3", 474 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", 475 | "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", 476 | "dev": true 477 | }, 478 | "get-stream": { 479 | "version": "4.1.0", 480 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 481 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 482 | "dev": true, 483 | "requires": { 484 | "pump": "^3.0.0" 485 | } 486 | }, 487 | "glob": { 488 | "version": "7.1.6", 489 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 490 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 491 | "requires": { 492 | "fs.realpath": "^1.0.0", 493 | "inflight": "^1.0.4", 494 | "inherits": "2", 495 | "minimatch": "^3.0.4", 496 | "once": "^1.3.0", 497 | "path-is-absolute": "^1.0.0" 498 | } 499 | }, 500 | "glob-parent": { 501 | "version": "5.1.0", 502 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", 503 | "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", 504 | "dev": true, 505 | "requires": { 506 | "is-glob": "^4.0.1" 507 | } 508 | }, 509 | "has-flag": { 510 | "version": "3.0.0", 511 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 512 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 513 | }, 514 | "hosted-git-info": { 515 | "version": "2.8.5", 516 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", 517 | "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", 518 | "dev": true 519 | }, 520 | "ignore": { 521 | "version": "5.1.4", 522 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", 523 | "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", 524 | "dev": true 525 | }, 526 | "inflight": { 527 | "version": "1.0.6", 528 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 529 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 530 | "requires": { 531 | "once": "^1.3.0", 532 | "wrappy": "1" 533 | } 534 | }, 535 | "inherits": { 536 | "version": "2.0.4", 537 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 538 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 539 | }, 540 | "invert-kv": { 541 | "version": "2.0.0", 542 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", 543 | "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", 544 | "dev": true 545 | }, 546 | "is-arrayish": { 547 | "version": "0.2.1", 548 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 549 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 550 | "dev": true 551 | }, 552 | "is-binary-path": { 553 | "version": "2.1.0", 554 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 555 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 556 | "dev": true, 557 | "requires": { 558 | "binary-extensions": "^2.0.0" 559 | } 560 | }, 561 | "is-extglob": { 562 | "version": "2.1.1", 563 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 564 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 565 | "dev": true 566 | }, 567 | "is-fullwidth-code-point": { 568 | "version": "2.0.0", 569 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 570 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 571 | "dev": true 572 | }, 573 | "is-glob": { 574 | "version": "4.0.1", 575 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 576 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 577 | "dev": true, 578 | "requires": { 579 | "is-extglob": "^2.1.1" 580 | } 581 | }, 582 | "is-number": { 583 | "version": "7.0.0", 584 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 585 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 586 | "dev": true 587 | }, 588 | "is-stream": { 589 | "version": "1.1.0", 590 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 591 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", 592 | "dev": true 593 | }, 594 | "isexe": { 595 | "version": "2.0.0", 596 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 597 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 598 | "dev": true 599 | }, 600 | "jasmine-focused": { 601 | "version": "1.0.7", 602 | "resolved": "https://registry.npmjs.org/jasmine-focused/-/jasmine-focused-1.0.7.tgz", 603 | "integrity": "sha1-uDx1fIAOaOHW78GjoaE/85/23NI=", 604 | "dev": true, 605 | "requires": { 606 | "jasmine-node": "git+https://github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", 607 | "underscore-plus": "1.x", 608 | "walkdir": "0.0.7" 609 | } 610 | }, 611 | "jasmine-node": { 612 | "version": "git+https://github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", 613 | "from": "git+https://github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", 614 | "dev": true, 615 | "requires": { 616 | "coffee-script": ">=1.0.1", 617 | "coffeestack": ">=1 <2", 618 | "gaze": "~0.3.2", 619 | "jasmine-reporters": ">=0.2.0", 620 | "mkdirp": "~0.3.5", 621 | "requirejs": ">=0.27.1", 622 | "underscore": ">= 1.3.1", 623 | "walkdir": ">= 0.0.1" 624 | } 625 | }, 626 | "jasmine-reporters": { 627 | "version": "2.3.2", 628 | "resolved": "https://registry.npmjs.org/jasmine-reporters/-/jasmine-reporters-2.3.2.tgz", 629 | "integrity": "sha512-u/7AT9SkuZsUfFBLLzbErohTGNsEUCKaQbsVYnLFW1gEuL2DzmBL4n8v90uZsqIqlWvWUgian8J6yOt5Fyk/+A==", 630 | "dev": true, 631 | "requires": { 632 | "mkdirp": "^0.5.1", 633 | "xmldom": "^0.1.22" 634 | }, 635 | "dependencies": { 636 | "mkdirp": { 637 | "version": "0.5.1", 638 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 639 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 640 | "dev": true, 641 | "requires": { 642 | "minimist": "0.0.8" 643 | } 644 | } 645 | } 646 | }, 647 | "js-tokens": { 648 | "version": "4.0.0", 649 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 650 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 651 | }, 652 | "js-yaml": { 653 | "version": "3.13.1", 654 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 655 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 656 | "requires": { 657 | "argparse": "^1.0.7", 658 | "esprima": "^4.0.0" 659 | } 660 | }, 661 | "json-parse-better-errors": { 662 | "version": "1.0.2", 663 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 664 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 665 | "dev": true 666 | }, 667 | "lcid": { 668 | "version": "2.0.0", 669 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", 670 | "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", 671 | "dev": true, 672 | "requires": { 673 | "invert-kv": "^2.0.0" 674 | } 675 | }, 676 | "locate-path": { 677 | "version": "3.0.0", 678 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 679 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 680 | "dev": true, 681 | "requires": { 682 | "p-locate": "^3.0.0", 683 | "path-exists": "^3.0.0" 684 | } 685 | }, 686 | "lodash": { 687 | "version": "4.17.15", 688 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 689 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", 690 | "dev": true 691 | }, 692 | "lru-cache": { 693 | "version": "5.1.1", 694 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 695 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 696 | "requires": { 697 | "yallist": "^3.0.2" 698 | } 699 | }, 700 | "map-age-cleaner": { 701 | "version": "0.1.3", 702 | "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", 703 | "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", 704 | "dev": true, 705 | "requires": { 706 | "p-defer": "^1.0.0" 707 | } 708 | }, 709 | "mem": { 710 | "version": "4.3.0", 711 | "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", 712 | "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", 713 | "dev": true, 714 | "requires": { 715 | "map-age-cleaner": "^0.1.1", 716 | "mimic-fn": "^2.0.0", 717 | "p-is-promise": "^2.0.0" 718 | } 719 | }, 720 | "mimic-fn": { 721 | "version": "2.1.0", 722 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 723 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 724 | "dev": true 725 | }, 726 | "minimatch": { 727 | "version": "3.0.4", 728 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 729 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 730 | "requires": { 731 | "brace-expansion": "^1.1.7" 732 | } 733 | }, 734 | "minimist": { 735 | "version": "0.0.8", 736 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 737 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 738 | }, 739 | "mkdirp": { 740 | "version": "0.3.5", 741 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", 742 | "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", 743 | "dev": true 744 | }, 745 | "nice-try": { 746 | "version": "1.0.5", 747 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 748 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 749 | "dev": true 750 | }, 751 | "normalize-package-data": { 752 | "version": "2.5.0", 753 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 754 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 755 | "dev": true, 756 | "requires": { 757 | "hosted-git-info": "^2.1.4", 758 | "resolve": "^1.10.0", 759 | "semver": "2 || 3 || 4 || 5", 760 | "validate-npm-package-license": "^3.0.1" 761 | } 762 | }, 763 | "normalize-path": { 764 | "version": "3.0.0", 765 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 766 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 767 | "dev": true 768 | }, 769 | "npm-run-path": { 770 | "version": "2.0.2", 771 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 772 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 773 | "dev": true, 774 | "requires": { 775 | "path-key": "^2.0.0" 776 | } 777 | }, 778 | "number-is-nan": { 779 | "version": "1.0.1", 780 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 781 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 782 | "dev": true 783 | }, 784 | "once": { 785 | "version": "1.4.0", 786 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 787 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 788 | "requires": { 789 | "wrappy": "1" 790 | } 791 | }, 792 | "onchange": { 793 | "version": "6.1.0", 794 | "resolved": "https://registry.npmjs.org/onchange/-/onchange-6.1.0.tgz", 795 | "integrity": "sha512-T0wvi3yzNd+Lut2ymJp2e6fTiob0TLrXnjqGaiK9MAFB8MYo/k/ZClx6ps7YhTtQ88dDm+hDHmtJXP1nJT5WNA==", 796 | "dev": true, 797 | "requires": { 798 | "@blakeembrey/deque": "^1.0.3", 799 | "arrify": "^2.0.0", 800 | "chokidar": "^3.0.0", 801 | "cross-spawn": "^6.0.0", 802 | "ignore": "^5.1.4", 803 | "minimist": "^1.2.0", 804 | "supports-color": "^7.0.0", 805 | "tree-kill": "^1.2.0" 806 | }, 807 | "dependencies": { 808 | "has-flag": { 809 | "version": "4.0.0", 810 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 811 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 812 | "dev": true 813 | }, 814 | "minimist": { 815 | "version": "1.2.0", 816 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 817 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 818 | "dev": true 819 | }, 820 | "supports-color": { 821 | "version": "7.1.0", 822 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", 823 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", 824 | "dev": true, 825 | "requires": { 826 | "has-flag": "^4.0.0" 827 | } 828 | } 829 | } 830 | }, 831 | "os-locale": { 832 | "version": "3.1.0", 833 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", 834 | "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", 835 | "dev": true, 836 | "requires": { 837 | "execa": "^1.0.0", 838 | "lcid": "^2.0.0", 839 | "mem": "^4.0.0" 840 | } 841 | }, 842 | "p-defer": { 843 | "version": "1.0.0", 844 | "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", 845 | "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", 846 | "dev": true 847 | }, 848 | "p-finally": { 849 | "version": "1.0.0", 850 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 851 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", 852 | "dev": true 853 | }, 854 | "p-is-promise": { 855 | "version": "2.1.0", 856 | "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", 857 | "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", 858 | "dev": true 859 | }, 860 | "p-limit": { 861 | "version": "2.2.1", 862 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", 863 | "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", 864 | "dev": true, 865 | "requires": { 866 | "p-try": "^2.0.0" 867 | } 868 | }, 869 | "p-locate": { 870 | "version": "3.0.0", 871 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 872 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 873 | "dev": true, 874 | "requires": { 875 | "p-limit": "^2.0.0" 876 | } 877 | }, 878 | "p-try": { 879 | "version": "2.2.0", 880 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 881 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 882 | "dev": true 883 | }, 884 | "parse-json": { 885 | "version": "4.0.0", 886 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", 887 | "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", 888 | "dev": true, 889 | "requires": { 890 | "error-ex": "^1.3.1", 891 | "json-parse-better-errors": "^1.0.1" 892 | } 893 | }, 894 | "path-exists": { 895 | "version": "3.0.0", 896 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 897 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 898 | "dev": true 899 | }, 900 | "path-is-absolute": { 901 | "version": "1.0.1", 902 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 903 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 904 | }, 905 | "path-key": { 906 | "version": "2.0.1", 907 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 908 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 909 | "dev": true 910 | }, 911 | "path-parse": { 912 | "version": "1.0.6", 913 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 914 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 915 | }, 916 | "picomatch": { 917 | "version": "2.1.1", 918 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", 919 | "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", 920 | "dev": true 921 | }, 922 | "pify": { 923 | "version": "3.0.0", 924 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 925 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 926 | "dev": true 927 | }, 928 | "pump": { 929 | "version": "3.0.0", 930 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 931 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 932 | "dev": true, 933 | "requires": { 934 | "end-of-stream": "^1.1.0", 935 | "once": "^1.3.1" 936 | } 937 | }, 938 | "read-pkg": { 939 | "version": "4.0.1", 940 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", 941 | "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", 942 | "dev": true, 943 | "requires": { 944 | "normalize-package-data": "^2.3.2", 945 | "parse-json": "^4.0.0", 946 | "pify": "^3.0.0" 947 | } 948 | }, 949 | "readdirp": { 950 | "version": "3.2.0", 951 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", 952 | "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", 953 | "dev": true, 954 | "requires": { 955 | "picomatch": "^2.0.4" 956 | } 957 | }, 958 | "require-directory": { 959 | "version": "2.1.1", 960 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 961 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 962 | "dev": true 963 | }, 964 | "require-main-filename": { 965 | "version": "1.0.1", 966 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 967 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", 968 | "dev": true 969 | }, 970 | "requirejs": { 971 | "version": "2.3.6", 972 | "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", 973 | "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==", 974 | "dev": true 975 | }, 976 | "resolve": { 977 | "version": "1.12.0", 978 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", 979 | "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", 980 | "requires": { 981 | "path-parse": "^1.0.6" 982 | } 983 | }, 984 | "rimraf": { 985 | "version": "3.0.0", 986 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", 987 | "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", 988 | "dev": true, 989 | "requires": { 990 | "glob": "^7.1.3" 991 | } 992 | }, 993 | "rxjs": { 994 | "version": "6.5.3", 995 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", 996 | "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", 997 | "dev": true, 998 | "requires": { 999 | "tslib": "^1.9.0" 1000 | } 1001 | }, 1002 | "semver": { 1003 | "version": "5.7.1", 1004 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 1005 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 1006 | }, 1007 | "set-blocking": { 1008 | "version": "2.0.0", 1009 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 1010 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 1011 | "dev": true 1012 | }, 1013 | "shebang-command": { 1014 | "version": "1.2.0", 1015 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1016 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1017 | "dev": true, 1018 | "requires": { 1019 | "shebang-regex": "^1.0.0" 1020 | } 1021 | }, 1022 | "shebang-regex": { 1023 | "version": "1.0.0", 1024 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1025 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1026 | "dev": true 1027 | }, 1028 | "sigmund": { 1029 | "version": "1.0.1", 1030 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 1031 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 1032 | "dev": true 1033 | }, 1034 | "signal-exit": { 1035 | "version": "3.0.2", 1036 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1037 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1038 | "dev": true 1039 | }, 1040 | "source-map": { 1041 | "version": "0.1.43", 1042 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", 1043 | "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", 1044 | "dev": true, 1045 | "requires": { 1046 | "amdefine": ">=0.0.4" 1047 | } 1048 | }, 1049 | "spawn-command": { 1050 | "version": "0.0.2-1", 1051 | "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", 1052 | "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", 1053 | "dev": true 1054 | }, 1055 | "spdx-correct": { 1056 | "version": "3.1.0", 1057 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", 1058 | "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", 1059 | "dev": true, 1060 | "requires": { 1061 | "spdx-expression-parse": "^3.0.0", 1062 | "spdx-license-ids": "^3.0.0" 1063 | } 1064 | }, 1065 | "spdx-exceptions": { 1066 | "version": "2.2.0", 1067 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", 1068 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", 1069 | "dev": true 1070 | }, 1071 | "spdx-expression-parse": { 1072 | "version": "3.0.0", 1073 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", 1074 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", 1075 | "dev": true, 1076 | "requires": { 1077 | "spdx-exceptions": "^2.1.0", 1078 | "spdx-license-ids": "^3.0.0" 1079 | } 1080 | }, 1081 | "spdx-license-ids": { 1082 | "version": "3.0.5", 1083 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", 1084 | "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", 1085 | "dev": true 1086 | }, 1087 | "sprintf-js": { 1088 | "version": "1.0.3", 1089 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1090 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" 1091 | }, 1092 | "string-width": { 1093 | "version": "2.1.1", 1094 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1095 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1096 | "dev": true, 1097 | "requires": { 1098 | "is-fullwidth-code-point": "^2.0.0", 1099 | "strip-ansi": "^4.0.0" 1100 | } 1101 | }, 1102 | "strip-ansi": { 1103 | "version": "4.0.0", 1104 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1105 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1106 | "dev": true, 1107 | "requires": { 1108 | "ansi-regex": "^3.0.0" 1109 | } 1110 | }, 1111 | "strip-eof": { 1112 | "version": "1.0.0", 1113 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 1114 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", 1115 | "dev": true 1116 | }, 1117 | "supports-color": { 1118 | "version": "4.5.0", 1119 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", 1120 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", 1121 | "dev": true, 1122 | "requires": { 1123 | "has-flag": "^2.0.0" 1124 | }, 1125 | "dependencies": { 1126 | "has-flag": { 1127 | "version": "2.0.0", 1128 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 1129 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 1130 | "dev": true 1131 | } 1132 | } 1133 | }, 1134 | "to-regex-range": { 1135 | "version": "5.0.1", 1136 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1137 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1138 | "dev": true, 1139 | "requires": { 1140 | "is-number": "^7.0.0" 1141 | } 1142 | }, 1143 | "tree-kill": { 1144 | "version": "1.2.1", 1145 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", 1146 | "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", 1147 | "dev": true 1148 | }, 1149 | "tslib": { 1150 | "version": "1.10.0", 1151 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", 1152 | "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" 1153 | }, 1154 | "tslint": { 1155 | "version": "5.20.1", 1156 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", 1157 | "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", 1158 | "requires": { 1159 | "@babel/code-frame": "^7.0.0", 1160 | "builtin-modules": "^1.1.1", 1161 | "chalk": "^2.3.0", 1162 | "commander": "^2.12.1", 1163 | "diff": "^4.0.1", 1164 | "glob": "^7.1.1", 1165 | "js-yaml": "^3.13.1", 1166 | "minimatch": "^3.0.4", 1167 | "mkdirp": "^0.5.1", 1168 | "resolve": "^1.3.2", 1169 | "semver": "^5.3.0", 1170 | "tslib": "^1.8.0", 1171 | "tsutils": "^2.29.0" 1172 | }, 1173 | "dependencies": { 1174 | "mkdirp": { 1175 | "version": "0.5.1", 1176 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1177 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1178 | "requires": { 1179 | "minimist": "0.0.8" 1180 | } 1181 | } 1182 | } 1183 | }, 1184 | "tsutils": { 1185 | "version": "2.29.0", 1186 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 1187 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 1188 | "requires": { 1189 | "tslib": "^1.8.1" 1190 | } 1191 | }, 1192 | "typescript": { 1193 | "version": "3.7.2", 1194 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", 1195 | "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", 1196 | "dev": true 1197 | }, 1198 | "underscore": { 1199 | "version": "1.9.1", 1200 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", 1201 | "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==", 1202 | "dev": true 1203 | }, 1204 | "underscore-plus": { 1205 | "version": "1.7.0", 1206 | "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.7.0.tgz", 1207 | "integrity": "sha512-A3BEzkeicFLnr+U/Q3EyWwJAQPbA19mtZZ4h+lLq3ttm9kn8WC4R3YpuJZEXmWdLjYP47Zc8aLZm9kwdv+zzvA==", 1208 | "dev": true, 1209 | "requires": { 1210 | "underscore": "^1.9.1" 1211 | } 1212 | }, 1213 | "validate-npm-package-license": { 1214 | "version": "3.0.4", 1215 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 1216 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 1217 | "dev": true, 1218 | "requires": { 1219 | "spdx-correct": "^3.0.0", 1220 | "spdx-expression-parse": "^3.0.0" 1221 | } 1222 | }, 1223 | "walkdir": { 1224 | "version": "0.0.7", 1225 | "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.7.tgz", 1226 | "integrity": "sha1-BNoCcKh6d4VAFzzb8KLbSZqNnik=", 1227 | "dev": true 1228 | }, 1229 | "which": { 1230 | "version": "1.3.1", 1231 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1232 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1233 | "dev": true, 1234 | "requires": { 1235 | "isexe": "^2.0.0" 1236 | } 1237 | }, 1238 | "which-module": { 1239 | "version": "2.0.0", 1240 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 1241 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", 1242 | "dev": true 1243 | }, 1244 | "wrap-ansi": { 1245 | "version": "2.1.0", 1246 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 1247 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 1248 | "dev": true, 1249 | "requires": { 1250 | "string-width": "^1.0.1", 1251 | "strip-ansi": "^3.0.1" 1252 | }, 1253 | "dependencies": { 1254 | "ansi-regex": { 1255 | "version": "2.1.1", 1256 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 1257 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 1258 | "dev": true 1259 | }, 1260 | "is-fullwidth-code-point": { 1261 | "version": "1.0.0", 1262 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 1263 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 1264 | "dev": true, 1265 | "requires": { 1266 | "number-is-nan": "^1.0.0" 1267 | } 1268 | }, 1269 | "string-width": { 1270 | "version": "1.0.2", 1271 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1272 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1273 | "dev": true, 1274 | "requires": { 1275 | "code-point-at": "^1.0.0", 1276 | "is-fullwidth-code-point": "^1.0.0", 1277 | "strip-ansi": "^3.0.0" 1278 | } 1279 | }, 1280 | "strip-ansi": { 1281 | "version": "3.0.1", 1282 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1283 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1284 | "dev": true, 1285 | "requires": { 1286 | "ansi-regex": "^2.0.0" 1287 | } 1288 | } 1289 | } 1290 | }, 1291 | "wrappy": { 1292 | "version": "1.0.2", 1293 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1294 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1295 | }, 1296 | "xmldom": { 1297 | "version": "0.1.27", 1298 | "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", 1299 | "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", 1300 | "dev": true 1301 | }, 1302 | "y18n": { 1303 | "version": "4.0.0", 1304 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", 1305 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", 1306 | "dev": true 1307 | }, 1308 | "yallist": { 1309 | "version": "3.1.1", 1310 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1311 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 1312 | }, 1313 | "yargs": { 1314 | "version": "12.0.5", 1315 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", 1316 | "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", 1317 | "dev": true, 1318 | "requires": { 1319 | "cliui": "^4.0.0", 1320 | "decamelize": "^1.2.0", 1321 | "find-up": "^3.0.0", 1322 | "get-caller-file": "^1.0.1", 1323 | "os-locale": "^3.0.0", 1324 | "require-directory": "^2.1.1", 1325 | "require-main-filename": "^1.0.1", 1326 | "set-blocking": "^2.0.0", 1327 | "string-width": "^2.0.0", 1328 | "which-module": "^2.0.0", 1329 | "y18n": "^3.2.1 || ^4.0.0", 1330 | "yargs-parser": "^11.1.1" 1331 | } 1332 | }, 1333 | "yargs-parser": { 1334 | "version": "11.1.1", 1335 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", 1336 | "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", 1337 | "dev": true, 1338 | "requires": { 1339 | "camelcase": "^5.0.0", 1340 | "decamelize": "^1.2.0" 1341 | } 1342 | } 1343 | } 1344 | } 1345 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "onigasm", 3 | "version": "2.2.5", 4 | "description": "WebAssembly port of Oniguruma regex library", 5 | "main": "lib/index.js", 6 | "typings": "lib/typings/index.d.ts", 7 | "scripts": { 8 | "build::onig": "./scripts/build.sh", 9 | "watch::onig": "onchange 'src/**/*.cc' -w -p 1000 -- npm run build::onig", 10 | "build::tsc": "tsc", 11 | "watch::tsc": "tsc -w", 12 | "build": "concurrently \"npm run build::tsc\" \"npm run build::onig\"", 13 | "watch": "concurrently \"npm run watch::tsc\" \"npm run watch::onig\"", 14 | "clean": "git submodule foreach --recursive git clean -xfd && rimraf lib", 15 | "test": "node test/index.js", 16 | "benchmark": "node benchmark.js", 17 | "preversion": "npm run setup-emsdk && npm run clean && npm run build && npm run test", 18 | "setup-emsdk": "./scripts/setup-emsdk.sh 1.39.2" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/NeekSandhu/onigasm.git" 23 | }, 24 | "keywords": [ 25 | "oniguruma", 26 | "onig", 27 | "regex", 28 | "wasm", 29 | "asm", 30 | "web", 31 | "assembly" 32 | ], 33 | "author": "Neek Sandhu ", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/NeekSandhu/onigasm/issues" 37 | }, 38 | "homepage": "https://github.com/NeekSandhu/onigasm#readme", 39 | "devDependencies": { 40 | "@types/lru-cache": "^5.1.0", 41 | "concurrently": "^5.0.0", 42 | "durations": "^3.4.1", 43 | "jasmine-focused": "^1.0.7", 44 | "onchange": "^6.1.0", 45 | "rimraf": "^3.0.0", 46 | "tslint": "^5.20.1", 47 | "typescript": "^3.7.2" 48 | }, 49 | "dependencies": { 50 | "lru-cache": "^5.1.1" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ROOT_DIR=$(dirname "$(dirname "$(readlink -f "$0")")") 3 | 4 | source "$ROOT_DIR/emsdk/emsdk_env.sh" 5 | 6 | if [ -f oniguruma/src/.libs/libonig.so ] 7 | then 8 | echo "libonig.so exists, skipping oniguruma build" 9 | else 10 | echo "libonig.so not found. Running oniguruma build" 11 | cd oniguruma 12 | if [ ! -f configure ] 13 | then 14 | echo "Running autoreconf -vfi" 15 | autoreconf -vfi 16 | fi 17 | if [ ! -f src/Makefile ] 18 | then 19 | echo "Running emconfigure ./configure" 20 | emconfigure ./configure --enable-posix-api=no 21 | autoreconf -vfi 22 | fi 23 | make clean 24 | emmake make 25 | cd .. 26 | fi 27 | 28 | # ATM emcc blows up if path passed to -o doesn't exist 29 | if [ ! -d lib ] 30 | then 31 | mkdir lib 32 | fi 33 | 34 | emcc -O2 \ 35 | oniguruma/src/.libs/libonig.so \ 36 | src/onigasm.cc\ 37 | -Isrc -Ioniguruma/src \ 38 | -s ENVIRONMENT=shell \ 39 | -s NO_EXIT_RUNTIME=1 \ 40 | -s NO_FILESYSTEM=1 \ 41 | -s TOTAL_MEMORY=157286400 \ 42 | -s ALLOW_MEMORY_GROWTH=1 \ 43 | -s DEMANGLE_SUPPORT=1 \ 44 | -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']" \ 45 | -s MODULARIZE=1 \ 46 | -s EXPORT_NAME="'Onigasm'" \ 47 | -o lib/onigasm.js 48 | -------------------------------------------------------------------------------- /scripts/setup-emsdk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | VERSION=${1:-latest} 3 | 4 | ROOT_DIR=$(dirname "$(dirname "$(readlink -f "$0")")") 5 | EMSDK_DIR="$ROOT_DIR/emsdk" 6 | 7 | CURRENT_DIR="$PWD" 8 | if [ ! -d "$EMSDK_DIR" ]; then 9 | echo "*** Cloning emscripten-core/emsdk.git to $EMSDK_DIR" 10 | cd "$ROOT_DIR" 11 | git clone https://github.com/emscripten-core/emsdk.git 12 | else 13 | echo "*** Updating emscripten-core/emsdk.git at $EMSDK_DIR" 14 | cd "$EMSDK_DIR" 15 | git pull 16 | fi 17 | cd "$CURRENT_DIR" 18 | 19 | echo "*** Using emsdk version: $VERSION" 20 | 21 | "$EMSDK_DIR/emsdk" install "$VERSION" 22 | "$EMSDK_DIR/emsdk" activate "$VERSION" -------------------------------------------------------------------------------- /spec/README.md: -------------------------------------------------------------------------------- 1 | Files in `/spec` should be in sync with `atom/node-oniguruma` to ensure 100% API/usage/behaviour compliance -------------------------------------------------------------------------------- /spec/onig-reg-exp-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const OnigRegExp = require('..').OnigRegExp 4 | 5 | describe('OnigRegExp', () => { 6 | describe('::search(string, index, callback)', () => { 7 | it('returns an array of the match and all capture groups', () => { 8 | let regex = new OnigRegExp('\\w(\\d+)') 9 | let searchCallback = jasmine.createSpy('searchCallback') 10 | let result = regex.search('----a123----', searchCallback) 11 | 12 | waitsFor(() => searchCallback.callCount === 1) 13 | 14 | runs(() => { 15 | result = searchCallback.argsForCall[0][1] 16 | expect(result.length).toBe(2) 17 | expect(result[0].match).toBe('a123') 18 | expect(result[0].start).toBe(4) 19 | expect(result[0].end).toBe(8) 20 | expect(result[0].index).toBe(0) 21 | expect(result[0].length).toBe(4) 22 | expect(result[1].match).toBe('123') 23 | expect(result[1].start).toBe(5) 24 | expect(result[1].end).toBe(8) 25 | expect(result[1].index).toBe(1) 26 | expect(result[1].length).toBe(3) 27 | }) 28 | }) 29 | 30 | it('returns null if it does not match', () => { 31 | let regex = new OnigRegExp('\\w(\\d+)') 32 | let searchCallback = jasmine.createSpy('searchCallback') 33 | let result = regex.search('--------', searchCallback) 34 | 35 | waitsFor(() => searchCallback.callCount === 1) 36 | 37 | runs(() => { 38 | result = searchCallback.argsForCall[0][1] 39 | expect(result).toBeNull() 40 | }) 41 | }) 42 | 43 | describe('when the string being searched contains a unicode character', () => 44 | it('returns correct indices and lengths', () => { 45 | let regex = new OnigRegExp('a') 46 | let searchCallback = jasmine.createSpy('searchCallback') 47 | regex.search('ç√Ωa', 0, searchCallback) 48 | 49 | waitsFor(() => searchCallback.callCount === 1) 50 | 51 | runs(() => { 52 | let firstMatch = searchCallback.argsForCall[0][1] 53 | expect(firstMatch[0].start).toBe(3) 54 | expect(firstMatch[0].match).toBe('a') 55 | regex.search('ç√Ωabcd≈ßåabcd', 5, searchCallback) 56 | }) 57 | 58 | waitsFor(() => searchCallback.callCount === 2) 59 | 60 | runs(() => { 61 | let secondMatch = searchCallback.argsForCall[1][1] 62 | expect(secondMatch[0].start).toBe(10) 63 | expect(secondMatch[0].match).toBe('a') 64 | }) 65 | }) 66 | ) 67 | 68 | describe('when the string being searched contains non-Basic Multilingual Plane characters', () => 69 | it('returns correct indices and matches', () => { 70 | let regex = new OnigRegExp("'") 71 | let searchCallback = jasmine.createSpy('searchCallback') 72 | regex.search("'\uD835\uDF97'", 0, searchCallback) 73 | 74 | waitsFor(() => searchCallback.callCount === 1) 75 | 76 | runs(() => { 77 | let match = searchCallback.argsForCall[0][1] 78 | expect(match[0].start).toBe(0) 79 | expect(match[0].match).toBe("'") 80 | regex.search("'\uD835\uDF97'", 1, searchCallback) 81 | }) 82 | 83 | waitsFor(() => searchCallback.callCount === 2) 84 | 85 | runs(() => { 86 | let match = searchCallback.argsForCall[1][1] 87 | expect(match[0].start).toBe(3) 88 | expect(match[0].match).toBe("'") 89 | regex.search("'\uD835\uDF97'", 2, searchCallback) 90 | }) 91 | 92 | waitsFor(() => searchCallback.callCount === 3) 93 | 94 | runs(() => { 95 | let match = searchCallback.argsForCall[2][1] 96 | expect(match[0].start).toBe(3) 97 | expect(match[0].match).toBe("'") 98 | }) 99 | }) 100 | ) 101 | }) 102 | 103 | describe('::searchSync(string, index)', () => { 104 | it('returns an array of the match and all capture groups', () => { 105 | let regex = new OnigRegExp('\\w(\\d+)') 106 | let result = regex.searchSync('----a123----') 107 | expect(result.length).toBe(2) 108 | expect(result[0].match).toBe('a123') 109 | expect(result[0].start).toBe(4) 110 | expect(result[0].end).toBe(8) 111 | expect(result[0].index).toBe(0) 112 | expect(result[0].length).toBe(4) 113 | expect(result[1].match).toBe('123') 114 | expect(result[1].start).toBe(5) 115 | expect(result[1].end).toBe(8) 116 | expect(result[1].index).toBe(1) 117 | expect(result[1].length).toBe(3) 118 | }) 119 | 120 | it('returns null if it does not match', () => { 121 | let regex = new OnigRegExp('\\w(\\d+)') 122 | let result = regex.searchSync('--------') 123 | expect(result).toBeNull() 124 | }) 125 | 126 | describe('when the string being searched contains a unicode character', () => 127 | it('returns correct indices and lengths', () => { 128 | let regex = new OnigRegExp('a') 129 | 130 | let firstMatch = regex.searchSync('ç√Ωa', 0) 131 | expect(firstMatch[0].start).toBe(3) 132 | expect(firstMatch[0].match).toBe('a') 133 | 134 | let secondMatch = regex.searchSync('ç√Ωabcd≈ßåabcd', 5) 135 | expect(secondMatch[0].start).toBe(10) 136 | expect(secondMatch[0].match).toBe('a') 137 | }) 138 | ) 139 | 140 | describe('when the string being searched contains non-Basic Multilingual Plane characters', () => 141 | it('returns correct indices and matches', () => { 142 | let regex = new OnigRegExp("'") 143 | 144 | let match = regex.searchSync("'\uD835\uDF97'", 0) 145 | expect(match[0].start).toBe(0) 146 | expect(match[0].match).toBe("'") 147 | 148 | match = regex.searchSync("'\uD835\uDF97'", 1) 149 | expect(match[0].start).toBe(3) 150 | expect(match[0].match).toBe("'") 151 | 152 | match = regex.searchSync("'\uD835\uDF97'", 2) 153 | expect(match[0].start).toBe(3) 154 | expect(match[0].match).toBe("'") 155 | 156 | match = regex.searchSync("'\uD835\uDF97'", 3) 157 | expect(match[0].start).toBe(3) 158 | expect(match[0].match).toBe("'") 159 | }) 160 | ) 161 | }) 162 | 163 | describe('::testSync(string)', () => 164 | it('returns true if the string matches the pattern', () => { 165 | expect(new OnigRegExp('a[b-d]c').testSync('aec')).toBe(false) 166 | expect(new OnigRegExp('a[b-d]c').testSync('abc')).toBe(true) 167 | expect(new OnigRegExp(false).testSync(false)).toBe(true) 168 | expect(new OnigRegExp(false).testSync(true)).toBe(false) 169 | }) 170 | ) 171 | 172 | describe('::test(string, callback)', () => 173 | it('calls back with true if the string matches the pattern', () => { 174 | let testCallback = jasmine.createSpy('testCallback') 175 | 176 | new OnigRegExp('a[b-d]c').test('aec', testCallback) 177 | 178 | waitsFor(() => testCallback.callCount === 1) 179 | 180 | runs(() => { 181 | expect(testCallback.argsForCall[0][0]).toBeNull() 182 | expect(testCallback.argsForCall[0][1]).toBe(false) 183 | new OnigRegExp('a[b-d]c').test('abc', testCallback) 184 | }) 185 | 186 | waitsFor(() => testCallback.callCount === 2) 187 | 188 | runs(() => { 189 | expect(testCallback.argsForCall[1][0]).toBeNull() 190 | expect(testCallback.argsForCall[1][1]).toBe(true) 191 | }) 192 | }) 193 | ) 194 | }) 195 | -------------------------------------------------------------------------------- /spec/onig-scanner-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const OnigScanner = require('..').OnigScanner 4 | 5 | describe('OnigScanner', () => { 6 | describe('::findNextMatchSync', () => { 7 | it('returns the index of the matching pattern', () => { 8 | let scanner = new OnigScanner(['a', 'b', 'c']) 9 | expect(scanner.findNextMatchSync('x', 0)).toBe(null) 10 | expect(scanner.findNextMatchSync('xxaxxbxxc', 0).index).toBe(0) 11 | expect(scanner.findNextMatchSync('xxaxxbxxc', 4).index).toBe(1) 12 | expect(scanner.findNextMatchSync('xxaxxbxxc', 7).index).toBe(2) 13 | expect(scanner.findNextMatchSync('xxaxxbxxc', 9)).toBe(null) 14 | }) 15 | 16 | it('includes the scanner with the results', () => { 17 | let scanner = new OnigScanner(['a']) 18 | expect(scanner.findNextMatchSync('a', 0).scanner).toBe(scanner) 19 | }) 20 | 21 | describe('when the string searched contains unicode characters', () => 22 | it('returns the correct matching pattern', () => { 23 | let scanner = new OnigScanner(['1', '2']) 24 | let match = scanner.findNextMatchSync('ab…cde21', 5) 25 | expect(match.index).toBe(1) 26 | 27 | scanner = new OnigScanner(['\"']) 28 | match = scanner.findNextMatchSync('{"…": 1}', 1) 29 | expect(match.captureIndices).toEqual([{index: 0, start: 1, end: 2, length: 1}]) 30 | })) 31 | 32 | describe('when the string searched contains surrogate pairs', () => 33 | it('counts paired characters as 2 characters in both arguments and return values', () => { 34 | let scanner = new OnigScanner(['Y', 'X']) 35 | let match = scanner.findNextMatchSync('a💻bYX', 0) 36 | expect(match.captureIndices).toEqual([{index: 0, start: 4, end: 5, length: 1}]) 37 | 38 | match = scanner.findNextMatchSync('a💻bYX', 1) 39 | expect(match.captureIndices).toEqual([{index: 0, start: 4, end: 5, length: 1}]) 40 | 41 | match = scanner.findNextMatchSync('a💻bYX', 3) 42 | expect(match.captureIndices).toEqual([{index: 0, start: 4, end: 5, length: 1}]) 43 | 44 | match = scanner.findNextMatchSync('a💻bYX', 4) 45 | expect(match.captureIndices).toEqual([{index: 0, start: 4, end: 5, length: 1}]) 46 | 47 | match = scanner.findNextMatchSync('a💻bYX', 5) 48 | expect(match.index).toBe(1) 49 | expect(match.captureIndices).toEqual([{index: 0, start: 5, end: 6, length: 1}]) 50 | })) 51 | 52 | it("returns false when the input string isn't a string", () => { 53 | let scanner = new OnigScanner(['1']) 54 | expect(scanner.findNextMatchSync()).toBe(null) 55 | expect(scanner.findNextMatchSync(null)).toBe(null) 56 | expect(scanner.findNextMatchSync(2)).toBe(null) 57 | expect(scanner.findNextMatchSync(false)).toBe(null) 58 | }) 59 | 60 | it("uses 0 as the start position when the input start position isn't a valid number", () => { 61 | let scanner = new OnigScanner(['1']) 62 | expect(scanner.findNextMatchSync('a1', Infinity).index).toBe(0) 63 | expect(scanner.findNextMatchSync('a1', -1).index).toBe(0) 64 | expect(scanner.findNextMatchSync('a1', false).index).toBe(0) 65 | expect(scanner.findNextMatchSync('a1', 'food').index).toBe(0) 66 | }) 67 | }) 68 | 69 | describe('when the regular expression contains double byte characters', () => 70 | it('returns the correct match length', () => { 71 | let scanner = new OnigScanner(['Возврат']) 72 | let match = scanner.findNextMatchSync('Возврат long_var_name;', 0) 73 | expect(match.captureIndices).toEqual([{index: 0, start: 0, end: 7, length: 7}]) 74 | })) 75 | 76 | describe('when the input string contains invalid surrogate pairs', () => 77 | it('interprets them as a code point', () => { 78 | let scanner = new OnigScanner(['X']) 79 | let match = scanner.findNextMatchSync(`X${String.fromCharCode(0xd83c)}X`, 0) 80 | expect(match.captureIndices).toEqual([{index: 0, start: 0, end: 1, length: 1}]) 81 | 82 | match = scanner.findNextMatchSync(`X${String.fromCharCode(0xd83c)}X`, 1) 83 | expect(match.captureIndices).toEqual([{index: 0, start: 2, end: 3, length: 1}]) 84 | 85 | match = scanner.findNextMatchSync(`X${String.fromCharCode(0xd83c)}X`, 2) 86 | expect(match.captureIndices).toEqual([{index: 0, start: 2, end: 3, length: 1}]) 87 | 88 | match = scanner.findNextMatchSync(`X${String.fromCharCode(0xdfff)}X`, 0) 89 | expect(match.captureIndices).toEqual([{index: 0, start: 0, end: 1, length: 1}]) 90 | 91 | match = scanner.findNextMatchSync(`X${String.fromCharCode(0xdfff)}X`, 1) 92 | expect(match.captureIndices).toEqual([{index: 0, start: 2, end: 3, length: 1}]) 93 | 94 | match = scanner.findNextMatchSync(`X${String.fromCharCode(0xdfff)}X`, 2) 95 | expect(match.captureIndices).toEqual([{index: 0, start: 2, end: 3, length: 1}]) 96 | 97 | // These are actually valid, just testing the min & max 98 | match = scanner.findNextMatchSync(`X${String.fromCharCode(0xd800)}${String.fromCharCode(0xdc00)}X`, 2) 99 | expect(match.captureIndices).toEqual([{index: 0, start: 3, end: 4, length: 1}]) 100 | 101 | match = scanner.findNextMatchSync(`X${String.fromCharCode(0xdbff)}${String.fromCharCode(0xdfff)}X`, 2) 102 | expect(match.captureIndices).toEqual([{index: 0, start: 3, end: 4, length: 1}]) 103 | })) 104 | 105 | describe('when the start offset is out of bounds', () => 106 | it('it gets clamped', () => { 107 | let scanner = new OnigScanner(['X']) 108 | let match = scanner.findNextMatchSync('X💻X', -1000) 109 | expect(match.captureIndices).toEqual([{index: 0, start: 0, end: 1, length: 1}]) 110 | 111 | match = scanner.findNextMatchSync('X💻X', 1000) 112 | expect(match).toEqual(null) 113 | }) 114 | ) 115 | 116 | describe('::findNextMatch', () => { 117 | let matchCallback 118 | 119 | beforeEach(() => matchCallback = jasmine.createSpy('matchCallback')) 120 | 121 | it('returns the index of the matching pattern', () => { 122 | let scanner = new OnigScanner(['a', 'b', 'c']) 123 | scanner.findNextMatch('x', 0, matchCallback) 124 | 125 | waitsFor(() => matchCallback.callCount === 1) 126 | 127 | runs(() => { 128 | expect(matchCallback.argsForCall[0][0]).toBeNull() 129 | expect(matchCallback.argsForCall[0][1]).toBeNull() 130 | scanner.findNextMatch('xxaxxbxxc', 0, matchCallback) 131 | }) 132 | 133 | waitsFor(() => matchCallback.callCount === 2) 134 | 135 | runs(() => { 136 | expect(matchCallback.argsForCall[1][0]).toBeNull() 137 | expect(matchCallback.argsForCall[1][1].index).toBe(0) 138 | scanner.findNextMatch('xxaxxbxxc', 4, matchCallback) 139 | }) 140 | 141 | waitsFor(() => matchCallback.callCount === 3) 142 | 143 | runs(() => { 144 | expect(matchCallback.argsForCall[2][0]).toBeNull() 145 | expect(matchCallback.argsForCall[2][1].index).toBe(1) 146 | scanner.findNextMatch('xxaxxbxxc', 7, matchCallback) 147 | }) 148 | 149 | waitsFor(() => matchCallback.callCount === 4) 150 | 151 | runs(() => { 152 | expect(matchCallback.argsForCall[3][0]).toBeNull() 153 | expect(matchCallback.argsForCall[3][1].index).toBe(2) 154 | scanner.findNextMatch('xxaxxbxxc', 9, matchCallback) 155 | }) 156 | 157 | waitsFor(() => matchCallback.callCount === 5) 158 | 159 | runs(() => { 160 | expect(matchCallback.argsForCall[4][0]).toBeNull() 161 | expect(matchCallback.argsForCall[4][1]).toBeNull() 162 | }) 163 | }) 164 | 165 | it('includes the scanner with the results', () => { 166 | let scanner = new OnigScanner(['a']) 167 | scanner.findNextMatch('a', 0, matchCallback) 168 | 169 | waitsFor(() => matchCallback.callCount === 1) 170 | 171 | runs(() => { 172 | expect(matchCallback.argsForCall[0][0]).toBeNull() 173 | expect(matchCallback.argsForCall[0][1].scanner).toBe(scanner) 174 | }) 175 | }) 176 | 177 | describe('when the string searched contains unicode characters', () => 178 | it('returns the correct matching pattern', () => { 179 | let scanner = new OnigScanner(['1', '2']) 180 | scanner.findNextMatch('ab…cde21', 5, matchCallback) 181 | 182 | waitsFor(() => matchCallback.callCount === 1) 183 | 184 | runs(() => { 185 | expect(matchCallback.argsForCall[0][0]).toBeNull() 186 | expect(matchCallback.argsForCall[0][1].index).toBe(1) 187 | }) 188 | }) 189 | ) 190 | 191 | describe('when searching with start index', () => 192 | it('returns correct results for indexes > 255', () => { 193 | let scanner = new OnigScanner(['88']) 194 | let content = Array(300).join().split(',').map((v, i) => String(i)).join(' ') // '0 1 2 3 4 ...298 299' 195 | 196 | let match = scanner.findNextMatchSync(content, 0) 197 | expect(!!match).toBe(true) 198 | expect(match.captureIndices[0].start).toBe(254) 199 | 200 | match = scanner.findNextMatchSync(content, 260) 201 | expect(!!match).toBe(true) 202 | expect(match.captureIndices[0].start).toBe(643) 203 | 204 | match = scanner.findNextMatchSync(content, 650) 205 | expect(!!match).toBe(true) 206 | expect(match.captureIndices[0].start).toBe(1043) 207 | 208 | match = scanner.findNextMatchSync(content, 1050) 209 | expect(!!match).toBe(false) 210 | 211 | }) 212 | ) 213 | }) 214 | }) 215 | -------------------------------------------------------------------------------- /spec/onig-string-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const OnigString = require('..').OnigString 4 | 5 | describe('OnigString', () => { 6 | it('has a length property', () => { 7 | expect(new OnigString('abc').length).toBe(3) 8 | }) 9 | 10 | it('can be converted back into a string', () => { 11 | expect(new OnigString('abc').toString()).toBe('abc') 12 | }) 13 | 14 | it('can retrieve substrings (for conveniently inspecting captured text)', () => { 15 | const string = 'abcdef' 16 | const onigString = new OnigString(string) 17 | expect(onigString.substring(2, 3)).toBe(string.substring(2, 3)) 18 | expect(onigString.substring(2)).toBe(string.substring(2)) 19 | expect(onigString.substring()).toBe(string.substring()) 20 | expect(onigString.substring(-1)).toBe(string.substring(-1)) 21 | expect(onigString.substring(-1, -2)).toBe(string.substring(-1, -2)) 22 | 23 | onigString.substring({}) 24 | onigString.substring(null, undefined) 25 | }) 26 | 27 | it('handles invalid arguments', () => { 28 | expect(() => new OnigString(undefined)).toThrow('Argument must be a string') 29 | }) 30 | 31 | it('handles encoding', () => { 32 | let string = new OnigString('Wörld'); 33 | expect(Array.from(string.utf8Bytes)).toEqual([0x57, 0xc3, 0xb6, 0x72, 0x6c, 0x64, 0x00]); 34 | expect(string.convertUtf16OffsetToUtf8(0)).toEqual(0); 35 | expect(string.convertUtf16OffsetToUtf8(1)).toEqual(1); 36 | expect(string.convertUtf16OffsetToUtf8(2)).toEqual(3); 37 | expect(string.convertUtf16OffsetToUtf8(3)).toEqual(4); 38 | expect(string.convertUtf8OffsetToUtf16(0)).toEqual(0); 39 | expect(string.convertUtf8OffsetToUtf16(1)).toEqual(1); 40 | expect(string.convertUtf8OffsetToUtf16(2)).toEqual(1); 41 | expect(string.convertUtf8OffsetToUtf16(3)).toEqual(2); 42 | expect(string.convertUtf8OffsetToUtf16(4)).toEqual(3); 43 | }) 44 | 45 | it('mapping 2/3/4 byte UTF-8 encoding', () => { 46 | let string = new OnigString('123$¢€𐍈123'); 47 | expect(Array.from(string.utf8Bytes)).toEqual( 48 | [0x31 /*1*/, 0x32 /*2*/, 0x33 /*3*/, 0x24 /*$*/, 0xc2 /*¢*/, 0xa2, 0xe2 /*€*/, 0x82, 0xac, 0xf0 /*𐍈*/, 0x90, 0x8d, 0x88, 0x31 /*1*/, 0x32 /*2*/, 0x33 /*3*/, 0x00] 49 | ); 50 | expect(string.convertUtf16OffsetToUtf8(0)).toEqual(0); 51 | expect(string.convertUtf16OffsetToUtf8(1)).toEqual(1); 52 | expect(string.convertUtf16OffsetToUtf8(2)).toEqual(2); 53 | expect(string.convertUtf16OffsetToUtf8(3)).toEqual(3); 54 | expect(string.convertUtf16OffsetToUtf8(4)).toEqual(4); 55 | expect(string.convertUtf16OffsetToUtf8(5)).toEqual(6); 56 | expect(string.convertUtf16OffsetToUtf8(6)).toEqual(9); 57 | expect(string.convertUtf16OffsetToUtf8(7)).toEqual(9); 58 | expect(string.convertUtf16OffsetToUtf8(8)).toEqual(13); 59 | expect(string.convertUtf16OffsetToUtf8(9)).toEqual(14); 60 | expect(string.convertUtf16OffsetToUtf8(10)).toEqual(15); 61 | 62 | expect(string.convertUtf8OffsetToUtf16(0)).toEqual(0); 63 | expect(string.convertUtf8OffsetToUtf16(1)).toEqual(1); 64 | expect(string.convertUtf8OffsetToUtf16(2)).toEqual(2); 65 | expect(string.convertUtf8OffsetToUtf16(3)).toEqual(3); 66 | expect(string.convertUtf8OffsetToUtf16(4)).toEqual(4); 67 | expect(string.convertUtf8OffsetToUtf16(5)).toEqual(4); 68 | expect(string.convertUtf8OffsetToUtf16(6)).toEqual(5); 69 | expect(string.convertUtf8OffsetToUtf16(7)).toEqual(5); 70 | expect(string.convertUtf8OffsetToUtf16(8)).toEqual(5); 71 | expect(string.convertUtf8OffsetToUtf16(9)).toEqual(6); 72 | expect(string.convertUtf8OffsetToUtf16(10)).toEqual(6); 73 | expect(string.convertUtf8OffsetToUtf16(11)).toEqual(6); 74 | expect(string.convertUtf8OffsetToUtf16(12)).toEqual(6); 75 | expect(string.convertUtf8OffsetToUtf16(13)).toEqual(8); 76 | expect(string.convertUtf8OffsetToUtf16(14)).toEqual(9); 77 | expect(string.convertUtf8OffsetToUtf16(15)).toEqual(10); 78 | }) 79 | 80 | it('mapping UTF-16 surrogate pairs ', () => { 81 | let string = new OnigString('1𩸽𩹀'); 82 | expect(Array.from(string.utf8Bytes)).toEqual( 83 | [0x31, 0xf0, 0xa9, 0xb8, 0xbd, 0xf0, 0xa9, 0xb9, 0x80, 0x0] 84 | ); 85 | expect(string.convertUtf16OffsetToUtf8(0)).toEqual(0); 86 | expect(string.convertUtf16OffsetToUtf8(1)).toEqual(1); 87 | expect(string.convertUtf16OffsetToUtf8(2)).toEqual(1); 88 | expect(string.convertUtf16OffsetToUtf8(3)).toEqual(5); 89 | expect(string.convertUtf16OffsetToUtf8(4)).toEqual(5); 90 | 91 | expect(string.convertUtf8OffsetToUtf16(0)).toEqual(0); 92 | expect(string.convertUtf8OffsetToUtf16(1)).toEqual(1); 93 | expect(string.convertUtf8OffsetToUtf16(2)).toEqual(1); 94 | expect(string.convertUtf8OffsetToUtf16(3)).toEqual(1); 95 | expect(string.convertUtf8OffsetToUtf16(4)).toEqual(1); 96 | expect(string.convertUtf8OffsetToUtf16(5)).toEqual(3); 97 | expect(string.convertUtf8OffsetToUtf16(6)).toEqual(3); 98 | expect(string.convertUtf8OffsetToUtf16(7)).toEqual(3); 99 | expect(string.convertUtf8OffsetToUtf16(8)).toEqual(3); 100 | 101 | }) 102 | 103 | }) 104 | -------------------------------------------------------------------------------- /spec/test-scan.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const OnigString = require('..').OnigString 4 | const OnigScanner = require('..').OnigScanner 5 | 6 | describe('Scanner', () => { 7 | it('does not throw on PHP regexp from issue #17', () => { 8 | const scanner = new OnigScanner(["(?i)^\\s*(trait)\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)"]); 9 | const res = scanner.findNextMatchSync(new OnigString("trait test {\n"), 0); 10 | expect(res.captureIndices[1].start).toBe(0) 11 | }) 12 | }); -------------------------------------------------------------------------------- /src/OnigRegExp.ts: -------------------------------------------------------------------------------- 1 | import OnigScanner, { IOnigCaptureIndex } from './OnigScanner' 2 | import OnigString from './OnigString' 3 | 4 | export interface IOnigSearchResult extends IOnigCaptureIndex { 5 | match: string 6 | } 7 | 8 | class OnigRegExp { 9 | private source: string 10 | private scanner: OnigScanner 11 | /** 12 | * Create a new regex with the given pattern 13 | * @param source A string pattern 14 | */ 15 | constructor(source: string) { 16 | this.source = source 17 | 18 | try { 19 | this.scanner = new OnigScanner([this.source]) 20 | } catch (error) { 21 | // doesn't make much sense, but this to pass atom/node-oniguruam tests 22 | } 23 | } 24 | 25 | /** 26 | * Synchronously search the string for a match starting at the given position 27 | * @param string The string to search 28 | * @param startPosition The optional position to start the search at, defaults to `0` 29 | */ 30 | public searchSync(string: string | OnigString, startPosition?: number): IOnigSearchResult[] { 31 | let match 32 | if (startPosition == null) { 33 | startPosition = 0 34 | } 35 | match = this.scanner.findNextMatchSync(string, startPosition) 36 | return this.captureIndicesForMatch(string, match) 37 | } 38 | 39 | /** 40 | * Search the string for a match starting at the given position 41 | * @param string The string to search 42 | * @param startPosition The optional position to start the search at, defaults to `0` 43 | * @param callback The `(error, match)` function to call when done, match will be null if no matches were found. match will be an array of objects for each matched group on a successful search 44 | */ 45 | public search(string: string | OnigString, startPosition?: number, callback?: (error: any, match?: IOnigSearchResult[]) => void) { 46 | if (startPosition == null) { 47 | startPosition = 0 48 | } 49 | if (typeof startPosition === 'function') { 50 | callback = startPosition 51 | startPosition = 0 52 | } 53 | try { 54 | const ret = this.searchSync(string, startPosition) 55 | callback(null, ret) 56 | } catch (error) { 57 | callback(error) 58 | } 59 | } 60 | 61 | /** 62 | * Synchronously test if this regular expression matches the given string 63 | * @param string The string to test against 64 | */ 65 | public testSync(string: string | OnigString): boolean { 66 | if ((typeof this.source === 'boolean' || typeof string === 'boolean')) { 67 | return this.source === string 68 | } 69 | return this.searchSync(string) != null 70 | } 71 | 72 | /** 73 | * Test if this regular expression matches the given string 74 | * @param string The string to test against 75 | * @param callback The (error, matches) function to call when done, matches will be true if at least one match is found, false otherwise 76 | */ 77 | public test(string: string | OnigString, callback?: (error: any, matches?: boolean) => void) { 78 | if (typeof callback !== 'function') { 79 | callback = () => { } 80 | } 81 | try { 82 | callback(null, this.testSync(string)) 83 | } catch (error) { 84 | callback(error) 85 | } 86 | } 87 | 88 | private captureIndicesForMatch(string: string | OnigString, match) { 89 | if (match != null) { 90 | const { captureIndices } = match 91 | let capture 92 | string = this.scanner.convertToString(string) 93 | for (let i = 0; i < captureIndices.length; i++) { 94 | capture = captureIndices[i] 95 | capture.match = (string as string).slice(capture.start, capture.end) 96 | } 97 | return captureIndices 98 | } else { 99 | return null 100 | } 101 | } 102 | } 103 | 104 | export default OnigRegExp 105 | -------------------------------------------------------------------------------- /src/OnigScanner.ts: -------------------------------------------------------------------------------- 1 | import * as LRUCache from 'lru-cache' 2 | import { onigasmH } from './onigasmH' 3 | import OnigString from './OnigString' 4 | 5 | /** 6 | * Every instance of OnigScanner internally calls native libonig API 7 | * Since (at the moment) transferring complex objects between C runtime and JS runtime is not easy, 8 | * pointers are used to tap into their runtimes to read values (for example result of regex match) 9 | */ 10 | interface INativeOnigHInfo { 11 | /** 12 | * regex_t* is used by libonig to match string against an expression 13 | * this is the output of compiling raw string pattern to libonig's internal representation 14 | */ 15 | regexTPtrs: Uint8Array | null 16 | } 17 | 18 | export interface IOnigCaptureIndex { 19 | index: number 20 | start: number 21 | end: number 22 | length: number 23 | } 24 | 25 | export interface IOnigMatch { 26 | index: number 27 | captureIndices: IOnigCaptureIndex[] 28 | scanner: OnigScanner 29 | } 30 | 31 | /** 32 | * Allocates space on the heap and copies the string bytes on to it 33 | * @param str 34 | * @returns pointer to the first byte's address on heap 35 | */ 36 | function mallocAndWriteString(str: OnigString): number { 37 | const ptr = onigasmH._malloc(str.utf8Bytes.length) 38 | onigasmH.HEAPU8.set(str.utf8Bytes, ptr) 39 | return ptr 40 | } 41 | 42 | function convertUTF8BytesFromPtrToString(ptr: number): string { 43 | const chars = [] 44 | let i = 0 45 | while (onigasmH.HEAPU8[ptr] !== 0x00) { 46 | chars[i++] = onigasmH.HEAPU8[ptr++] 47 | } 48 | return chars.join() 49 | } 50 | 51 | const cache = new LRUCache({ 52 | dispose: (scanner: OnigScanner, info: INativeOnigHInfo) => { 53 | const regexTPtrsPtr = onigasmH._malloc(info.regexTPtrs.length) 54 | onigasmH.HEAPU8.set(info.regexTPtrs, regexTPtrsPtr) 55 | const status = onigasmH._disposeCompiledPatterns(regexTPtrsPtr, scanner.patterns.length) 56 | if (status !== 0) { 57 | const errMessage = convertUTF8BytesFromPtrToString(onigasmH._getLastError()) 58 | throw new Error(errMessage) 59 | } 60 | onigasmH._free(regexTPtrsPtr) 61 | }, 62 | max: 1000, 63 | }) 64 | 65 | export class OnigScanner { 66 | private sources: string[] 67 | /** 68 | * Create a new scanner with the given patterns 69 | * @param patterns An array of string patterns 70 | */ 71 | constructor(patterns: string[]) { 72 | if (onigasmH === null) { 73 | throw new Error(`Onigasm has not been initialized, call loadWASM from 'onigasm' exports before using any other API`) 74 | } 75 | for (let i = 0; i < patterns.length; i++) { 76 | const pattern = patterns[i] 77 | if (typeof pattern !== 'string') { 78 | throw new TypeError(`First parameter to OnigScanner constructor must be array of (pattern) strings`) 79 | } 80 | } 81 | this.sources = patterns.slice() 82 | } 83 | 84 | public get patterns() { 85 | return this.sources.slice() 86 | } 87 | 88 | /** 89 | * Find the next match from a given position 90 | * @param string The string to search 91 | * @param startPosition The optional position to start at, defaults to 0 92 | * @param callback The (error, match) function to call when done, match will null when there is no match 93 | */ 94 | public findNextMatch(string: string | OnigString, startPosition: number, callback: (err, match?: IOnigMatch) => void) { 95 | if (startPosition == null) { startPosition = 0 } 96 | if (typeof startPosition === 'function') { 97 | callback = startPosition 98 | startPosition = 0 99 | } 100 | 101 | try { 102 | const match = this.findNextMatchSync(string, startPosition) 103 | callback(null, match) 104 | } catch (error) { 105 | callback(error) 106 | } 107 | } 108 | 109 | /** 110 | * Find the next match from a given position 111 | * @param string The string to search 112 | * @param startPosition The optional position to start at, defaults to 0 113 | */ 114 | public findNextMatchSync(string: string | OnigString, startPosition: number): IOnigMatch { 115 | if (startPosition == null) { startPosition = 0 } 116 | startPosition = this.convertToNumber(startPosition) 117 | 118 | let onigNativeInfo = cache.get(this) 119 | let status = 0 120 | if (!onigNativeInfo) { 121 | const regexTAddrRecieverPtr = onigasmH._malloc(4) 122 | const regexTPtrs = [] 123 | for (let i = 0; i < this.sources.length; i++) { 124 | const pattern = this.sources[i] 125 | const patternStrPtr = mallocAndWriteString(new OnigString(pattern)) 126 | status = onigasmH._compilePattern(patternStrPtr, regexTAddrRecieverPtr) 127 | if (status !== 0) { 128 | const errMessage = convertUTF8BytesFromPtrToString(onigasmH._getLastError()) 129 | throw new Error(errMessage) 130 | } 131 | const regexTAddress = onigasmH.HEAP32[regexTAddrRecieverPtr / 4] 132 | regexTPtrs.push(regexTAddress) 133 | onigasmH._free(patternStrPtr) 134 | } 135 | onigNativeInfo = { 136 | regexTPtrs: new Uint8Array(Uint32Array.from(regexTPtrs).buffer), 137 | } 138 | onigasmH._free(regexTAddrRecieverPtr) 139 | cache.set(this, onigNativeInfo) 140 | } 141 | 142 | const onigString = string instanceof OnigString ? string : new OnigString(this.convertToString(string)) 143 | const strPtr = mallocAndWriteString(onigString) 144 | const resultInfoReceiverPtr = onigasmH._malloc(8) 145 | const regexTPtrsPtr = onigasmH._malloc(onigNativeInfo.regexTPtrs.length) 146 | onigasmH.HEAPU8.set(onigNativeInfo.regexTPtrs, regexTPtrsPtr) 147 | 148 | status = onigasmH._findBestMatch( 149 | // regex_t **patterns 150 | regexTPtrsPtr, 151 | // int patternCount 152 | this.sources.length, 153 | // UChar *utf8String 154 | strPtr, 155 | // int strLen 156 | onigString.utf8Bytes.length - 1, 157 | // int startOffset 158 | onigString.convertUtf16OffsetToUtf8(startPosition), 159 | // int *resultInfo 160 | resultInfoReceiverPtr, 161 | ) 162 | 163 | if (status !== 0) { 164 | const errMessage = convertUTF8BytesFromPtrToString(onigasmH._getLastError()) 165 | throw new Error(errMessage) 166 | } 167 | const [ 168 | // The index of pattern which matched the string at least offset from 0 (start) 169 | bestPatternIdx, 170 | 171 | // Begin address of capture info encoded as pairs 172 | // like [start, end, start, end, start, end, ...] 173 | // - first start-end pair is entire match (index 0 and 1) 174 | // - subsequent pairs are capture groups (2, 3 = first capture group, 4, 5 = second capture group and so on) 175 | encodedResultBeginAddress, 176 | 177 | // Length of the [start, end, ...] sequence so we know how much memory to read (will always be 0 or multiple of 2) 178 | encodedResultLength, 179 | ] = new Uint32Array(onigasmH.HEAPU32.buffer, resultInfoReceiverPtr, 3) 180 | 181 | onigasmH._free(strPtr) 182 | onigasmH._free(resultInfoReceiverPtr) 183 | onigasmH._free(regexTPtrsPtr) 184 | 185 | if (encodedResultLength > 0) { 186 | const encodedResult = new Uint32Array(onigasmH.HEAPU32.buffer, encodedResultBeginAddress, encodedResultLength) 187 | const captureIndices = [] 188 | let i = 0 189 | let captureIdx = 0 190 | while (i < encodedResultLength) { 191 | const index = captureIdx++ 192 | let start = encodedResult[i++] 193 | let end = encodedResult[i++] 194 | if (onigString.hasMultiByteCharacters) { 195 | start = onigString.convertUtf8OffsetToUtf16(start) 196 | end = onigString.convertUtf8OffsetToUtf16(end) 197 | } 198 | captureIndices.push({ 199 | end, 200 | index, 201 | length: end - start, 202 | start, 203 | }) 204 | } 205 | onigasmH._free(encodedResultBeginAddress) 206 | return { 207 | captureIndices, 208 | index: bestPatternIdx, 209 | scanner: this, 210 | } 211 | } 212 | return null 213 | } 214 | 215 | public convertToString(value) { 216 | if (value === undefined) { return 'undefined' } 217 | if (value === null) { return 'null' } 218 | if (value instanceof OnigString) { return value.content } 219 | return value.toString() 220 | } 221 | 222 | public convertToNumber(value) { 223 | value = parseInt(value, 10) 224 | if (!isFinite(value)) { value = 0 } 225 | value = Math.max(value, 0) 226 | return value 227 | } 228 | } 229 | 230 | export default OnigScanner 231 | -------------------------------------------------------------------------------- /src/OnigString.ts: -------------------------------------------------------------------------------- 1 | 2 | type UintArray = Uint8Array | Uint16Array | Uint32Array 3 | 4 | class OnigString { 5 | private source: string 6 | private _utf8Bytes: Uint8Array | null 7 | 8 | /** 9 | * utf16-offset where the mapping table starts. Before that index: utf16-index === utf8-index 10 | */ 11 | private _mappingTableStartOffset: number 12 | /** 13 | * utf-16 to utf-8 mapping table for all uft-8 indexes starting at `_mappingTableStartOffset`. utf8-index are always starting at 0. 14 | * `null` if there are no multibyte characters in the utf8 string and all utf-8 indexes are matching the utf-16 indexes. 15 | * Example: _mappingTableStartOffset === 10, _utf16OffsetToUtf8 = [0, 3, 6] -> _utf8Indexes[10] = 10, _utf8Indexes[11] = 13 16 | */ 17 | private _utf8Indexes: UintArray | null 18 | 19 | constructor(content: string) { 20 | if (typeof content !== 'string') { 21 | throw new TypeError('Argument must be a string') 22 | } 23 | this.source = content 24 | this._utf8Bytes = null 25 | this._utf8Indexes = null 26 | 27 | } 28 | 29 | public get utf8Bytes(): Uint8Array { 30 | if (!this._utf8Bytes) { 31 | this.encode() 32 | } 33 | return this._utf8Bytes 34 | } 35 | 36 | /** 37 | * Returns `null` if all utf8 offsets match utf-16 offset (content has no multi byte characters) 38 | */ 39 | private get utf8Indexes(): UintArray { 40 | if (!this._utf8Bytes) { 41 | this.encode() 42 | } 43 | return this._utf8Indexes 44 | } 45 | 46 | public get content(): string { 47 | return this.source 48 | } 49 | 50 | public get length(): number { 51 | return this.source.length 52 | } 53 | 54 | public substring = (start, end) => { 55 | return this.source.substring(start, end) 56 | } 57 | 58 | public toString = (start, end) => { 59 | return this.source 60 | } 61 | 62 | public get hasMultiByteCharacters() { 63 | return this.utf8Indexes !== null 64 | } 65 | 66 | public convertUtf8OffsetToUtf16(utf8Offset: number): number { 67 | if (utf8Offset < 0) { 68 | return 0 69 | } 70 | const utf8Array = this._utf8Bytes 71 | if (utf8Offset >= utf8Array.length - 1) { 72 | return this.source.length 73 | } 74 | 75 | const utf8OffsetMap = this.utf8Indexes 76 | if (utf8OffsetMap && utf8Offset >= this._mappingTableStartOffset) { 77 | return findFirstInSorted(utf8OffsetMap, utf8Offset - this._mappingTableStartOffset) + this._mappingTableStartOffset 78 | } 79 | return utf8Offset 80 | } 81 | 82 | public convertUtf16OffsetToUtf8(utf16Offset: number): number { 83 | if (utf16Offset < 0) { 84 | return 0 85 | } 86 | const utf8Array = this._utf8Bytes 87 | if (utf16Offset >= this.source.length) { 88 | return utf8Array.length - 1 89 | } 90 | 91 | const utf8OffsetMap = this.utf8Indexes 92 | if (utf8OffsetMap && utf16Offset >= this._mappingTableStartOffset) { 93 | return utf8OffsetMap[utf16Offset - this._mappingTableStartOffset] + this._mappingTableStartOffset 94 | } 95 | return utf16Offset 96 | } 97 | 98 | private encode(): void { 99 | const str = this.source 100 | const n = str.length 101 | let utf16OffsetToUtf8: UintArray 102 | let utf8Offset = 0 103 | let mappingTableStartOffset = 0 104 | function createOffsetTable(startOffset: number) { 105 | const maxUtf8Len = (n - startOffset) * 3 106 | if (maxUtf8Len <= 0xff) { 107 | utf16OffsetToUtf8 = new Uint8Array(n - startOffset) 108 | } else if (maxUtf8Len <= 0xffff) { 109 | utf16OffsetToUtf8 = new Uint16Array(n - startOffset) 110 | } else { 111 | utf16OffsetToUtf8 = new Uint32Array(n - startOffset) 112 | } 113 | mappingTableStartOffset = startOffset 114 | utf16OffsetToUtf8[utf8Offset++] = 0 115 | } 116 | 117 | const u8view = new Uint8Array((n * 3) /* alloc max now, trim later*/ + 1 /** null termination character */) 118 | 119 | let ptrHead = 0 120 | let i = 0 121 | // for some reason, v8 is faster with str.length than using a variable (might be illusion) 122 | while (i < str.length) { 123 | let codepoint 124 | const c = str.charCodeAt(i) 125 | 126 | if (utf16OffsetToUtf8) { 127 | utf16OffsetToUtf8[utf8Offset++] = ptrHead - mappingTableStartOffset 128 | } 129 | 130 | if (c < 0xD800 || c > 0xDFFF) { 131 | codepoint = c 132 | } 133 | 134 | else if (c >= 0xDC00) { 135 | codepoint = 0xFFFD 136 | } 137 | 138 | else { 139 | if (i === n - 1) { 140 | codepoint = 0xFFFD 141 | } 142 | else { 143 | const d = str.charCodeAt(i + 1) 144 | 145 | if (0xDC00 <= d && d <= 0xDFFF) { 146 | if (!utf16OffsetToUtf8) { 147 | createOffsetTable(i) 148 | } 149 | 150 | const a = c & 0x3FF 151 | 152 | const b = d & 0x3FF 153 | 154 | codepoint = 0x10000 + (a << 10) + b 155 | i += 1 156 | 157 | utf16OffsetToUtf8[utf8Offset++] = ptrHead - mappingTableStartOffset 158 | } 159 | 160 | else { 161 | codepoint = 0xFFFD 162 | } 163 | } 164 | } 165 | 166 | let bytesRequiredToEncode: number 167 | let offset: number 168 | 169 | if (codepoint <= 0x7F) { 170 | bytesRequiredToEncode = 1 171 | offset = 0 172 | } else if (codepoint <= 0x07FF) { 173 | bytesRequiredToEncode = 2 174 | offset = 0xC0 175 | } else if (codepoint <= 0xFFFF) { 176 | bytesRequiredToEncode = 3 177 | offset = 0xE0 178 | } else { 179 | bytesRequiredToEncode = 4 180 | offset = 0xF0 181 | } 182 | 183 | if (bytesRequiredToEncode === 1) { 184 | u8view[ptrHead++] = codepoint 185 | } 186 | else { 187 | if (!utf16OffsetToUtf8) { 188 | createOffsetTable(ptrHead) 189 | } 190 | u8view[ptrHead++] = (codepoint >> (6 * (--bytesRequiredToEncode))) + offset 191 | 192 | while (bytesRequiredToEncode > 0) { 193 | 194 | const temp = codepoint >> (6 * (bytesRequiredToEncode - 1)) 195 | 196 | u8view[ptrHead++] = (0x80 | (temp & 0x3F)) 197 | 198 | bytesRequiredToEncode -= 1 199 | } 200 | } 201 | 202 | i += 1 203 | } 204 | 205 | const utf8 = u8view.slice(0, ptrHead + 1) 206 | utf8[ptrHead] = 0x00 207 | 208 | this._utf8Bytes = utf8 209 | if (utf16OffsetToUtf8) { // set if UTF-16 surrogate chars or multi-byte characters found 210 | this._utf8Indexes = utf16OffsetToUtf8 211 | this._mappingTableStartOffset = mappingTableStartOffset 212 | } 213 | } 214 | } 215 | 216 | function findFirstInSorted(array: UintArray, i: number): number { 217 | let low = 0 218 | let high = array.length 219 | 220 | if (high === 0) { 221 | return 0 // no children 222 | } 223 | while (low < high) { 224 | const mid = Math.floor((low + high) / 2) 225 | if (array[mid] >= i) { 226 | high = mid 227 | } else { 228 | low = mid + 1 229 | } 230 | } 231 | 232 | // low is on the index of the first value >= i or array.length. Decrement low until we find array[low] <= i 233 | while (low > 0 && (low >= array.length || array[low] > i)) { 234 | low-- 235 | } 236 | // check whether we are on the second index of a utf-16 surrogate char. If so, go to the first index. 237 | if (low > 0 && array[low] === array[low - 1]) { 238 | low-- 239 | } 240 | 241 | return low 242 | 243 | } 244 | 245 | export default OnigString 246 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { loadWASM } from './onigasmH' 2 | import OnigRegExp, { IOnigSearchResult } from './OnigRegExp' 3 | import OnigScanner, { IOnigCaptureIndex } from './OnigScanner' 4 | import OnigString from './OnigString' 5 | 6 | export { loadWASM, OnigScanner, OnigRegExp, OnigString, IOnigCaptureIndex, IOnigSearchResult } 7 | -------------------------------------------------------------------------------- /src/onigasm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "oniguruma.h" 5 | #include 6 | 7 | extern "C" { 8 | 9 | int lastErrCode = 0; 10 | 11 | EMSCRIPTEN_KEEPALIVE 12 | char *getLastError() 13 | { 14 | static char s[ONIG_MAX_ERROR_MESSAGE_LEN]; 15 | onig_error_code_to_str((UChar *)s, lastErrCode); 16 | return s; 17 | } 18 | 19 | EMSCRIPTEN_KEEPALIVE 20 | int compilePattern(UChar *pattern, int *regexTPtr) 21 | { 22 | int r; 23 | regex_t *reg; 24 | OnigErrorInfo einfo; 25 | r = onig_new(®, pattern, pattern + strlen((char *)pattern), 26 | ONIG_OPTION_CAPTURE_GROUP, ONIG_ENCODING_UTF8, 27 | ONIG_SYNTAX_DEFAULT, &einfo); 28 | if (r != ONIG_NORMAL) 29 | { 30 | lastErrCode = r; 31 | return -1; 32 | } 33 | *regexTPtr = (int)reg; 34 | return 0; 35 | } 36 | 37 | EMSCRIPTEN_KEEPALIVE 38 | int disposeCompiledPatterns(regex_t **patterns, int patternCount) 39 | { 40 | for (int i = 0; i < patternCount; i++) 41 | { 42 | onig_free(patterns[i]); 43 | } 44 | return 0; 45 | } 46 | 47 | EMSCRIPTEN_KEEPALIVE 48 | int findBestMatch(regex_t **patterns, int patternCount, UChar *utf8String, int strLen, int startOffset, int *resultInfo) 49 | { 50 | int r; 51 | unsigned char *start, *range, *end; 52 | start = utf8String + startOffset; 53 | end = utf8String + strLen; 54 | range = end; 55 | OnigErrorInfo einfo; 56 | OnigRegion *bestRegion = NULL; 57 | int bestRegionIdx = 0; 58 | for (int i = 0; i < patternCount; i++) 59 | { 60 | OnigRegion *region; 61 | region = onig_region_new(); 62 | r = onig_search(patterns[i], utf8String, end, start, range, region, ONIG_OPTION_NONE); 63 | if (r >= 0) 64 | { 65 | if (region->num_regs > 0 && (bestRegion == NULL || region->beg[0] < bestRegion->beg[0])) 66 | { 67 | bestRegion = region; 68 | bestRegionIdx = i; 69 | continue; 70 | } 71 | } 72 | else if (r == ONIG_MISMATCH) 73 | { 74 | // TODO 75 | } 76 | else 77 | { /* error */ 78 | onig_region_free(region, 1); 79 | lastErrCode = r; 80 | return -1; 81 | } 82 | onig_region_free(region, 1); 83 | } 84 | 85 | if (bestRegion != NULL) 86 | { 87 | int resultLen = (bestRegion->num_regs) * 2; 88 | int *res = (int *)malloc(resultLen * sizeof(int)); 89 | int i = 0; 90 | int j = 0; 91 | 92 | while (i < bestRegion->num_regs) 93 | { 94 | res[j++] = bestRegion->beg[i]; 95 | res[j++] = bestRegion->end[i]; 96 | i++; 97 | } 98 | 99 | resultInfo[0] = bestRegionIdx; 100 | resultInfo[1] = (int)res; 101 | resultInfo[2] = resultLen; 102 | onig_region_free(bestRegion, 1); 103 | } 104 | else 105 | { 106 | resultInfo[0] = 0; 107 | resultInfo[1] = 0; 108 | resultInfo[2] = 0; 109 | } 110 | return 0; 111 | } 112 | } -------------------------------------------------------------------------------- /src/onigasmH.ts: -------------------------------------------------------------------------------- 1 | // Just to keep typescript quiet 2 | declare const require 3 | declare const WebAssembly 4 | 5 | const OnigasmModuleFactory = require('./onigasm.js' /** when TS is compiled to JS, this will mean `lib/onigasm.js` (emitted by `emcc`) */) 6 | 7 | /** 8 | * Handle to onigasm module (the JS glue code emitted by emscripten, that provides access to C/C++ runtime) 9 | * 10 | * Single handle shared among modules that decorate the C runtime to deliver `atom/node-oniguruma` API 11 | */ 12 | export let onigasmH 13 | 14 | async function initModule(bytes: ArrayBuffer) { 15 | return new Promise((resolve, reject) => { 16 | const { log, warn, error } = console 17 | OnigasmModuleFactory({ 18 | instantiateWasm(imports, successCallback) { 19 | WebAssembly.instantiate(bytes, imports) 20 | .then((output) => { 21 | successCallback(output.instance) 22 | }) 23 | .catch((e) => { 24 | throw e 25 | }) 26 | return {} 27 | }, 28 | }) 29 | .then(moduleH => { 30 | onigasmH = moduleH 31 | resolve() 32 | }) 33 | if (typeof print !== 'undefined') { 34 | // can be removed when https://github.com/emscripten-core/emscripten/issues/9829 is fixed. 35 | // tslint:disable-next-line:no-console 36 | console.log = log 37 | // tslint:disable-next-line:no-console 38 | console.error = error 39 | // tslint:disable-next-line:no-console 40 | console.warn = warn 41 | } 42 | }) 43 | } 44 | 45 | let isInitialized = false 46 | 47 | /** 48 | * Mount the .wasm file that will act as library's "backend" 49 | * @param data Path to .wasm file or it's ArrayBuffer 50 | */ 51 | export async function loadWASM(data: string | ArrayBuffer) { 52 | if (isInitialized) { 53 | throw new Error(`Onigasm#init has been called and was succesful, subsequent calls are not allowed once initialized`) 54 | } 55 | if (typeof data === 'string') { 56 | const arrayBuffer = await (await fetch(data)).arrayBuffer() 57 | await initModule(arrayBuffer) 58 | } else if (data instanceof ArrayBuffer) { 59 | await initModule(data) 60 | } else { 61 | throw new TypeError(`Expected a string (URL of .wasm file) or ArrayBuffer (.wasm file itself) as first parameter`) 62 | } 63 | 64 | isInitialized = true 65 | } 66 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | // test https://github.com/NeekSandhu/onigasm/issues/19 2 | print = (str) => { assert.fail('Should not use print for console.log') }; // define a global 'print' methods 3 | const origConsoleLog = console.log; 4 | 5 | const fs = require('fs') 6 | const path = require('path') 7 | const jasmine = require('jasmine-focused'); 8 | const assert = require('assert') 9 | const { 10 | loadWASM 11 | } = require('../lib'); 12 | 13 | const wasmBin = fs.readFileSync(path.join(__dirname, '../lib/onigasm.wasm')).buffer 14 | 15 | loadWASM(wasmBin).then(() => { 16 | 17 | assert.equal(console.log, origConsoleLog); // test https://github.com/NeekSandhu/onigasm/issues/19 18 | 19 | jasmine.executeSpecsInFolder({ 20 | specFolders: [path.join(__dirname, '../spec')] 21 | }) 22 | }) 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "commonjs", 5 | "sourceMap": true, 6 | "outDir": "lib", 7 | "declaration": true, 8 | "declarationDir": "lib/typings" 9 | } 10 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "jsRules": { }, 4 | "rules": { 5 | "semicolon": [true, "never"], 6 | "max-line-length": false, 7 | "arrow-parens": false, 8 | "quotemark": [true, "single"], 9 | "variable-name": false, 10 | "no-require-imports": false, 11 | "no-bitwise": false, 12 | "no-empty": false, 13 | "prefer-for-of": false, 14 | "no-var-requires": false, 15 | "one-line": false 16 | } 17 | } 18 | --------------------------------------------------------------------------------