├── .github ├── dependabot.yml └── workflows │ └── node.js.yml ├── .gitignore ├── .npmignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin └── regenerator ├── docs ├── .gitignore ├── .nojekyll ├── bundle.js ├── codemirror │ ├── lib │ │ ├── codemirror.css │ │ └── codemirror.js │ └── mode │ │ └── javascript.js ├── index.html ├── promise-6.0.0.js ├── sandbox.css ├── sandbox.js ├── yield_ahead.16px.png ├── yield_ahead.200px.png └── yield_ahead.svg ├── lib ├── util.js └── visit.js ├── main.js ├── package-lock.json ├── package.json ├── packages ├── preset │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── index.js │ └── package.json ├── runtime │ ├── .gitignore │ ├── .npmignore │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── path.js │ └── runtime.js └── transform │ ├── .gitignore │ ├── .npmignore │ ├── LICENSE │ ├── README.md │ ├── package.json │ └── src │ ├── emit.js │ ├── hoist.js │ ├── index.js │ ├── leap.js │ ├── meta.js │ ├── replaceShorthandObjectMethod.js │ ├── util.js │ └── visit.js ├── runtime-module.js ├── runtime.js └── test ├── async-custom-promise.js ├── async.js ├── class.js ├── frozen-intrinsics.js ├── index.html ├── non-native.js ├── non-writable-tostringtag-property.js ├── nothing-to-transform.js ├── regression.js ├── replaceWith-falsy.js ├── run.js ├── run.sh ├── runtime.js ├── shared.js ├── tests-node4.es6.js ├── tests.es6.js └── tests.transform.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "npm" # See documentation for possible values 7 | directory: "/" # Location of package manifests 8 | schedule: 9 | interval: "daily" 10 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [12.x, 14.x, 16.x, 18.x, 20.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v1 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | - name: Use npm v8 29 | run: npm install --global npm@8 30 | - run: npm ci 31 | - run: npm run build --if-present 32 | - run: npm test 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | 4 | test/mocha.js 5 | test/mocha.css 6 | 7 | test/*.es5.js 8 | test/*.regenerator.js 9 | test/tests.browser.js 10 | 11 | .idea 12 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /test 3 | # Don't publish the helper packages as part of the parent package. 4 | /packages 5 | # Don't publish docs directory to npm (it's very large). 6 | /docs 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated. 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Regenerator 2 | 3 | Regenerator uses GitHub as its sole source of truth. Everything happens 4 | here. Facebook employees who contribute to Regenerator are expected to do 5 | so in the same way as everyone else. In other words, this document applies 6 | equally to all contributors. 7 | 8 | ### Code of Conduct 9 | The code of conduct is described in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) 10 | 11 | ### `master` is unsafe 12 | 13 | We will do our best to keep `master` in good shape, with tests passing at 14 | all times. But in order to move fast, we will make API changes that your 15 | application might not be compatible with. We will do our best to 16 | communicate these changes and always version appropriately so you can lock 17 | into a specific version if need be. 18 | 19 | ### Pull Requests 20 | 21 | In case you've never submitted a pull request (PR) via GitHub before, 22 | please read [this short 23 | tutorial](https://help.github.com/articles/creating-a-pull-request). If 24 | you've submitted a PR before, there should be nothing surprising about our 25 | procedures for Regenerator. 26 | 27 | *Before* submitting a pull request, please make sure the following is done… 28 | 29 | 1. Fork the repo and create your branch from `master`. 30 | 2. If you've added code that should be tested, add tests! 31 | 3. Ensure the test suite passes (`npm test`). 32 | 4. If you haven't already, complete the CLA. 33 | 5. Submit a pull request via GitHub. 34 | 6. Check that Travis CI tests pass (pull request turns green). 35 | 36 | ### Contributor License Agreement ("CLA") 37 | 38 | In order to accept your pull request, we need you to submit a CLA. You 39 | only need to do this once, so if you've done this for another Facebook 40 | open source project, you're good to go. If you are submitting a pull 41 | request for the first time, just let us know that you have completed the 42 | CLA and we can cross-check with your GitHub username. 43 | 44 | Complete your CLA here: <https://code.facebook.com/cla> 45 | 46 | ## Bugs 47 | 48 | ### Where to Find Known Issues 49 | 50 | We will be using GitHub Issues for all bugs. Before filing a new issue, 51 | please try to make sure your problem doesn't already exist. If you think 52 | your issue is more general than one that already exists, our preference is 53 | still to modify the original issue to reflect the underlying problem more 54 | faithfully. 55 | 56 | ### Reporting New Issues 57 | 58 | The best way to get a bug fixed is to provide a reduced test case, and the 59 | easiest way to reduce a testcase is to edit it in [the 60 | sandbox](http://facebook.github.io/regenerator/) until you're satisfied 61 | and then click the "report a bug" link (the new issue will be populated 62 | automatically with your code). 63 | 64 | ### Security Bugs 65 | 66 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for 67 | the safe disclosure of security bugs. With that in mind, please do not 68 | file public issues and go through the process outlined on that page. 69 | 70 | ## Coding Style 71 | 72 | * Use semicolons; 73 | * Commas last, 74 | * 2 spaces for indentation (no tabs). 75 | * Prefer `"` over `'` 76 | * 80 character line length 77 | * Match surrounding coding style. 78 | * Less code is better code. 79 | 80 | ## License 81 | 82 | By contributing to Regenerator, you agree that your contributions will be 83 | licensed under the [MIT License](LICENSE). 84 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | regenerator [](https://travis-ci.org/facebook/regenerator) 2 | === 3 | 4 | This package implements a fully-functional source transformation that 5 | takes the syntax for generators/`yield` from [ECMAScript 2015 or ES2015](http://www.ecma-international.org/ecma-262/6.0/) and [Asynchronous Iteration](https://github.com/tc39/proposal-async-iteration) proposal and 6 | spits out efficient JS-of-today (ES5) that behaves the same way. 7 | 8 | A small runtime library (less than 1KB compressed) is required to provide the 9 | `wrapGenerator` function. You can install it either as a CommonJS module 10 | or as a standalone .js file, whichever you prefer. 11 | 12 | Installation 13 | --- 14 | 15 | From npm: 16 | ```sh 17 | npm install -g regenerator 18 | ``` 19 | 20 | From GitHub: 21 | ```sh 22 | cd path/to/node_modules 23 | git clone git://github.com/facebook/regenerator.git 24 | cd regenerator 25 | npm install . 26 | npm test 27 | ``` 28 | 29 | Usage 30 | --- 31 | 32 | You have several options for using this module. 33 | 34 | Simplest usage: 35 | ```sh 36 | regenerator es6.js > es5.js # Just the transform. 37 | regenerator --include-runtime es6.js > es5.js # Add the runtime too. 38 | regenerator src lib # Transform every .js file in src and output to lib. 39 | ``` 40 | 41 | Programmatic usage: 42 | ```js 43 | var es5Source = require("regenerator").compile(es6Source).code; 44 | var es5SourceWithRuntime = require("regenerator").compile(es6Source, { 45 | includeRuntime: true 46 | }).code; 47 | ``` 48 | 49 | AST transformation: 50 | ```js 51 | var recast = require("recast"); 52 | var ast = recast.parse(es6Source); 53 | ast = require("regenerator").transform(ast); 54 | var es5Source = recast.print(ast); 55 | ``` 56 | 57 | How can you get involved? 58 | --- 59 | 60 | The easiest way to get involved is to look for buggy examples using [the 61 | sandbox](http://facebook.github.io/regenerator/), and when you find 62 | something strange just click the "report a bug" link (the new issue form 63 | will be populated automatically with the problematic code). 64 | 65 | Alternatively, you can 66 | [fork](https://github.com/facebook/regenerator/fork) the repository, 67 | create some failing tests cases in [test/tests.es6.js](test/tests.es6.js), 68 | and send pull requests for me to fix. 69 | 70 | If you're feeling especially brave, you are more than welcome to dive into 71 | the transformer code and fix the bug(s) yourself, but I must warn you that 72 | the code could really benefit from [better implementation 73 | comments](https://github.com/facebook/regenerator/issues/7). 74 | -------------------------------------------------------------------------------- /bin/regenerator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // -*- mode: js -*- 3 | 4 | var compile = require("../main").compile; 5 | 6 | require("commoner").version( 7 | require("../package.json").version 8 | ).resolve(function(id) { 9 | return this.readModuleP(id); 10 | }).option( 11 | "-r, --include-runtime", 12 | "Prepend the runtime to the output." 13 | ).option( 14 | "--disable-async", 15 | "Disable transformation of async functions." 16 | ).process(function(id, source) { 17 | return compile(source, { 18 | includeRuntime: this.options.includeRuntime, 19 | disableAsync: this.options.disableAsync 20 | }).code; 21 | }); 22 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | 4 | test/mocha.js 5 | test/mocha.css 6 | 7 | test/tests.es5.js 8 | test/tests.browser.js 9 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/regenerator/cb755fd82c648cbc5307a5a2d61cdd598e698fc4/docs/.nojekyll -------------------------------------------------------------------------------- /docs/codemirror/lib/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 300px; 7 | } 8 | .CodeMirror-scroll { 9 | /* Set scrolling behaviour here */ 10 | overflow: auto; 11 | } 12 | 13 | /* PADDING */ 14 | 15 | .CodeMirror-lines { 16 | padding: 4px 0; /* Vertical padding around content */ 17 | } 18 | .CodeMirror pre { 19 | padding: 0 4px; /* Horizontal padding of content */ 20 | } 21 | 22 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 23 | background-color: white; /* The little square between H and V scrollbars */ 24 | } 25 | 26 | /* GUTTER */ 27 | 28 | .CodeMirror-gutters { 29 | border-right: 1px solid #ddd; 30 | background-color: #f7f7f7; 31 | white-space: nowrap; 32 | } 33 | .CodeMirror-linenumbers {} 34 | .CodeMirror-linenumber { 35 | padding: 0 3px 0 5px; 36 | min-width: 20px; 37 | text-align: right; 38 | color: #999; 39 | } 40 | 41 | /* CURSOR */ 42 | 43 | .CodeMirror div.CodeMirror-cursor { 44 | border-left: 1px solid black; 45 | z-index: 3; 46 | } 47 | /* Shown when moving in bi-directional text */ 48 | .CodeMirror div.CodeMirror-secondarycursor { 49 | border-left: 1px solid silver; 50 | } 51 | .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { 52 | width: auto; 53 | border: 0; 54 | background: #7e7; 55 | z-index: 1; 56 | } 57 | /* Can style cursor different in overwrite (non-insert) mode */ 58 | .CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {} 59 | 60 | .cm-tab { display: inline-block; } 61 | 62 | /* DEFAULT THEME */ 63 | 64 | .cm-s-default .cm-keyword {color: #708;} 65 | .cm-s-default .cm-atom {color: #219;} 66 | .cm-s-default .cm-number {color: #164;} 67 | .cm-s-default .cm-def {color: #00f;} 68 | .cm-s-default .cm-variable {color: black;} 69 | .cm-s-default .cm-variable-2 {color: #05a;} 70 | .cm-s-default .cm-variable-3 {color: #085;} 71 | .cm-s-default .cm-property {color: black;} 72 | .cm-s-default .cm-operator {color: black;} 73 | .cm-s-default .cm-comment {color: #a50;} 74 | .cm-s-default .cm-string {color: #a11;} 75 | .cm-s-default .cm-string-2 {color: #f50;} 76 | .cm-s-default .cm-meta {color: #555;} 77 | .cm-s-default .cm-qualifier {color: #555;} 78 | .cm-s-default .cm-builtin {color: #30a;} 79 | .cm-s-default .cm-bracket {color: #997;} 80 | .cm-s-default .cm-tag {color: #170;} 81 | .cm-s-default .cm-attribute {color: #00c;} 82 | .cm-s-default .cm-header {color: blue;} 83 | .cm-s-default .cm-quote {color: #090;} 84 | .cm-s-default .cm-hr {color: #999;} 85 | .cm-s-default .cm-link {color: #00c;} 86 | 87 | .cm-negative {color: #d44;} 88 | .cm-positive {color: #292;} 89 | .cm-header, .cm-strong {font-weight: bold;} 90 | .cm-em {font-style: italic;} 91 | .cm-link {text-decoration: underline;} 92 | 93 | .cm-s-default .cm-error {color: #f00;} 94 | .cm-invalidchar {color: #f00;} 95 | 96 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 97 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 98 | .CodeMirror-activeline-background {background: #e8f2ff;} 99 | 100 | /* STOP */ 101 | 102 | /* The rest of this file contains styles related to the mechanics of 103 | the editor. You probably shouldn't touch them. */ 104 | 105 | .CodeMirror { 106 | line-height: 1; 107 | position: relative; 108 | overflow: hidden; 109 | background: white; 110 | color: black; 111 | } 112 | 113 | .CodeMirror-scroll { 114 | /* 30px is the magic margin used to hide the element's real scrollbars */ 115 | /* See overflow: hidden in .CodeMirror */ 116 | margin-bottom: -30px; margin-right: -30px; 117 | padding-bottom: 30px; padding-right: 30px; 118 | height: 100%; 119 | outline: none; /* Prevent dragging from highlighting the element */ 120 | position: relative; 121 | -moz-box-sizing: content-box; 122 | box-sizing: content-box; 123 | } 124 | .CodeMirror-sizer { 125 | position: relative; 126 | } 127 | 128 | /* The fake, visible scrollbars. Used to force redraw during scrolling 129 | before actuall scrolling happens, thus preventing shaking and 130 | flickering artifacts. */ 131 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 132 | position: absolute; 133 | z-index: 6; 134 | display: none; 135 | } 136 | .CodeMirror-vscrollbar { 137 | right: 0; top: 0; 138 | overflow-x: hidden; 139 | overflow-y: scroll; 140 | } 141 | .CodeMirror-hscrollbar { 142 | bottom: 0; left: 0; 143 | overflow-y: hidden; 144 | overflow-x: scroll; 145 | } 146 | .CodeMirror-scrollbar-filler { 147 | right: 0; bottom: 0; 148 | } 149 | .CodeMirror-gutter-filler { 150 | left: 0; bottom: 0; 151 | } 152 | 153 | .CodeMirror-gutters { 154 | position: absolute; left: 0; top: 0; 155 | padding-bottom: 30px; 156 | z-index: 3; 157 | } 158 | .CodeMirror-gutter { 159 | white-space: normal; 160 | height: 100%; 161 | -moz-box-sizing: content-box; 162 | box-sizing: content-box; 163 | padding-bottom: 30px; 164 | margin-bottom: -32px; 165 | display: inline-block; 166 | /* Hack to make IE7 behave */ 167 | *zoom:1; 168 | *display:inline; 169 | } 170 | .CodeMirror-gutter-elt { 171 | position: absolute; 172 | cursor: default; 173 | z-index: 4; 174 | } 175 | 176 | .CodeMirror-lines { 177 | cursor: text; 178 | } 179 | .CodeMirror pre { 180 | /* Reset some styles that the rest of the page might have set */ 181 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; 182 | border-width: 0; 183 | background: transparent; 184 | font-family: inherit; 185 | font-size: inherit; 186 | margin: 0; 187 | white-space: pre; 188 | word-wrap: normal; 189 | line-height: inherit; 190 | color: inherit; 191 | z-index: 2; 192 | position: relative; 193 | overflow: visible; 194 | } 195 | .CodeMirror-wrap pre { 196 | word-wrap: break-word; 197 | white-space: pre-wrap; 198 | word-break: normal; 199 | } 200 | .CodeMirror-code pre { 201 | border-right: 30px solid transparent; 202 | width: -webkit-fit-content; 203 | width: -moz-fit-content; 204 | width: fit-content; 205 | } 206 | .CodeMirror-wrap .CodeMirror-code pre { 207 | border-right: none; 208 | width: auto; 209 | } 210 | .CodeMirror-linebackground { 211 | position: absolute; 212 | left: 0; right: 0; top: 0; bottom: 0; 213 | z-index: 0; 214 | } 215 | 216 | .CodeMirror-linewidget { 217 | position: relative; 218 | z-index: 2; 219 | overflow: auto; 220 | } 221 | 222 | .CodeMirror-widget {} 223 | 224 | .CodeMirror-wrap .CodeMirror-scroll { 225 | overflow-x: hidden; 226 | } 227 | 228 | .CodeMirror-measure { 229 | position: absolute; 230 | width: 100%; 231 | height: 0; 232 | overflow: hidden; 233 | visibility: hidden; 234 | } 235 | .CodeMirror-measure pre { position: static; } 236 | 237 | .CodeMirror div.CodeMirror-cursor { 238 | position: absolute; 239 | visibility: hidden; 240 | border-right: none; 241 | width: 0; 242 | } 243 | .CodeMirror-focused div.CodeMirror-cursor { 244 | visibility: visible; 245 | } 246 | 247 | .CodeMirror-selected { background: #d9d9d9; } 248 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 249 | 250 | .cm-searching { 251 | background: #ffa; 252 | background: rgba(255, 255, 0, .4); 253 | } 254 | 255 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */ 256 | .CodeMirror span { *vertical-align: text-bottom; } 257 | 258 | @media print { 259 | /* Hide the cursor when printing */ 260 | .CodeMirror div.CodeMirror-cursor { 261 | visibility: hidden; 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /docs/codemirror/mode/javascript.js: -------------------------------------------------------------------------------- 1 | // TODO actually recognize syntax of TypeScript constructs 2 | 3 | CodeMirror.defineMode("javascript", function(config, parserConfig) { 4 | var indentUnit = config.indentUnit; 5 | var statementIndent = parserConfig.statementIndent; 6 | var jsonMode = parserConfig.json; 7 | var isTS = parserConfig.typescript; 8 | 9 | // Tokenizer 10 | 11 | var keywords = function(){ 12 | function kw(type) {return {type: type, style: "keyword"};} 13 | var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); 14 | var operator = kw("operator"), atom = {type: "atom", style: "atom"}; 15 | 16 | var jsKeywords = { 17 | "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, 18 | "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, 19 | "var": kw("var"), "const": kw("var"), "let": kw("var"), 20 | "function": kw("function"), "catch": kw("catch"), 21 | "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), 22 | "in": operator, "typeof": operator, "instanceof": operator, 23 | "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, 24 | "this": kw("this") 25 | }; 26 | 27 | // Extend the 'normal' keywords with the TypeScript language extensions 28 | if (isTS) { 29 | var type = {type: "variable", style: "variable-3"}; 30 | var tsKeywords = { 31 | // object-like things 32 | "interface": kw("interface"), 33 | "class": kw("class"), 34 | "extends": kw("extends"), 35 | "constructor": kw("constructor"), 36 | 37 | // scope modifiers 38 | "public": kw("public"), 39 | "private": kw("private"), 40 | "protected": kw("protected"), 41 | "static": kw("static"), 42 | 43 | "super": kw("super"), 44 | 45 | // types 46 | "string": type, "number": type, "bool": type, "any": type 47 | }; 48 | 49 | for (var attr in tsKeywords) { 50 | jsKeywords[attr] = tsKeywords[attr]; 51 | } 52 | } 53 | 54 | return jsKeywords; 55 | }(); 56 | 57 | var isOperatorChar = /[+\-*&%=<>!?|~^]/; 58 | 59 | function chain(stream, state, f) { 60 | state.tokenize = f; 61 | return f(stream, state); 62 | } 63 | 64 | function nextUntilUnescaped(stream, end) { 65 | var escaped = false, next; 66 | while ((next = stream.next()) != null) { 67 | if (next == end && !escaped) 68 | return false; 69 | escaped = !escaped && next == "\\"; 70 | } 71 | return escaped; 72 | } 73 | 74 | // Used as scratch variables to communicate multiple values without 75 | // consing up tons of objects. 76 | var type, content; 77 | function ret(tp, style, cont) { 78 | type = tp; content = cont; 79 | return style; 80 | } 81 | function jsTokenBase(stream, state) { 82 | var ch = stream.next(); 83 | if (ch == '"' || ch == "'") 84 | return chain(stream, state, jsTokenString(ch)); 85 | else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) 86 | return ret("number", "number"); 87 | else if (/[\[\]{}\(\),;\:\.]/.test(ch)) 88 | return ret(ch); 89 | else if (ch == "0" && stream.eat(/x/i)) { 90 | stream.eatWhile(/[\da-f]/i); 91 | return ret("number", "number"); 92 | } 93 | else if (/\d/.test(ch)) { 94 | stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); 95 | return ret("number", "number"); 96 | } 97 | else if (ch == "/") { 98 | if (stream.eat("*")) { 99 | return chain(stream, state, jsTokenComment); 100 | } 101 | else if (stream.eat("/")) { 102 | stream.skipToEnd(); 103 | return ret("comment", "comment"); 104 | } 105 | else if (state.lastType == "operator" || state.lastType == "keyword c" || 106 | /^[\[{}\(,;:]$/.test(state.lastType)) { 107 | nextUntilUnescaped(stream, "/"); 108 | stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla 109 | return ret("regexp", "string-2"); 110 | } 111 | else { 112 | stream.eatWhile(isOperatorChar); 113 | return ret("operator", null, stream.current()); 114 | } 115 | } 116 | else if (ch == "#") { 117 | stream.skipToEnd(); 118 | return ret("error", "error"); 119 | } 120 | else if (isOperatorChar.test(ch)) { 121 | stream.eatWhile(isOperatorChar); 122 | return ret("operator", null, stream.current()); 123 | } 124 | else { 125 | stream.eatWhile(/[\w\$_]/); 126 | var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; 127 | return (known && state.lastType != ".") ? ret(known.type, known.style, word) : 128 | ret("variable", "variable", word); 129 | } 130 | } 131 | 132 | function jsTokenString(quote) { 133 | return function(stream, state) { 134 | if (!nextUntilUnescaped(stream, quote)) 135 | state.tokenize = jsTokenBase; 136 | return ret("string", "string"); 137 | }; 138 | } 139 | 140 | function jsTokenComment(stream, state) { 141 | var maybeEnd = false, ch; 142 | while (ch = stream.next()) { 143 | if (ch == "/" && maybeEnd) { 144 | state.tokenize = jsTokenBase; 145 | break; 146 | } 147 | maybeEnd = (ch == "*"); 148 | } 149 | return ret("comment", "comment"); 150 | } 151 | 152 | // Parser 153 | 154 | var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true}; 155 | 156 | function JSLexical(indented, column, type, align, prev, info) { 157 | this.indented = indented; 158 | this.column = column; 159 | this.type = type; 160 | this.prev = prev; 161 | this.info = info; 162 | if (align != null) this.align = align; 163 | } 164 | 165 | function inScope(state, varname) { 166 | for (var v = state.localVars; v; v = v.next) 167 | if (v.name == varname) return true; 168 | } 169 | 170 | function parseJS(state, style, type, content, stream) { 171 | var cc = state.cc; 172 | // Communicate our context to the combinators. 173 | // (Less wasteful than consing up a hundred closures on every call.) 174 | cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; 175 | 176 | if (!state.lexical.hasOwnProperty("align")) 177 | state.lexical.align = true; 178 | 179 | while(true) { 180 | var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; 181 | if (combinator(type, content)) { 182 | while(cc.length && cc[cc.length - 1].lex) 183 | cc.pop()(); 184 | if (cx.marked) return cx.marked; 185 | if (type == "variable" && inScope(state, content)) return "variable-2"; 186 | return style; 187 | } 188 | } 189 | } 190 | 191 | // Combinator utils 192 | 193 | var cx = {state: null, column: null, marked: null, cc: null}; 194 | function pass() { 195 | for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); 196 | } 197 | function cont() { 198 | pass.apply(null, arguments); 199 | return true; 200 | } 201 | function register(varname) { 202 | function inList(list) { 203 | for (var v = list; v; v = v.next) 204 | if (v.name == varname) return true; 205 | return false; 206 | } 207 | var state = cx.state; 208 | if (state.context) { 209 | cx.marked = "def"; 210 | if (inList(state.localVars)) return; 211 | state.localVars = {name: varname, next: state.localVars}; 212 | } else { 213 | if (inList(state.globalVars)) return; 214 | state.globalVars = {name: varname, next: state.globalVars}; 215 | } 216 | } 217 | 218 | // Combinators 219 | 220 | var defaultVars = {name: "this", next: {name: "arguments"}}; 221 | function pushcontext() { 222 | cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; 223 | cx.state.localVars = defaultVars; 224 | } 225 | function popcontext() { 226 | cx.state.localVars = cx.state.context.vars; 227 | cx.state.context = cx.state.context.prev; 228 | } 229 | function pushlex(type, info) { 230 | var result = function() { 231 | var state = cx.state, indent = state.indented; 232 | if (state.lexical.type == "stat") indent = state.lexical.indented; 233 | state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); 234 | }; 235 | result.lex = true; 236 | return result; 237 | } 238 | function poplex() { 239 | var state = cx.state; 240 | if (state.lexical.prev) { 241 | if (state.lexical.type == ")") 242 | state.indented = state.lexical.indented; 243 | state.lexical = state.lexical.prev; 244 | } 245 | } 246 | poplex.lex = true; 247 | 248 | function expect(wanted) { 249 | return function(type) { 250 | if (type == wanted) return cont(); 251 | else if (wanted == ";") return pass(); 252 | else return cont(arguments.callee); 253 | }; 254 | } 255 | 256 | function statement(type) { 257 | if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex); 258 | if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); 259 | if (type == "keyword b") return cont(pushlex("form"), statement, poplex); 260 | if (type == "{") return cont(pushlex("}"), block, poplex); 261 | if (type == ";") return cont(); 262 | if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse); 263 | if (type == "function") return cont(functiondef); 264 | if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), 265 | poplex, statement, poplex); 266 | if (type == "variable") return cont(pushlex("stat"), maybelabel); 267 | if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), 268 | block, poplex, poplex); 269 | if (type == "case") return cont(expression, expect(":")); 270 | if (type == "default") return cont(expect(":")); 271 | if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), 272 | statement, poplex, popcontext); 273 | return pass(pushlex("stat"), expression, expect(";"), poplex); 274 | } 275 | function expression(type) { 276 | return expressionInner(type, false); 277 | } 278 | function expressionNoComma(type) { 279 | return expressionInner(type, true); 280 | } 281 | function expressionInner(type, noComma) { 282 | var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; 283 | if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); 284 | if (type == "function") return cont(functiondef); 285 | if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); 286 | if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); 287 | if (type == "operator") return cont(noComma ? expressionNoComma : expression); 288 | if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop); 289 | if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop); 290 | return cont(); 291 | } 292 | function maybeexpression(type) { 293 | if (type.match(/[;\}\)\],]/)) return pass(); 294 | return pass(expression); 295 | } 296 | function maybeexpressionNoComma(type) { 297 | if (type.match(/[;\}\)\],]/)) return pass(); 298 | return pass(expressionNoComma); 299 | } 300 | 301 | function maybeoperatorComma(type, value) { 302 | if (type == ",") return cont(expression); 303 | return maybeoperatorNoComma(type, value, false); 304 | } 305 | function maybeoperatorNoComma(type, value, noComma) { 306 | var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; 307 | var expr = noComma == false ? expression : expressionNoComma; 308 | if (type == "operator") { 309 | if (/\+\+|--/.test(value)) return cont(me); 310 | if (value == "?") return cont(expression, expect(":"), expr); 311 | return cont(expr); 312 | } 313 | if (type == ";") return; 314 | if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me); 315 | if (type == ".") return cont(property, me); 316 | if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); 317 | } 318 | function maybelabel(type) { 319 | if (type == ":") return cont(poplex, statement); 320 | return pass(maybeoperatorComma, expect(";"), poplex); 321 | } 322 | function property(type) { 323 | if (type == "variable") {cx.marked = "property"; return cont();} 324 | } 325 | function objprop(type, value) { 326 | if (type == "variable") { 327 | cx.marked = "property"; 328 | if (value == "get" || value == "set") return cont(getterSetter); 329 | } else if (type == "number" || type == "string") { 330 | cx.marked = type + " property"; 331 | } 332 | if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expressionNoComma); 333 | } 334 | function getterSetter(type) { 335 | if (type == ":") return cont(expression); 336 | if (type != "variable") return cont(expect(":"), expression); 337 | cx.marked = "property"; 338 | return cont(functiondef); 339 | } 340 | function commasep(what, end) { 341 | function proceed(type) { 342 | if (type == ",") { 343 | var lex = cx.state.lexical; 344 | if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; 345 | return cont(what, proceed); 346 | } 347 | if (type == end) return cont(); 348 | return cont(expect(end)); 349 | } 350 | return function(type) { 351 | if (type == end) return cont(); 352 | else return pass(what, proceed); 353 | }; 354 | } 355 | function block(type) { 356 | if (type == "}") return cont(); 357 | return pass(statement, block); 358 | } 359 | function maybetype(type) { 360 | if (type == ":") return cont(typedef); 361 | return pass(); 362 | } 363 | function typedef(type) { 364 | if (type == "variable"){cx.marked = "variable-3"; return cont();} 365 | return pass(); 366 | } 367 | function vardef1(type, value) { 368 | if (type == "variable") { 369 | register(value); 370 | return isTS ? cont(maybetype, vardef2) : cont(vardef2); 371 | } 372 | return pass(); 373 | } 374 | function vardef2(type, value) { 375 | if (value == "=") return cont(expressionNoComma, vardef2); 376 | if (type == ",") return cont(vardef1); 377 | } 378 | function maybeelse(type, value) { 379 | if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex); 380 | } 381 | function forspec1(type) { 382 | if (type == "var") return cont(vardef1, expect(";"), forspec2); 383 | if (type == ";") return cont(forspec2); 384 | if (type == "variable") return cont(formaybein); 385 | return pass(expression, expect(";"), forspec2); 386 | } 387 | function formaybein(_type, value) { 388 | if (value == "in") return cont(expression); 389 | return cont(maybeoperatorComma, forspec2); 390 | } 391 | function forspec2(type, value) { 392 | if (type == ";") return cont(forspec3); 393 | if (value == "in") return cont(expression); 394 | return pass(expression, expect(";"), forspec3); 395 | } 396 | function forspec3(type) { 397 | if (type != ")") cont(expression); 398 | } 399 | function functiondef(type, value) { 400 | if (type == "variable") {register(value); return cont(functiondef);} 401 | if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext); 402 | } 403 | function funarg(type, value) { 404 | if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();} 405 | } 406 | 407 | // Interface 408 | 409 | return { 410 | startState: function(basecolumn) { 411 | return { 412 | tokenize: jsTokenBase, 413 | lastType: null, 414 | cc: [], 415 | lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), 416 | localVars: parserConfig.localVars, 417 | globalVars: parserConfig.globalVars, 418 | context: parserConfig.localVars && {vars: parserConfig.localVars}, 419 | indented: 0 420 | }; 421 | }, 422 | 423 | token: function(stream, state) { 424 | if (stream.sol()) { 425 | if (!state.lexical.hasOwnProperty("align")) 426 | state.lexical.align = false; 427 | state.indented = stream.indentation(); 428 | } 429 | if (state.tokenize != jsTokenComment && stream.eatSpace()) return null; 430 | var style = state.tokenize(stream, state); 431 | if (type == "comment") return style; 432 | state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; 433 | return parseJS(state, style, type, content, stream); 434 | }, 435 | 436 | indent: function(state, textAfter) { 437 | if (state.tokenize == jsTokenComment) return CodeMirror.Pass; 438 | if (state.tokenize != jsTokenBase) return 0; 439 | var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; 440 | // Kludge to prevent 'maybelse' from blocking lexical scope pops 441 | for (var i = state.cc.length - 1; i >= 0; --i) { 442 | var c = state.cc[i]; 443 | if (c == poplex) lexical = lexical.prev; 444 | else if (c != maybeelse || /^else\b/.test(textAfter)) break; 445 | } 446 | if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; 447 | if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") 448 | lexical = lexical.prev; 449 | var type = lexical.type, closing = firstChar == type; 450 | 451 | if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0); 452 | else if (type == "form" && firstChar == "{") return lexical.indented; 453 | else if (type == "form") return lexical.indented + indentUnit; 454 | else if (type == "stat") 455 | return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0); 456 | else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) 457 | return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); 458 | else if (lexical.align) return lexical.column + (closing ? 0 : 1); 459 | else return lexical.indented + (closing ? 0 : indentUnit); 460 | }, 461 | 462 | electricChars: ":{}", 463 | blockCommentStart: jsonMode ? null : "/*", 464 | blockCommentEnd: jsonMode ? null : "*/", 465 | lineComment: jsonMode ? null : "//", 466 | fold: "brace", 467 | 468 | helperType: jsonMode ? "json" : "javascript", 469 | jsonMode: jsonMode 470 | }; 471 | }); 472 | 473 | CodeMirror.defineMIME("text/javascript", "javascript"); 474 | CodeMirror.defineMIME("text/ecmascript", "javascript"); 475 | CodeMirror.defineMIME("application/javascript", "javascript"); 476 | CodeMirror.defineMIME("application/ecmascript", "javascript"); 477 | CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); 478 | CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); 479 | CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); 480 | CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); 481 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head profile="http://www.w3.org/2005/10/profile"> 4 | <title>Regenerator</title> 5 | <script src="codemirror/lib/codemirror.js"></script> 6 | <link rel="stylesheet" href="codemirror/lib/codemirror.css" /> 7 | <link rel="stylesheet" href="sandbox.css" /> 8 | <link rel="icon" type="image/png" href="yield_ahead.16px.png" /> 9 | <meta property="og:title" content="Regenerator" /> 10 | <meta property="og:type" content="website" /> 11 | <meta property="og:image" content="http://facebook.github.io/regenerator/yield_ahead.200px.png" /> 12 | <meta property="og:url" content="http://facebook.github.io/regenerator/" /> 13 | <script src="promise-6.0.0.js"></script> 14 | <script src="codemirror/mode/javascript.js"></script> 15 | <script src="bundle.js"></script> 16 | </head> 17 | <body> 18 | <div id="fb-root"></div> 19 | <script>(function(d, s, id) { 20 | var js, fjs = d.getElementsByTagName(s)[0]; 21 | if (d.getElementById(id)) return; 22 | js = d.createElement(s); js.id = id; 23 | js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=35921810593"; 24 | fjs.parentNode.insertBefore(js, fjs); 25 | }(document, 'script', 'facebook-jssdk')); 26 | </script> 27 | 28 | <a href="https://github.com/facebook/regenerator"> 29 | <img style="position: absolute; top: 0; right: 0; border: 0;" 30 | src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" 31 | alt="Fork me on GitHub" /> 32 | </a> 33 | 34 | <div id="content"> 35 | <h1>Let’s get serious about ES6 generator functions.</h1> 36 | 37 | <div class="fb-like" 38 | data-href="https://facebook.github.io/regenerator" 39 | data-colorscheme="light" 40 | data-layout="standard" 41 | data-action="like" 42 | data-show-faces="true" 43 | data-send="true"> 44 | </div> 45 | 46 | <p> 47 | Several months have passed since support 48 | for <a href="http://jlongster.com/2012/10/05/javascript-yield.html">generator 49 | functions</a> and the <code>yield</code> 50 | keyword <a href="http://wingolog.org/archives/2013/05/08/generators-in-v8">arrived</a> 51 | in Node.js v0.11.2. This news was 52 | <a href="http://devsmash.com/blog/whats-the-big-deal-with-generators">greeted</a> 53 | <a href="http://tobyho.com/2013/06/16/what-are-generators/">with</a> 54 | <a href="http://blog.alexmaccaw.com/how-yield-will-transform-node">great</a> 55 | <a href="http://almostobsolete.net/coffeescript-generators.html">excitement</a>, 56 | because generator syntax 57 | provides <a href="http://jlongster.com/A-Study-on-Solving-Callbacks-with-JavaScript-Generators">a 58 | much cleaner alternative</a> to using callbacks when writing 59 | asynchronous server-side code. 60 | </p> 61 | 62 | <p> 63 | One of the biggest benefits of using JavaScript on the server is 64 | that you can (in theory at least) run the very same code in a web 65 | browser. However, if you choose to use generator functions in 66 | Node.js, you end up with a bunch of code that can't be executed 67 | client-side. So there's the rub: native support for generators is 68 | only so exciting because it enables you to write really clean, 69 | powerful, unportable code. 70 | </p> 71 | 72 | <p> 73 | Some of us on the JavaScript Infrastructure team at Facebook got 74 | restless waiting for the future to get here, so we developed a tool 75 | called <a href="https://npmjs.org/package/regenerator">regenerator</a> 76 | to replace generator functions with efficient JavaScript-of-today 77 | (ECMAScript 5 or ES5 for short) that behaves the same way. Since 78 | the tool itself is implemented in ES5, you can try it right now, 79 | in this web browser, without leaving this web page. 80 | </p> 81 | 82 | <p> 83 | Regenerator relies heavily on 84 | the <a href="https://github.com/ariya/esprima/tree/harmony">Esprima</a> 85 | JavaScript parser and two libraries that we maintain for 86 | manipulating abstract syntax 87 | trees, <a href="https://npmjs.org/package/ast-types">ast-types</a> 88 | and <a href="https://npmjs.org/package/recast">recast</a>. It is 89 | similar in spirit to 90 | Google's <a href="https://github.com/google/traceur-compiler">Traceur 91 | Compiler</a>, which supports generators and many other ES6 92 | features through source transformation, but we would argue it 93 | compares favorably to 94 | Traceur <a href="javascript:toggleComparison()">in several 95 | ways</a><span id="punctuation">.</span> 96 | <ul id="comparison" class="hidden"> 97 | <li> 98 | Traceur supports <code>yield</code> expressions only on the 99 | right-hand sides of assignment statements and variable 100 | declarations, or as standalone statements, whereas regenerator 101 | allows a <code>yield</code> expression to appear anywhere an 102 | expression is permitted to appear. 103 | </li> 104 | <li> 105 | Regenerator aims to generate as little boilerplate as 106 | possible, whereas Traceur 107 | generates <a href="http://google.github.io/traceur-compiler/demo/repl.html#function%20*gen(x)%20%7B%0A%20%20return%20yield%20x%3B%0A%7D" 108 | target="_blank">twice as much code</a> for the simplest of generators. 109 | </li> 110 | <li> 111 | Regenerator transforms generator functions and nothing else, 112 | so you don't have to buy into the entire Traceur runtime just 113 | to get support for generators. 114 | </li> 115 | </ul> 116 | </p> 117 | 118 | <p> 119 | Please give the transformer a try below, and feel free to report 120 | bugs. Regenerator 121 | is <a href="https://github.com/facebook/regenerator/blob/master/test/tests.es6.js">well-tested</a> 122 | and feature-complete, but we'd love your help in making it 123 | completely bulletproof! 124 | </p> 125 | 126 | <div id="sandbox" class="clearfix"> 127 | <div id="inputWrapper"> 128 | <h2 class="clearfix">Input: 129 | <span class="hint"> 130 | <a href="javascript:reportBug()">report</a> a bug 131 | </span> 132 | </h2> 133 | </div> 134 | <div id="outputWrapper"> 135 | <h2 class="clearfix">Output: 136 | <span class="hint"> 137 | control-return to <a href="javascript:evaluateOutput()">run</a> 138 | </span> 139 | </h2> 140 | </div> 141 | </div> 142 | </div> 143 | 144 | <span id="attribution">An open-source project from Facebook.</span> 145 | <span id="copyright">© 2013 Facebook Inc.</span> 146 | 147 | <script src="sandbox.js"></script> 148 | </body> 149 | </html> 150 | -------------------------------------------------------------------------------- /docs/promise-6.0.0.js: -------------------------------------------------------------------------------- 1 | (function e(t, n, r) { 2 | function s(o, u) { 3 | if (!n[o]) { 4 | if (!t[o]) { 5 | var a = typeof require == "function" && require; 6 | if (!u && a) return a(o, !0); 7 | if (i) return i(o, !0); 8 | var f = new Error("Cannot find module '" + o + "'"); 9 | throw f.code = "MODULE_NOT_FOUND", f; 10 | } 11 | var l = n[o] = { 12 | exports: {} 13 | }; 14 | t[o][0].call(l.exports, function(e) { 15 | var n = t[o][1][e]; 16 | return s(n ? n : e); 17 | }, l, l.exports, e, t, n, r); 18 | } 19 | return n[o].exports; 20 | } 21 | var i = typeof require == "function" && require; 22 | for (var o = 0; o < r.length; o++) s(r[o]); 23 | return s; 24 | })({ 25 | 1: [ function(require, module, exports) { 26 | var process = module.exports = {}; 27 | process.nextTick = function() { 28 | var canSetImmediate = typeof window !== "undefined" && window.setImmediate; 29 | var canPost = typeof window !== "undefined" && window.postMessage && window.addEventListener; 30 | if (canSetImmediate) { 31 | return function(f) { 32 | return window.setImmediate(f); 33 | }; 34 | } 35 | if (canPost) { 36 | var queue = []; 37 | window.addEventListener("message", function(ev) { 38 | var source = ev.source; 39 | if ((source === window || source === null) && ev.data === "process-tick") { 40 | ev.stopPropagation(); 41 | if (queue.length > 0) { 42 | var fn = queue.shift(); 43 | fn(); 44 | } 45 | } 46 | }, true); 47 | return function nextTick(fn) { 48 | queue.push(fn); 49 | window.postMessage("process-tick", "*"); 50 | }; 51 | } 52 | return function nextTick(fn) { 53 | setTimeout(fn, 0); 54 | }; 55 | }(); 56 | process.title = "browser"; 57 | process.browser = true; 58 | process.env = {}; 59 | process.argv = []; 60 | function noop() {} 61 | process.on = noop; 62 | process.addListener = noop; 63 | process.once = noop; 64 | process.off = noop; 65 | process.removeListener = noop; 66 | process.removeAllListeners = noop; 67 | process.emit = noop; 68 | process.binding = function(name) { 69 | throw new Error("process.binding is not supported"); 70 | }; 71 | process.cwd = function() { 72 | return "/"; 73 | }; 74 | process.chdir = function(dir) { 75 | throw new Error("process.chdir is not supported"); 76 | }; 77 | }, {} ], 78 | 2: [ function(require, module, exports) { 79 | "use strict"; 80 | var asap = require("asap"); 81 | module.exports = Promise; 82 | function Promise(fn) { 83 | if (typeof this !== "object") throw new TypeError("Promises must be constructed via new"); 84 | if (typeof fn !== "function") throw new TypeError("not a function"); 85 | var state = null; 86 | var value = null; 87 | var deferreds = []; 88 | var self = this; 89 | this.then = function(onFulfilled, onRejected) { 90 | return new self.constructor(function(resolve, reject) { 91 | handle(new Handler(onFulfilled, onRejected, resolve, reject)); 92 | }); 93 | }; 94 | function handle(deferred) { 95 | if (state === null) { 96 | deferreds.push(deferred); 97 | return; 98 | } 99 | asap(function() { 100 | var cb = state ? deferred.onFulfilled : deferred.onRejected; 101 | if (cb === null) { 102 | (state ? deferred.resolve : deferred.reject)(value); 103 | return; 104 | } 105 | var ret; 106 | try { 107 | ret = cb(value); 108 | } catch (e) { 109 | deferred.reject(e); 110 | return; 111 | } 112 | deferred.resolve(ret); 113 | }); 114 | } 115 | function resolve(newValue) { 116 | try { 117 | if (newValue === self) throw new TypeError("A promise cannot be resolved with itself."); 118 | if (newValue && (typeof newValue === "object" || typeof newValue === "function")) { 119 | var then = newValue.then; 120 | if (typeof then === "function") { 121 | doResolve(then.bind(newValue), resolve, reject); 122 | return; 123 | } 124 | } 125 | state = true; 126 | value = newValue; 127 | finale(); 128 | } catch (e) { 129 | reject(e); 130 | } 131 | } 132 | function reject(newValue) { 133 | state = false; 134 | value = newValue; 135 | finale(); 136 | } 137 | function finale() { 138 | for (var i = 0, len = deferreds.length; i < len; i++) handle(deferreds[i]); 139 | deferreds = null; 140 | } 141 | doResolve(fn, resolve, reject); 142 | } 143 | function Handler(onFulfilled, onRejected, resolve, reject) { 144 | this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null; 145 | this.onRejected = typeof onRejected === "function" ? onRejected : null; 146 | this.resolve = resolve; 147 | this.reject = reject; 148 | } 149 | function doResolve(fn, onFulfilled, onRejected) { 150 | var done = false; 151 | try { 152 | fn(function(value) { 153 | if (done) return; 154 | done = true; 155 | onFulfilled(value); 156 | }, function(reason) { 157 | if (done) return; 158 | done = true; 159 | onRejected(reason); 160 | }); 161 | } catch (ex) { 162 | if (done) return; 163 | done = true; 164 | onRejected(ex); 165 | } 166 | } 167 | }, { 168 | asap: 4 169 | } ], 170 | 3: [ function(require, module, exports) { 171 | "use strict"; 172 | var Promise = require("./core.js"); 173 | var asap = require("asap"); 174 | module.exports = Promise; 175 | function ValuePromise(value) { 176 | this.then = function(onFulfilled) { 177 | if (typeof onFulfilled !== "function") return this; 178 | return new Promise(function(resolve, reject) { 179 | asap(function() { 180 | try { 181 | resolve(onFulfilled(value)); 182 | } catch (ex) { 183 | reject(ex); 184 | } 185 | }); 186 | }); 187 | }; 188 | } 189 | ValuePromise.prototype = Promise.prototype; 190 | var TRUE = new ValuePromise(true); 191 | var FALSE = new ValuePromise(false); 192 | var NULL = new ValuePromise(null); 193 | var UNDEFINED = new ValuePromise(undefined); 194 | var ZERO = new ValuePromise(0); 195 | var EMPTYSTRING = new ValuePromise(""); 196 | Promise.resolve = function(value) { 197 | if (value instanceof Promise) return value; 198 | if (value === null) return NULL; 199 | if (value === undefined) return UNDEFINED; 200 | if (value === true) return TRUE; 201 | if (value === false) return FALSE; 202 | if (value === 0) return ZERO; 203 | if (value === "") return EMPTYSTRING; 204 | if (typeof value === "object" || typeof value === "function") { 205 | try { 206 | var then = value.then; 207 | if (typeof then === "function") { 208 | return new Promise(then.bind(value)); 209 | } 210 | } catch (ex) { 211 | return new Promise(function(resolve, reject) { 212 | reject(ex); 213 | }); 214 | } 215 | } 216 | return new ValuePromise(value); 217 | }; 218 | Promise.all = function(arr) { 219 | var args = Array.prototype.slice.call(arr); 220 | return new Promise(function(resolve, reject) { 221 | if (args.length === 0) return resolve([]); 222 | var remaining = args.length; 223 | function res(i, val) { 224 | try { 225 | if (val && (typeof val === "object" || typeof val === "function")) { 226 | var then = val.then; 227 | if (typeof then === "function") { 228 | then.call(val, function(val) { 229 | res(i, val); 230 | }, reject); 231 | return; 232 | } 233 | } 234 | args[i] = val; 235 | if (--remaining === 0) { 236 | resolve(args); 237 | } 238 | } catch (ex) { 239 | reject(ex); 240 | } 241 | } 242 | for (var i = 0; i < args.length; i++) { 243 | res(i, args[i]); 244 | } 245 | }); 246 | }; 247 | Promise.reject = function(value) { 248 | return new Promise(function(resolve, reject) { 249 | reject(value); 250 | }); 251 | }; 252 | Promise.race = function(values) { 253 | return new Promise(function(resolve, reject) { 254 | values.forEach(function(value) { 255 | Promise.resolve(value).then(resolve, reject); 256 | }); 257 | }); 258 | }; 259 | Promise.prototype["catch"] = function(onRejected) { 260 | return this.then(null, onRejected); 261 | }; 262 | }, { 263 | "./core.js": 2, 264 | asap: 4 265 | } ], 266 | 4: [ function(require, module, exports) { 267 | (function(process) { 268 | var head = { 269 | task: void 0, 270 | next: null 271 | }; 272 | var tail = head; 273 | var flushing = false; 274 | var requestFlush = void 0; 275 | var isNodeJS = false; 276 | function flush() { 277 | while (head.next) { 278 | head = head.next; 279 | var task = head.task; 280 | head.task = void 0; 281 | var domain = head.domain; 282 | if (domain) { 283 | head.domain = void 0; 284 | domain.enter(); 285 | } 286 | try { 287 | task(); 288 | } catch (e) { 289 | if (isNodeJS) { 290 | if (domain) { 291 | domain.exit(); 292 | } 293 | setTimeout(flush, 0); 294 | if (domain) { 295 | domain.enter(); 296 | } 297 | throw e; 298 | } else { 299 | setTimeout(function() { 300 | throw e; 301 | }, 0); 302 | } 303 | } 304 | if (domain) { 305 | domain.exit(); 306 | } 307 | } 308 | flushing = false; 309 | } 310 | if (typeof process !== "undefined" && process.nextTick) { 311 | isNodeJS = true; 312 | requestFlush = function() { 313 | process.nextTick(flush); 314 | }; 315 | } else if (typeof setImmediate === "function") { 316 | if (typeof window !== "undefined") { 317 | requestFlush = setImmediate.bind(window, flush); 318 | } else { 319 | requestFlush = function() { 320 | setImmediate(flush); 321 | }; 322 | } 323 | } else if (typeof MessageChannel !== "undefined") { 324 | var channel = new MessageChannel(); 325 | channel.port1.onmessage = flush; 326 | requestFlush = function() { 327 | channel.port2.postMessage(0); 328 | }; 329 | } else { 330 | requestFlush = function() { 331 | setTimeout(flush, 0); 332 | }; 333 | } 334 | function asap(task) { 335 | tail = tail.next = { 336 | task: task, 337 | domain: isNodeJS && process.domain, 338 | next: null 339 | }; 340 | if (!flushing) { 341 | flushing = true; 342 | requestFlush(); 343 | } 344 | } 345 | module.exports = asap; 346 | }).call(this, require("_process")); 347 | }, { 348 | _process: 1 349 | } ], 350 | 5: [ function(require, module, exports) { 351 | if (typeof Promise.prototype.done !== "function") { 352 | Promise.prototype.done = function(onFulfilled, onRejected) { 353 | var self = arguments.length ? this.then.apply(this, arguments) : this; 354 | self.then(null, function(err) { 355 | setTimeout(function() { 356 | throw err; 357 | }, 0); 358 | }); 359 | }; 360 | } 361 | }, {} ], 362 | 6: [ function(require, module, exports) { 363 | var asap = require("asap"); 364 | if (typeof Promise === "undefined") { 365 | Promise = require("./lib/core.js"); 366 | require("./lib/es6-extensions.js"); 367 | } 368 | require("./polyfill-done.js"); 369 | }, { 370 | "./lib/core.js": 2, 371 | "./lib/es6-extensions.js": 3, 372 | "./polyfill-done.js": 5, 373 | asap: 4 374 | } ] 375 | }, {}, [ 6 ]); 376 | //# sourceMappingURL=/polyfills/promise-6.0.0.js.map -------------------------------------------------------------------------------- /docs/sandbox.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url("yield_ahead.200px.png"); 3 | background-position: 25px 25px; 4 | background-repeat: no-repeat; 5 | font-family: sans-serif; 6 | } 7 | 8 | #content { 9 | position: relative; 10 | margin: 0 250px 40px; 11 | min-width: 600px; 12 | max-width: 1024px; 13 | } 14 | 15 | h1, h2 { 16 | letter-spacing: -1px; 17 | } 18 | 19 | .CodeMirror { 20 | height: auto; 21 | } 22 | 23 | #sandbox { 24 | } 25 | 26 | #inputWrapper, #outputWrapper { 27 | width: 50%; 28 | box-sizing: border-box; 29 | -moz-box-sizing: border-box; 30 | } 31 | 32 | #inputWrapper { 33 | float: left; 34 | padding-right: 20px; 35 | } 36 | 37 | #outputWrapper { 38 | float: right; 39 | padding-left: 20px; 40 | } 41 | 42 | .CodeMirror-scroll { 43 | overflow-x: auto; 44 | overflow-y: hidden; 45 | } 46 | 47 | .hint { 48 | color: #999; 49 | float: right; 50 | } 51 | 52 | .hidden { 53 | display: none; 54 | } 55 | 56 | #attribution, #copyright { 57 | position: fixed; 58 | bottom: 25px; 59 | max-width: 250px; 60 | border: none; 61 | } 62 | 63 | #attribution { 64 | left: 25px; 65 | } 66 | 67 | #copyright { 68 | right: 25px; 69 | } 70 | 71 | .clearfix:after { 72 | clear: both; 73 | content: ""; 74 | display: table; 75 | } 76 | -------------------------------------------------------------------------------- /docs/sandbox.js: -------------------------------------------------------------------------------- 1 | // Make sure regeneratorRuntime is defined. 2 | regenerator.runtime(); 3 | 4 | var input = CodeMirror(function(input) { 5 | document.getElementById("inputWrapper").appendChild(input); 6 | }, { 7 | value: [ 8 | "function *range(max, step) {", 9 | " var count = 0;", 10 | " step = step || 1;", 11 | "", 12 | " for (var i = 0; i < max; i += step) {", 13 | " count++;", 14 | " yield i;", 15 | " }", 16 | "", 17 | " return count;", 18 | "}", 19 | "", 20 | "var gen = range(20, 3), info;", 21 | "", 22 | "while (!(info = gen.next()).done) {", 23 | " console.log(info.value);", 24 | "}", 25 | "", 26 | 'console.log("steps taken: " + info.value);' 27 | ].join("\n"), 28 | mode: "javascript", 29 | indentUnit: 2, 30 | autofocus: true 31 | }); 32 | 33 | var regeneratorOptions = { 34 | supportBlockBinding: true 35 | }; 36 | 37 | var output = CodeMirror(function(output) { 38 | document.getElementById("outputWrapper").appendChild(output); 39 | }, { 40 | value: regenerator.compile(input.getValue(), regeneratorOptions).code, 41 | readOnly: true 42 | }); 43 | 44 | var doc = document; 45 | var head = doc.documentElement.firstChild; 46 | var delayTimer; 47 | var delayMS = 100; 48 | 49 | CodeMirror.on(input.doc, "change", function(instance) { 50 | clearTimeout(delayTimer); 51 | delayTimer = setTimeout(function() { 52 | try { 53 | output.setValue(regenerator.compile( 54 | instance.getValue(), 55 | regeneratorOptions 56 | ).code); 57 | } catch (err) { 58 | console.log(err); 59 | } 60 | }, delayMS); 61 | }); 62 | 63 | function toggleComparison(a) { 64 | var ul = document.getElementById("comparison"); 65 | ul.setAttribute("class", ul.className.match(/\bhidden\b/) ? "" : "hidden"); 66 | 67 | var tn = document.getElementById("punctuation").firstChild; 68 | tn.nodeValue = tn.nodeValue.replace(/^\s*([\.:])/, function(_, punctuation) { 69 | return punctuation === "." ? ":" : "."; 70 | }); 71 | } 72 | 73 | function reportBug() { 74 | var doc = document; 75 | var form = doc.createElement("form"); 76 | 77 | var title = doc.createElement("input"); 78 | title.setAttribute("type", "hidden"); 79 | var body = title.cloneNode(false); 80 | 81 | title.setAttribute("name", "title"); 82 | title.setAttribute("value", "Sandbox bug report"); 83 | form.appendChild(title); 84 | 85 | body.setAttribute("name", "body"); 86 | body.setAttribute("value", [ 87 | "The following code does not transform as expected:", 88 | "```js", 89 | input.getValue(), 90 | "```" 91 | ].join("\n")); 92 | form.appendChild(body); 93 | 94 | form.setAttribute("action", "https://github.com/facebook/regenerator/issues/new"); 95 | form.setAttribute("method", "GET"); 96 | form.setAttribute("target", "_blank"); 97 | 98 | document.body.appendChild(form); 99 | form.submit(); 100 | form.parentNode.removeChild(form); 101 | } 102 | 103 | function evaluateOutput() { 104 | var script = doc.createElement("script"); 105 | script.appendChild(doc.createTextNode(output.getValue())); 106 | head.appendChild(script); 107 | } 108 | 109 | CodeMirror.on(document, "keydown", function(event) { 110 | if (event.ctrlKey && event.which === 13) { 111 | event.preventDefault(); 112 | evaluateOutput(); 113 | } 114 | }); 115 | -------------------------------------------------------------------------------- /docs/yield_ahead.16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/regenerator/cb755fd82c648cbc5307a5a2d61cdd598e698fc4/docs/yield_ahead.16px.png -------------------------------------------------------------------------------- /docs/yield_ahead.200px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/regenerator/cb755fd82c648cbc5307a5a2d61cdd598e698fc4/docs/yield_ahead.200px.png -------------------------------------------------------------------------------- /docs/yield_ahead.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <!-- Created with Inkscape (http://www.inkscape.org/) --> 3 | 4 | <svg 5 | xmlns:dc="http://purl.org/dc/elements/1.1/" 6 | xmlns:cc="http://creativecommons.org/ns#" 7 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 8 | xmlns:svg="http://www.w3.org/2000/svg" 9 | xmlns="http://www.w3.org/2000/svg" 10 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 11 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 12 | width="681.62006" 13 | height="681.62006" 14 | id="svg2" 15 | version="1.1" 16 | inkscape:version="0.48.4 r9939" 17 | sodipodi:docname="Ajax.svg"> 18 | <defs 19 | id="defs4" /> 20 | <sodipodi:namedview 21 | id="base" 22 | pagecolor="#ffffff" 23 | bordercolor="#666666" 24 | borderopacity="1.0" 25 | inkscape:pageopacity="0.0" 26 | inkscape:pageshadow="2" 27 | inkscape:zoom="0.49497475" 28 | inkscape:cx="107.29238" 29 | inkscape:cy="301.39794" 30 | inkscape:document-units="px" 31 | inkscape:current-layer="layer1" 32 | showgrid="false" 33 | fit-margin-top="0.2" 34 | fit-margin-left="0.2" 35 | fit-margin-bottom="0.2" 36 | fit-margin-right="0.2" 37 | inkscape:window-width="1280" 38 | inkscape:window-height="1001" 39 | inkscape:window-x="-8" 40 | inkscape:window-y="-8" 41 | inkscape:window-maximized="1" /> 42 | <metadata 43 | id="metadata7"> 44 | <rdf:RDF> 45 | <cc:Work 46 | rdf:about=""> 47 | <dc:format>image/svg+xml</dc:format> 48 | <dc:type 49 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 50 | <dc:title /> 51 | </cc:Work> 52 | </rdf:RDF> 53 | </metadata> 54 | <g 55 | inkscape:label="Layer 1" 56 | inkscape:groupmode="layer" 57 | id="layer1" 58 | transform="translate(89.359446,-81.801905)"> 59 | <path 60 | inkscape:connector-curvature="0" 61 | style="fill:#ffd033;fill-opacity:1;fill-rule:nonzero;stroke:none" 62 | d="m 582.90746,444.70907 c 12.20418,-12.20417 12.20416,-31.99003 10e-6,-44.19419 L 273.54755,91.154954 c -12.20396,-12.20396 -31.99001,-12.20417 -44.19418,0 L -80.00651,400.51482 c -12.20388,12.20388 -12.20395,31.99021 0,44.19418 l 309.35994,309.35991 c 12.20416,12.20419 31.99028,12.2039 44.19418,2e-5 z" 63 | id="path11-1" 64 | sodipodi:nodetypes="sssssssss" /> 65 | <path 66 | inkscape:connector-curvature="0" 67 | style="fill:#000000;fill-rule:nonzero;stroke:none" 68 | d="m 235.24596,748.17639 c 8.93529,8.93529 23.47368,8.93544 32.4091,2e-5 l 309.35987,-309.3599 c 8.93528,-8.93528 8.93528,-23.47381 0,-32.40909 L 267.65501,97.047504 c -8.93543,-8.93543 -23.47383,-8.93529 -32.40911,-1e-5 L -74.11397,406.40736 c -8.93542,8.93542 -8.93542,23.47369 0,32.40911 z" 69 | id="path13-7" 70 | sodipodi:nodetypes="sssssssss" /> 71 | <path 72 | inkscape:connector-curvature="0" 73 | style="fill:#ffd033;fill-opacity:1;fill-rule:nonzero;stroke:none" 74 | d="m 244.08479,739.3399 c 4.06148,4.06148 10.67045,4.06098 14.73143,0 L 568.17844,429.97768 c 4.06147,-4.06147 4.06148,-10.66996 0,-14.73144 L 258.81618,105.88399 c -4.06092,-4.06092 -10.66996,-4.06148 -14.73144,0 L -65.27747,415.2462 c -4.06099,4.06098 -4.06092,10.67052 0,14.73144 z" 75 | id="path15-4" 76 | sodipodi:nodetypes="sssssssss" /> 77 | <path 78 | inkscape:connector-curvature="0" 79 | style="fill:#000000;fill-rule:nonzero;stroke:none" 80 | d="M 122.09824,251.94924 251.45049,130.00191 380.80286,251.94924 c 1.01455,0.95484 1.64769,2.30995 1.64769,3.81214 0,2.89362 -2.34486,5.23998 -5.23998,5.23998 -0.21402,0 -0.42504,-0.015 -0.63314,-0.0391 l -83.20691,-10.42758 0,68.10747 -83.83995,0 0,-68.10747 -83.20539,10.42758 c -0.2081,0.0251 -0.41923,0.0391 -0.63465,0.0391 -2.89362,0 -5.23998,-2.34636 -5.23998,-5.23998 0,-1.50219 0.63465,-2.8573 1.64769,-3.81214 z" 81 | id="path17" /> 82 | <path 83 | style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 84 | d="m 409.8968,369.60756 c 5.78871,0 11.29932,2.2764 15.40447,6.3743 4.47972,4.4942 6.72903,10.6333 6.33634,16.9602 -0.2145,3.2689 -1.34141,6.3188 -2.95948,9.144 L 269.89042,677.12924 c -3.70879,6.4106 -11.15305,10.0927 -18.43985,10.0927 -7.28681,0 -14.73108,-3.6821 -18.43987,-10.0927 L 74.223,402.08606 c -1.61807,-2.8252 -2.74497,-5.8751 -2.9595,-9.144 -0.3927,-6.3269 1.85663,-12.466 6.33635,-16.9602 4.10517,-4.0979 9.61578,-6.3743 15.40448,-6.3743 z" 85 | id="path3354" 86 | inkscape:connector-curvature="0" 87 | sodipodi:nodetypes="cccccscccccc" /> 88 | <path 89 | style="fill:#c4122e;fill-opacity:1;fill-rule:evenodd;stroke:none" 90 | d="m 409.67012,377.74536 c 6.28324,0.015 12.20099,4.7205 13.39363,10.9274 0.60364,3.2289 0.0464,6.4597 -1.59357,9.2959 L 262.56764,673.01274 c -1.3999,2.4216 -3.71459,4.2381 -6.33634,5.1982 -1.50596,0.5518 -3.13865,0.8356 -4.78074,0.8726 -1.64213,-0.037 -3.27482,-0.3208 -4.78074,-0.8726 -2.62174,-0.9601 -4.93645,-2.7766 -6.33638,-5.1982 L 81.43089,397.96866 c -1.63988,-2.8362 -2.19717,-6.067 -1.59355,-9.2959 1.19264,-6.2069 7.11037,-10.9128 13.39363,-10.9274 z" 91 | id="path3362" 92 | inkscape:connector-curvature="0" 93 | sodipodi:nodetypes="cccccccccccc" /> 94 | <path 95 | style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" 96 | d="m 315.30719,432.11733 c 6.25058,0 12.08711,4.46009 13.27975,10.69971 0.62544,3.23613 0.28859,6.41238 -1.36593,9.29584 L 263.2884,563.09386 c -2.53803,4.38884 -6.67102,7.12067 -11.83799,7.09519 -5.16697,0.0255 -9.29991,-2.70635 -11.83794,-7.09519 L 175.67981,452.11288 c -1.6545,-2.88346 -1.99135,-6.05971 -1.36593,-9.29584 1.19268,-6.23962 7.02922,-10.69971 13.27982,-10.69971 z" 97 | id="path3366" 98 | inkscape:connector-curvature="0" 99 | sodipodi:nodetypes="cccccccccc" /> 100 | </g> 101 | </svg> 102 | -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | var types = require("recast").types; 10 | var n = types.namedTypes; 11 | var b = types.builders; 12 | var hasOwn = Object.prototype.hasOwnProperty; 13 | 14 | exports.defaults = function(obj) { 15 | var len = arguments.length; 16 | var extension; 17 | 18 | for (var i = 1; i < len; ++i) { 19 | if ((extension = arguments[i])) { 20 | for (var key in extension) { 21 | if (hasOwn.call(extension, key) && !hasOwn.call(obj, key)) { 22 | obj[key] = extension[key]; 23 | } 24 | } 25 | } 26 | } 27 | 28 | return obj; 29 | }; 30 | 31 | exports.runtimeProperty = function(name) { 32 | return b.memberExpression( 33 | b.identifier("regeneratorRuntime"), 34 | b.identifier(name), 35 | false 36 | ); 37 | }; 38 | 39 | // Inspired by the isReference function from ast-util: 40 | // https://github.com/eventualbuddha/ast-util/blob/9bf91c5ce8/lib/index.js#L466-L506 41 | exports.isReference = function(path, name) { 42 | var node = path.value; 43 | 44 | if (!n.Identifier.check(node)) { 45 | return false; 46 | } 47 | 48 | if (name && node.name !== name) { 49 | return false; 50 | } 51 | 52 | var parent = path.parent.value; 53 | 54 | switch (parent.type) { 55 | case "VariableDeclarator": 56 | return path.name === "init"; 57 | 58 | case "MemberExpression": 59 | return path.name === "object" || ( 60 | parent.computed && path.name === "property" 61 | ); 62 | 63 | case "FunctionExpression": 64 | case "FunctionDeclaration": 65 | case "ArrowFunctionExpression": 66 | if (path.name === "id") { 67 | return false; 68 | } 69 | 70 | if (path.parentPath.name === "params" && 71 | parent.params === path.parentPath.value && 72 | parent.params[path.name] === node) { 73 | return false; 74 | } 75 | 76 | return true; 77 | 78 | case "ClassDeclaration": 79 | case "ClassExpression": 80 | return path.name !== "id"; 81 | 82 | case "CatchClause": 83 | return path.name !== "param"; 84 | 85 | case "Property": 86 | case "MethodDefinition": 87 | return path.name !== "key"; 88 | 89 | case "ImportSpecifier": 90 | case "ImportDefaultSpecifier": 91 | case "ImportNamespaceSpecifier": 92 | case "LabeledStatement": 93 | return false; 94 | 95 | default: 96 | return true; 97 | } 98 | }; 99 | -------------------------------------------------------------------------------- /lib/visit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var recast = require("recast"); 9 | var types = recast.types; 10 | var n = types.namedTypes; 11 | var util = require("./util.js"); 12 | 13 | exports.transform = function transform(node, options) { 14 | options = util.defaults(options || {}, { 15 | includeRuntime: false 16 | }); 17 | 18 | var result = require("@babel/core").transformFromAstSync(node, null, { 19 | presets: [require("regenerator-preset")], 20 | code: false, 21 | ast: true, 22 | // The deep-clone utility that Babel uses (based on V8's Serialization API 23 | // https://nodejs.org/api/v8.html#v8_serialization_api in Node.js) removes 24 | // the prototypes from the cloned node.loc.lines objects that Recast uses 25 | // internally, leading to _blockHoist test failures in tests.transform.js. 26 | // Also, unless cloning is somehow truly necessary, it should be faster to 27 | // skip this step. 28 | cloneInputAst: false 29 | }); 30 | 31 | node = result.ast; 32 | 33 | if (options.includeRuntime === true) { 34 | injectRuntime(n.File.check(node) ? node.program : node); 35 | } 36 | 37 | return node; 38 | }; 39 | 40 | function injectRuntime(program) { 41 | n.Program.assert(program); 42 | 43 | // Include the runtime by modifying the AST rather than by concatenating 44 | // strings. This technique will allow for more accurate source mapping. 45 | var runtimePath = require("..").runtime.path; 46 | var runtime = fs.readFileSync(runtimePath, "utf8"); 47 | var runtimeBody = recast.parse(runtime, { 48 | sourceFileName: runtimePath 49 | }).program.body; 50 | 51 | var body = program.body; 52 | body.unshift.apply(body, runtimeBody); 53 | } 54 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var fs = require("fs"); 9 | var through = require("through"); 10 | var transform = require("./lib/visit").transform; 11 | var utils = require("./lib/util"); 12 | 13 | function exports(file, options) { 14 | var data = []; 15 | return through(write, end); 16 | 17 | function write(buf) { 18 | data.push(buf); 19 | } 20 | 21 | function end() { 22 | try { 23 | this.queue(compile(data.join(""), options).code); 24 | this.queue(null); 25 | } catch (e) { this.emit('error', e); } 26 | } 27 | } 28 | 29 | // To get a writable stream for use as a browserify transform, call 30 | // require("regenerator")(). 31 | module.exports = exports; 32 | 33 | // To include the runtime globally in the current node process, call 34 | // require("regenerator").runtime(). 35 | function runtime() { 36 | regeneratorRuntime = require("regenerator-runtime"); 37 | } 38 | exports.runtime = runtime; 39 | runtime.path = require("regenerator-runtime/path.js").path; 40 | 41 | var cachedRuntimeCode; 42 | function getRuntimeCode() { 43 | return cachedRuntimeCode || 44 | (cachedRuntimeCode = fs.readFileSync(runtime.path, "utf8")); 45 | } 46 | 47 | var transformOptions = { 48 | presets: [require("regenerator-preset")], 49 | parserOpts: { 50 | sourceType: "module", 51 | allowImportExportEverywhere: true, 52 | allowReturnOutsideFunction: true, 53 | allowSuperOutsideMethod: true, 54 | strictMode: false, 55 | plugins: ["*", "jsx", "flow"] 56 | } 57 | }; 58 | 59 | function compile(source, options) { 60 | var result; 61 | 62 | options = utils.defaults(options || {}, { 63 | includeRuntime: false 64 | }); 65 | 66 | var result = require("@babel/core").transformSync( 67 | source, 68 | transformOptions 69 | ); 70 | 71 | if (options.includeRuntime === true) { 72 | result.code = getRuntimeCode() + "\n" + result.code; 73 | } 74 | 75 | return result; 76 | } 77 | 78 | // Allow packages that depend on Regenerator to use the same copy of 79 | // ast-types, in case multiple versions are installed by NPM. 80 | exports.types = require("recast").types; 81 | 82 | // Transforms a string of source code, returning a { code, map? } result. 83 | exports.compile = compile; 84 | 85 | // To modify an AST directly, call require("regenerator").transform(ast). 86 | exports.transform = transform; 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Ben Newman <bn@cs.stanford.edu>", 3 | "name": "regenerator", 4 | "description": "Source transformer enabling ECMAScript 6 generator functions (yield) in JavaScript-of-today (ES5)", 5 | "keywords": [ 6 | "generator", 7 | "yield", 8 | "coroutine", 9 | "rewriting", 10 | "transformation", 11 | "syntax", 12 | "codegen", 13 | "rewriting", 14 | "refactoring", 15 | "transpiler", 16 | "desugaring", 17 | "ES6" 18 | ], 19 | "version": "0.14.12", 20 | "homepage": "http://github.com/facebook/regenerator", 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/facebook/regenerator.git" 24 | }, 25 | "main": "main.js", 26 | "bin": "bin/regenerator", 27 | "scripts": { 28 | "test": "test/run.sh" 29 | }, 30 | "dependencies": { 31 | "@babel/core": "^7.8.4", 32 | "@babel/runtime": "^7.8.4", 33 | "@babel/types": "^7.8.3", 34 | "commoner": "^0.10.8", 35 | "recast": "^0.23.3", 36 | "regenerator-preset": "^0.14.1", 37 | "regenerator-runtime": "^0.14.1", 38 | "regenerator-transform": "^0.15.2", 39 | "through": "^2.3.8" 40 | }, 41 | "devDependencies": { 42 | "@babel/cli": "^7.8.4", 43 | "@babel/parser": "^7.8.4", 44 | "@babel/plugin-transform-modules-commonjs": "^7.8.3", 45 | "@babel/plugin-transform-parameters": "^7.8.4", 46 | "babel-check-duplicated-nodes": "^1.0.0", 47 | "browserify": "^17.0.0", 48 | "mocha": "^10.0.0", 49 | "promise": "^8.0.3", 50 | "semver": "^7.1.3", 51 | "uglify-js": "^3.14.0" 52 | }, 53 | "license": "MIT", 54 | "engines": { 55 | "node": ">= 0.6" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/preset/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /packages/preset/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/preset/README.md: -------------------------------------------------------------------------------- 1 | # regenerator-preset 2 | 3 | Babel preset for easy use of [regenerator-transform](https://github.com/facebook/regenerator/tree/master/packages/regenerator-transform). 4 | -------------------------------------------------------------------------------- /packages/preset/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | module.exports = { 9 | plugins: [ 10 | require("@babel/plugin-syntax-async-generators"), 11 | require("@babel/plugin-proposal-function-sent"), 12 | require("@babel/plugin-transform-classes"), 13 | require("@babel/plugin-transform-arrow-functions"), 14 | require("@babel/plugin-transform-block-scoping"), 15 | require("@babel/plugin-transform-for-of"), 16 | require("regenerator-transform").default 17 | ] 18 | }; 19 | -------------------------------------------------------------------------------- /packages/preset/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "regenerator-preset", 3 | "author": "Ben Newman <bn@cs.stanford.edu>", 4 | "description": "Babel preset for easy use of regenerator-transform.", 5 | "version": "0.14.1", 6 | "main": "index.js", 7 | "keywords": [ 8 | "regenerator", 9 | "runtime", 10 | "generator", 11 | "async" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/facebook/regenerator/tree/main/packages/preset" 16 | }, 17 | "license": "MIT", 18 | "dependencies": { 19 | "@babel/plugin-proposal-function-sent": "^7.8.3", 20 | "@babel/plugin-syntax-async-generators": "^7.8.4", 21 | "@babel/plugin-transform-arrow-functions": "^7.8.3", 22 | "@babel/plugin-transform-block-scoping": "^7.8.3", 23 | "@babel/plugin-transform-classes": "^7.8.3", 24 | "@babel/plugin-transform-for-of": "^7.8.4", 25 | "regenerator-transform": "^0.15.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | .idea 4 | -------------------------------------------------------------------------------- /packages/runtime/.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /test 3 | -------------------------------------------------------------------------------- /packages/runtime/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/runtime/README.md: -------------------------------------------------------------------------------- 1 | # regenerator-runtime 2 | 3 | Standalone runtime for 4 | [Regenerator](https://github.com/facebook/regenerator)-compiled generator 5 | and `async` functions. 6 | 7 | To import the runtime as a module (recommended), either of the following 8 | import styles will work: 9 | ```js 10 | // CommonJS 11 | const regeneratorRuntime = require("regenerator-runtime"); 12 | 13 | // ECMAScript 2015 14 | import regeneratorRuntime from "regenerator-runtime"; 15 | ``` 16 | 17 | To ensure that `regeneratorRuntime` is defined globally, either of the 18 | following styles will work: 19 | ```js 20 | // CommonJS 21 | require("regenerator-runtime/runtime"); 22 | 23 | // ECMAScript 2015 24 | import "regenerator-runtime/runtime.js"; 25 | ``` 26 | 27 | To get the absolute file system path of `runtime.js`, evaluate the 28 | following expression: 29 | ```js 30 | require("regenerator-runtime/path").path 31 | ``` 32 | -------------------------------------------------------------------------------- /packages/runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "regenerator-runtime", 3 | "author": "Ben Newman <bn@cs.stanford.edu>", 4 | "description": "Runtime for Regenerator-compiled generator and async functions.", 5 | "version": "0.14.1", 6 | "main": "runtime.js", 7 | "keywords": [ 8 | "regenerator", 9 | "runtime", 10 | "generator", 11 | "async" 12 | ], 13 | "sideEffects": true, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/facebook/regenerator/tree/main/packages/runtime" 17 | }, 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /packages/runtime/path.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | exports.path = require("path").join( 9 | __dirname, 10 | "runtime.js" 11 | ); 12 | -------------------------------------------------------------------------------- /packages/runtime/runtime.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var runtime = (function (exports) { 9 | "use strict"; 10 | 11 | var Op = Object.prototype; 12 | var hasOwn = Op.hasOwnProperty; 13 | var defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }; 14 | var undefined; // More compressible than void 0. 15 | var $Symbol = typeof Symbol === "function" ? Symbol : {}; 16 | var iteratorSymbol = $Symbol.iterator || "@@iterator"; 17 | var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator"; 18 | var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; 19 | 20 | function define(obj, key, value) { 21 | Object.defineProperty(obj, key, { 22 | value: value, 23 | enumerable: true, 24 | configurable: true, 25 | writable: true 26 | }); 27 | return obj[key]; 28 | } 29 | try { 30 | // IE 8 has a broken Object.defineProperty that only works on DOM objects. 31 | define({}, ""); 32 | } catch (err) { 33 | define = function(obj, key, value) { 34 | return obj[key] = value; 35 | }; 36 | } 37 | 38 | function wrap(innerFn, outerFn, self, tryLocsList) { 39 | // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. 40 | var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator; 41 | var generator = Object.create(protoGenerator.prototype); 42 | var context = new Context(tryLocsList || []); 43 | 44 | // The ._invoke method unifies the implementations of the .next, 45 | // .throw, and .return methods. 46 | defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }); 47 | 48 | return generator; 49 | } 50 | exports.wrap = wrap; 51 | 52 | // Try/catch helper to minimize deoptimizations. Returns a completion 53 | // record like context.tryEntries[i].completion. This interface could 54 | // have been (and was previously) designed to take a closure to be 55 | // invoked without arguments, but in all the cases we care about we 56 | // already have an existing method we want to call, so there's no need 57 | // to create a new function object. We can even get away with assuming 58 | // the method takes exactly one argument, since that happens to be true 59 | // in every case, so we don't have to touch the arguments object. The 60 | // only additional allocation required is the completion record, which 61 | // has a stable shape and so hopefully should be cheap to allocate. 62 | function tryCatch(fn, obj, arg) { 63 | try { 64 | return { type: "normal", arg: fn.call(obj, arg) }; 65 | } catch (err) { 66 | return { type: "throw", arg: err }; 67 | } 68 | } 69 | 70 | var GenStateSuspendedStart = "suspendedStart"; 71 | var GenStateSuspendedYield = "suspendedYield"; 72 | var GenStateExecuting = "executing"; 73 | var GenStateCompleted = "completed"; 74 | 75 | // Returning this object from the innerFn has the same effect as 76 | // breaking out of the dispatch switch statement. 77 | var ContinueSentinel = {}; 78 | 79 | // Dummy constructor functions that we use as the .constructor and 80 | // .constructor.prototype properties for functions that return Generator 81 | // objects. For full spec compliance, you may wish to configure your 82 | // minifier not to mangle the names of these two functions. 83 | function Generator() {} 84 | function GeneratorFunction() {} 85 | function GeneratorFunctionPrototype() {} 86 | 87 | // This is a polyfill for %IteratorPrototype% for environments that 88 | // don't natively support it. 89 | var IteratorPrototype = {}; 90 | define(IteratorPrototype, iteratorSymbol, function () { 91 | return this; 92 | }); 93 | 94 | var getProto = Object.getPrototypeOf; 95 | var NativeIteratorPrototype = getProto && getProto(getProto(values([]))); 96 | if (NativeIteratorPrototype && 97 | NativeIteratorPrototype !== Op && 98 | hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) { 99 | // This environment has a native %IteratorPrototype%; use it instead 100 | // of the polyfill. 101 | IteratorPrototype = NativeIteratorPrototype; 102 | } 103 | 104 | var Gp = GeneratorFunctionPrototype.prototype = 105 | Generator.prototype = Object.create(IteratorPrototype); 106 | GeneratorFunction.prototype = GeneratorFunctionPrototype; 107 | defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: true }); 108 | defineProperty( 109 | GeneratorFunctionPrototype, 110 | "constructor", 111 | { value: GeneratorFunction, configurable: true } 112 | ); 113 | GeneratorFunction.displayName = define( 114 | GeneratorFunctionPrototype, 115 | toStringTagSymbol, 116 | "GeneratorFunction" 117 | ); 118 | 119 | // Helper for defining the .next, .throw, and .return methods of the 120 | // Iterator interface in terms of a single ._invoke method. 121 | function defineIteratorMethods(prototype) { 122 | ["next", "throw", "return"].forEach(function(method) { 123 | define(prototype, method, function(arg) { 124 | return this._invoke(method, arg); 125 | }); 126 | }); 127 | } 128 | 129 | exports.isGeneratorFunction = function(genFun) { 130 | var ctor = typeof genFun === "function" && genFun.constructor; 131 | return ctor 132 | ? ctor === GeneratorFunction || 133 | // For the native GeneratorFunction constructor, the best we can 134 | // do is to check its .name property. 135 | (ctor.displayName || ctor.name) === "GeneratorFunction" 136 | : false; 137 | }; 138 | 139 | exports.mark = function(genFun) { 140 | if (Object.setPrototypeOf) { 141 | Object.setPrototypeOf(genFun, GeneratorFunctionPrototype); 142 | } else { 143 | genFun.__proto__ = GeneratorFunctionPrototype; 144 | define(genFun, toStringTagSymbol, "GeneratorFunction"); 145 | } 146 | genFun.prototype = Object.create(Gp); 147 | return genFun; 148 | }; 149 | 150 | // Within the body of any async function, `await x` is transformed to 151 | // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test 152 | // `hasOwn.call(value, "__await")` to determine if the yielded value is 153 | // meant to be awaited. 154 | exports.awrap = function(arg) { 155 | return { __await: arg }; 156 | }; 157 | 158 | function AsyncIterator(generator, PromiseImpl) { 159 | function invoke(method, arg, resolve, reject) { 160 | var record = tryCatch(generator[method], generator, arg); 161 | if (record.type === "throw") { 162 | reject(record.arg); 163 | } else { 164 | var result = record.arg; 165 | var value = result.value; 166 | if (value && 167 | typeof value === "object" && 168 | hasOwn.call(value, "__await")) { 169 | return PromiseImpl.resolve(value.__await).then(function(value) { 170 | invoke("next", value, resolve, reject); 171 | }, function(err) { 172 | invoke("throw", err, resolve, reject); 173 | }); 174 | } 175 | 176 | return PromiseImpl.resolve(value).then(function(unwrapped) { 177 | // When a yielded Promise is resolved, its final value becomes 178 | // the .value of the Promise<{value,done}> result for the 179 | // current iteration. 180 | result.value = unwrapped; 181 | resolve(result); 182 | }, function(error) { 183 | // If a rejected Promise was yielded, throw the rejection back 184 | // into the async generator function so it can be handled there. 185 | return invoke("throw", error, resolve, reject); 186 | }); 187 | } 188 | } 189 | 190 | var previousPromise; 191 | 192 | function enqueue(method, arg) { 193 | function callInvokeWithMethodAndArg() { 194 | return new PromiseImpl(function(resolve, reject) { 195 | invoke(method, arg, resolve, reject); 196 | }); 197 | } 198 | 199 | return previousPromise = 200 | // If enqueue has been called before, then we want to wait until 201 | // all previous Promises have been resolved before calling invoke, 202 | // so that results are always delivered in the correct order. If 203 | // enqueue has not been called before, then it is important to 204 | // call invoke immediately, without waiting on a callback to fire, 205 | // so that the async generator function has the opportunity to do 206 | // any necessary setup in a predictable way. This predictability 207 | // is why the Promise constructor synchronously invokes its 208 | // executor callback, and why async functions synchronously 209 | // execute code before the first await. Since we implement simple 210 | // async functions in terms of async generators, it is especially 211 | // important to get this right, even though it requires care. 212 | previousPromise ? previousPromise.then( 213 | callInvokeWithMethodAndArg, 214 | // Avoid propagating failures to Promises returned by later 215 | // invocations of the iterator. 216 | callInvokeWithMethodAndArg 217 | ) : callInvokeWithMethodAndArg(); 218 | } 219 | 220 | // Define the unified helper method that is used to implement .next, 221 | // .throw, and .return (see defineIteratorMethods). 222 | defineProperty(this, "_invoke", { value: enqueue }); 223 | } 224 | 225 | defineIteratorMethods(AsyncIterator.prototype); 226 | define(AsyncIterator.prototype, asyncIteratorSymbol, function () { 227 | return this; 228 | }); 229 | exports.AsyncIterator = AsyncIterator; 230 | 231 | // Note that simple async functions are implemented on top of 232 | // AsyncIterator objects; they just return a Promise for the value of 233 | // the final result produced by the iterator. 234 | exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) { 235 | if (PromiseImpl === void 0) PromiseImpl = Promise; 236 | 237 | var iter = new AsyncIterator( 238 | wrap(innerFn, outerFn, self, tryLocsList), 239 | PromiseImpl 240 | ); 241 | 242 | return exports.isGeneratorFunction(outerFn) 243 | ? iter // If outerFn is a generator, return the full iterator. 244 | : iter.next().then(function(result) { 245 | return result.done ? result.value : iter.next(); 246 | }); 247 | }; 248 | 249 | function makeInvokeMethod(innerFn, self, context) { 250 | var state = GenStateSuspendedStart; 251 | 252 | return function invoke(method, arg) { 253 | if (state === GenStateExecuting) { 254 | throw new Error("Generator is already running"); 255 | } 256 | 257 | if (state === GenStateCompleted) { 258 | if (method === "throw") { 259 | throw arg; 260 | } 261 | 262 | // Be forgiving, per GeneratorResume behavior specified since ES2015: 263 | // ES2015 spec, step 3: https://262.ecma-international.org/6.0/#sec-generatorresume 264 | // Latest spec, step 2: https://tc39.es/ecma262/#sec-generatorresume 265 | return doneResult(); 266 | } 267 | 268 | context.method = method; 269 | context.arg = arg; 270 | 271 | while (true) { 272 | var delegate = context.delegate; 273 | if (delegate) { 274 | var delegateResult = maybeInvokeDelegate(delegate, context); 275 | if (delegateResult) { 276 | if (delegateResult === ContinueSentinel) continue; 277 | return delegateResult; 278 | } 279 | } 280 | 281 | if (context.method === "next") { 282 | // Setting context._sent for legacy support of Babel's 283 | // function.sent implementation. 284 | context.sent = context._sent = context.arg; 285 | 286 | } else if (context.method === "throw") { 287 | if (state === GenStateSuspendedStart) { 288 | state = GenStateCompleted; 289 | throw context.arg; 290 | } 291 | 292 | context.dispatchException(context.arg); 293 | 294 | } else if (context.method === "return") { 295 | context.abrupt("return", context.arg); 296 | } 297 | 298 | state = GenStateExecuting; 299 | 300 | var record = tryCatch(innerFn, self, context); 301 | if (record.type === "normal") { 302 | // If an exception is thrown from innerFn, we leave state === 303 | // GenStateExecuting and loop back for another invocation. 304 | state = context.done 305 | ? GenStateCompleted 306 | : GenStateSuspendedYield; 307 | 308 | if (record.arg === ContinueSentinel) { 309 | continue; 310 | } 311 | 312 | return { 313 | value: record.arg, 314 | done: context.done 315 | }; 316 | 317 | } else if (record.type === "throw") { 318 | state = GenStateCompleted; 319 | // Dispatch the exception by looping back around to the 320 | // context.dispatchException(context.arg) call above. 321 | context.method = "throw"; 322 | context.arg = record.arg; 323 | } 324 | } 325 | }; 326 | } 327 | 328 | // Call delegate.iterator[context.method](context.arg) and handle the 329 | // result, either by returning a { value, done } result from the 330 | // delegate iterator, or by modifying context.method and context.arg, 331 | // setting context.delegate to null, and returning the ContinueSentinel. 332 | function maybeInvokeDelegate(delegate, context) { 333 | var methodName = context.method; 334 | var method = delegate.iterator[methodName]; 335 | if (method === undefined) { 336 | // A .throw or .return when the delegate iterator has no .throw 337 | // method, or a missing .next method, always terminate the 338 | // yield* loop. 339 | context.delegate = null; 340 | 341 | // Note: ["return"] must be used for ES3 parsing compatibility. 342 | if (methodName === "throw" && delegate.iterator["return"]) { 343 | // If the delegate iterator has a return method, give it a 344 | // chance to clean up. 345 | context.method = "return"; 346 | context.arg = undefined; 347 | maybeInvokeDelegate(delegate, context); 348 | 349 | if (context.method === "throw") { 350 | // If maybeInvokeDelegate(context) changed context.method from 351 | // "return" to "throw", let that override the TypeError below. 352 | return ContinueSentinel; 353 | } 354 | } 355 | if (methodName !== "return") { 356 | context.method = "throw"; 357 | context.arg = new TypeError( 358 | "The iterator does not provide a '" + methodName + "' method"); 359 | } 360 | 361 | return ContinueSentinel; 362 | } 363 | 364 | var record = tryCatch(method, delegate.iterator, context.arg); 365 | 366 | if (record.type === "throw") { 367 | context.method = "throw"; 368 | context.arg = record.arg; 369 | context.delegate = null; 370 | return ContinueSentinel; 371 | } 372 | 373 | var info = record.arg; 374 | 375 | if (! info) { 376 | context.method = "throw"; 377 | context.arg = new TypeError("iterator result is not an object"); 378 | context.delegate = null; 379 | return ContinueSentinel; 380 | } 381 | 382 | if (info.done) { 383 | // Assign the result of the finished delegate to the temporary 384 | // variable specified by delegate.resultName (see delegateYield). 385 | context[delegate.resultName] = info.value; 386 | 387 | // Resume execution at the desired location (see delegateYield). 388 | context.next = delegate.nextLoc; 389 | 390 | // If context.method was "throw" but the delegate handled the 391 | // exception, let the outer generator proceed normally. If 392 | // context.method was "next", forget context.arg since it has been 393 | // "consumed" by the delegate iterator. If context.method was 394 | // "return", allow the original .return call to continue in the 395 | // outer generator. 396 | if (context.method !== "return") { 397 | context.method = "next"; 398 | context.arg = undefined; 399 | } 400 | 401 | } else { 402 | // Re-yield the result returned by the delegate method. 403 | return info; 404 | } 405 | 406 | // The delegate iterator is finished, so forget it and continue with 407 | // the outer generator. 408 | context.delegate = null; 409 | return ContinueSentinel; 410 | } 411 | 412 | // Define Generator.prototype.{next,throw,return} in terms of the 413 | // unified ._invoke helper method. 414 | defineIteratorMethods(Gp); 415 | 416 | define(Gp, toStringTagSymbol, "Generator"); 417 | 418 | // A Generator should always return itself as the iterator object when the 419 | // @@iterator function is called on it. Some browsers' implementations of the 420 | // iterator prototype chain incorrectly implement this, causing the Generator 421 | // object to not be returned from this call. This ensures that doesn't happen. 422 | // See https://github.com/facebook/regenerator/issues/274 for more details. 423 | define(Gp, iteratorSymbol, function() { 424 | return this; 425 | }); 426 | 427 | define(Gp, "toString", function() { 428 | return "[object Generator]"; 429 | }); 430 | 431 | function pushTryEntry(locs) { 432 | var entry = { tryLoc: locs[0] }; 433 | 434 | if (1 in locs) { 435 | entry.catchLoc = locs[1]; 436 | } 437 | 438 | if (2 in locs) { 439 | entry.finallyLoc = locs[2]; 440 | entry.afterLoc = locs[3]; 441 | } 442 | 443 | this.tryEntries.push(entry); 444 | } 445 | 446 | function resetTryEntry(entry) { 447 | var record = entry.completion || {}; 448 | record.type = "normal"; 449 | delete record.arg; 450 | entry.completion = record; 451 | } 452 | 453 | function Context(tryLocsList) { 454 | // The root entry object (effectively a try statement without a catch 455 | // or a finally block) gives us a place to store values thrown from 456 | // locations where there is no enclosing try statement. 457 | this.tryEntries = [{ tryLoc: "root" }]; 458 | tryLocsList.forEach(pushTryEntry, this); 459 | this.reset(true); 460 | } 461 | 462 | exports.keys = function(val) { 463 | var object = Object(val); 464 | var keys = []; 465 | for (var key in object) { 466 | keys.push(key); 467 | } 468 | keys.reverse(); 469 | 470 | // Rather than returning an object with a next method, we keep 471 | // things simple and return the next function itself. 472 | return function next() { 473 | while (keys.length) { 474 | var key = keys.pop(); 475 | if (key in object) { 476 | next.value = key; 477 | next.done = false; 478 | return next; 479 | } 480 | } 481 | 482 | // To avoid creating an additional object, we just hang the .value 483 | // and .done properties off the next function object itself. This 484 | // also ensures that the minifier will not anonymize the function. 485 | next.done = true; 486 | return next; 487 | }; 488 | }; 489 | 490 | function values(iterable) { 491 | if (iterable != null) { 492 | var iteratorMethod = iterable[iteratorSymbol]; 493 | if (iteratorMethod) { 494 | return iteratorMethod.call(iterable); 495 | } 496 | 497 | if (typeof iterable.next === "function") { 498 | return iterable; 499 | } 500 | 501 | if (!isNaN(iterable.length)) { 502 | var i = -1, next = function next() { 503 | while (++i < iterable.length) { 504 | if (hasOwn.call(iterable, i)) { 505 | next.value = iterable[i]; 506 | next.done = false; 507 | return next; 508 | } 509 | } 510 | 511 | next.value = undefined; 512 | next.done = true; 513 | 514 | return next; 515 | }; 516 | 517 | return next.next = next; 518 | } 519 | } 520 | 521 | throw new TypeError(typeof iterable + " is not iterable"); 522 | } 523 | exports.values = values; 524 | 525 | function doneResult() { 526 | return { value: undefined, done: true }; 527 | } 528 | 529 | Context.prototype = { 530 | constructor: Context, 531 | 532 | reset: function(skipTempReset) { 533 | this.prev = 0; 534 | this.next = 0; 535 | // Resetting context._sent for legacy support of Babel's 536 | // function.sent implementation. 537 | this.sent = this._sent = undefined; 538 | this.done = false; 539 | this.delegate = null; 540 | 541 | this.method = "next"; 542 | this.arg = undefined; 543 | 544 | this.tryEntries.forEach(resetTryEntry); 545 | 546 | if (!skipTempReset) { 547 | for (var name in this) { 548 | // Not sure about the optimal order of these conditions: 549 | if (name.charAt(0) === "t" && 550 | hasOwn.call(this, name) && 551 | !isNaN(+name.slice(1))) { 552 | this[name] = undefined; 553 | } 554 | } 555 | } 556 | }, 557 | 558 | stop: function() { 559 | this.done = true; 560 | 561 | var rootEntry = this.tryEntries[0]; 562 | var rootRecord = rootEntry.completion; 563 | if (rootRecord.type === "throw") { 564 | throw rootRecord.arg; 565 | } 566 | 567 | return this.rval; 568 | }, 569 | 570 | dispatchException: function(exception) { 571 | if (this.done) { 572 | throw exception; 573 | } 574 | 575 | var context = this; 576 | function handle(loc, caught) { 577 | record.type = "throw"; 578 | record.arg = exception; 579 | context.next = loc; 580 | 581 | if (caught) { 582 | // If the dispatched exception was caught by a catch block, 583 | // then let that catch block handle the exception normally. 584 | context.method = "next"; 585 | context.arg = undefined; 586 | } 587 | 588 | return !! caught; 589 | } 590 | 591 | for (var i = this.tryEntries.length - 1; i >= 0; --i) { 592 | var entry = this.tryEntries[i]; 593 | var record = entry.completion; 594 | 595 | if (entry.tryLoc === "root") { 596 | // Exception thrown outside of any try block that could handle 597 | // it, so set the completion value of the entire function to 598 | // throw the exception. 599 | return handle("end"); 600 | } 601 | 602 | if (entry.tryLoc <= this.prev) { 603 | var hasCatch = hasOwn.call(entry, "catchLoc"); 604 | var hasFinally = hasOwn.call(entry, "finallyLoc"); 605 | 606 | if (hasCatch && hasFinally) { 607 | if (this.prev < entry.catchLoc) { 608 | return handle(entry.catchLoc, true); 609 | } else if (this.prev < entry.finallyLoc) { 610 | return handle(entry.finallyLoc); 611 | } 612 | 613 | } else if (hasCatch) { 614 | if (this.prev < entry.catchLoc) { 615 | return handle(entry.catchLoc, true); 616 | } 617 | 618 | } else if (hasFinally) { 619 | if (this.prev < entry.finallyLoc) { 620 | return handle(entry.finallyLoc); 621 | } 622 | 623 | } else { 624 | throw new Error("try statement without catch or finally"); 625 | } 626 | } 627 | } 628 | }, 629 | 630 | abrupt: function(type, arg) { 631 | for (var i = this.tryEntries.length - 1; i >= 0; --i) { 632 | var entry = this.tryEntries[i]; 633 | if (entry.tryLoc <= this.prev && 634 | hasOwn.call(entry, "finallyLoc") && 635 | this.prev < entry.finallyLoc) { 636 | var finallyEntry = entry; 637 | break; 638 | } 639 | } 640 | 641 | if (finallyEntry && 642 | (type === "break" || 643 | type === "continue") && 644 | finallyEntry.tryLoc <= arg && 645 | arg <= finallyEntry.finallyLoc) { 646 | // Ignore the finally entry if control is not jumping to a 647 | // location outside the try/catch block. 648 | finallyEntry = null; 649 | } 650 | 651 | var record = finallyEntry ? finallyEntry.completion : {}; 652 | record.type = type; 653 | record.arg = arg; 654 | 655 | if (finallyEntry) { 656 | this.method = "next"; 657 | this.next = finallyEntry.finallyLoc; 658 | return ContinueSentinel; 659 | } 660 | 661 | return this.complete(record); 662 | }, 663 | 664 | complete: function(record, afterLoc) { 665 | if (record.type === "throw") { 666 | throw record.arg; 667 | } 668 | 669 | if (record.type === "break" || 670 | record.type === "continue") { 671 | this.next = record.arg; 672 | } else if (record.type === "return") { 673 | this.rval = this.arg = record.arg; 674 | this.method = "return"; 675 | this.next = "end"; 676 | } else if (record.type === "normal" && afterLoc) { 677 | this.next = afterLoc; 678 | } 679 | 680 | return ContinueSentinel; 681 | }, 682 | 683 | finish: function(finallyLoc) { 684 | for (var i = this.tryEntries.length - 1; i >= 0; --i) { 685 | var entry = this.tryEntries[i]; 686 | if (entry.finallyLoc === finallyLoc) { 687 | this.complete(entry.completion, entry.afterLoc); 688 | resetTryEntry(entry); 689 | return ContinueSentinel; 690 | } 691 | } 692 | }, 693 | 694 | "catch": function(tryLoc) { 695 | for (var i = this.tryEntries.length - 1; i >= 0; --i) { 696 | var entry = this.tryEntries[i]; 697 | if (entry.tryLoc === tryLoc) { 698 | var record = entry.completion; 699 | if (record.type === "throw") { 700 | var thrown = record.arg; 701 | resetTryEntry(entry); 702 | } 703 | return thrown; 704 | } 705 | } 706 | 707 | // The context.catch method must only be called with a location 708 | // argument that corresponds to a known catch block. 709 | throw new Error("illegal catch attempt"); 710 | }, 711 | 712 | delegateYield: function(iterable, resultName, nextLoc) { 713 | this.delegate = { 714 | iterator: values(iterable), 715 | resultName: resultName, 716 | nextLoc: nextLoc 717 | }; 718 | 719 | if (this.method === "next") { 720 | // Deliberately forget the last sent value so that we don't 721 | // accidentally pass it on to the delegate. 722 | this.arg = undefined; 723 | } 724 | 725 | return ContinueSentinel; 726 | } 727 | }; 728 | 729 | // Regardless of whether this script is executing as a CommonJS module 730 | // or not, return the runtime object so that we can declare the variable 731 | // regeneratorRuntime in the outer scope, which allows this module to be 732 | // injected easily by `bin/regenerator --include-runtime script.js`. 733 | return exports; 734 | 735 | }( 736 | // If this script is executing as a CommonJS module, use module.exports 737 | // as the regeneratorRuntime namespace. Otherwise create a new empty 738 | // object. Either way, the resulting object will be used to initialize 739 | // the regeneratorRuntime variable at the top of this file. 740 | typeof module === "object" ? module.exports : {} 741 | )); 742 | 743 | try { 744 | regeneratorRuntime = runtime; 745 | } catch (accidentalStrictMode) { 746 | // This module should not be running in strict mode, so the above 747 | // assignment should always work unless something is misconfigured. Just 748 | // in case runtime.js accidentally runs in strict mode, in modern engines 749 | // we can explicitly access globalThis. In older engines we can escape 750 | // strict mode using a global Function call. This could conceivably fail 751 | // if a Content Security Policy forbids using Function, but in that case 752 | // the proper solution is to fix the accidental strict mode problem. If 753 | // you've misconfigured your bundler to force strict mode and applied a 754 | // CSP to forbid Function, and you're not willing to fix either of those 755 | // problems, please detail your unique predicament in a GitHub issue. 756 | if (typeof globalThis === "object") { 757 | globalThis.regeneratorRuntime = runtime; 758 | } else { 759 | Function("r", "regeneratorRuntime = r")(runtime); 760 | } 761 | } 762 | -------------------------------------------------------------------------------- /packages/transform/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | -------------------------------------------------------------------------------- /packages/transform/.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /packages/transform/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/transform/README.md: -------------------------------------------------------------------------------- 1 | # regenerator-transform 2 | 3 | Transform async/generator functions with [regenerator](https://github.com/facebook/regenerator) 4 | 5 | ## Installation 6 | 7 | ```sh 8 | $ npm install regenerator-transform 9 | ``` 10 | 11 | ## Usage 12 | 13 | ### Via `.babelrc` (Recommended) 14 | 15 | **.babelrc** 16 | 17 | ```js 18 | // without options 19 | { 20 | "plugins": ["regenerator-transform"] 21 | } 22 | // with options 23 | { 24 | "plugins": [ 25 | ["regenerator-transform", { 26 | asyncGenerators: false, // true by default 27 | generators: false, // true by default 28 | async: false // true by default 29 | }] 30 | ] 31 | } 32 | ``` 33 | 34 | ### Via CLI 35 | 36 | ```sh 37 | $ babel --plugins regenerator-transform script.js 38 | ``` 39 | 40 | ### Via Node API 41 | 42 | ```javascript 43 | require("@babel/core").transformSync("code", { 44 | plugins: ["regenerator-transform"] 45 | }); 46 | ``` 47 | -------------------------------------------------------------------------------- /packages/transform/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "regenerator-transform", 3 | "author": "Ben Newman <bn@cs.stanford.edu>", 4 | "description": "Explode async and generator functions into a state machine.", 5 | "version": "0.15.2", 6 | "main": "lib/index.js", 7 | "keywords": [ 8 | "regenerator", 9 | "runtime", 10 | "generator", 11 | "async" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/facebook/regenerator/tree/main/packages/transform" 16 | }, 17 | "license": "MIT", 18 | "scripts": { 19 | "prepublish": "npx babel src/ --out-dir lib/" 20 | }, 21 | "babel": { 22 | "plugins": [ 23 | "@babel/plugin-transform-runtime" 24 | ], 25 | "presets": [ 26 | [ 27 | "@babel/preset-env", 28 | { 29 | "loose": true 30 | } 31 | ] 32 | ] 33 | }, 34 | "dependencies": { 35 | "@babel/runtime": "^7.8.4" 36 | }, 37 | "devDependencies": { 38 | "@babel/cli": "^7.8.4", 39 | "@babel/core": "^7.8.4", 40 | "@babel/plugin-transform-runtime": "^7.8.3", 41 | "@babel/preset-env": "^7.8.4" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/transform/src/hoist.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import * as util from "./util"; 9 | let hasOwn = Object.prototype.hasOwnProperty; 10 | 11 | // The hoist function takes a FunctionExpression or FunctionDeclaration 12 | // and replaces any Declaration nodes in its body with assignments, then 13 | // returns a VariableDeclaration containing just the names of the removed 14 | // declarations. 15 | exports.hoist = function(funPath) { 16 | const t = util.getTypes(); 17 | t.assertFunction(funPath.node); 18 | 19 | let vars = {}; 20 | 21 | function varDeclToExpr({ node: vdec, scope }, includeIdentifiers) { 22 | t.assertVariableDeclaration(vdec); 23 | // TODO assert.equal(vdec.kind, "var"); 24 | let exprs = []; 25 | 26 | vdec.declarations.forEach(function(dec) { 27 | // Note: We duplicate 'dec.id' here to ensure that the variable declaration IDs don't 28 | // have the same 'loc' value, since that can make sourcemaps and retainLines behave poorly. 29 | vars[dec.id.name] = t.identifier(dec.id.name); 30 | 31 | // Remove the binding, to avoid "duplicate declaration" errors when it will 32 | // be injected again. 33 | scope.removeBinding(dec.id.name); 34 | 35 | if (dec.init) { 36 | exprs.push(t.assignmentExpression( 37 | "=", dec.id, dec.init 38 | )); 39 | } else if (includeIdentifiers) { 40 | exprs.push(dec.id); 41 | } 42 | }); 43 | 44 | if (exprs.length === 0) 45 | return null; 46 | 47 | if (exprs.length === 1) 48 | return exprs[0]; 49 | 50 | return t.sequenceExpression(exprs); 51 | } 52 | 53 | funPath.get("body").traverse({ 54 | VariableDeclaration: { 55 | exit: function(path) { 56 | let expr = varDeclToExpr(path, false); 57 | if (expr === null) { 58 | path.remove(); 59 | } else { 60 | // We don't need to traverse this expression any further because 61 | // there can't be any new declarations inside an expression. 62 | util.replaceWithOrRemove(path, t.expressionStatement(expr)); 63 | } 64 | 65 | // Since the original node has been either removed or replaced, 66 | // avoid traversing it any further. 67 | path.skip(); 68 | } 69 | }, 70 | 71 | ForStatement: function(path) { 72 | let init = path.get("init"); 73 | if (init.isVariableDeclaration()) { 74 | util.replaceWithOrRemove(init, varDeclToExpr(init, false)); 75 | } 76 | }, 77 | 78 | ForXStatement: function(path) { 79 | let left = path.get("left"); 80 | if (left.isVariableDeclaration()) { 81 | util.replaceWithOrRemove(left, varDeclToExpr(left, true)); 82 | } 83 | }, 84 | 85 | FunctionDeclaration: function(path) { 86 | let node = path.node; 87 | vars[node.id.name] = node.id; 88 | 89 | let assignment = t.expressionStatement( 90 | t.assignmentExpression( 91 | "=", 92 | t.clone(node.id), 93 | t.functionExpression( 94 | path.scope.generateUidIdentifierBasedOnNode(node), 95 | node.params, 96 | node.body, 97 | node.generator, 98 | node.expression 99 | ) 100 | ) 101 | ); 102 | 103 | if (path.parentPath.isBlockStatement()) { 104 | // Insert the assignment form before the first statement in the 105 | // enclosing block. 106 | path.parentPath.unshiftContainer("body", assignment); 107 | 108 | // Remove the function declaration now that we've inserted the 109 | // equivalent assignment form at the beginning of the block. 110 | path.remove(); 111 | } else { 112 | // If the parent node is not a block statement, then we can just 113 | // replace the declaration with the equivalent assignment form 114 | // without worrying about hoisting it. 115 | util.replaceWithOrRemove(path, assignment); 116 | } 117 | 118 | // Remove the binding, to avoid "duplicate declaration" errors when it will 119 | // be injected again. 120 | path.scope.removeBinding(node.id.name); 121 | 122 | // Don't hoist variables out of inner functions. 123 | path.skip(); 124 | }, 125 | 126 | FunctionExpression: function(path) { 127 | // Don't descend into nested function expressions. 128 | path.skip(); 129 | }, 130 | 131 | ArrowFunctionExpression: function(path) { 132 | // Don't descend into nested function expressions. 133 | path.skip(); 134 | } 135 | }); 136 | 137 | let paramNames = {}; 138 | funPath.get("params").forEach(function(paramPath) { 139 | let param = paramPath.node; 140 | if (t.isIdentifier(param)) { 141 | paramNames[param.name] = param; 142 | } else { 143 | // Variables declared by destructuring parameter patterns will be 144 | // harmlessly re-declared. 145 | } 146 | }); 147 | 148 | let declarations = []; 149 | 150 | Object.keys(vars).forEach(function(name) { 151 | if (!hasOwn.call(paramNames, name)) { 152 | declarations.push(t.variableDeclarator(vars[name], null)); 153 | } 154 | }); 155 | 156 | if (declarations.length === 0) { 157 | return null; // Be sure to handle this case! 158 | } 159 | 160 | return t.variableDeclaration("var", declarations); 161 | }; 162 | -------------------------------------------------------------------------------- /packages/transform/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import { getVisitor } from "./visit"; 9 | 10 | export default function (context) { 11 | const plugin = { 12 | visitor: getVisitor(context), 13 | }; 14 | 15 | // Some presets manually call child presets, but fail to pass along the 16 | // context object. Out of an abundance of caution, we verify that it 17 | // exists first to avoid causing unnecessary breaking changes. 18 | const version = context && context.version; 19 | 20 | // The "name" property is not allowed in older versions of Babel (6.x) 21 | // and will cause the plugin validator to throw an exception. 22 | if (version && parseInt(version, 10) >= 7) { 23 | plugin.name = "regenerator-transform"; 24 | } 25 | 26 | return plugin; 27 | } 28 | -------------------------------------------------------------------------------- /packages/transform/src/leap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import assert from "assert"; 9 | import { Emitter } from "./emit"; 10 | import { inherits } from "util"; 11 | import { getTypes } from "./util"; 12 | 13 | function Entry() { 14 | assert.ok(this instanceof Entry); 15 | } 16 | 17 | function FunctionEntry(returnLoc) { 18 | Entry.call(this); 19 | getTypes().assertLiteral(returnLoc); 20 | this.returnLoc = returnLoc; 21 | } 22 | 23 | inherits(FunctionEntry, Entry); 24 | exports.FunctionEntry = FunctionEntry; 25 | 26 | function LoopEntry(breakLoc, continueLoc, label) { 27 | Entry.call(this); 28 | 29 | const t = getTypes(); 30 | 31 | t.assertLiteral(breakLoc); 32 | t.assertLiteral(continueLoc); 33 | 34 | if (label) { 35 | t.assertIdentifier(label); 36 | } else { 37 | label = null; 38 | } 39 | 40 | this.breakLoc = breakLoc; 41 | this.continueLoc = continueLoc; 42 | this.label = label; 43 | } 44 | 45 | inherits(LoopEntry, Entry); 46 | exports.LoopEntry = LoopEntry; 47 | 48 | function SwitchEntry(breakLoc) { 49 | Entry.call(this); 50 | getTypes().assertLiteral(breakLoc); 51 | this.breakLoc = breakLoc; 52 | } 53 | 54 | inherits(SwitchEntry, Entry); 55 | exports.SwitchEntry = SwitchEntry; 56 | 57 | function TryEntry(firstLoc, catchEntry, finallyEntry) { 58 | Entry.call(this); 59 | 60 | const t = getTypes(); 61 | t.assertLiteral(firstLoc); 62 | 63 | if (catchEntry) { 64 | assert.ok(catchEntry instanceof CatchEntry); 65 | } else { 66 | catchEntry = null; 67 | } 68 | 69 | if (finallyEntry) { 70 | assert.ok(finallyEntry instanceof FinallyEntry); 71 | } else { 72 | finallyEntry = null; 73 | } 74 | 75 | // Have to have one or the other (or both). 76 | assert.ok(catchEntry || finallyEntry); 77 | 78 | this.firstLoc = firstLoc; 79 | this.catchEntry = catchEntry; 80 | this.finallyEntry = finallyEntry; 81 | } 82 | 83 | inherits(TryEntry, Entry); 84 | exports.TryEntry = TryEntry; 85 | 86 | function CatchEntry(firstLoc, paramId) { 87 | Entry.call(this); 88 | 89 | const t = getTypes(); 90 | 91 | t.assertLiteral(firstLoc); 92 | t.assertIdentifier(paramId); 93 | 94 | this.firstLoc = firstLoc; 95 | this.paramId = paramId; 96 | } 97 | 98 | inherits(CatchEntry, Entry); 99 | exports.CatchEntry = CatchEntry; 100 | 101 | function FinallyEntry(firstLoc, afterLoc) { 102 | Entry.call(this); 103 | const t = getTypes(); 104 | t.assertLiteral(firstLoc); 105 | t.assertLiteral(afterLoc); 106 | this.firstLoc = firstLoc; 107 | this.afterLoc = afterLoc; 108 | } 109 | 110 | inherits(FinallyEntry, Entry); 111 | exports.FinallyEntry = FinallyEntry; 112 | 113 | function LabeledEntry(breakLoc, label) { 114 | Entry.call(this); 115 | 116 | const t = getTypes(); 117 | 118 | t.assertLiteral(breakLoc); 119 | t.assertIdentifier(label); 120 | 121 | this.breakLoc = breakLoc; 122 | this.label = label; 123 | } 124 | 125 | inherits(LabeledEntry, Entry); 126 | exports.LabeledEntry = LabeledEntry; 127 | 128 | function LeapManager(emitter) { 129 | assert.ok(this instanceof LeapManager); 130 | 131 | assert.ok(emitter instanceof Emitter); 132 | 133 | this.emitter = emitter; 134 | this.entryStack = [new FunctionEntry(emitter.finalLoc)]; 135 | } 136 | 137 | let LMp = LeapManager.prototype; 138 | exports.LeapManager = LeapManager; 139 | 140 | LMp.withEntry = function(entry, callback) { 141 | assert.ok(entry instanceof Entry); 142 | this.entryStack.push(entry); 143 | try { 144 | callback.call(this.emitter); 145 | } finally { 146 | let popped = this.entryStack.pop(); 147 | assert.strictEqual(popped, entry); 148 | } 149 | }; 150 | 151 | LMp._findLeapLocation = function(property, label) { 152 | for (let i = this.entryStack.length - 1; i >= 0; --i) { 153 | let entry = this.entryStack[i]; 154 | let loc = entry[property]; 155 | if (loc) { 156 | if (label) { 157 | if (entry.label && 158 | entry.label.name === label.name) { 159 | return loc; 160 | } 161 | } else if (entry instanceof LabeledEntry) { 162 | // Ignore LabeledEntry entries unless we are actually breaking to 163 | // a label. 164 | } else { 165 | return loc; 166 | } 167 | } 168 | } 169 | 170 | return null; 171 | }; 172 | 173 | LMp.getBreakLoc = function(label) { 174 | return this._findLeapLocation("breakLoc", label); 175 | }; 176 | 177 | LMp.getContinueLoc = function(label) { 178 | return this._findLeapLocation("continueLoc", label); 179 | }; 180 | -------------------------------------------------------------------------------- /packages/transform/src/meta.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import assert from "assert"; 9 | import { getTypes } from "./util.js"; 10 | 11 | const mMap = new WeakMap(); 12 | function m(node) { 13 | if (!mMap.has(node)) { 14 | mMap.set(node, {}); 15 | } 16 | return mMap.get(node); 17 | } 18 | 19 | const hasOwn = Object.prototype.hasOwnProperty; 20 | 21 | function makePredicate(propertyName, knownTypes) { 22 | function onlyChildren(node) { 23 | const t = getTypes(); 24 | t.assertNode(node); 25 | 26 | // Assume no side effects until we find out otherwise. 27 | let result = false; 28 | 29 | function check(child) { 30 | if (result) { 31 | // Do nothing. 32 | } else if (Array.isArray(child)) { 33 | child.some(check); 34 | } else if (t.isNode(child)) { 35 | assert.strictEqual(result, false); 36 | result = predicate(child); 37 | } 38 | return result; 39 | } 40 | 41 | let keys = t.VISITOR_KEYS[node.type]; 42 | if (keys) { 43 | for (let i = 0; i < keys.length; i++) { 44 | let key = keys[i]; 45 | let child = node[key]; 46 | check(child); 47 | } 48 | } 49 | 50 | return result; 51 | } 52 | 53 | function predicate(node) { 54 | getTypes().assertNode(node); 55 | 56 | let meta = m(node); 57 | if (hasOwn.call(meta, propertyName)) 58 | return meta[propertyName]; 59 | 60 | // Certain types are "opaque," which means they have no side 61 | // effects or leaps and we don't care about their subexpressions. 62 | if (hasOwn.call(opaqueTypes, node.type)) 63 | return meta[propertyName] = false; 64 | 65 | if (hasOwn.call(knownTypes, node.type)) 66 | return meta[propertyName] = true; 67 | 68 | return meta[propertyName] = onlyChildren(node); 69 | } 70 | 71 | predicate.onlyChildren = onlyChildren; 72 | 73 | return predicate; 74 | } 75 | 76 | let opaqueTypes = { 77 | FunctionExpression: true, 78 | ArrowFunctionExpression: true 79 | }; 80 | 81 | // These types potentially have side effects regardless of what side 82 | // effects their subexpressions have. 83 | let sideEffectTypes = { 84 | CallExpression: true, // Anything could happen! 85 | ForInStatement: true, // Modifies the key variable. 86 | UnaryExpression: true, // Think delete. 87 | BinaryExpression: true, // Might invoke .toString() or .valueOf(). 88 | AssignmentExpression: true, // Side-effecting by definition. 89 | UpdateExpression: true, // Updates are essentially assignments. 90 | NewExpression: true // Similar to CallExpression. 91 | }; 92 | 93 | // These types are the direct cause of all leaps in control flow. 94 | let leapTypes = { 95 | YieldExpression: true, 96 | BreakStatement: true, 97 | ContinueStatement: true, 98 | ReturnStatement: true, 99 | ThrowStatement: true 100 | }; 101 | 102 | // All leap types are also side effect types. 103 | for (let type in leapTypes) { 104 | if (hasOwn.call(leapTypes, type)) { 105 | sideEffectTypes[type] = leapTypes[type]; 106 | } 107 | } 108 | 109 | exports.hasSideEffects = makePredicate("hasSideEffects", sideEffectTypes); 110 | exports.containsLeap = makePredicate("containsLeap", leapTypes); 111 | -------------------------------------------------------------------------------- /packages/transform/src/replaceShorthandObjectMethod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import * as util from "./util"; 9 | 10 | // this function converts a shorthand object generator method into a normal 11 | // (non-shorthand) object property which is a generator function expression. for 12 | // example, this: 13 | // 14 | // var foo = { 15 | // *bar(baz) { return 5; } 16 | // } 17 | // 18 | // should be replaced with: 19 | // 20 | // var foo = { 21 | // bar: function*(baz) { return 5; } 22 | // } 23 | // 24 | // to do this, it clones the parameter array and the body of the object generator 25 | // method into a new FunctionExpression. 26 | // 27 | // this method can be passed any Function AST node path, and it will return 28 | // either: 29 | // a) the path that was passed in (iff the path did not need to be replaced) or 30 | // b) the path of the new FunctionExpression that was created as a replacement 31 | // (iff the path did need to be replaced) 32 | // 33 | // In either case, though, the caller can count on the fact that the return value 34 | // is a Function AST node path. 35 | // 36 | // If this function is called with an AST node path that is not a Function (or with an 37 | // argument that isn't an AST node path), it will throw an error. 38 | export default function replaceShorthandObjectMethod(path) { 39 | const t = util.getTypes(); 40 | 41 | if (!path.node || !t.isFunction(path.node)) { 42 | throw new Error("replaceShorthandObjectMethod can only be called on Function AST node paths."); 43 | } 44 | 45 | // this function only replaces shorthand object methods (called ObjectMethod 46 | // in Babel-speak). 47 | if (!t.isObjectMethod(path.node)) { 48 | return path; 49 | } 50 | 51 | // this function only replaces generators. 52 | if (!path.node.generator) { 53 | return path; 54 | } 55 | 56 | const parameters = path.node.params.map(function (param) { 57 | return t.cloneDeep(param); 58 | }) 59 | 60 | const functionExpression = t.functionExpression( 61 | null, // id 62 | parameters, // params 63 | t.cloneDeep(path.node.body), // body 64 | path.node.generator, 65 | path.node.async 66 | ); 67 | 68 | util.replaceWithOrRemove(path, 69 | t.objectProperty( 70 | t.cloneDeep(path.node.key), // key 71 | functionExpression, //value 72 | path.node.computed, // computed 73 | false // shorthand 74 | ) 75 | ); 76 | 77 | // path now refers to the ObjectProperty AST node path, but we want to return a 78 | // Function AST node path for the function expression we created. we know that 79 | // the FunctionExpression we just created is the value of the ObjectProperty, 80 | // so return the "value" path off of this path. 81 | return path.get("value"); 82 | } 83 | -------------------------------------------------------------------------------- /packages/transform/src/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | let currentTypes = null; 9 | 10 | export function wrapWithTypes(types, fn) { 11 | return function (...args) { 12 | const oldTypes = currentTypes; 13 | currentTypes = types; 14 | try { 15 | return fn.apply(this, args); 16 | } finally { 17 | currentTypes = oldTypes; 18 | } 19 | }; 20 | } 21 | 22 | export function getTypes() { 23 | return currentTypes; 24 | } 25 | 26 | export function runtimeProperty(name) { 27 | const t = getTypes(); 28 | return t.memberExpression( 29 | t.identifier("regeneratorRuntime"), 30 | t.identifier(name), 31 | false 32 | ); 33 | } 34 | 35 | export function isReference(path) { 36 | return path.isReferenced() || path.parentPath.isAssignmentExpression({ left: path.node }); 37 | } 38 | 39 | export function replaceWithOrRemove(path, replacement) { 40 | if (replacement) { 41 | path.replaceWith(replacement) 42 | } else { 43 | path.remove(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/transform/src/visit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | "use strict"; 9 | 10 | import assert from "assert"; 11 | import { hoist } from "./hoist"; 12 | import { Emitter } from "./emit"; 13 | import replaceShorthandObjectMethod from "./replaceShorthandObjectMethod"; 14 | import * as util from "./util"; 15 | 16 | exports.getVisitor = ({ types: t }) => ({ 17 | Method(path, state) { 18 | let node = path.node; 19 | 20 | if (!shouldRegenerate(node, state)) return; 21 | 22 | const container = t.functionExpression( 23 | null, 24 | [], 25 | t.cloneNode(node.body, false), 26 | node.generator, 27 | node.async, 28 | ); 29 | 30 | path.get("body").set("body", [ 31 | t.returnStatement( 32 | t.callExpression(container, []), 33 | ), 34 | ]); 35 | 36 | // Regardless of whether or not the wrapped function is a an async method 37 | // or generator the outer function should not be 38 | node.async = false; 39 | node.generator = false; 40 | 41 | // Unwrap the wrapper IIFE's environment so super and this and such still work. 42 | path 43 | .get("body.body.0.argument.callee") 44 | .unwrapFunctionEnvironment(); 45 | }, 46 | Function: { 47 | exit: util.wrapWithTypes(t, function(path, state) { 48 | let node = path.node; 49 | 50 | if (!shouldRegenerate(node, state)) return; 51 | 52 | // if this is an ObjectMethod, we need to convert it to an ObjectProperty 53 | path = replaceShorthandObjectMethod(path); 54 | node = path.node; 55 | 56 | let contextId = path.scope.generateUidIdentifier("context"); 57 | let argsId = path.scope.generateUidIdentifier("args"); 58 | 59 | path.ensureBlock(); 60 | let bodyBlockPath = path.get("body"); 61 | 62 | if (node.async) { 63 | bodyBlockPath.traverse(awaitVisitor); 64 | } 65 | 66 | bodyBlockPath.traverse(functionSentVisitor, { 67 | context: contextId 68 | }); 69 | 70 | let outerBody = []; 71 | let innerBody = []; 72 | 73 | bodyBlockPath.get("body").forEach(function(childPath) { 74 | let node = childPath.node; 75 | if (t.isExpressionStatement(node) && 76 | t.isStringLiteral(node.expression)) { 77 | // Babylon represents directives like "use strict" as elements 78 | // of a bodyBlockPath.node.directives array, but they could just 79 | // as easily be represented (by other parsers) as traditional 80 | // string-literal-valued expression statements, so we need to 81 | // handle that here. (#248) 82 | outerBody.push(node); 83 | } else if (node && node._blockHoist != null) { 84 | outerBody.push(node); 85 | } else { 86 | innerBody.push(node); 87 | } 88 | }); 89 | 90 | if (outerBody.length > 0) { 91 | // Only replace the inner body if we actually hoisted any statements 92 | // to the outer body. 93 | bodyBlockPath.node.body = innerBody; 94 | } 95 | 96 | let outerFnExpr = getOuterFnExpr(path); 97 | // Note that getOuterFnExpr has the side-effect of ensuring that the 98 | // function has a name (so node.id will always be an Identifier), even 99 | // if a temporary name has to be synthesized. 100 | t.assertIdentifier(node.id); 101 | let innerFnId = t.identifier(node.id.name + "quot;); 102 | 103 | // Turn all declarations into vars, and replace the original 104 | // declarations with equivalent assignment expressions. 105 | let vars = hoist(path); 106 | 107 | let context = { 108 | usesThis: false, 109 | usesArguments: false, 110 | getArgsId: () => t.clone(argsId), 111 | }; 112 | path.traverse(argumentsThisVisitor, context); 113 | 114 | if (context.usesArguments) { 115 | vars = vars || t.variableDeclaration("var", []); 116 | vars.declarations.push(t.variableDeclarator( 117 | t.clone(argsId), 118 | t.identifier("arguments"), 119 | )); 120 | } 121 | 122 | let emitter = new Emitter(contextId); 123 | emitter.explode(path.get("body")); 124 | 125 | if (vars && vars.declarations.length > 0) { 126 | outerBody.push(vars); 127 | } 128 | 129 | let wrapArgs = [emitter.getContextFunction(innerFnId)]; 130 | let tryLocsList = emitter.getTryLocsList(); 131 | 132 | if (node.generator) { 133 | wrapArgs.push(outerFnExpr); 134 | } else if (context.usesThis || tryLocsList || node.async) { 135 | // Async functions that are not generators don't care about the 136 | // outer function because they don't need it to be marked and don't 137 | // inherit from its .prototype. 138 | wrapArgs.push(t.nullLiteral()); 139 | } 140 | if (context.usesThis) { 141 | wrapArgs.push(t.thisExpression()); 142 | } else if (tryLocsList || node.async) { 143 | wrapArgs.push(t.nullLiteral()); 144 | } 145 | if (tryLocsList) { 146 | wrapArgs.push(tryLocsList); 147 | } else if (node.async) { 148 | wrapArgs.push(t.nullLiteral()); 149 | } 150 | 151 | if (node.async) { 152 | // Rename any locally declared "Promise" variable, 153 | // to use the global one. 154 | let currentScope = path.scope; 155 | do { 156 | if (currentScope.hasOwnBinding("Promise")) currentScope.rename("Promise"); 157 | } while (currentScope = currentScope.parent); 158 | 159 | wrapArgs.push(t.identifier("Promise")); 160 | } 161 | 162 | let wrapCall = t.callExpression( 163 | util.runtimeProperty(node.async ? "async" : "wrap"), 164 | wrapArgs 165 | ); 166 | 167 | outerBody.push(t.returnStatement(wrapCall)); 168 | node.body = t.blockStatement(outerBody); 169 | // We injected a few new variable declarations (for every hoisted var), 170 | // so we need to add them to the scope. 171 | path.get("body.body").forEach(p => p.scope.registerDeclaration(p)); 172 | 173 | const oldDirectives = bodyBlockPath.node.directives; 174 | if (oldDirectives) { 175 | // Babylon represents directives like "use strict" as elements of 176 | // a bodyBlockPath.node.directives array. (#248) 177 | node.body.directives = oldDirectives; 178 | } 179 | 180 | let wasGeneratorFunction = node.generator; 181 | if (wasGeneratorFunction) { 182 | node.generator = false; 183 | } 184 | 185 | if (node.async) { 186 | node.async = false; 187 | } 188 | 189 | if (wasGeneratorFunction && t.isExpression(node)) { 190 | util.replaceWithOrRemove(path, t.callExpression(util.runtimeProperty("mark"), [node])) 191 | path.addComment("leading", "#__PURE__"); 192 | } 193 | 194 | const insertedLocs = emitter.getInsertedLocs(); 195 | 196 | path.traverse({ 197 | NumericLiteral(path) { 198 | if (!insertedLocs.has(path.node)) { 199 | return; 200 | } 201 | 202 | path.replaceWith(t.numericLiteral(path.node.value)); 203 | }, 204 | }) 205 | 206 | // Generators are processed in 'exit' handlers so that regenerator only has to run on 207 | // an ES5 AST, but that means traversal will not pick up newly inserted references 208 | // to things like 'regeneratorRuntime'. To avoid this, we explicitly requeue. 209 | path.requeue(); 210 | }) 211 | } 212 | }); 213 | 214 | // Check if a node should be transformed by regenerator 215 | function shouldRegenerate(node, state) { 216 | if (node.generator) { 217 | if (node.async) { 218 | // Async generator 219 | return state.opts.asyncGenerators !== false; 220 | } else { 221 | // Plain generator 222 | return state.opts.generators !== false; 223 | } 224 | } else if (node.async) { 225 | // Async function 226 | return state.opts.async !== false; 227 | } else { 228 | // Not a generator or async function. 229 | return false; 230 | } 231 | } 232 | 233 | // Given a NodePath for a Function, return an Expression node that can be 234 | // used to refer reliably to the function object from inside the function. 235 | // This expression is essentially a replacement for arguments.callee, with 236 | // the key advantage that it works in strict mode. 237 | function getOuterFnExpr(funPath) { 238 | const t = util.getTypes(); 239 | let node = funPath.node; 240 | t.assertFunction(node); 241 | 242 | if (!node.id) { 243 | // Default-exported function declarations, and function expressions may not 244 | // have a name to reference, so we explicitly add one. 245 | node.id = funPath.scope.parent.generateUidIdentifier("callee"); 246 | } 247 | 248 | if (node.generator && // Non-generator functions don't need to be marked. 249 | t.isFunctionDeclaration(node)) { 250 | // Return the identifier returned by runtime.mark(<node.id>). 251 | return getMarkedFunctionId(funPath); 252 | } 253 | 254 | return t.clone(node.id); 255 | } 256 | 257 | const markInfo = new WeakMap(); 258 | 259 | function getMarkInfo(node) { 260 | if (!markInfo.has(node)) { 261 | markInfo.set(node, {}); 262 | } 263 | return markInfo.get(node); 264 | } 265 | 266 | function getMarkedFunctionId(funPath) { 267 | const t = util.getTypes(); 268 | const node = funPath.node; 269 | t.assertIdentifier(node.id); 270 | 271 | const blockPath = funPath.findParent(function (path) { 272 | return path.isProgram() || path.isBlockStatement(); 273 | }); 274 | 275 | if (!blockPath) { 276 | return node.id; 277 | } 278 | 279 | const block = blockPath.node; 280 | assert.ok(Array.isArray(block.body)); 281 | 282 | const info = getMarkInfo(block); 283 | if (!info.decl) { 284 | info.decl = t.variableDeclaration("var", []); 285 | blockPath.unshiftContainer("body", info.decl); 286 | info.declPath = blockPath.get("body.0"); 287 | } 288 | 289 | assert.strictEqual(info.declPath.node, info.decl); 290 | 291 | // Get a new unique identifier for our marked variable. 292 | const markedId = blockPath.scope.generateUidIdentifier("marked"); 293 | const markCallExp = t.callExpression( 294 | util.runtimeProperty("mark"), 295 | [t.clone(node.id)] 296 | ); 297 | 298 | const index = info.decl.declarations.push( 299 | t.variableDeclarator(markedId, markCallExp) 300 | ) - 1; 301 | 302 | const markCallExpPath = 303 | info.declPath.get("declarations." + index + ".init"); 304 | 305 | assert.strictEqual(markCallExpPath.node, markCallExp); 306 | 307 | markCallExpPath.addComment("leading", "#__PURE__"); 308 | 309 | return t.clone(markedId); 310 | } 311 | 312 | let argumentsThisVisitor = { 313 | "FunctionExpression|FunctionDeclaration|Method": function(path) { 314 | path.skip(); 315 | }, 316 | 317 | Identifier: function(path, state) { 318 | if (path.node.name === "arguments" && util.isReference(path)) { 319 | util.replaceWithOrRemove(path, state.getArgsId()); 320 | state.usesArguments = true; 321 | } 322 | }, 323 | 324 | ThisExpression: function(path, state) { 325 | state.usesThis = true; 326 | } 327 | }; 328 | 329 | let functionSentVisitor = { 330 | MetaProperty(path) { 331 | let { node } = path; 332 | 333 | if (node.meta.name === "function" && 334 | node.property.name === "sent") { 335 | const t = util.getTypes(); 336 | util.replaceWithOrRemove( 337 | path, 338 | t.memberExpression( 339 | t.clone(this.context), 340 | t.identifier("_sent") 341 | ) 342 | ); 343 | } 344 | } 345 | }; 346 | 347 | let awaitVisitor = { 348 | Function: function(path) { 349 | path.skip(); // Don't descend into nested function scopes. 350 | }, 351 | 352 | AwaitExpression: function(path) { 353 | const t = util.getTypes(); 354 | 355 | // Convert await expressions to yield expressions. 356 | let argument = path.node.argument; 357 | 358 | // Transforming `await x` to `yield regeneratorRuntime.awrap(x)` 359 | // causes the argument to be wrapped in such a way that the runtime 360 | // can distinguish between awaited and merely yielded values. 361 | util.replaceWithOrRemove(path, t.yieldExpression( 362 | t.callExpression( 363 | util.runtimeProperty("awrap"), 364 | [argument] 365 | ), 366 | false 367 | )); 368 | } 369 | }; 370 | -------------------------------------------------------------------------------- /runtime-module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | console.warn( 9 | "The regenerator/runtime-module module is deprecated; " + 10 | "please import regenerator-runtime instead." 11 | ); 12 | 13 | module.exports = require("regenerator-runtime"); 14 | -------------------------------------------------------------------------------- /runtime.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | console.warn( 9 | "The regenerator/runtime module is deprecated; " + 10 | "please import regenerator-runtime/runtime instead." 11 | ); 12 | 13 | module.exports = require("regenerator-runtime/runtime"); 14 | -------------------------------------------------------------------------------- /test/async-custom-promise.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | 10 | function SyncPromise(run) { 11 | this.resolved = null; 12 | this.value = null; 13 | try { 14 | run( 15 | val => { this.resolved = true; this.value = val; }, 16 | val => { this.resolved = false; this.value = val; } 17 | ); 18 | } catch (e) { 19 | this.resolved = false; 20 | this.value = e; 21 | } 22 | if (this.resolved === null) { 23 | throw new Error("SyncPromise must be run synchronously"); 24 | } 25 | if (this.value instanceof SyncPromise) this.value = this.value.value; 26 | } 27 | SyncPromise.prototype.then = function(onRes, onRej) { 28 | try { 29 | if (this.resolved) return SyncPromise.resolve(onRes(this.value)); 30 | if (onRej) return SyncPromise.resolve(onRej(this.value)); 31 | return this; 32 | } catch (e) { 33 | return SyncPromise.reject(e); 34 | } 35 | }; 36 | SyncPromise.prototype.catch = function(onRej) { 37 | try { 38 | if (this.resolved) return this; 39 | return SyncPromise.resolve(onRej(this.value)); 40 | } catch (e) { 41 | return SyncPromise.reject(e); 42 | } 43 | }; 44 | SyncPromise.resolve = val => new SyncPromise(res => res(val)); 45 | SyncPromise.reject = val => new SyncPromise((_, rej) => rej(val)); 46 | 47 | describe("custom Promise polyfills", function() { 48 | it("should work with async functions", function() { 49 | babelInjectPromise: SyncPromise; 50 | 51 | async function fn() { 52 | var first = await SyncPromise.resolve(2); 53 | var second = await 3; 54 | return 4 * first * second; 55 | } 56 | 57 | assert.ok(fn() instanceof SyncPromise); 58 | assert.ok(fn().resolved); 59 | assert.strictEqual(fn().value, 24); 60 | }); 61 | 62 | it("should correctly handle rejections", function() { 63 | babelInjectPromise: SyncPromise; 64 | 65 | async function fn() { 66 | throw 2; 67 | } 68 | 69 | assert.ok(fn() instanceof SyncPromise); 70 | assert.strictEqual(fn().resolved, false); 71 | assert.strictEqual(fn().value, 2); 72 | }); 73 | 74 | it("should work with async generators", function() { 75 | babelInjectPromise: SyncPromise; 76 | 77 | async function* fn() { 78 | await 1; 79 | var input = yield 2; 80 | await 3; 81 | return input; 82 | } 83 | 84 | var it = fn(); 85 | var val = it.next(); 86 | 87 | assert.ok(val instanceof SyncPromise); 88 | assert.ok(val.resolved); 89 | assert.deepStrictEqual(val.value, { done: false, value: 2 }); 90 | 91 | val = it.next(7); 92 | 93 | assert.ok(val instanceof SyncPromise); 94 | assert.ok(val.resolved); 95 | assert.deepStrictEqual(val.value, { done: true, value: 7 }); 96 | }); 97 | }); 98 | -------------------------------------------------------------------------------- /test/async.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | 10 | assert( 11 | function*() {}.toString().indexOf("regenerator") !== -1, 12 | "regenerator-transform should be enabled" 13 | ); 14 | 15 | describe("async functions and await expressions", function() { 16 | Promise = require("promise"); 17 | 18 | describe("regeneratorRuntime", function() { 19 | it("should be defined globally", function() { 20 | var global = Function("return this")(); 21 | assert.ok("regeneratorRuntime" in global); 22 | assert.strictEqual(global.regeneratorRuntime, regeneratorRuntime); 23 | }); 24 | 25 | it("should have a .wrap method", function() { 26 | assert.strictEqual(typeof regeneratorRuntime.wrap, "function"); 27 | }); 28 | }); 29 | 30 | describe("Promise", function() { 31 | it("should be defined globally", function() { 32 | var global = Function("return this")(); 33 | assert.ok("Promise" in global); 34 | assert.strictEqual(global.Promise, Promise); 35 | }); 36 | 37 | it("should be a function", function() { 38 | assert.strictEqual(typeof Promise, "function"); 39 | }); 40 | }); 41 | 42 | describe("no-await async function", function() { 43 | it("should return a Promise", function(done) { 44 | var called = false; 45 | 46 | async function noAwait(value) { 47 | called = true; 48 | return value; 49 | } 50 | 51 | var promise = noAwait("asdf"); 52 | assert.strictEqual(called, true); 53 | 54 | promise.then(function(value) { 55 | assert.strictEqual(called, true); 56 | assert.strictEqual(value, "asdf"); 57 | done(); 58 | }).catch(done); 59 | }); 60 | }); 61 | 62 | describe("one-await async function", function() { 63 | it("should finish asynchronously", function(done) { 64 | var flag1 = false; 65 | var flag2 = false; 66 | 67 | async function oneAwait(value) { 68 | flag1 = true; 69 | var result = await value; 70 | flag2 = true; 71 | return result; 72 | } 73 | 74 | var promise = oneAwait("asdf"); 75 | assert.strictEqual(flag1, true); 76 | assert.strictEqual(flag2, false); 77 | 78 | promise.then(function(value) { 79 | assert.strictEqual(flag2, true); 80 | assert.strictEqual(value, "asdf"); 81 | done(); 82 | }).catch(done); 83 | }); 84 | }); 85 | 86 | describe("nested async function calls", function() { 87 | it("should evaluate in the right order", function(done) { 88 | var markers = []; 89 | 90 | async function innerMost(marker) { 91 | markers.push(marker); 92 | return await marker; 93 | } 94 | 95 | async function inner(marker) { 96 | markers.push(marker); 97 | 98 | assert.strictEqual( 99 | await innerMost(marker + 1), 100 | marker + 1 101 | ); 102 | 103 | markers.push(marker + 2); 104 | 105 | assert.strictEqual( 106 | await innerMost(marker + 3), 107 | marker + 3 108 | ); 109 | 110 | markers.push(marker + 4); 111 | } 112 | 113 | async function outer() { 114 | markers.push(0); 115 | await inner(1); 116 | markers.push(6); 117 | await inner(7); 118 | markers.push(12); 119 | } 120 | 121 | outer().then(function() { 122 | var expected = []; 123 | for (var i = 0; i <= 12; ++i) 124 | expected.push(i); 125 | assert.deepEqual(markers, expected); 126 | done(); 127 | }).catch(done); 128 | }); 129 | }); 130 | 131 | describe("dependent promises", function() { 132 | it("should be awaitable out of order", function(done) { 133 | async function outer(value) { 134 | var resolved = false; 135 | var p1 = new Promise(function(resolve) { 136 | setTimeout(function() { 137 | resolve(value + 1); 138 | resolved = true; 139 | }, 0); 140 | }); 141 | 142 | assert.strictEqual(resolved, false); 143 | 144 | var v2 = await p1.then(function(value) { 145 | return value + 1; 146 | }); 147 | 148 | assert.strictEqual(resolved, true); 149 | 150 | var v1 = await p1; 151 | 152 | return [v1, v2]; 153 | } 154 | 155 | outer(1).then(function(pair) { 156 | assert.deepEqual(pair, [2, 3]); 157 | done(); 158 | }).catch(done); 159 | }); 160 | }); 161 | 162 | describe("rejected promises", function() { 163 | it("should cause await expressions to throw", function(done) { 164 | var error = new Error("rejected"); 165 | 166 | async function f(arg) { 167 | try { 168 | return await arg; 169 | } catch (e) { 170 | assert.strictEqual(e, error); 171 | return "did throw"; 172 | } 173 | } 174 | 175 | Promise.all([ 176 | f(Promise.reject(error)), 177 | f(Promise.resolve("did not throw")) 178 | ]).then(function(results) { 179 | assert.deepEqual(results, [ 180 | "did throw", 181 | "did not throw" 182 | ]); 183 | done(); 184 | }).catch(done); 185 | }); 186 | 187 | it("should be returned by exceptional async functions", function(done) { 188 | var error = new Error("rejected"); 189 | 190 | async function e(arg) { 191 | if (arg) { 192 | throw arg; 193 | } 194 | return "did not throw"; 195 | } 196 | 197 | async function f(arg) { 198 | return await e(arg); 199 | } 200 | 201 | async function g(arg) { 202 | return await f(arg); 203 | } 204 | 205 | async function h(arg) { 206 | return await Promise.all([ 207 | g(arg), 208 | Promise.resolve("dummy") 209 | ]); 210 | } 211 | 212 | Promise.all([ 213 | h(error).then(function() { 214 | done(new Error("should not have resolved")); 215 | }, function(e) { 216 | assert.strictEqual(e, error); 217 | return "ok1"; 218 | }), 219 | h(null).then(function(result) { 220 | assert.deepEqual(result, [ 221 | "did not throw", 222 | "dummy" 223 | ]); 224 | return "ok2"; 225 | }) 226 | ]).then(function(results) { 227 | assert.deepEqual(results, ["ok1", "ok2"]); 228 | done(); 229 | }).catch(done); 230 | }); 231 | 232 | it("should propagate failure when returned", function() { 233 | var rejection = new Error("rejection"); 234 | 235 | async function f() { 236 | return new Promise(function(resolve, reject) { 237 | reject(rejection); 238 | }); 239 | } 240 | 241 | return f().then(function(result) { 242 | assert.ok(false, "should have been rejected"); 243 | }, function(error) { 244 | assert.strictEqual(error, rejection); 245 | }); 246 | }); 247 | }); 248 | 249 | describe("async function expressions", function() { 250 | it("should be allowed", function(done) { 251 | (async function(arg) { 252 | return await arg; 253 | })(Promise.resolve(1234)).then(function(value) { 254 | assert.strictEqual(value, 1234); 255 | done(); 256 | }).catch(done); 257 | }); 258 | }); 259 | 260 | describe("the this object", function () { 261 | it("should default to undefined (strict)", function (done) { 262 | async function f() { 263 | "use strict"; 264 | 265 | return this; 266 | } 267 | 268 | f().then(function(value) { 269 | assert.strictEqual(value, undefined); 270 | done(); 271 | }).catch(done); 272 | }); 273 | 274 | it("should respect .call's this", function (done) { 275 | async function f() { 276 | return this; 277 | } 278 | 279 | var self = {}; 280 | f.call(self).then(function(value) { 281 | assert.strictEqual(value, self); 282 | done(); 283 | }).catch(done); 284 | }); 285 | 286 | it("shouldn't capture this when not needed", function () { 287 | // https://github.com/babel/babel/issues/4056 288 | 289 | async function f() { 290 | return 0; 291 | } 292 | 293 | var source = String(f); 294 | assert.strictEqual(source.indexOf("this"), -1); 295 | }); 296 | }); 297 | }); 298 | 299 | describe("async generator functions", function() { 300 | it("should return a working AsyncIterator", function() { 301 | var markers = []; 302 | 303 | async function *gen(arg) { 304 | markers.push(0); 305 | var sent = yield arg; 306 | markers.push(1); 307 | var result = await sent; 308 | markers.push(2); 309 | assert.strictEqual(await (yield "second"), "sent after second"); 310 | markers.push(3); 311 | return result; 312 | } 313 | 314 | var iter = gen("initial argument"); 315 | assert.deepEqual(markers, []); 316 | 317 | var firstPromise = iter.next(); 318 | assert.deepEqual(markers, [0]); 319 | 320 | return firstPromise.then(function(firstResult) { 321 | assert.deepEqual(firstResult, { 322 | value: "initial argument", 323 | done: false 324 | }); 325 | 326 | assert.deepEqual(markers, [0]); 327 | 328 | return iter.next(new Promise(function(resolve) { 329 | setTimeout(resolve, 100); 330 | }).then(function() { 331 | assert.deepEqual(markers, [0, 1]); 332 | return "will become final result"; 333 | })); 334 | 335 | }).then(function(secondResult) { 336 | assert.deepEqual(secondResult, { 337 | value: "second", 338 | done: false 339 | }); 340 | 341 | assert.deepEqual(markers, [0, 1, 2]); 342 | 343 | return iter.next("sent after second"); 344 | 345 | }).then(function(finalResult) { 346 | assert.deepEqual(markers, [0, 1, 2, 3]); 347 | assert.deepEqual(finalResult, { 348 | value: "will become final result", 349 | done: true 350 | }); 351 | }); 352 | }); 353 | 354 | it("should keep results in order", function() { 355 | async function *range(limit) { 356 | var before = []; 357 | var after = []; 358 | for (var i = 0; i < limit; ++i) { 359 | before.push(i); 360 | yield i; 361 | after.push(i); 362 | } 363 | assert.deepEqual(before, after); 364 | return before; 365 | } 366 | 367 | var limit = 10; 368 | var iter = range(limit); 369 | var promises = []; 370 | var results = []; 371 | 372 | for (var i = 0; i < limit; ++i) { 373 | var promise = iter.next(); 374 | promises.push(promise); 375 | 376 | promise.then(function(result) { 377 | assert.strictEqual(result.done, false); 378 | results.push(result); 379 | }); 380 | } 381 | 382 | assert.deepEqual(results, []); 383 | 384 | return Promise.all(promises).then(function(promiseResults) { 385 | assert.deepEqual(results, promiseResults); 386 | 387 | return iter.next(); 388 | 389 | }).then(function(finalResult) { 390 | assert.deepEqual(results.map(function(result) { 391 | return result.value; 392 | }), finalResult.value); 393 | 394 | assert.strictEqual(finalResult.done, true); 395 | }); 396 | }); 397 | 398 | it("should be able to handle many awaits", function() { 399 | var awaitCount = 0; 400 | 401 | function countAwait(i) { 402 | return Promise.resolve(i).then(function() { 403 | ++awaitCount; 404 | }); 405 | } 406 | 407 | async function *gen(limit) { 408 | await countAwait(0); 409 | yield 1; 410 | await countAwait(2); 411 | await countAwait(3); 412 | yield 4; 413 | await countAwait(5); 414 | await countAwait(6); 415 | await countAwait(7); 416 | yield 8; 417 | for (var i = 0; i < limit; ++i) { 418 | await countAwait(i); 419 | } 420 | return "done"; 421 | } 422 | 423 | var iter = gen(100); 424 | 425 | return iter.next().then(function(result) { 426 | assert.strictEqual(awaitCount, 1); 427 | 428 | assert.deepEqual(result, { 429 | value: 1, 430 | done: false 431 | }); 432 | 433 | return iter.next(); 434 | 435 | }).then(function(result) { 436 | assert.strictEqual(awaitCount, 3); 437 | 438 | assert.deepEqual(result, { 439 | value: 4, 440 | done: false 441 | }); 442 | 443 | return iter.next(); 444 | 445 | }).then(function(result) { 446 | assert.strictEqual(awaitCount, 6); 447 | 448 | assert.deepEqual(result, { 449 | value: 8, 450 | done: false 451 | }); 452 | 453 | return iter.next(); 454 | 455 | }).then(function(result) { 456 | assert.strictEqual(awaitCount, 6 + 100); 457 | 458 | assert.deepEqual(result, { 459 | value: "done", 460 | done: true 461 | }); 462 | 463 | return iter.next(); 464 | 465 | }).then(function(result) { 466 | assert.deepEqual(result, { 467 | value: void 0, 468 | done: true 469 | }); 470 | }); 471 | }); 472 | 473 | it("should not propagate exceptions between iterations", function() { 474 | async function *gen() { 475 | yield 1; 476 | yield 2; 477 | } 478 | 479 | var iter = gen(); 480 | 481 | return iter.next().then(function(result) { 482 | assert.deepEqual(result, { 483 | value: 1, 484 | done: false 485 | }); 486 | 487 | return iter.throw(new Error("thrown from first yield")); 488 | 489 | }).then(function() { 490 | throw new Error("should have thrown"); 491 | 492 | }, function(error) { 493 | assert.strictEqual(error.message, "thrown from first yield"); 494 | return iter.next(); 495 | 496 | }).then(function(result) { 497 | assert.deepEqual(result, { 498 | value: void 0, 499 | done: true 500 | }); 501 | }); 502 | }); 503 | 504 | it("should allow yielding a rejected Promise", function() { 505 | var yielded = new Error("yielded rejection"); 506 | var returned = new Error("returned rejection"); 507 | 508 | async function *gen() { 509 | assert.strictEqual(yield "first yielded", "first sent"); 510 | try { 511 | assert.strictEqual(yield Promise.reject(yielded), "not reached"); 512 | } catch (e) { 513 | assert.strictEqual(yield e, "second sent"); 514 | return Promise.reject(returned); 515 | } 516 | } 517 | 518 | var iter = gen(); 519 | 520 | return iter.next().then(function(result) { 521 | assert.deepEqual(result, { 522 | value: "first yielded", 523 | done: false 524 | }); 525 | return iter.next("first sent"); 526 | }).then(function (result) { 527 | assert.deepEqual(result, { 528 | value: yielded, 529 | done: false 530 | }); 531 | return iter.next("second sent"); 532 | }).then(function(result) { 533 | assert.ok(false, "should have returned a rejected Promise"); 534 | }, function(error) { 535 | assert.strictEqual(error, returned); 536 | }); 537 | }); 538 | 539 | it("should work with nested arrow functions", async function () { 540 | var a = async b => { 541 | return await (async () => { 542 | return await b(); 543 | })(); 544 | }; 545 | 546 | assert.strictEqual( 547 | await a(() => Promise.resolve(1234)), 548 | 1234 549 | ); 550 | }); 551 | 552 | it("should support super.method(...) in async methods", async function () { 553 | class A { 554 | async method() { 555 | return "from A"; 556 | } 557 | } 558 | 559 | class B extends A { 560 | async method() { 561 | return "from B " + (await super.method()); 562 | } 563 | } 564 | 565 | assert.strictEqual(await new B().method(), "from B from A"); 566 | }); 567 | }); 568 | 569 | describe("update operators", function() { 570 | it("should read left side before yielding", function() { 571 | let x = 0; 572 | 573 | function* test() { 574 | x += yield; 575 | } 576 | 577 | var gen = test(); 578 | gen.next(); 579 | x += 1; 580 | assert.strictEqual(x, 1); 581 | 582 | gen.next(2); 583 | assert.strictEqual(x, 2); 584 | }); 585 | 586 | it("should explode left side before yielding", function() { 587 | let obj = { count: 0 }; 588 | 589 | function* test() { 590 | obj[yield "key"] += yield "value"; 591 | } 592 | 593 | var gen = test(); 594 | 595 | assert.deepEqual(gen.next(), { value: "key", done: false }); 596 | assert.strictEqual(obj.count, 0); 597 | 598 | assert.deepEqual(gen.next("count"), { value: "value", done: false }); 599 | assert.strictEqual(obj.count, 0); 600 | 601 | obj.count += 1; 602 | assert.strictEqual(obj.count, 1); 603 | 604 | assert.deepEqual(gen.next(2), { value: void 0, done: true }); 605 | assert.strictEqual(obj.count, 2); 606 | }); 607 | 608 | it("should read left side before awaiting", function() { 609 | let x = 0; 610 | 611 | async function test(val) { 612 | x += await val; 613 | return x; 614 | } 615 | 616 | const promise = test(2); 617 | x += 1; 618 | 619 | return promise.then(result => { 620 | assert.strictEqual(result, 2); 621 | }); 622 | }); 623 | }); 624 | -------------------------------------------------------------------------------- /test/class.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | var shared = require("./shared.js"); 10 | var check = shared.check; 11 | 12 | assert( 13 | function*() {}.toString().indexOf("regenerator") !== -1, 14 | "regenerator-transform should be enabled" 15 | ); 16 | 17 | describe("class methods", function () { 18 | it("should work if the generator is a class method", function () { 19 | class Foo { 20 | *gen(x) { 21 | yield x; 22 | } 23 | } 24 | 25 | check(new Foo().gen("boom"), ["boom"]); 26 | }); 27 | 28 | it("should work if the generator is a computed class method", function () { 29 | var fnName = "gen"; 30 | class Foo { 31 | *[fnName](x) { 32 | yield x; 33 | } 34 | } 35 | 36 | check(new Foo().gen("boom"), ["boom"]); 37 | }); 38 | 39 | it("should work with this", function () { 40 | class A { 41 | *gen() { yield this } 42 | } 43 | 44 | const a = new A; 45 | check(a.gen(), [a]); 46 | }) 47 | 48 | it("should work with super", function () { 49 | class A { 50 | *gen() { yield 1 } 51 | } 52 | 53 | class B extends A { 54 | *gen() { yield super.gen; } 55 | } 56 | 57 | check(new B().gen(), [A.prototype.gen]); 58 | }); 59 | 60 | it("should work with arguments", function () { 61 | class A { 62 | *gen() { yield arguments } 63 | } 64 | 65 | const args = new A().gen(1, 2, 3).next().value; 66 | assert.strictEqual(args.length, 3); 67 | assert.strictEqual(args[0], 1); 68 | assert.strictEqual(args[1], 2); 69 | assert.strictEqual(args[2], 3) 70 | }); 71 | 72 | it("should allow yield as super expression", function () { 73 | function* gen() { 74 | return class extends (yield) {} 75 | } 76 | 77 | class B {} 78 | 79 | const it = gen(); 80 | it.next(); 81 | const res = it.next(B).value; 82 | 83 | assert.ok(new res instanceof B); 84 | }); 85 | 86 | it("should allow yield as super expression with argument", function () { 87 | function* gen() { 88 | return class extends (yield 123) {} 89 | } 90 | 91 | class B {} 92 | 93 | const it = gen(); 94 | assert.deepEqual(it.next(), { value: 123, done: false }); 95 | const res = it.next(B).value; 96 | 97 | assert.ok(new res instanceof B); 98 | }); 99 | 100 | it("should allow yield as computed key", function () { 101 | if (class {}.toString().indexOf("class") !== 0) { 102 | return; 103 | // The class transform is broken: 104 | // https://github.com/babel/babel/issues/8300 105 | } 106 | 107 | function* gen() { 108 | return class { 109 | [yield]() { return 1 } 110 | [yield]() { return 2 } 111 | } 112 | } 113 | 114 | const it = gen(); 115 | it.next(); 116 | it.next("one"); 117 | const res = it.next("two").value; 118 | 119 | assert.strictEqual(new res().one(), 1); 120 | assert.strictEqual(new res().two(), 2); 121 | }); 122 | }); 123 | -------------------------------------------------------------------------------- /test/frozen-intrinsics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | 10 | var getPrototypeOf = Reflect.getPrototypeOf; 11 | function getConstructorOf(obj) { 12 | return getPrototypeOf(obj).constructor; 13 | } 14 | 15 | var SymbolIterator = (typeof Symbol && Symbol.iterator) || '@@iterator'; 16 | var ArrayIteratorObject = new Array()[SymbolIterator](); 17 | var ArrayIteratorPrototype = getPrototypeOf(ArrayIteratorObject); 18 | var IteratorPrototype = getPrototypeOf(ArrayIteratorPrototype); 19 | async function* AsyncGeneratorFunctionInstance() {} 20 | var AsyncGeneratorFunction = getConstructorOf( 21 | AsyncGeneratorFunctionInstance, 22 | ); 23 | var AsyncGenerator = AsyncGeneratorFunction.prototype; 24 | var AsyncGeneratorPrototype = AsyncGenerator.prototype; 25 | var AsyncIteratorPrototype = getPrototypeOf(AsyncGeneratorPrototype); 26 | 27 | // freeze relevant intrinsics 28 | Object.freeze(Object.prototype); 29 | Object.freeze(IteratorPrototype); 30 | Object.freeze(ArrayIteratorPrototype); 31 | Object.freeze(AsyncGenerator); 32 | Object.freeze(AsyncGeneratorPrototype); 33 | Object.freeze(AsyncIteratorPrototype); 34 | 35 | describe("Frozen intrinsics test", function () { 36 | it("regenerator-runtime doesn't fail to initialize when Object prototype is frozen", function() { 37 | require("./runtime.js"); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <title>Mocha</title> 5 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 6 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 | <link rel="stylesheet" href="mocha.css" /> 8 | </head> 9 | <body> 10 | <div id="mocha"></div> 11 | <script src="mocha.js"></script> 12 | <script>mocha.setup('bdd')</script> 13 | <script src="tests.browser.js"></script> 14 | <script> 15 | mocha.run(); 16 | </script> 17 | </body> 18 | </html> 19 | -------------------------------------------------------------------------------- /test/non-native.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | // These tests run only in translation, not in native Node. 9 | 10 | var assert = require("assert"); 11 | var shared = require("./shared.js"); 12 | var Symbol = shared.Symbol; 13 | var check = shared.check; 14 | var assertAlreadyFinished = shared.assertAlreadyFinished; 15 | 16 | describe("@@iterator", function() { 17 | it("is defined on Generator.prototype and returns this", function() { 18 | function *gen(){} 19 | var iterator = gen(); 20 | assert.ok(!iterator.hasOwnProperty(Symbol.iterator)); 21 | assert.ok(!Object.getPrototypeOf(iterator).hasOwnProperty(Symbol.iterator)); 22 | assert.ok(Object.getPrototypeOf(Object.getPrototypeOf( 23 | Object.getPrototypeOf(iterator) 24 | )).hasOwnProperty(Symbol.iterator)); 25 | assert.strictEqual(iterator[Symbol.iterator](), iterator); 26 | }); 27 | }); 28 | 29 | describe("throw", function() { 30 | it("should complete throwing generator", function() { 31 | function *gen(x) { 32 | throw 1; 33 | } 34 | 35 | var u = gen(); 36 | 37 | try { 38 | u.next(); 39 | } catch (err) { 40 | assert.strictEqual(err, 1); 41 | } 42 | 43 | assertAlreadyFinished(u); 44 | }); 45 | 46 | it("should complete yielding/throwing generator", function () { 47 | function *gen(x) { 48 | yield 2; 49 | throw 1; 50 | } 51 | 52 | var u = gen(); 53 | 54 | u.next(); 55 | 56 | try { 57 | u.throw(2); 58 | } catch (err) { 59 | assert.strictEqual(err, 2); 60 | } 61 | 62 | assertAlreadyFinished(u); 63 | }); 64 | }); 65 | 66 | describe("completed generator", function() { 67 | function *gen() { 68 | return "ALL DONE"; 69 | } 70 | 71 | it("should refuse to resume", function() { 72 | var g = gen(); 73 | 74 | assert.deepEqual(g.next(), { 75 | value: "ALL DONE", done: true 76 | }); 77 | 78 | assertAlreadyFinished(g); 79 | }); 80 | }); 81 | 82 | describe("delegate yield", function() { 83 | it("should support any iterable argument", function() { 84 | function *gen() { 85 | yield 0; 86 | yield* [ 87 | yield "one", 88 | yield "two", 89 | yield "three" 90 | ]; 91 | yield 5; 92 | } 93 | 94 | check(gen(), [0, "one", "two", "three", 2, 3, 4, 5]); 95 | 96 | function *string() { 97 | return yield* "asdf"; 98 | } 99 | 100 | check(string(), ["a", "s", "d", "f"]); 101 | }); 102 | }); 103 | 104 | describe("newborn generators", function () { 105 | it("should be able to access function.sent", function () { 106 | function *gen() { 107 | var sent = yield function.sent; 108 | assert.strictEqual(sent, function.sent); 109 | return function.sent; 110 | } 111 | 112 | var g = gen(); 113 | 114 | assert.deepEqual(g.next("first"), { 115 | value: "first", 116 | done: false 117 | }); 118 | 119 | assert.deepEqual(g.next("second"), { 120 | value: "second", 121 | done: true 122 | }); 123 | }); 124 | }); 125 | -------------------------------------------------------------------------------- /test/non-writable-tostringtag-property.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | 10 | var getProto = Object.getPrototypeOf; 11 | var NativeIteratorPrototype = 12 | typeof Symbol === "function" && 13 | typeof Symbol.iterator === "symbol" && 14 | typeof [][Symbol.iterator] === "function" && 15 | getProto && 16 | getProto(getProto([][Symbol.iterator]())); 17 | 18 | // https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype-@@tostringtag 19 | Object.defineProperty(NativeIteratorPrototype, Symbol.toStringTag, { 20 | configurable: true, 21 | value: "Iterator", 22 | }); 23 | 24 | (NativeIteratorPrototype ? describe : describe.skip)("Symbol.toStringTag safety (#399, #400)", function () { 25 | it("regenerator-runtime doesn't fail to initialize when native iterator prototype has a non-writable @@toStringTag property", function() { 26 | require("./runtime.js"); 27 | }); 28 | 29 | it("regenerator-runtime's polyfilled generator prototype has the correct @@toStringTag value", function() { 30 | require("./runtime.js"); 31 | function foo() {} 32 | regeneratorRuntime.mark(foo); 33 | 34 | assert.strictEqual(foo.prototype[Symbol.toStringTag], "Generator"); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/nothing-to-transform.js: -------------------------------------------------------------------------------- 1 | function asdf() { 2 | return "no generators or a-s-y-n-c functions to see here"; 3 | } 4 | -------------------------------------------------------------------------------- /test/regression.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | 10 | describe("regressions", function() { 11 | it("should correctly hoist arguments", async function () { 12 | function test(fn) { 13 | return async (...args) => { 14 | return fn(...args); 15 | }; 16 | } 17 | const result = []; 18 | await test((arg1, arg2) => { result.push(arg1, arg2); })(1, "foo"); 19 | 20 | assert.deepEqual(result, [1, "foo"]); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/replaceWith-falsy.js: -------------------------------------------------------------------------------- 1 | async function foo() { 2 | for (let i; i;); 3 | } 4 | -------------------------------------------------------------------------------- /test/run.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var fs = require("fs"); 9 | var path = require("path"); 10 | var semver = require("semver"); 11 | var spawn = require("child_process").spawn; 12 | var babel = require("@babel/core"); 13 | var checkDuplicatedNodes = require("babel-check-duplicated-nodes").default; 14 | var regenerator = require("../main"); 15 | var mochaDir = path.dirname(require.resolve("mocha")); 16 | 17 | function convert(es6File, es5File, callback) { 18 | var transformOptions = { 19 | presets:[require("regenerator-preset")], 20 | parserOpts: { 21 | strictMode: false, 22 | }, 23 | ast: true 24 | }; 25 | 26 | fs.readFile(es6File, "utf-8", function(err, es6) { 27 | if (err) { 28 | return callback(err); 29 | } 30 | 31 | var { code: es5, ast } = babel.transformSync(es6, transformOptions); 32 | fs.writeFileSync(es5File, es5); 33 | try { 34 | checkDuplicatedNodes(babel, ast); 35 | } catch (err) { 36 | err.message = "Occurred while transforming: " + es6File + "\n" + err.message; 37 | throw err; 38 | } 39 | callback(); 40 | }); 41 | } 42 | 43 | function bundle(es5Files, browserFile, callback) { 44 | var bundle = require("browserify")(); 45 | es5Files.forEach(bundle.add, bundle); 46 | bundle.bundle(function(err, src) { 47 | if (err) { 48 | return callback(err); 49 | } 50 | fs.writeFile(browserFile, src, callback); 51 | }); 52 | } 53 | 54 | var queue = []; 55 | function enqueue(cmd, args, quiet) { 56 | queue.push({ 57 | cmd: cmd, 58 | args: args || [], 59 | quiet: !!quiet 60 | }); 61 | } 62 | 63 | function flush() { 64 | var entry = queue.shift(); 65 | if (entry) { 66 | var cmd = entry.cmd; 67 | if (typeof cmd === "function") { 68 | cmd.apply(null, entry.args.concat(asyncCallback)); 69 | } else { 70 | spawn(cmd, entry.args, { 71 | stdio: [ 72 | process.stdin, 73 | entry.quiet ? "ignore" : process.stdout, 74 | process.stderr 75 | ] 76 | }).on("exit", asyncCallback); 77 | } 78 | } 79 | } 80 | 81 | function asyncCallback(err) { 82 | if (err) { 83 | console.error("process exited abnormally:", err); 84 | process.exit(typeof err === "number" ? err : -1); 85 | } else { 86 | process.nextTick(flush); 87 | } 88 | } 89 | 90 | function makeMochaCopyFunction(fileName) { 91 | return function copy(callback) { 92 | var src = path.join(mochaDir, fileName); 93 | var dst = path.join(__dirname, fileName); 94 | fs.unlink(dst, function() { 95 | fs.symlink(src, dst, callback); 96 | }); 97 | }; 98 | } 99 | 100 | enqueue(convert, [ 101 | "./test/tests.es6.js", 102 | "./test/tests.es5.js" 103 | ]); 104 | 105 | if (semver.gte(process.version, "4.0.0")) { 106 | enqueue(convert, [ 107 | "./test/tests-node4.es6.js", 108 | "./test/tests-node4.es5.js" 109 | ]); 110 | } else { 111 | // we are on an older platform, but we still need to create an empty 112 | // tests-node4.es5.js file so that the test commands below have a file to refer 113 | // to. 114 | fs.writeFileSync("./test/tests-node4.es5.js", ""); 115 | } 116 | 117 | enqueue(convert, [ 118 | "./test/non-native.js", 119 | "./test/non-native.es5.js" 120 | ]); 121 | 122 | enqueue(convert, [ 123 | "./test/async.js", 124 | "./test/async.es5.js" 125 | ]); 126 | 127 | enqueue(convert, [ 128 | "./test/class.js", 129 | "./test/class.es5.js" 130 | ]); 131 | 132 | enqueue(convertWithRegeneratorPluginOnly, [ 133 | "./test/class.js", 134 | "./test/class.regenerator.js" 135 | ]); 136 | 137 | Error.stackTraceLimit = 1000; 138 | 139 | /** 140 | * Comvert without using the preset (which also transforms things like classes and arrows) 141 | */ 142 | function convertWithRegeneratorPluginOnly(inputFile, outputFile, callback) { 143 | var transformOptions = { 144 | plugins:[require("regenerator-transform")], 145 | parserOpts: { 146 | sourceType: "module", 147 | allowImportExportEverywhere: true, 148 | allowReturnOutsideFunction: true, 149 | allowSuperOutsideMethod: true, 150 | strictMode: false, 151 | plugins: ["*", "jsx", "flow"] 152 | }, 153 | ast: true 154 | }; 155 | 156 | fs.readFile(inputFile, "utf-8", function(err, input) { 157 | if (err) { 158 | return callback(err); 159 | } 160 | 161 | var { code: output, ast } = babel.transformSync(input, transformOptions); 162 | fs.writeFileSync(outputFile, output); 163 | try { 164 | checkDuplicatedNodes(babel, ast); 165 | } catch (err) { 166 | err.message = "Occurred while transforming: " + inputFile + "\n" + err.message; 167 | throw err; 168 | } 169 | callback(); 170 | }); 171 | } 172 | 173 | function convertWithParamsTransform(es6File, es5File, callback) { 174 | var transformOptions = { 175 | presets:[require("regenerator-preset")], 176 | plugins: [ 177 | require("@babel/plugin-transform-parameters") 178 | ], 179 | parserOpts: { 180 | sourceType: "module", 181 | allowImportExportEverywhere: true, 182 | allowReturnOutsideFunction: true, 183 | allowSuperOutsideMethod: true, 184 | strictMode: false, 185 | plugins: ["*", "jsx", "flow"] 186 | }, 187 | ast: true 188 | }; 189 | 190 | fs.readFile(es6File, "utf-8", function(err, es6) { 191 | if (err) { 192 | return callback(err); 193 | } 194 | 195 | var { code: es5, ast } = babel.transformSync(es6, transformOptions); 196 | fs.writeFileSync(es5File, es5); 197 | try { 198 | checkDuplicatedNodes(babel, ast); 199 | } catch (err) { 200 | err.message = "Occurred while transforming: " + es6File + "\n" + err.message; 201 | throw err; 202 | } 203 | callback(); 204 | }); 205 | } 206 | 207 | enqueue(convertWithParamsTransform, [ 208 | "./test/regression.js", 209 | "./test/regression.es5.js" 210 | ]); 211 | 212 | function convertWithCustomPromiseReplacer(es6File, es5File, callback) { 213 | var transformOptions = { 214 | presets: [require("regenerator-preset")], 215 | plugins: [function(babel) { 216 | return { 217 | visitor: { 218 | FunctionExpression: { 219 | exit(path) { 220 | const stmt = path.get("body.body").find(function (stmt) { 221 | return stmt.isLabeledStatement() && 222 | stmt.get("label").isIdentifier({ name: "babelInjectPromise" }); 223 | }); 224 | if (!stmt) return; 225 | 226 | path.traverse({ 227 | ReferencedIdentifier(path) { 228 | if (path.node.name === "Promise") { 229 | path.replaceWith( 230 | babel.types.cloneNode(stmt.node.body.expression) 231 | ); 232 | } 233 | } 234 | }); 235 | } 236 | } 237 | } 238 | }; 239 | }], 240 | parserOpts: { 241 | strictMode: false, 242 | }, 243 | ast: true 244 | }; 245 | 246 | fs.readFile(es6File, "utf-8", function(err, es6) { 247 | if (err) { 248 | return callback(err); 249 | } 250 | 251 | var { code: es5, ast } = babel.transformSync(es6, transformOptions); 252 | fs.writeFileSync(es5File, es5); 253 | try { 254 | checkDuplicatedNodes(babel, ast); 255 | } catch (err) { 256 | err.message = "Occurred while transforming: " + es6File + "\n" + err.message; 257 | callback(err); 258 | } 259 | callback(); 260 | }); 261 | } 262 | 263 | enqueue(convertWithCustomPromiseReplacer, [ 264 | "./test/async-custom-promise.js", 265 | "./test/async-custom-promise.es5.js" 266 | ]) 267 | 268 | enqueue(makeMochaCopyFunction("mocha.js")); 269 | enqueue(makeMochaCopyFunction("mocha.css")); 270 | 271 | // uglify-js does not work properly due to Node 0.11.7 bug. 272 | // (https://github.com/joyent/node/issues/6235) 273 | if (!semver.eq(process.version, "0.11.7")) { 274 | try { 275 | require.resolve("browserify"); // Throws if missing. 276 | enqueue(bundle, [ 277 | [ 278 | "./test/runtime.js", 279 | "./test/tests.es5.js", 280 | "./test/tests-node4.es5.js", 281 | "./test/non-native.es5.js", 282 | "./test/async.es5.js", 283 | "./test/regression.es5.js" 284 | ], 285 | "./test/tests.browser.js" 286 | ]); 287 | } catch (ignored) { 288 | console.error("browserify not installed; skipping bundle step"); 289 | } 290 | } 291 | 292 | enqueue("mocha", [ 293 | "--reporter", "spec", 294 | "--require", "./test/runtime.js", 295 | "./test/tests.es5.js", 296 | "./test/tests-node4.es5.js", 297 | "./test/non-native.es5.js", 298 | "./test/async.es5.js", 299 | "./test/async-custom-promise.es5.js", 300 | "./test/regression.es5.js", 301 | "./test/tests.transform.js" 302 | ]); 303 | 304 | // Run command-line tool with available options to make sure it works. 305 | 306 | enqueue("./bin/regenerator", [ 307 | "./test/async.es5.js" 308 | ], true); 309 | 310 | enqueue("./bin/regenerator", [ 311 | "--include-runtime", 312 | "./test/async.es5.js" 313 | ], true); 314 | 315 | enqueue("./bin/regenerator", [ 316 | "--disable-async", 317 | "./test/async.es5.js" 318 | ], true); 319 | 320 | enqueue("./bin/regenerator", [ 321 | "--include-runtime", 322 | "--disable-async", 323 | "./test/async.es5.js" 324 | ], true); 325 | 326 | // Make sure we run the command-line tool on a file that does not need any 327 | // transformation, too. 328 | 329 | enqueue("./bin/regenerator", [ 330 | "./test/nothing-to-transform.js" 331 | ], true); 332 | 333 | enqueue("./bin/regenerator", [ 334 | "--include-runtime", 335 | "./test/nothing-to-transform.js" 336 | ], true); 337 | 338 | enqueue("./bin/regenerator", [ 339 | "--disable-async", 340 | "./test/nothing-to-transform.js" 341 | ], true); 342 | 343 | enqueue("./bin/regenerator", [ 344 | "--include-runtime", 345 | "--disable-async", 346 | "./test/nothing-to-transform.js" 347 | ], true); 348 | 349 | // Make sure we run the command-line tool on a file that would trigger this error: 350 | // 351 | // You passed `path.replaceWith()` a falsy node, use `path.remove()` instead 352 | 353 | enqueue("./bin/regenerator", [ 354 | "./test/replaceWith-falsy.js" 355 | ], true); 356 | 357 | enqueue("./bin/regenerator", [ 358 | "--include-runtime", 359 | "./test/replaceWith-falsy.js" 360 | ], true); 361 | 362 | enqueue("./bin/regenerator", [ 363 | "--disable-async", 364 | "./test/replaceWith-falsy.js" 365 | ], true); 366 | 367 | enqueue("./bin/regenerator", [ 368 | "--include-runtime", 369 | "--disable-async", 370 | "./test/replaceWith-falsy.js" 371 | ], true); 372 | 373 | enqueue("mocha", [ 374 | "--harmony", 375 | "--reporter", "spec", 376 | "--require", "./test/runtime.js", 377 | "./test/tests.es5.js", 378 | ]); 379 | 380 | enqueue("mocha", [ 381 | "--harmony", 382 | "--reporter", "spec", 383 | "--require", "./test/runtime.js", 384 | "./test/async.es5.js", 385 | ]); 386 | 387 | if (semver.gte(process.version, "6.0.0")) { 388 | enqueue("mocha", [ 389 | "--harmony", 390 | "--reporter", "spec", 391 | "--require", "./test/runtime.js", 392 | "./test/class.regenerator.js", 393 | ]); 394 | } 395 | enqueue("mocha", [ 396 | "--harmony", 397 | "--reporter", "spec", 398 | "--require", "./test/runtime.js", 399 | "./test/class.es5.js", 400 | ]); 401 | 402 | if (semver.gte(process.version, "4.0.0")) { 403 | enqueue("mocha", [ 404 | "--harmony", 405 | "--reporter", "spec", 406 | "--require", "./test/runtime.js", 407 | "./test/tests-node4.es6.js", 408 | ]); 409 | } 410 | 411 | if (semver.gte(process.version, "4.0.0")) { 412 | enqueue("mocha", [ 413 | "--harmony", 414 | "--reporter", "spec", 415 | "./test/non-writable-tostringtag-property.js", 416 | ]); 417 | } 418 | 419 | enqueue("mocha", [ 420 | "--harmony", 421 | "--reporter", "spec", 422 | "./test/frozen-intrinsics.js", 423 | ]); 424 | 425 | flush(); 426 | -------------------------------------------------------------------------------- /test/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | 6 | cd $(dirname $0)/.. 7 | ROOT_DIR=$(pwd) 8 | 9 | npm install 10 | 11 | install() { 12 | npm install ./packages/$1 13 | pushd node_modules/regenerator-$1 14 | npm install 15 | # Force the child packages to look in $ROOT_DIR/node_modules to find 16 | # one another. 17 | rm -rf node_modules 18 | popd 19 | } 20 | 21 | PKG=$(<package.json) 22 | PKG_LOCK=$(<package-lock.json) 23 | 24 | # Link local packages into node_modules. 25 | install runtime 26 | install transform 27 | install preset 28 | 29 | echo "$PKG" > package.json 30 | echo "$PKG_LOCK" > package-lock.json 31 | 32 | # We need to use the symlink paths rather than the real paths, so that the 33 | # regenerator-* packages appear to reside in node_modules. 34 | node test/run.js 35 | -------------------------------------------------------------------------------- /test/runtime.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | require("regenerator-runtime"); 9 | -------------------------------------------------------------------------------- /test/shared.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | 10 | if (typeof Symbol === "function") { 11 | exports.Symbol = Symbol; 12 | } else { 13 | exports.Symbol = function Symbol() {}; 14 | } 15 | 16 | if (! exports.Symbol.iterator) { 17 | exports.Symbol.iterator = "@@iterator"; 18 | } 19 | 20 | exports.check = function check(g, yields, returnValue) { 21 | for (var i = 0; i < yields.length; ++i) { 22 | var info = g.next(i); 23 | assert.deepEqual(info.value, yields[i]); 24 | assert.strictEqual(info.done, false); 25 | } 26 | 27 | assert.deepEqual( 28 | i > 0 ? g.next(i) : g.next(), 29 | { value: returnValue, done: true } 30 | ); 31 | }; 32 | 33 | exports.assertAlreadyFinished = 34 | function assertAlreadyFinished(generator) { 35 | assert.deepEqual(generator.next(), { 36 | value: void 0, 37 | done: true 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /test/tests-node4.es6.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | // tests that should be run only in node 4 and higher, as they use 9 | // language features not supported by versions < 4 (even with --harmony). 10 | var shared = require("./shared.js"); 11 | var check = shared.check; 12 | 13 | describe("object properties", function () { 14 | it("should work if the generator is a simple object property", function () { 15 | var obj = { 16 | gen: function*(x) { 17 | yield x; 18 | } 19 | }; 20 | 21 | check(obj.gen("oyez"), ["oyez"]); 22 | }); 23 | 24 | it("should work if the generator is a shorthand object method", function () { 25 | var obj = { 26 | *gen(x) { 27 | yield x; 28 | } 29 | }; 30 | 31 | check(obj.gen("oyez"), ["oyez"]); 32 | }); 33 | 34 | it("should work if the generator is a shorthand computed object method", function () { 35 | var fnName = "gen"; 36 | var obj = { 37 | *[fnName](x) { 38 | yield x; 39 | } 40 | }; 41 | 42 | check(obj.gen("oyez"), ["oyez"]); 43 | }); 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /test/tests.transform.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | var assert = require("assert"); 9 | var recast = require("recast"); 10 | var v8 = require("v8"); 11 | var types = recast.types; 12 | var n = types.namedTypes; 13 | var transform = require("..").transform; 14 | var compile = require("..").compile; 15 | 16 | var UglifyJS = require("uglify-js"); 17 | 18 | describe("_blockHoist nodes", function() { 19 | it("should be hoisted to the outer body", function() { 20 | var foo; 21 | var names = []; 22 | var ast = recast.parse([ 23 | "function *foo(doNotHoistMe, hoistMe) {", 24 | " var sent = yield doNotHoistMe();", 25 | " hoistMe();", 26 | " names.push(sent);", 27 | " return 123;", 28 | "}" 29 | ].join("\n"), { 30 | parser: require("@babel/parser") 31 | }); 32 | 33 | var hoistMeStmt = ast.program.body[0].body.body[1]; 34 | n.ExpressionStatement.assert(hoistMeStmt); 35 | n.CallExpression.assert(hoistMeStmt.expression); 36 | n.Identifier.assert(hoistMeStmt.expression.callee); 37 | assert.strictEqual(hoistMeStmt.expression.callee.name, "hoistMe"); 38 | 39 | hoistMeStmt._blockHoist = 1; 40 | 41 | eval(recast.print(transform(ast)).code); 42 | 43 | assert.strictEqual(typeof foo, "function"); 44 | assert.ok(regeneratorRuntime.isGeneratorFunction(foo)); 45 | assert.strictEqual(names.length, 0); 46 | 47 | var g = foo(function doNotHoistMe() { 48 | names.push("doNotHoistMe"); 49 | return "yielded"; 50 | }, function hoistMe() { 51 | names.push("hoistMe"); 52 | }); 53 | 54 | assert.deepEqual(names, ["hoistMe"]); 55 | assert.deepEqual(g.next(), { value: "yielded", done: false }); 56 | assert.deepEqual(names, ["hoistMe", "doNotHoistMe"]); 57 | assert.deepEqual(g.next("oyez"), { value: 123, done: true }); 58 | assert.deepEqual(names, ["hoistMe", "doNotHoistMe", "oyez"]); 59 | }); 60 | }); 61 | 62 | describe("uglifyjs dead code removal", function() { 63 | function uglifyAndParse(file1, file2) { 64 | var code = { 65 | "file1.js": file1, 66 | "file2.js": file2 67 | }; 68 | 69 | var options = { 70 | toplevel: true, 71 | // don't mangle function or variable names so we can find them 72 | mangle: false, 73 | output: { 74 | // make it easier to parse the output 75 | beautify: true 76 | } 77 | }; 78 | 79 | // uglify our code 80 | var result = UglifyJS.minify(code, options); 81 | 82 | // parse and return the output 83 | return recast.parse(result.code, { 84 | parser: require("@babel/parser") 85 | }); 86 | } 87 | 88 | it("works with function expressions", function() { 89 | var file1 = compile([ 90 | 'var foo = function* () {};', 91 | 'var bar = function* () {};' 92 | ].join("\n")).code; 93 | var file2 = compile('console.log(foo());').code; 94 | 95 | var ast = uglifyAndParse(file1, file2); 96 | 97 | // the results should have a single variable declaration 98 | var variableDeclarations = ast.program.body.filter(function(b) { 99 | return b.type === 'VariableDeclaration'; 100 | }); 101 | assert.strictEqual(variableDeclarations.length, 1); 102 | assert.strictEqual(variableDeclarations[0].declarations.length, 1); 103 | var declaration = variableDeclarations[0].declarations[0]; 104 | 105 | // named foo 106 | assert.strictEqual(declaration.id.name, 'foo'); 107 | }); 108 | 109 | it("works with function declarations", function() { 110 | var file1 = compile([ 111 | 'function* foo() {};', 112 | 'function* bar() {};' 113 | ].join("\n")).code; 114 | 115 | var file2 = compile('console.log(foo());').code; 116 | 117 | var ast = uglifyAndParse(file1, file2); 118 | 119 | // the results should have our foo() function 120 | assert.ok(ast.program.body.some(function(b) { 121 | return b.type === 'FunctionDeclaration' && b.id.name === 'foo'; 122 | })); 123 | 124 | // but not our bar() function 125 | assert.ok(!ast.program.body.some(function(b) { 126 | return b.type === 'FunctionDeclaration' && b.id.name === 'bar'; 127 | })); 128 | 129 | // and a single mark declaration 130 | var variableDeclarations = ast.program.body.filter(function(b) { 131 | return b.type === 'VariableDeclaration'; 132 | }); 133 | assert.strictEqual(variableDeclarations.length, 1); 134 | var declarations = variableDeclarations[0].declarations; 135 | assert.strictEqual(declarations.length, 1); 136 | var declaration = declarations[0]; 137 | 138 | // with our function name as an argument' 139 | assert.strictEqual(declaration.init.arguments.length, 1); 140 | assert.strictEqual(declaration.init.arguments[0].name, 'foo'); 141 | }); 142 | }) 143 | 144 | context("functions", function() { 145 | function marksCorrectly(marked, varName) { 146 | // marked should be a VariableDeclarator 147 | n.VariableDeclarator.assert(marked); 148 | 149 | // using our variable name 150 | assert.strictEqual(marked.id.name, varName); 151 | 152 | assertMarkCall(marked.init); 153 | } 154 | 155 | function assertMarkCall(node) { 156 | // assigning a call expression to regeneratorRuntime.mark() 157 | 158 | n.CallExpression.assert(node); 159 | assert.strictEqual(node.callee.object.name, 'regeneratorRuntime') 160 | assert.strictEqual(node.callee.property.name, 'mark') 161 | 162 | // with said call expression marked as a pure function 163 | assert.strictEqual(node.leadingComments[0].value, '#__PURE__'); 164 | } 165 | 166 | describe("function declarations", function() { 167 | it("should work with a single function", function() { 168 | var ast = recast.parse('function* foo(){};', { 169 | parser: require("@babel/parser") 170 | }); 171 | 172 | // get our declarations 173 | const declaration = transform(ast).program.body[0]; 174 | n.VariableDeclaration.assert(declaration); 175 | const declarations = declaration.declarations; 176 | 177 | // verify our declaration is marked correctly 178 | marksCorrectly(declarations[0], '_marked'); 179 | 180 | // and has our function name as its first argument 181 | assert.strictEqual(declarations[0].init.arguments[0].name, 'foo'); 182 | }); 183 | 184 | it("should work with multiple functions", function() { 185 | var ast = recast.parse([ 186 | 'function* foo() {};', 187 | 'function* bar() {};' 188 | ].join("\n"), { 189 | parser: require("@babel/parser") 190 | }); 191 | 192 | // get our declarations 193 | const declaration = transform(ast).program.body[0]; 194 | n.VariableDeclaration.assert(declaration); 195 | const declarations = declaration.declarations; 196 | 197 | // verify our declarations are marked correctly and have our function name 198 | // as their first argument 199 | marksCorrectly(declarations[0], '_marked'); 200 | n.Identifier.assert(declarations[0].init.arguments[0]); 201 | assert.strictEqual(declarations[0].init.arguments[0].name, 'foo'); 202 | 203 | marksCorrectly(declarations[1], '_marked2'); 204 | n.Identifier.assert(declarations[1].init.arguments[0]); 205 | assert.strictEqual(declarations[1].init.arguments[0].name, 'bar'); 206 | }); 207 | }); 208 | 209 | describe("function expressions", function() { 210 | it("should work with a named function", function() { 211 | var ast = recast.parse('var a = function* foo(){};', { 212 | parser: require("@babel/parser") 213 | }); 214 | 215 | // get our declarations 216 | const declaration = transform(ast).program.body[0]; 217 | n.VariableDeclaration.assert(declaration); 218 | const declarator = declaration.declarations[0]; 219 | 220 | // verify our declaration is marked correctly 221 | marksCorrectly(declarator, 'a'); 222 | 223 | // and that our first argument is our original function expression 224 | n.FunctionExpression.assert(declarator.init.arguments[0]); 225 | assert.strictEqual(declarator.init.arguments[0].id.name, 'foo'); 226 | }); 227 | 228 | it("should work with an anonymous function", function() { 229 | var ast = recast.parse('var a = function* (){};', { 230 | parser: require("@babel/parser") 231 | }); 232 | 233 | // get our declarations 234 | const declaration = transform(ast).program.body[0]; 235 | n.VariableDeclaration.assert(declaration); 236 | const declarator = declaration.declarations[0]; 237 | 238 | // verify our declaration is marked correctly 239 | marksCorrectly(declarator, 'a'); 240 | 241 | // and that our first argument is our original function expression 242 | n.FunctionExpression.assert(declarator.init.arguments[0]); 243 | assert.strictEqual(declarator.init.arguments[0].id.name, '_callee'); 244 | }); 245 | }); 246 | 247 | describe("class methods", function() { 248 | it("should be correctly wrapped", function () { 249 | const input = ` 250 | class A { 251 | *foo() {} 252 | } 253 | `; 254 | 255 | // The regenerator preset also transpiles classes 256 | const { ast } = require("@babel/core").transformSync(input, { 257 | configFile: false, 258 | ast: true, 259 | plugins: [require("../packages/transform")], 260 | }); 261 | 262 | const method = ast.program.body[0].body.body[0]; 263 | n.ClassMethod.assert(method); 264 | 265 | const return_ = method.body.body[0]; 266 | n.ReturnStatement.assert(return_); 267 | n.CallExpression.assert(return_.argument); 268 | 269 | assertMarkCall(return_.argument.callee); 270 | 271 | /* 272 | class A { 273 | foo() { 274 | return ( 275 | #__PURE__ 276 | regeneratorRuntime.mark(function _callee() { 277 | return regeneratorRuntime.wrap(function _callee$(_context) { 278 | while (1) switch (_context.prev = _context.next) { 279 | case 0: 280 | case "end": 281 | return _context.stop(); 282 | } 283 | }, _callee); 284 | })() 285 | ); 286 | } 287 | 288 | } 289 | */ 290 | }); 291 | }); 292 | 293 | describe("variables hoisting", function() { 294 | it("shouldn't throw about duplicate bindings", function() { 295 | // https://github.com/babel/babel/issues/6923 296 | 297 | const code = ` 298 | async function foo() { 299 | (async function f(number) { 300 | const tmp = number 301 | }) 302 | } 303 | `; 304 | 305 | assert.doesNotThrow(function() { 306 | require("@babel/core").transformSync(code, { 307 | configFile: false, 308 | plugins: [require("../packages/transform")], 309 | }); 310 | }); 311 | }); 312 | 313 | it("should register hoisted variable bindings", function() { 314 | // https://github.com/babel/babel/issues/10193 315 | 316 | const code = ` 317 | import { someAction } from 'actions'; 318 | 319 | function* foo() { const someAction = bar; } 320 | `; 321 | 322 | const compiled = require("@babel/core").transformSync(code, { 323 | configFile: false, 324 | plugins: [ 325 | require("../packages/transform"), 326 | require("@babel/plugin-transform-modules-commonjs") 327 | ] 328 | }).code; 329 | 330 | assert.strictEqual(compiled.indexOf("throw"), -1); 331 | assert.strictEqual(compiled.indexOf("read-only"), -1); 332 | }); 333 | }); 334 | }); 335 | 336 | describe("ast serialization", function() { 337 | function getAST() { 338 | return require("@babel/core").transformSync( 339 | `function* foo() { 340 | arguments; 341 | }`, 342 | { 343 | ast: true, 344 | configFile: false, 345 | plugins: [require("../packages/transform")], 346 | }, 347 | ).ast; 348 | } 349 | 350 | it("produces an ast that is JSON serializable", function() { 351 | assert.doesNotThrow(function() { 352 | JSON.stringify(getAST()); 353 | }); 354 | }) 355 | 356 | it("produces an ast that is serializable with v8's serializer", function() { 357 | assert.doesNotThrow(function() { 358 | v8.serialize(getAST()); 359 | }); 360 | }) 361 | }) 362 | --------------------------------------------------------------------------------