├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── src ├── Brain.ts ├── Token.ts └── index.ts ├── test └── BrainSpec.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .idea 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BrainScript 2 | 3 | A [BrainF***](https://en.wikipedia.org/wiki/Brainfuck) (BF) interpreter and REPL, written in TypeScript. 4 | 5 | ## Installation 6 | 7 | Install from [npm](https://www.npmjs.com/package/brainscript) with 8 | 9 | `$ npm i brainscript` 10 | 11 | Or try it online at [npm.runkit.com](https://npm.runkit.com/brainscript) 12 | 13 | ```ts 14 | var lib = require("brainscript") 15 | 16 | lib.bf("++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.") 17 | ``` 18 | 19 | ## Use 20 | 21 | BrainScript provides a BF interpreter `bf` which can be used in interactive or batch mode, as well as a BF REPL `brain`. 22 | 23 | `bf` can be used to batch process BF code, returning any resulting output as a `string` 24 | 25 | ```ts 26 | const output: string = bf("++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.") 27 | 28 | console.log(output) // Hello World!\n 29 | ``` 30 | 31 | ...but it also provides basic interactive capabilities for programs which require user input 32 | 33 | ```ts 34 | // input.ts 35 | console.log(bf(",.")) 36 | ``` 37 | 38 | ```ts 39 | $ npx ts-node input.ts 40 | 41 | Please provide a single character for ',' input: 42 | ❓: ! 43 | 44 | ! 45 | ``` 46 | 47 | `brain` is an interactive REPL which accepts single- or multi-line programs as input: 48 | 49 | ```ts 50 | // brain.ts 51 | // ... imports, etc. ... 52 | brain() 53 | ``` 54 | 55 | ```ts 56 | $ npx ts-node brain.ts 57 | 58 | Enter single-line BF code below or 59 | type :paste to paste multiline code 60 | type :classic to toggle classic / default mode 61 | type :numin to toggle numeric input mode 62 | type :numout to toggle numeric output mode 63 | type :quit or enter -C to quit 64 | 65 | 🧠: ++++++>+++++++[-<[->>+>+<<<]>>[-<<+>>]<]>>. 66 | * 67 | 68 | 🧠: :paste 69 | 70 | Entering multiline input mode. 71 | Enter two blank lines in a row to interpret. 72 | ~~~~~~~~~~~~~~~ BEGIN INPUT ~~~~~~~~~~~~~~~ 73 | 74 | 75 | ++++ +++ 76 | +[>++++ ++[>+<-][ 77 | <]< -]> >++ +++ 78 | +.- --- --- --- 79 | --.+++++++ +++ 80 | +++ .++ 81 | +++ +.- 82 | --- -----.--. 83 | 84 | 85 | ~~~~~~~~~~~~~ INTERPRETING... ~~~~~~~~~~~~~ 86 | 87 | 6*7=42 88 | 89 | 🧠: 90 | ``` 91 | 92 | ## Customisation 93 | 94 | ### Custom Input Streams 95 | 96 | When input is required by the BF program, `bf` will prompt the user for single-character input (using the [`UTF32Char` encoding](https://www.npmjs.com/package/utf32char)): 97 | 98 | ```ts 99 | // example.ts 100 | // ... imports, etc. ... 101 | const io: string = bf(",.") 102 | console.log(io) 103 | ``` 104 | 105 | ```ts 106 | $ npx ts-node example.ts 107 | 108 | Please provide a single character for ',' input: 109 | ❓: 😃 110 | 111 | 😃 112 | ``` 113 | 114 | `bf` defaults to interactively querying `stdin`, but this can be customised by the user: 115 | 116 | ```ts 117 | // customInput.ts 118 | // ... imports, etc. ... 119 | function input(): UTF32Char { return UTF32Char.fromString("hi") } 120 | const memory: UInt32 = UInt32.fromNumber(1) 121 | 122 | const custom: string = bf(",.", false, false, false, memory, input) 123 | console.log(custom) 124 | ``` 125 | 126 | ```ts 127 | $ npx ts-node customInput.ts 128 | 129 | Please provide a single character for ',' input: 130 | hi 131 | ``` 132 | 133 | ### Flags 134 | 135 | `bf` provides a few boolean flags which affect how it interprets BF programs. These include: 136 | 137 | - `numin` - when `true`, treats all input as numeric, rather than as characters 138 | - `numout` - when `true`, outputs raw numeric data, rather than trying to convert them to characters 139 | - `classic` - sets maximum cell values to `255`; allows "wraparound" in both the cell values and the memory tape 140 | 141 | Using `bf`, these flags can be set in the function call (they are all `false` by default), but when running the interactive REPL `brain`, they must be toggled using the special REPL commands `:numin`, `:numout`, and `:classic`, respectively. 142 | 143 | `numin` and `numout`, in particular, can make BF programs much easier to write and use. 144 | 145 | By default (when `numin` is `false`), BF interprets all input as characters. So `63` is not the number `63`, but the character `6` (ASCII #54) followed by the character `3` (ASCII #51), which is interpreted as a 4-byte Unicode character with the higher bytes as `54` and lower bytes as `51`. (An [undefined character](https://unicode-table.com/en/search/?q=360033).) 146 | 147 | And the number `42`, when written to the terminal as output, is interpreted as ASCII #42, or the `*` character. 148 | 149 | These subtleties mean that programs which are written to perform basic arithmetic must be much more complex. 150 | 151 | To ease the pain a bit, the `numin` and `numout` flags allow input and output, respectively, to be interpreted as numeric data, rather than characters. This greatly simplifies calculation. Here is [the Wikipedia-prescribed method for addition](https://en.wikipedia.org/wiki/Brainfuck#Adding_two_values) which is fragile and relies on hard-coded values 152 | 153 | ```ts 154 | 🧠: ++>+++++[<+>-]++++++++[<++++++>-]<. 155 | 7 156 | 157 | 🧠: ,>,[<+>-]++++++++[<++++++>-]<. 158 | 159 | Please provide a single character for ',' input: 160 | ❓: 2 161 | 162 | 163 | Please provide a single character for ',' input: 164 | ❓: 5 165 | 166 | ``` 167 | 168 | Above, the input `2` is interpreted as the _character_ `2` (ASCII #50) and `5` is interpreted as the _character_ `5` (ASCII #53). Adding them should yield `103` or the ASCII character `g`, but something has gone wrong. Try debugging that. 169 | 170 | Instead, we can simply set `numin` and `numout` to true, and then provide any two 1 or 2-digit numbers to add to the following (much simpler) program: 171 | 172 | ```ts 173 | 🧠: ,>,[-<+>]<. 174 | 175 | Please provide a 1 or 2-digit number for ',' input: 176 | ❓: 2 177 | 178 | 179 | Please provide a 1 or 2-digit number for ',' input: 180 | ❓: 5 181 | 182 | 7 183 | 184 | 🧠: ,>,[-<+>]<. 185 | 186 | Please provide a 1 or 2-digit number for ',' input: 187 | ❓: 19 188 | 189 | 190 | Please provide a 1 or 2-digit number for ',' input: 191 | ❓: 42 192 | 193 | 61 194 | ``` 195 | 196 | We can even write a pretty simple multiplication program: 197 | 198 | ```ts 199 | 🧠: ,>,[-<[->>+>+<<<]>>[-<<+>>]<]>>. 200 | 201 | Please provide a 1 or 2-digit number for ',' input: 202 | ❓: 19 203 | 204 | 205 | Please provide a 1 or 2-digit number for ',' input: 206 | ❓: 34 207 | 208 | 646 209 | ``` 210 | 211 | `classic` is the last flag which can be toggled. There are two interpretation modes which `bf` and `brain` can run in. The default interpretation mode: 212 | 213 | - allows cells with values on the range `[0, 2**32)` 214 | - throws an error when the user tries to decrement a cell's value below `0` 215 | - throws an error when the user tries to increment a cell's value above `2**32 - 1` 216 | - throws an error when the user tries to move the memory pointer left when it's already on the cell at index `0` 217 | - throws an error when the user tries to move the memory pointer right when it's already on the rightmost cell 218 | 219 | The `classic` interpolation mode: 220 | 221 | - allows cells with values on the range `[0, 256)` 222 | - wraps around to `255` when the user decrements a cell with value `0` 223 | - wraps around to `0` when the user increments a cell with value `255` 224 | - wraps around to the rightmost cell when the memory pointer is on cell index `0` and the user tries to move it left 225 | - wraps around to the cell at index `0` when the memory pointer is already on the rightmost cell and the user tries to move it right 226 | 227 | Emoji and other characters beyond `0xFF` will only properly render in the default interpretation mode (`classic === false`), but some programs will only run in `classic` mode, for instance, [this code golfed "Hello World" from StackExchange](https://codegolf.stackexchange.com/a/68494/79936): 228 | 229 | ```ts 230 | 🧠: --<-<<+[+[<+>--->->->-<<<]>]<<--.<++++++.<<-..<<.<+.>>.>>.<<<.+++.>>.>>-.<<<+. 231 | 232 | --<-<<+[+[<+>- 233 | Error at ^ char index 0 234 | message: cell 0 is already at minimum allowable value, 0... try setting `classic` to `true` 235 | output: 236 | 237 | 238 | 🧠: :classic 239 | 240 | Changed interpretation mode to 'classic' 241 | 242 | 🧠: --<-<<+[+[<+>--->->->-<<<]>]<<--.<++++++.<<-..<<.<+.>>.>>.<<<.+++.>>.>>-.<<<+. 243 | Hello, World! 244 | 245 | 🧠: 246 | ``` 247 | 248 | ## Known Issues 249 | 250 | ANSI escape sequences (arrow keys, etc.) do not work properly in `brain`. This is being investigated. 251 | 252 | ## Contact 253 | 254 | Feel free to open an issue with any `bug fixes` or a PR with any `performance improvements`. 255 | 256 | Support me @ [Ko-fi](https://ko-fi.com/awwsmm)! 257 | 258 | Check out [my DEV.to blog](https://dev.to/awwsmm)! -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brainscript", 3 | "version": "5.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/chai": { 8 | "version": "4.2.11", 9 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz", 10 | "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==", 11 | "dev": true 12 | }, 13 | "@types/mocha": { 14 | "version": "7.0.2", 15 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", 16 | "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", 17 | "dev": true 18 | }, 19 | "@types/node": { 20 | "version": "14.0.5", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", 22 | "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==", 23 | "dev": true 24 | }, 25 | "ansi-colors": { 26 | "version": "3.2.3", 27 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", 28 | "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", 29 | "dev": true 30 | }, 31 | "ansi-regex": { 32 | "version": "3.0.0", 33 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 34 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 35 | "dev": true 36 | }, 37 | "ansi-styles": { 38 | "version": "3.2.1", 39 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 40 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 41 | "dev": true, 42 | "requires": { 43 | "color-convert": "^1.9.0" 44 | } 45 | }, 46 | "anymatch": { 47 | "version": "3.1.1", 48 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 49 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 50 | "dev": true, 51 | "requires": { 52 | "normalize-path": "^3.0.0", 53 | "picomatch": "^2.0.4" 54 | } 55 | }, 56 | "arg": { 57 | "version": "4.1.3", 58 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 59 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 60 | "dev": true 61 | }, 62 | "argparse": { 63 | "version": "1.0.10", 64 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 65 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 66 | "dev": true, 67 | "requires": { 68 | "sprintf-js": "~1.0.2" 69 | } 70 | }, 71 | "assertion-error": { 72 | "version": "1.1.0", 73 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 74 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 75 | "dev": true 76 | }, 77 | "balanced-match": { 78 | "version": "1.0.0", 79 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 80 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 81 | "dev": true 82 | }, 83 | "binary-extensions": { 84 | "version": "2.0.0", 85 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", 86 | "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", 87 | "dev": true 88 | }, 89 | "brace-expansion": { 90 | "version": "1.1.11", 91 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 92 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 93 | "dev": true, 94 | "requires": { 95 | "balanced-match": "^1.0.0", 96 | "concat-map": "0.0.1" 97 | } 98 | }, 99 | "braces": { 100 | "version": "3.0.2", 101 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 102 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 103 | "dev": true, 104 | "requires": { 105 | "fill-range": "^7.0.1" 106 | } 107 | }, 108 | "browser-stdout": { 109 | "version": "1.3.1", 110 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 111 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 112 | "dev": true 113 | }, 114 | "buffer-from": { 115 | "version": "1.1.1", 116 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 117 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 118 | "dev": true 119 | }, 120 | "camelcase": { 121 | "version": "5.3.1", 122 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 123 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 124 | "dev": true 125 | }, 126 | "chai": { 127 | "version": "4.2.0", 128 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", 129 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", 130 | "dev": true, 131 | "requires": { 132 | "assertion-error": "^1.1.0", 133 | "check-error": "^1.0.2", 134 | "deep-eql": "^3.0.1", 135 | "get-func-name": "^2.0.0", 136 | "pathval": "^1.1.0", 137 | "type-detect": "^4.0.5" 138 | } 139 | }, 140 | "chalk": { 141 | "version": "2.4.2", 142 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 143 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 144 | "dev": true, 145 | "requires": { 146 | "ansi-styles": "^3.2.1", 147 | "escape-string-regexp": "^1.0.5", 148 | "supports-color": "^5.3.0" 149 | }, 150 | "dependencies": { 151 | "supports-color": { 152 | "version": "5.5.0", 153 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 154 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 155 | "dev": true, 156 | "requires": { 157 | "has-flag": "^3.0.0" 158 | } 159 | } 160 | } 161 | }, 162 | "check-error": { 163 | "version": "1.0.2", 164 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 165 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 166 | "dev": true 167 | }, 168 | "chokidar": { 169 | "version": "3.3.0", 170 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", 171 | "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", 172 | "dev": true, 173 | "requires": { 174 | "anymatch": "~3.1.1", 175 | "braces": "~3.0.2", 176 | "fsevents": "~2.1.1", 177 | "glob-parent": "~5.1.0", 178 | "is-binary-path": "~2.1.0", 179 | "is-glob": "~4.0.1", 180 | "normalize-path": "~3.0.0", 181 | "readdirp": "~3.2.0" 182 | } 183 | }, 184 | "cliui": { 185 | "version": "5.0.0", 186 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", 187 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", 188 | "dev": true, 189 | "requires": { 190 | "string-width": "^3.1.0", 191 | "strip-ansi": "^5.2.0", 192 | "wrap-ansi": "^5.1.0" 193 | }, 194 | "dependencies": { 195 | "ansi-regex": { 196 | "version": "4.1.0", 197 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 198 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 199 | "dev": true 200 | }, 201 | "string-width": { 202 | "version": "3.1.0", 203 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 204 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 205 | "dev": true, 206 | "requires": { 207 | "emoji-regex": "^7.0.1", 208 | "is-fullwidth-code-point": "^2.0.0", 209 | "strip-ansi": "^5.1.0" 210 | } 211 | }, 212 | "strip-ansi": { 213 | "version": "5.2.0", 214 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 215 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 216 | "dev": true, 217 | "requires": { 218 | "ansi-regex": "^4.1.0" 219 | } 220 | } 221 | } 222 | }, 223 | "color-convert": { 224 | "version": "1.9.3", 225 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 226 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 227 | "dev": true, 228 | "requires": { 229 | "color-name": "1.1.3" 230 | } 231 | }, 232 | "color-name": { 233 | "version": "1.1.3", 234 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 235 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 236 | "dev": true 237 | }, 238 | "concat-map": { 239 | "version": "0.0.1", 240 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 241 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 242 | "dev": true 243 | }, 244 | "debug": { 245 | "version": "3.2.6", 246 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 247 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 248 | "dev": true, 249 | "requires": { 250 | "ms": "^2.1.1" 251 | } 252 | }, 253 | "decamelize": { 254 | "version": "1.2.0", 255 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 256 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 257 | "dev": true 258 | }, 259 | "deep-eql": { 260 | "version": "3.0.1", 261 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 262 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 263 | "dev": true, 264 | "requires": { 265 | "type-detect": "^4.0.0" 266 | } 267 | }, 268 | "define-properties": { 269 | "version": "1.1.3", 270 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 271 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 272 | "dev": true, 273 | "requires": { 274 | "object-keys": "^1.0.12" 275 | } 276 | }, 277 | "diff": { 278 | "version": "4.0.2", 279 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 280 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 281 | "dev": true 282 | }, 283 | "emoji-regex": { 284 | "version": "7.0.3", 285 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 286 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 287 | "dev": true 288 | }, 289 | "es-abstract": { 290 | "version": "1.17.5", 291 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", 292 | "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", 293 | "dev": true, 294 | "requires": { 295 | "es-to-primitive": "^1.2.1", 296 | "function-bind": "^1.1.1", 297 | "has": "^1.0.3", 298 | "has-symbols": "^1.0.1", 299 | "is-callable": "^1.1.5", 300 | "is-regex": "^1.0.5", 301 | "object-inspect": "^1.7.0", 302 | "object-keys": "^1.1.1", 303 | "object.assign": "^4.1.0", 304 | "string.prototype.trimleft": "^2.1.1", 305 | "string.prototype.trimright": "^2.1.1" 306 | } 307 | }, 308 | "es-to-primitive": { 309 | "version": "1.2.1", 310 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 311 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 312 | "dev": true, 313 | "requires": { 314 | "is-callable": "^1.1.4", 315 | "is-date-object": "^1.0.1", 316 | "is-symbol": "^1.0.2" 317 | } 318 | }, 319 | "escape-string-regexp": { 320 | "version": "1.0.5", 321 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 322 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 323 | "dev": true 324 | }, 325 | "esprima": { 326 | "version": "4.0.1", 327 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 328 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 329 | "dev": true 330 | }, 331 | "fast-check": { 332 | "version": "1.24.2", 333 | "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-1.24.2.tgz", 334 | "integrity": "sha512-ZL48cyZZLJnVsUj127Zi1mfFLM98yzw0LlSSH8CMeVmpL5RCfSRcZSZZ0kJWrRK4eOgNFnXXKNDbzuRb3Vsdhg==", 335 | "dev": true, 336 | "requires": { 337 | "pure-rand": "^2.0.0", 338 | "tslib": "^1.10.0" 339 | } 340 | }, 341 | "fill-range": { 342 | "version": "7.0.1", 343 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 344 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 345 | "dev": true, 346 | "requires": { 347 | "to-regex-range": "^5.0.1" 348 | } 349 | }, 350 | "find-up": { 351 | "version": "3.0.0", 352 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 353 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 354 | "dev": true, 355 | "requires": { 356 | "locate-path": "^3.0.0" 357 | } 358 | }, 359 | "flat": { 360 | "version": "4.1.0", 361 | "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", 362 | "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", 363 | "dev": true, 364 | "requires": { 365 | "is-buffer": "~2.0.3" 366 | } 367 | }, 368 | "fs.realpath": { 369 | "version": "1.0.0", 370 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 371 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 372 | "dev": true 373 | }, 374 | "fsevents": { 375 | "version": "2.1.3", 376 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", 377 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", 378 | "dev": true, 379 | "optional": true 380 | }, 381 | "function-bind": { 382 | "version": "1.1.1", 383 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 384 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 385 | "dev": true 386 | }, 387 | "get-caller-file": { 388 | "version": "2.0.5", 389 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 390 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 391 | "dev": true 392 | }, 393 | "get-func-name": { 394 | "version": "2.0.0", 395 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 396 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 397 | "dev": true 398 | }, 399 | "glob": { 400 | "version": "7.1.3", 401 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 402 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 403 | "dev": true, 404 | "requires": { 405 | "fs.realpath": "^1.0.0", 406 | "inflight": "^1.0.4", 407 | "inherits": "2", 408 | "minimatch": "^3.0.4", 409 | "once": "^1.3.0", 410 | "path-is-absolute": "^1.0.0" 411 | } 412 | }, 413 | "glob-parent": { 414 | "version": "5.1.1", 415 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 416 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 417 | "dev": true, 418 | "requires": { 419 | "is-glob": "^4.0.1" 420 | } 421 | }, 422 | "growl": { 423 | "version": "1.10.5", 424 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 425 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 426 | "dev": true 427 | }, 428 | "has": { 429 | "version": "1.0.3", 430 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 431 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 432 | "dev": true, 433 | "requires": { 434 | "function-bind": "^1.1.1" 435 | } 436 | }, 437 | "has-flag": { 438 | "version": "3.0.0", 439 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 440 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 441 | "dev": true 442 | }, 443 | "has-symbols": { 444 | "version": "1.0.1", 445 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 446 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", 447 | "dev": true 448 | }, 449 | "he": { 450 | "version": "1.2.0", 451 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 452 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 453 | "dev": true 454 | }, 455 | "inflight": { 456 | "version": "1.0.6", 457 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 458 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 459 | "dev": true, 460 | "requires": { 461 | "once": "^1.3.0", 462 | "wrappy": "1" 463 | } 464 | }, 465 | "inherits": { 466 | "version": "2.0.4", 467 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 468 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 469 | "dev": true 470 | }, 471 | "is-binary-path": { 472 | "version": "2.1.0", 473 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 474 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 475 | "dev": true, 476 | "requires": { 477 | "binary-extensions": "^2.0.0" 478 | } 479 | }, 480 | "is-buffer": { 481 | "version": "2.0.4", 482 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", 483 | "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", 484 | "dev": true 485 | }, 486 | "is-callable": { 487 | "version": "1.1.5", 488 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", 489 | "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", 490 | "dev": true 491 | }, 492 | "is-date-object": { 493 | "version": "1.0.2", 494 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 495 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", 496 | "dev": true 497 | }, 498 | "is-extglob": { 499 | "version": "2.1.1", 500 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 501 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 502 | "dev": true 503 | }, 504 | "is-fullwidth-code-point": { 505 | "version": "2.0.0", 506 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 507 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 508 | "dev": true 509 | }, 510 | "is-glob": { 511 | "version": "4.0.1", 512 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 513 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 514 | "dev": true, 515 | "requires": { 516 | "is-extglob": "^2.1.1" 517 | } 518 | }, 519 | "is-number": { 520 | "version": "7.0.0", 521 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 522 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 523 | "dev": true 524 | }, 525 | "is-regex": { 526 | "version": "1.0.5", 527 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", 528 | "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", 529 | "dev": true, 530 | "requires": { 531 | "has": "^1.0.3" 532 | } 533 | }, 534 | "is-symbol": { 535 | "version": "1.0.3", 536 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 537 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 538 | "dev": true, 539 | "requires": { 540 | "has-symbols": "^1.0.1" 541 | } 542 | }, 543 | "isexe": { 544 | "version": "2.0.0", 545 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 546 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 547 | "dev": true 548 | }, 549 | "js-yaml": { 550 | "version": "3.13.1", 551 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 552 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 553 | "dev": true, 554 | "requires": { 555 | "argparse": "^1.0.7", 556 | "esprima": "^4.0.0" 557 | } 558 | }, 559 | "locate-path": { 560 | "version": "3.0.0", 561 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 562 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 563 | "dev": true, 564 | "requires": { 565 | "p-locate": "^3.0.0", 566 | "path-exists": "^3.0.0" 567 | } 568 | }, 569 | "lodash": { 570 | "version": "4.17.19", 571 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", 572 | "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", 573 | "dev": true 574 | }, 575 | "log-symbols": { 576 | "version": "3.0.0", 577 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", 578 | "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", 579 | "dev": true, 580 | "requires": { 581 | "chalk": "^2.4.2" 582 | } 583 | }, 584 | "make-error": { 585 | "version": "1.3.6", 586 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 587 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 588 | "dev": true 589 | }, 590 | "minimatch": { 591 | "version": "3.0.4", 592 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 593 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 594 | "dev": true, 595 | "requires": { 596 | "brace-expansion": "^1.1.7" 597 | } 598 | }, 599 | "minimist": { 600 | "version": "1.2.5", 601 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 602 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 603 | "dev": true 604 | }, 605 | "mkdirp": { 606 | "version": "0.5.5", 607 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 608 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 609 | "dev": true, 610 | "requires": { 611 | "minimist": "^1.2.5" 612 | } 613 | }, 614 | "mocha": { 615 | "version": "7.2.0", 616 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", 617 | "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", 618 | "dev": true, 619 | "requires": { 620 | "ansi-colors": "3.2.3", 621 | "browser-stdout": "1.3.1", 622 | "chokidar": "3.3.0", 623 | "debug": "3.2.6", 624 | "diff": "3.5.0", 625 | "escape-string-regexp": "1.0.5", 626 | "find-up": "3.0.0", 627 | "glob": "7.1.3", 628 | "growl": "1.10.5", 629 | "he": "1.2.0", 630 | "js-yaml": "3.13.1", 631 | "log-symbols": "3.0.0", 632 | "minimatch": "3.0.4", 633 | "mkdirp": "0.5.5", 634 | "ms": "2.1.1", 635 | "node-environment-flags": "1.0.6", 636 | "object.assign": "4.1.0", 637 | "strip-json-comments": "2.0.1", 638 | "supports-color": "6.0.0", 639 | "which": "1.3.1", 640 | "wide-align": "1.1.3", 641 | "yargs": "13.3.2", 642 | "yargs-parser": "13.1.2", 643 | "yargs-unparser": "1.6.0" 644 | }, 645 | "dependencies": { 646 | "diff": { 647 | "version": "3.5.0", 648 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 649 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 650 | "dev": true 651 | } 652 | } 653 | }, 654 | "ms": { 655 | "version": "2.1.1", 656 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 657 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 658 | "dev": true 659 | }, 660 | "node-environment-flags": { 661 | "version": "1.0.6", 662 | "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", 663 | "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", 664 | "dev": true, 665 | "requires": { 666 | "object.getownpropertydescriptors": "^2.0.3", 667 | "semver": "^5.7.0" 668 | } 669 | }, 670 | "normalize-path": { 671 | "version": "3.0.0", 672 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 673 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 674 | "dev": true 675 | }, 676 | "object-inspect": { 677 | "version": "1.7.0", 678 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", 679 | "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", 680 | "dev": true 681 | }, 682 | "object-keys": { 683 | "version": "1.1.1", 684 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 685 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 686 | "dev": true 687 | }, 688 | "object.assign": { 689 | "version": "4.1.0", 690 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 691 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 692 | "dev": true, 693 | "requires": { 694 | "define-properties": "^1.1.2", 695 | "function-bind": "^1.1.1", 696 | "has-symbols": "^1.0.0", 697 | "object-keys": "^1.0.11" 698 | } 699 | }, 700 | "object.getownpropertydescriptors": { 701 | "version": "2.1.0", 702 | "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", 703 | "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", 704 | "dev": true, 705 | "requires": { 706 | "define-properties": "^1.1.3", 707 | "es-abstract": "^1.17.0-next.1" 708 | } 709 | }, 710 | "once": { 711 | "version": "1.4.0", 712 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 713 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 714 | "dev": true, 715 | "requires": { 716 | "wrappy": "1" 717 | } 718 | }, 719 | "p-limit": { 720 | "version": "2.3.0", 721 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 722 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 723 | "dev": true, 724 | "requires": { 725 | "p-try": "^2.0.0" 726 | } 727 | }, 728 | "p-locate": { 729 | "version": "3.0.0", 730 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 731 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 732 | "dev": true, 733 | "requires": { 734 | "p-limit": "^2.0.0" 735 | } 736 | }, 737 | "p-try": { 738 | "version": "2.2.0", 739 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 740 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 741 | "dev": true 742 | }, 743 | "path-exists": { 744 | "version": "3.0.0", 745 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 746 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 747 | "dev": true 748 | }, 749 | "path-is-absolute": { 750 | "version": "1.0.1", 751 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 752 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 753 | "dev": true 754 | }, 755 | "pathval": { 756 | "version": "1.1.0", 757 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 758 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 759 | "dev": true 760 | }, 761 | "picomatch": { 762 | "version": "2.2.2", 763 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 764 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 765 | "dev": true 766 | }, 767 | "pure-rand": { 768 | "version": "2.0.0", 769 | "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-2.0.0.tgz", 770 | "integrity": "sha512-mk98aayyd00xbfHgE3uEmAUGzz3jCdm8Mkf5DUXUhc7egmOaGG2D7qhVlynGenNe9VaNJZvzO9hkc8myuTkDgw==", 771 | "dev": true 772 | }, 773 | "readdirp": { 774 | "version": "3.2.0", 775 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", 776 | "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", 777 | "dev": true, 778 | "requires": { 779 | "picomatch": "^2.0.4" 780 | } 781 | }, 782 | "readline-sync": { 783 | "version": "1.4.10", 784 | "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", 785 | "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==" 786 | }, 787 | "require-directory": { 788 | "version": "2.1.1", 789 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 790 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 791 | "dev": true 792 | }, 793 | "require-main-filename": { 794 | "version": "2.0.0", 795 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", 796 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", 797 | "dev": true 798 | }, 799 | "semver": { 800 | "version": "5.7.1", 801 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 802 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 803 | "dev": true 804 | }, 805 | "set-blocking": { 806 | "version": "2.0.0", 807 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 808 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 809 | "dev": true 810 | }, 811 | "source-map": { 812 | "version": "0.6.1", 813 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 814 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 815 | "dev": true 816 | }, 817 | "source-map-support": { 818 | "version": "0.5.19", 819 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 820 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 821 | "dev": true, 822 | "requires": { 823 | "buffer-from": "^1.0.0", 824 | "source-map": "^0.6.0" 825 | } 826 | }, 827 | "sprintf-js": { 828 | "version": "1.0.3", 829 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 830 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 831 | "dev": true 832 | }, 833 | "string-width": { 834 | "version": "2.1.1", 835 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 836 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 837 | "dev": true, 838 | "requires": { 839 | "is-fullwidth-code-point": "^2.0.0", 840 | "strip-ansi": "^4.0.0" 841 | } 842 | }, 843 | "string.prototype.trimend": { 844 | "version": "1.0.1", 845 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", 846 | "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", 847 | "dev": true, 848 | "requires": { 849 | "define-properties": "^1.1.3", 850 | "es-abstract": "^1.17.5" 851 | } 852 | }, 853 | "string.prototype.trimleft": { 854 | "version": "2.1.2", 855 | "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", 856 | "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", 857 | "dev": true, 858 | "requires": { 859 | "define-properties": "^1.1.3", 860 | "es-abstract": "^1.17.5", 861 | "string.prototype.trimstart": "^1.0.0" 862 | } 863 | }, 864 | "string.prototype.trimright": { 865 | "version": "2.1.2", 866 | "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", 867 | "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", 868 | "dev": true, 869 | "requires": { 870 | "define-properties": "^1.1.3", 871 | "es-abstract": "^1.17.5", 872 | "string.prototype.trimend": "^1.0.0" 873 | } 874 | }, 875 | "string.prototype.trimstart": { 876 | "version": "1.0.1", 877 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", 878 | "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", 879 | "dev": true, 880 | "requires": { 881 | "define-properties": "^1.1.3", 882 | "es-abstract": "^1.17.5" 883 | } 884 | }, 885 | "strip-ansi": { 886 | "version": "4.0.0", 887 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 888 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 889 | "dev": true, 890 | "requires": { 891 | "ansi-regex": "^3.0.0" 892 | } 893 | }, 894 | "strip-json-comments": { 895 | "version": "2.0.1", 896 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 897 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 898 | "dev": true 899 | }, 900 | "supports-color": { 901 | "version": "6.0.0", 902 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", 903 | "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", 904 | "dev": true, 905 | "requires": { 906 | "has-flag": "^3.0.0" 907 | } 908 | }, 909 | "to-regex-range": { 910 | "version": "5.0.1", 911 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 912 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 913 | "dev": true, 914 | "requires": { 915 | "is-number": "^7.0.0" 916 | } 917 | }, 918 | "ts-node": { 919 | "version": "8.10.1", 920 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz", 921 | "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==", 922 | "dev": true, 923 | "requires": { 924 | "arg": "^4.1.0", 925 | "diff": "^4.0.1", 926 | "make-error": "^1.1.1", 927 | "source-map-support": "^0.5.17", 928 | "yn": "3.1.1" 929 | } 930 | }, 931 | "tslib": { 932 | "version": "1.13.0", 933 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", 934 | "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", 935 | "dev": true 936 | }, 937 | "type-detect": { 938 | "version": "4.0.8", 939 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 940 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 941 | "dev": true 942 | }, 943 | "typescript": { 944 | "version": "3.9.3", 945 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", 946 | "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", 947 | "dev": true 948 | }, 949 | "utf32char": { 950 | "version": "1.4.0", 951 | "resolved": "https://registry.npmjs.org/utf32char/-/utf32char-1.4.0.tgz", 952 | "integrity": "sha512-drKLpGHQY1bRfcAPoPJAMbaaroTIi2Ob0FKwjB8zBmzDUKI2rv3dLbHk8uZg2t8N+noFxudSQHjHd6NXby7H7w==" 953 | }, 954 | "which": { 955 | "version": "1.3.1", 956 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 957 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 958 | "dev": true, 959 | "requires": { 960 | "isexe": "^2.0.0" 961 | } 962 | }, 963 | "which-module": { 964 | "version": "2.0.0", 965 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 966 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", 967 | "dev": true 968 | }, 969 | "wide-align": { 970 | "version": "1.1.3", 971 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 972 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 973 | "dev": true, 974 | "requires": { 975 | "string-width": "^1.0.2 || 2" 976 | } 977 | }, 978 | "wrap-ansi": { 979 | "version": "5.1.0", 980 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 981 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", 982 | "dev": true, 983 | "requires": { 984 | "ansi-styles": "^3.2.0", 985 | "string-width": "^3.0.0", 986 | "strip-ansi": "^5.0.0" 987 | }, 988 | "dependencies": { 989 | "ansi-regex": { 990 | "version": "4.1.0", 991 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 992 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 993 | "dev": true 994 | }, 995 | "string-width": { 996 | "version": "3.1.0", 997 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 998 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 999 | "dev": true, 1000 | "requires": { 1001 | "emoji-regex": "^7.0.1", 1002 | "is-fullwidth-code-point": "^2.0.0", 1003 | "strip-ansi": "^5.1.0" 1004 | } 1005 | }, 1006 | "strip-ansi": { 1007 | "version": "5.2.0", 1008 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1009 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1010 | "dev": true, 1011 | "requires": { 1012 | "ansi-regex": "^4.1.0" 1013 | } 1014 | } 1015 | } 1016 | }, 1017 | "wrappy": { 1018 | "version": "1.0.2", 1019 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1020 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1021 | "dev": true 1022 | }, 1023 | "y18n": { 1024 | "version": "4.0.0", 1025 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", 1026 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", 1027 | "dev": true 1028 | }, 1029 | "yargs": { 1030 | "version": "13.3.2", 1031 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", 1032 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", 1033 | "dev": true, 1034 | "requires": { 1035 | "cliui": "^5.0.0", 1036 | "find-up": "^3.0.0", 1037 | "get-caller-file": "^2.0.1", 1038 | "require-directory": "^2.1.1", 1039 | "require-main-filename": "^2.0.0", 1040 | "set-blocking": "^2.0.0", 1041 | "string-width": "^3.0.0", 1042 | "which-module": "^2.0.0", 1043 | "y18n": "^4.0.0", 1044 | "yargs-parser": "^13.1.2" 1045 | }, 1046 | "dependencies": { 1047 | "ansi-regex": { 1048 | "version": "4.1.0", 1049 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1050 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1051 | "dev": true 1052 | }, 1053 | "string-width": { 1054 | "version": "3.1.0", 1055 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1056 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1057 | "dev": true, 1058 | "requires": { 1059 | "emoji-regex": "^7.0.1", 1060 | "is-fullwidth-code-point": "^2.0.0", 1061 | "strip-ansi": "^5.1.0" 1062 | } 1063 | }, 1064 | "strip-ansi": { 1065 | "version": "5.2.0", 1066 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1067 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1068 | "dev": true, 1069 | "requires": { 1070 | "ansi-regex": "^4.1.0" 1071 | } 1072 | } 1073 | } 1074 | }, 1075 | "yargs-parser": { 1076 | "version": "13.1.2", 1077 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", 1078 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", 1079 | "dev": true, 1080 | "requires": { 1081 | "camelcase": "^5.0.0", 1082 | "decamelize": "^1.2.0" 1083 | } 1084 | }, 1085 | "yargs-unparser": { 1086 | "version": "1.6.0", 1087 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", 1088 | "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", 1089 | "dev": true, 1090 | "requires": { 1091 | "flat": "^4.1.0", 1092 | "lodash": "^4.17.15", 1093 | "yargs": "^13.3.0" 1094 | } 1095 | }, 1096 | "yn": { 1097 | "version": "3.1.1", 1098 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1099 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1100 | "dev": true 1101 | } 1102 | } 1103 | } 1104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@awwsmm/brainscript", 3 | "version": "5.0.0", 4 | "description": "A BrainF*** interpreter written in TypeScript", 5 | "main": "build/index.js", 6 | "scripts": { 7 | "test": "mocha --require ts-node/register test/**/*.ts" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/awwsmm/BrainScript.git" 12 | }, 13 | "keywords": [ 14 | "brainfuck", 15 | "bf", 16 | "ts", 17 | "typescript", 18 | "interpreter", 19 | "compiler" 20 | ], 21 | "author": "awwsmm", 22 | "license": "UNLICENSED", 23 | "bugs": { 24 | "url": "https://github.com/awwsmm/BrainScript/issues" 25 | }, 26 | "homepage": "https://github.com/awwsmm/BrainScript#readme", 27 | "dependencies": { 28 | "readline-sync": "^1.4.10", 29 | "utf32char": "^1.4.0" 30 | }, 31 | "devDependencies": { 32 | "@types/chai": "^4.2.11", 33 | "@types/mocha": "^7.0.2", 34 | "@types/node": "^14.0.5", 35 | "chai": "^4.2.0", 36 | "fast-check": "^1.24.2", 37 | "mocha": "^7.2.0", 38 | "ts-node": "^8.10.1", 39 | "typescript": "^3.9.3" 40 | }, 41 | "publishConfig": { 42 | "registry": "https://npm.pkg.github.com" 43 | }, 44 | "bin": { 45 | "brain": "npx ts-node brain.ts" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Brain.ts: -------------------------------------------------------------------------------- 1 | import { UTF32Char, UInt32 } from 'utf32char' 2 | import { isToken } from './Token' 3 | 4 | const readline = require('readline') 5 | const readlineSync = require('readline-sync') 6 | 7 | export function readUTF32Char(): UTF32Char { 8 | let input: string = "" 9 | while (true) { 10 | try { 11 | input = readlineSync.question(" ❓: ") 12 | const char: UTF32Char = UTF32Char.fromString(input) 13 | console.log("") 14 | return char 15 | } catch (error) { 16 | console.log(error.message) 17 | console.log(`Not a valid UTF-32 character: "${input}"`) 18 | console.log(" Please try again, or press CTRL-C to quit") 19 | } 20 | } 21 | } 22 | 23 | export function bf ( 24 | program: string, 25 | numin: boolean = false, 26 | numout: boolean = false, 27 | classic: boolean = false, 28 | memory: UInt32 = UInt32.fromNumber(1000), 29 | input: () => UTF32Char = readUTF32Char 30 | ): string { 31 | 32 | // validate memory 33 | if (memory.lt(1)) throw new Error("must provide at least 1 cell of memory") 34 | 35 | // program state setup 36 | let state = new Array(memory.toNumber()).fill(UInt32.fromNumber(0)) 37 | let memoryPointer: UInt32 = new UInt32(0) 38 | let programPointer: UInt32 = new UInt32(0) 39 | let output: string = "" 40 | 41 | // move the memory pointer left or right 42 | function movePointer (op: string): void { 43 | 44 | // move back one cell in memory 45 | if (op === '<') { 46 | if (classic) { 47 | if (memoryPointer.lt(1)) memoryPointer = memory.minus(1) 48 | else memoryPointer = memoryPointer.minus(1) 49 | } else { 50 | try { 51 | memoryPointer = memoryPointer.minus(1) 52 | } catch (error) { 53 | throw new Error("cannot decrement memory pointer below minimum index 0... try setting `classic` to `true`") 54 | } 55 | } 56 | 57 | // move forward one cell in memory 58 | } else if (op === '>') { 59 | if (classic) { 60 | if (memoryPointer.ge(memory.minus(1))) memoryPointer = UInt32.fromNumber(0) 61 | else memoryPointer = memoryPointer.plus(1) 62 | } else { 63 | if (memoryPointer.ge(memory.minus(1))) 64 | throw new Error(`cannot increment memory pointer above maximum index ${memory.minus(1).toString()}... try setting \`classic\` to \`true\``) 65 | else memoryPointer = memoryPointer.plus(1) 66 | } 67 | 68 | // if not '<' or '>', invalid argument 69 | } else throw new Error(`movePointer received invalid op: ${op}`) 70 | } 71 | 72 | // changes the value of the memory cell at the pointer 73 | function changeCell (op: string): void { 74 | if (!isToken(op)) throw new Error(`changeCell received invalid op: ${op}`) 75 | 76 | const index: number = memoryPointer.toNumber() 77 | const value: UInt32 = state[index] 78 | 79 | if (op === '+') { 80 | if (classic) { 81 | if (value.ge(255)) state[index] = UInt32.fromNumber(0) 82 | else state[index] = value.plus(1) 83 | } else { 84 | if (value.ge(UInt32.MAX_VALUE)) 85 | throw new Error(`cell ${index} is already at maximum allowable value, 2^32 - 1... try setting \`classic\` to \`true\``) 86 | else state[index] = value.plus(1) 87 | } 88 | } else if (op === '-') { 89 | if (classic) { 90 | if (value.lt(1)) state[index] = UInt32.fromNumber(255) 91 | else state[index] = value.minus(1) 92 | } else { 93 | if (value.le(UInt32.MIN_VALUE)) 94 | throw new Error(`cell ${index} is already at minimum allowable value, 0... try setting \`classic\` to \`true\``) 95 | else state[index] = value.minus(1) 96 | } 97 | } else { 98 | throw new Error(`changeCell received invalid op: ${op}`) 99 | } 100 | } 101 | 102 | // tries to run a side-effecting function and propagates Errors with helpful messages 103 | function mayFail (op: () => void): void { 104 | try { op() } catch(err) { 105 | 106 | const padWith: string = " " 107 | const padding: number = padWith.length 108 | const ptr: number = programPointer.toNumber() 109 | const minChIncl: number = Math.max(0, ptr - padding) 110 | const maxChExcl: number = Math.min(ptr + padding, program.length) 111 | const padLeft: string = padWith.slice(ptr - padding) 112 | 113 | const errString: string = "\n" + 114 | padLeft + program.slice(minChIncl, maxChExcl) + '\n' + 115 | `Error at ^ char index ${ptr}` + '\n' + 116 | ` message: ${err.message}` + '\n' + 117 | ` output: ${output}` + '\n' 118 | 119 | throw new Error(errString) 120 | } 121 | } 122 | 123 | // tries to move the programPointer to the character after the matching 124 | // '[' if this is a ']' and vice versa 125 | function jump (op: string): void { 126 | if (!isToken(op)) throw new Error(`moveToMatch received invalid op: ${op}`) 127 | 128 | let delta: number = 1 129 | let index: number = 1 130 | 131 | if (op === '[') { 132 | const chars = program.slice(programPointer.toNumber() + 1).split("") 133 | 134 | for (const char of chars) { 135 | if (char === ']') delta -= 1 136 | else if (char === '[') delta += 1 137 | if (delta > 0) index += 1 138 | else break 139 | } 140 | 141 | if (delta > 0) 142 | throw new Error("missing close-brace ] for this open-brace [") 143 | else programPointer = programPointer.plus(index) 144 | 145 | } else if (op === ']') { 146 | const chars = program.slice(0, programPointer.toNumber()).split("").reverse() 147 | 148 | for (const char of chars) { 149 | if (char === '[') delta -= 1 150 | else if (char === ']') delta += 1 151 | if (delta > 0) index += 1 152 | else break 153 | } 154 | 155 | if (delta > 0) 156 | throw new Error("missing open-brace [ for this close-brace ]") 157 | else programPointer = programPointer.minus(index) 158 | 159 | } else { 160 | throw new Error(`moveToMatch received invalid op: ${op}`) 161 | } 162 | } 163 | 164 | function isDigit (num: number): boolean { return num < 58 && num > 47 } 165 | function toDigit (num: number): number { return num - 48 } 166 | 167 | // simply interpret token unless we see a '[' or a ']' 168 | while (programPointer.toNumber() < program.length) { 169 | let nextChar = program[programPointer.toNumber()] 170 | 171 | // ignore non-token characters 172 | if (isToken(nextChar)) { 173 | 174 | const index: number = memoryPointer.toNumber() 175 | const value: UInt32 = state[index] 176 | 177 | // begin while loop 178 | if (nextChar === '[' && value.lt(1)) { 179 | mayFail(() => jump(nextChar)) 180 | 181 | // end while loop 182 | } else if (nextChar === ']' && value.gt(0)) { 183 | mayFail(() => jump(nextChar)) 184 | 185 | // operations which move the pointer 186 | } else if (nextChar === '<' || nextChar === '>') { 187 | mayFail(() => movePointer(nextChar)) 188 | 189 | // operations which change the values in cells 190 | } else if (nextChar === '+' || nextChar === '-') { 191 | mayFail(() => changeCell(nextChar)) 192 | 193 | // output -- add to output buffer 194 | } else if (nextChar === '.') { 195 | if (numout) { 196 | let given: number = value.toNumber() 197 | 198 | if (isDigit(given)) given = toDigit(given) 199 | else { 200 | let hiDigit: number = Math.floor(given / 10) 201 | let loDigit: number = given - 10*hiDigit 202 | if (isDigit(hiDigit) && isDigit(loDigit)) 203 | given = toDigit(hiDigit) * 10 + toDigit(loDigit) 204 | } 205 | 206 | output += given.toString() 207 | 208 | } else output += UTF32Char.fromUInt32(value).toString() 209 | 210 | // input -- get one character from the user 211 | } else if (nextChar === ',') { 212 | if (numin) { 213 | console.log("\n Please provide a 1 or 2-digit number for ',' input:") 214 | let given: number = input().toNumber() 215 | 216 | if (isDigit(given)) given = toDigit(given) 217 | else { 218 | let hiDigit: number = given >> 16 219 | let loDigit: number = given & 0x0000FFFF 220 | if (isDigit(hiDigit) && isDigit(loDigit)) 221 | given = toDigit(hiDigit) * 10 + toDigit(loDigit) 222 | else throw new Error("non-digit characters entered in numeric mode") 223 | } 224 | 225 | state[index] = UInt32.fromNumber(given) 226 | 227 | } else { 228 | console.log("\n Please provide a single character for ',' input:") 229 | state[index] = input().toUInt32() 230 | } 231 | } 232 | } 233 | 234 | programPointer = programPointer.plus(1) 235 | } 236 | 237 | return output 238 | } 239 | 240 | export function brain (): void { 241 | 242 | let classic: boolean = false // default interpretation mode ('default' vs. 'classic') 243 | let numin: boolean = false // character input by default 244 | let numout: boolean = false // character output by default 245 | 246 | const signoffs: Array = [ 247 | "Totsiens", "Ma'a as-salaama", "Bidāẏa", "Zdravo", "Joigin", 248 | "Donadagohvi", "Doviđenja", "Sbohem", "Farvel", "Tot ziens", 249 | "Nägemist", "Näkemiin", "Au Revoir", "Auf Wiedersehen", "Yasou", 250 | "Aloha", "L'hitraot", "Namaste", "Viszlát", "Vertu sæll", 251 | "Sampai Jumpa", "Slán", "Arrivederci", "Sayōnara", "안녕", 252 | "Vale", "Uz redzēšanos", "Atsiprasau", "Zài jiàn", "Ha det bra", 253 | "Khodaa haafez", "Żegnaj", "Adeus", "Alweda", "La revedere", 254 | "Прощай", "Dovidenia", "Nasvidenje", "Adios", "Adjö", 255 | "Poitu varein", "Laa Gòn", "Görüşürüz", "Do pobachennia", "Khuda hafiz", 256 | "Tạm biệt", "Hwyl fawr", "Hamba kahle", "再见", "وداعا", 257 | "May the force be with you", "ลาก่อน", "பிரியாவிடை", "Namárië", 258 | "Qapla'", 259 | "Live long and prosper" 260 | ] 261 | 262 | const signoff = "👋 " + signoffs[Math.floor(Math.random() * signoffs.length)]; 263 | 264 | let multiLine: string = "" 265 | let pasteMode: boolean = false 266 | let previousLine: string = "" 267 | 268 | function interpret (program: string, numin: boolean, numout: boolean, classic: boolean): void { 269 | const memory: UInt32 = UInt32.fromNumber(1000) 270 | try { 271 | console.log(bf(program, numin, numout, classic, memory)) 272 | } catch (error) { 273 | console.log(error.message) 274 | } 275 | } 276 | 277 | console.log("\nEnter single-line BF code below or") 278 | console.log(" type :paste to paste multiline code") 279 | console.log(" type :numin to toggle numeric input mode") 280 | console.log(" type :numout to toggle numeric output mode") 281 | console.log(" type :classic to toggle classic / default mode") 282 | console.log(" type :quit or enter -C to quit") 283 | 284 | const defaultPrompt: string = "\n🧠: " 285 | readlineSync.setDefaultOptions({prompt: defaultPrompt}) 286 | readlineSync.promptLoop(function(line: string) { 287 | 288 | // continue in :paste mode 289 | if (pasteMode) { 290 | 291 | // exit :paste mode 292 | if (previousLine === "" && previousLine === line) { 293 | console.log("~~~~~~~~~~~~~ INTERPRETING... ~~~~~~~~~~~~~\n") 294 | interpret(multiLine, numin, numout, classic) 295 | multiLine = "" 296 | pasteMode = false 297 | readlineSync.setDefaultOptions({prompt: defaultPrompt}) 298 | return false 299 | 300 | // continue in :paste mode 301 | } else { 302 | previousLine = line 303 | multiLine += line 304 | } 305 | 306 | // enter :paste mode 307 | } else if (line === ":paste" && multiLine === "" && !pasteMode) { 308 | console.log("\nEntering multiline input mode.") 309 | console.log("Enter two blank lines in a row to interpret.") 310 | console.log("~~~~~~~~~~~~~~~ BEGIN INPUT ~~~~~~~~~~~~~~~\n\n") 311 | readlineSync.setDefaultOptions({prompt: ""}) 312 | pasteMode = true 313 | 314 | // toggle classic / default interpretation mode 315 | } else if (line === ":classic") { 316 | classic = !classic 317 | let modeStr: string 318 | if (classic) modeStr = "classic"; else modeStr = "default" 319 | console.log(`\nChanged interpretation mode to '${modeStr}'`) 320 | return false 321 | 322 | // toggle numeric / character input mode 323 | } else if (line === ":numin") { 324 | numin = !numin 325 | let numinStr: string 326 | if (numin) numinStr = "numeric"; else numinStr = "character" 327 | console.log(`\nChanged input mode to '${numinStr}'`) 328 | return false 329 | 330 | // toggle numeric / character output mode 331 | } else if (line === ":numout") { 332 | numout = !numout 333 | let numoutStr: string 334 | if (numout) numoutStr = "numeric"; else numoutStr = "character" 335 | console.log(`\nChanged output mode to '${numoutStr}'`) 336 | return false 337 | 338 | } else if (line === ":quit") { 339 | return true 340 | 341 | // interpret single line 342 | } else { 343 | if (line.length > 0) interpret(line, numin, numout, classic) 344 | return false 345 | } 346 | }) 347 | 348 | console.log(`${signoff}\n`) 349 | } -------------------------------------------------------------------------------- /src/Token.ts: -------------------------------------------------------------------------------- 1 | export enum Token { ">", "<", "+", "-", ".", ",", "[", "]" } 2 | 3 | export function isToken (str: string): boolean { 4 | return Object.values(Token).includes(str) 5 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { readUTF32Char, brain, bf } from './Brain' 2 | export { Token, isToken } from './Token' 3 | 4 | // to publish: 5 | // $ npm run test 6 | // $ npx tsc 7 | // $ git add . 8 | // $ git commit -am 9 | // $ npm version 10 | // $ npm publish 11 | // $ git push -------------------------------------------------------------------------------- /test/BrainSpec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { bf } from '../src' 3 | import { UInt32, UTF32Char } from 'utf32char' 4 | 5 | // suspend program output during testing 6 | console.log = function (_: any) { } 7 | 8 | describe('bf, regardless of mode', () => { 9 | 10 | it ("throws an error when '[' is missing a matching ']'", () => { 11 | expect(() => bf("[", false, false, true)).to.throw() 12 | expect(() => bf("[", false, false, false)).to.throw() 13 | }) 14 | 15 | it ("throws an error when ']' is missing a matching '['", () => { 16 | expect(() => bf("+]", false, false, true)).to.throw() 17 | expect(() => bf("+]", false, false, false)).to.throw() 18 | }) 19 | 20 | it ("throws an error when the user gives a length-0 string as input", () => { 21 | const memory: UInt32 = UInt32.fromNumber(1) 22 | for (const classic of [ true, false ]) 23 | for (const numin of [ true, false ]) 24 | expect(() => bf(",", numin, false, classic, memory, () => UTF32Char.fromString(""))).to.throw() 25 | }) 26 | 27 | it ("throws an error when the user gives a length-3+ string as input", () => { 28 | const memory: UInt32 = UInt32.fromNumber(1) 29 | for (const classic of [ true, false ]) 30 | for (const numin of [ true, false ]) 31 | expect(() => bf(",", numin, false, classic, memory, () => UTF32Char.fromString("abc"))).to.throw() 32 | }) 33 | 34 | it ("correctly interprets the addition example from Wikipedia", () => { 35 | expect(bf(test_wikiAddition, false, false, true)).to.equal("7") 36 | expect(bf(test_wikiAddition, false, false, false)).to.equal("7") 37 | }) 38 | 39 | it ("correctly interprets the long 'Hello World!' example from Wikipedia", () => { 40 | expect(bf(test_wikiHelloWorldLong, false, false, true)).to.equal("Hello World!\n") 41 | expect(bf(test_wikiHelloWorldLong, false, false, false)).to.equal("Hello World!\n") 42 | }) 43 | 44 | it ("correctly interprets the short 'Hello World!' example from Wikipedia", () => { 45 | expect(bf(test_wikiHelloWorldShort, false, false, true)).to.equal("Hello World!\n") 46 | expect(bf(test_wikiHelloWorldShort, false, false, false)).to.equal("Hello World!\n") 47 | }) 48 | 49 | // https://codegolf.stackexchange.com/a/21857/79936 50 | it ("correctly interprets the two-part '42' example from StackExchange", () => { 51 | expect(bf(test_se42Part1, false, false, true)).to.equal(test_se42Part2) 52 | expect(bf(test_se42Part1, false, false, false)).to.equal(test_se42Part2) 53 | expect(bf(test_se42Part2, false, false, true)).to.equal("6*7=42") 54 | expect(bf(test_se42Part2, false, false, false)).to.equal("6*7=42") 55 | }) 56 | 57 | }) 58 | 59 | describe('bf in classic mode', () => { 60 | 61 | const classic: boolean = true 62 | 63 | it ("does not throw an error when attempting to access negative memory cells", () => { 64 | expect(() => bf("<", false, false, classic)).to.not.throw() 65 | }) 66 | 67 | it ("does not throw an error when attempting to access too-high memory cells", () => { 68 | const memory: UInt32 = UInt32.fromNumber(1) 69 | expect(() => bf(">>", false, false, classic, memory)).to.not.throw() 70 | }) 71 | 72 | it ("does not throw an error when attempting to set a cell to a negative value", () => { 73 | expect(() => bf("-", false, false, classic)).to.not.throw() 74 | }) 75 | 76 | it ("does not throw an error when attempting to set a cell to a too-high value", () => { 77 | const memory: UInt32 = UInt32.fromNumber(1) 78 | expect(() => bf(",+", false, false, classic, memory, () => UTF32Char.fromNumber(UInt32.MAX_VALUE))).to.not.throw() 79 | }) 80 | 81 | it ("correctly interprets the code-golfed 'Hello, World!' example from StackExchange", () => { 82 | expect(bf(test_seCodeGolfHelloWorld, false, false, classic)).to.equal("Hello, World!") 83 | }) 84 | 85 | }) 86 | 87 | describe('bf not in classic mode', () => { 88 | 89 | const classic: boolean = false 90 | 91 | it ("throws an error when attempting to access negative memory cells", () => { 92 | expect(() => bf("<", false, false, classic)).to.throw() 93 | }) 94 | 95 | it ("throws an error when attempting to access too-high memory cells", () => { 96 | const memory: UInt32 = UInt32.fromNumber(1) 97 | expect(() => bf(">>", false, false, classic, memory)).to.throw() 98 | }) 99 | 100 | it ("throws an error when attempting to set a cell to a negative value", () => { 101 | expect(() => bf("-", false, false, classic)).to.throw() 102 | }) 103 | 104 | it ("throws an error when attempting to set a cell to a too-high value", () => { 105 | const memory: UInt32 = UInt32.fromNumber(1) 106 | expect(() => bf(",+", false, false, classic, memory, () => UTF32Char.fromNumber(UInt32.MAX_VALUE))).to.throw() 107 | }) 108 | 109 | it ("throws an error with the code-golfed 'Hello, World!' example from StackExchange", () => { 110 | expect(() => bf(test_seCodeGolfHelloWorld, false, false, classic)).to.throw() 111 | }) 112 | 113 | }) 114 | 115 | const test_wikiAddition: string = ` 116 | ++ Cell c0 = 2 117 | > +++++ Cell c1 = 5 118 | 119 | [ Start your loops with your cell pointer on the loop counter (c1 in our case) 120 | < + Add 1 to c0 121 | > - Subtract 1 from c1 122 | ] End your loops with the cell pointer on the loop counter 123 | 124 | At this point our program has added 5 to 2 leaving 7 in c0 and 0 in c1 125 | but we cannot output this value to the terminal since it is not ASCII encoded! 126 | 127 | To display the ASCII character "7" we must add 48 to the value 7 128 | 48 = 6 * 8 so let's use another loop to help us! 129 | 130 | ++++ ++++ c1 = 8 and this will be our loop counter again 131 | [ 132 | < +++ +++ Add 6 to c0 133 | > - Subtract 1 from c1 134 | ] 135 | < . Print out c0 which has the value 55 which translates to "7"! 136 | ` 137 | 138 | const test_wikiHelloWorldLong: string = ` 139 | [ This program prints "Hello World!" and a newline to the screen, its 140 | length is 106 active command characters. [It is not the shortest.] 141 | 142 | This loop is an "initial comment loop", a simple way of adding a comment 143 | to a BF program such that you don't have to worry about any command 144 | characters. Any ".", ",", "+", "-", "<" and ">" characters are simply 145 | ignored, the "[" and "]" characters just have to be balanced. This 146 | loop and the commands it contains are ignored because the current cell 147 | defaults to a value of 0; the 0 value causes this loop to be skipped. 148 | ] 149 | ++++++++ Set Cell #0 to 8 150 | [ 151 | >++++ Add 4 to Cell #1; this will always set Cell #1 to 4 152 | [ as the cell will be cleared by the loop 153 | >++ Add 2 to Cell #2 154 | >+++ Add 3 to Cell #3 155 | >+++ Add 3 to Cell #4 156 | >+ Add 1 to Cell #5 157 | <<<<- Decrement the loop counter in Cell #1 158 | ] Loop till Cell #1 is zero; number of iterations is 4 159 | >+ Add 1 to Cell #2 160 | >+ Add 1 to Cell #3 161 | >- Subtract 1 from Cell #4 162 | >>+ Add 1 to Cell #6 163 | [<] Move back to the first zero cell you find; this will 164 | be Cell #1 which was cleared by the previous loop 165 | <- Decrement the loop Counter in Cell #0 166 | ] Loop till Cell #0 is zero; number of iterations is 8 167 | 168 | The result of this is: 169 | Cell No : 0 1 2 3 4 5 6 170 | Contents: 0 0 72 104 88 32 8 171 | Pointer : ^ 172 | 173 | >>. Cell #2 has value 72 which is 'H' 174 | >---. Subtract 3 from Cell #3 to get 101 which is 'e' 175 | +++++++..+++. Likewise for 'llo' from Cell #3 176 | >>. Cell #5 is 32 for the space 177 | <-. Subtract 1 from Cell #4 for 87 to give a 'W' 178 | <. Cell #3 was set to 'o' from the end of 'Hello' 179 | +++.------.--------. Cell #3 for 'rl' and 'd' 180 | >>+. Add 1 to Cell #5 gives us an exclamation point 181 | >++. And finally a newline from Cell #6 182 | ` 183 | 184 | const test_wikiHelloWorldShort: string = ` 185 | ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. 186 | ` 187 | 188 | const test_seCodeGolfHelloWorld: string = ` 189 | --<-<<+[+[<+>--->->->-<<<]>]<<--.<++++++.<<-..<<.<+.>>.>>.<<<.+++.>>.>>-.<<<+. 190 | ` 191 | 192 | const test_se42Part1: string = ` 193 | +++++[>++[>+>+ ++>++++>++++>++++>++++++ 194 | >++++++>+++++++ ++>+++++++++<<<<<<<<<-]>> 195 | >+>+>+> >>>+[<]< -]>> >++>-->>+>>++>+ 196 | >--<<<< <<<..... .> ....<...... 197 | ...>... <<.>.... >.>>>>>.<. 198 | <<<<.. ..<.... >..>>>>>.< 199 | .<<<<. >>>.<<. >>>>>.<.< 200 | <<<<< <.>...> >>>.>>>. 201 | <<<.< <<<..>> .>>>>>.< 202 | <.<<< <<...>> >>>.<<< 203 | <..<. ...>... <<.>..>. 204 | >>.<.<<...>>...<<...>>...< <....>>.. 205 | .<<<.>.>>..>.<<.......<.... .....>... 206 | <<.>... .....>... 207 | <...... .>>>.<<.. 208 | <<.>... .....>...<......>.>>.<.<<< 209 | .>...... ..>>...<<....>>.....>.<..>. 210 | ` 211 | 212 | const test_se42Part2: string = 213 | ` ++++ +++ 214 | +[>++++ ++[>+<-][ 215 | <]< -]> >++ +++ 216 | +.- --- --- --- 217 | --.+++++++ +++ 218 | +++ .++ 219 | +++ +.- 220 | --- -----.--.` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": true, 4 | "removeComments": true, 5 | "allowUnreachableCode": false, 6 | "strictNullChecks": true, 7 | "rootDir": "src", 8 | "outDir": "build", 9 | "lib": [ "es6" ], 10 | "target": "es5", 11 | "module": "commonjs", 12 | "declaration": true 13 | }, 14 | "exclude" : [ 15 | "test/**/*", 16 | "build/**/*" 17 | ] 18 | } --------------------------------------------------------------------------------