[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\ncharset = utf-8\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "Thank you for taking the time to contribute to this proposal!\nWe’re so happy you’re helping out.\n\n1. Please take a look at the [contributing guidelines][]\n   and the resources to which it links.\n2. Please include the purpose of the pull request. For example:\n   * “This adds…”\n   * “This simplifies…”\n   * “This fixes…”\n3. Please be explicit about what feedback, if any, you want:\n   a quick pair of eyes, discussion or critique of its approach,\n   a review of its copywriting, and so on.\n4. Please mark the pull request as a Draft if it is still unfinished.\n\nAll text in this repository is under the\n[same BSD license as Ecma-262][LICENSE.md].\nAs is the norm in open source, by contributing to this GitHub repository,\nyou are licensing your contribution under the same license,\nas per the\n[GitHub terms of service][ToS].\n\n[contributing guidelines]: https://github.com/tc39/proposal-pipeline-operator/blob/main/CONTRIBUTING.md\n[LICENSE.md]: https://github.com/tc39/proposal-pipeline-operator/blob/main/LICENSE.md\n[ToS]: https://help.github.com/en/github/site-policy/github-terms-of-service\n"
  },
  {
    "path": ".github/workflows/floodgate.yml",
    "content": "name: Comment Floodgate\non: issue_comment\njobs:\n  floodgate:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: js-choi/github-comment-floodgate@v2\n      with:\n        minutes-in-period: 60\n        # This number is how many comments are allowed per period per issue.\n        max-comments-per-period: 12\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Build and Deploy to GitHub Pages\non:\n  push:\n    branches:\n    - main\n  workflow_dispatch:\njobs:\n  build-and-deploy:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout 🛎️\n      uses: actions/checkout@v2\n      with:\n        persist-credentials: false\n\n    - name: Setup Node\n      uses: actions/setup-node@v1\n      with:\n        node-version: '14.x'\n\n    - name: Install and Build 🔧\n      run: |\n        npm install\n        npm run build\n\n    - name: Deploy 🚀\n      uses: peaceiris/actions-gh-pages@v3\n      with:\n        github_token: ${{ secrets.GITHUB_TOKEN }}\n        publish_dir: ./dist\n"
  },
  {
    "path": ".github/workflows/stale-lock.yml",
    "content": "name: Lock Stale Threads\n\non:\n  schedule:\n  - cron: '0 0 * * *'\n\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-requests: write\n\nconcurrency:\n  group: lock\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: dessant/lock-threads@v3\n      with:\n        issue-inactive-days: 7\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\nout\ndist\nnpm-debug.log\ndeploy_key\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: off\n\nlanguage: node_js\n\nnode_js:\n  - \"8\"\n\nscript:\n  - bash ./deploy.sh\n\nenv:\n  global:\n    - ENCRYPTION_LABEL: \"bc1f69dfbe70\"\n    - GH_USER_NAME: \"littledan\"\n    - GH_USER_EMAIL: \"littledan@igalia.com\"\n    - PRIVATE_KEY_FILE_NAME: \"github_deploy_key.enc\"\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of conduct\nThis repository is a TC39 project, and it therefore subscribes to\nits [code of conduct][CoC]. It is available at <https://tc39.es/code-of-conduct/>.\n\nWe all should strive here to be respectful, friendly and patient,\ninclusive, considerate, and careful in the words we choose.\nWhen we disagree, we should try to understand why.\n\nTo ask a question or report an issue, please follow the [CoC]’s directions, e.g., emailing\n[tc39-conduct-reports@googlegroups.com][].\n\nMore information about contributing is also available in [CONTRIBUTING.md][].\n\n[CoC]: https://tc39.es/code-of-conduct/\n[tc39-conduct-reports@googlegroups.com]: mailto:tc39-conduct-reports@googlegroups.com\n[CONTRIBUTING.md]: https://github.com/tc39/proposal-pipeline-operator/blob/main/CONTRIBUTING.md\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to the ES pipe operator’s proposal\nFirst off, thank you for taking the time to contribute! 🎉\n\nHere are some suggestions to contributing to this proposal.\nThe pipe operator in JavaScript has a [long and twisty history][HISTORY.md].\nA lot of issues have already been argued round in round in circles.\n\nBearing that in mind, please try to read the following\nbefore making new issues or comments:\n\n1. [HISTORY.md][]: This will give a lot of context\n   behind what’s been happening to the proposal since its creation in 2015.\n2. The general [TC39 Process][], which summarizes\n   how TC39’s “consensus” and “Stages” work.\n3. The guide on [contributing to TC39 proposals][contributing guide].\n4. The [TC39 Code of Conduct][CoC]:\n   It has important information about how we’re all expected to act\n   and what to do when we feel like someone’s conduct does not meet the Code.\n   We all want to maintain a friendly, productive working environment!\n5. The [TC39 How to Give Feedback][feedback] article.\n6. The [proposal explainer][] to make sure that it is\n   not already addressed there.\n7. The [TC39 Matrix guide][] (if you want to chat with TC39 members on Matrix,\n   which is a real-time chat platform).\n8. If the explainer does not already explain your topic adequately,\n   then please [search the GitHub repository’s issues][issues]\n   to see if any issues match the topic you had in mind.\n   This proposal is more than four years old,\n   and it is likely that the topic has already been raised and thoroughly discussed.\n\nYou can leave a comment on an [existing GitHub issue][issues],\ncreate a new issue (but really do try to [find an existing GitHub issue][issues] first),\nor [participate on Matrix][TC39 Matrix guide].\n\nPlease try to keep any existing GitHub issues on their original topic.\n\nWe’ve also installed a [“floodgate” moderation bot](https://github.com/marketplace/actions/comment-floodgate)\n(see [issue #231](https://github.com/tc39/proposal-pipeline-operator/issues/231)).\nWhen a issue gets a huge flood of new comments (i.e., new comments are being created at a very high rate),\nthen the bot will temporarily lock that issue.\n(The threshold rate is currently set to twelve messages in the same thread in the same sixty minutes.)\nThis doesn’t mean that the automatically locked high-traffic threads will get locked permanently.\nIt just means that the issue’s thread will cool down until a volunteer moderator is able to look at what’s going on.\n\nIf you feel that someone’s conduct is not meeting the [TC39 Code of Conduct][CoC],\nwhether in this GitHub repository or in a [TC39 Matrix room][TC39 Matrix guide],\nthen please follow the [Code of Conduct][CoC]’s directions for reporting the violation,\nincluding emailing [tc39-conduct-reports@googlegroups.com][].\n\nThank you again for taking the time to contribute!\n\n[HISTORY.md]: https://github.com/tc39/proposal-pipeline-operator/blob/main/HISTORY.md\n[CoC]: https://tc39.es/code-of-conduct/\n[TC39 process]: https://tc39.es/process-document/\n[contributing guide]: https://github.com/tc39/ecma262/blob/master/CONTRIBUTING.md#new-feature-proposals\n[feedback]: https://github.com/tc39/how-we-work/blob/master/feedback.md\n[proposal explainer]: https://github.com/tc39/proposal-pipeline-operator/blob/main/README.md\n[TC39 Matrix guide]: https://github.com/tc39/how-we-work/blob/master/matrix-guide.md\n[issues]: https://github.com/tc39/proposal-pipeline-operator/issues?q=is%3Aissue+\n[tc39-conduct-reports@googlegroups.com]: mailto:tc39-conduct-reports@googlegroups.com\n"
  },
  {
    "path": "HISTORY.md",
    "content": "# Brief history of the JavaScript pipe operator\nThe pipe operator in JavaScript has a long and twisty history.\nUnderstanding that history can give context behind\nwhat’s been happening to the proposal since its creation in 2015.\n\nFor information on what “Stage 1” and “Stage 2” mean,\nread about the [TC39 Process][].\n\nMore information about contributing is also available in [CONTRIBUTING.md][].\n\n## 2015–2017\nPeople are debating about a [proposed bind operator `::`][bind]\nby [@zenparsing][] (Brave).\nA binary `::` operator that binds its left-hand side to its right-hand side (a function)\nwould serve as a “pipe” operator in JavaScript\n(e.g., `a::f(b, c)::g(d, e)` would be a “pipeline” equivalent to\n`g.call(f.call(a, b, c), d, e)`).\nHowever, parts of TC39 object to using `this`,\nsaying that using `this` is strange outside of methods.\nDebate online in the `::` repository (and also offline) is bogged down in circles.\n\n[@littledan][] (Igalia) and [@gilbert][] create a proposal\nfor an alternative pipe operator that does not use `this`.\nThey start out [comparing F# pipes with Elixir pipes][first pipe preso].\nThey also [explore other syntaxes such as “placeholder” pipes (i.e., Hack pipes)][I4].\n\nMeanwhile, [@rbuckton][] (Microsoft) discusses pipelining with the F# team\nand plans to simultaneously propose F# pipes and syntax\nfor [partial function application][].\nUpon discovering [@littledan][] (Igalia)’s proposal for F#-or-Elixir pipes,\n[@rbuckton][] (Microsoft) finds that it already\naligns with the F# pipe that he had been planning to present,\nand he switches to focusing on syntax for [partial function application][].\n\n## 2017-07\nOn [2017-09-26][S1], [@littledan][] makes a first\n[presentation for F#-or-Elixir pipes to TC39, successfully advancing to Stage 1][S1].\n\nHowever, parts of TC39 object to redundancy with a bind operator.\nA condition of the advancement to Stage 1 is that it would not be redundant\nwith a bind operator; this will become relevant later.\n\nIn addition, parts of TC39 object to aspects of F# pipes,\nsuch as how they handle `await` and `yield`.\n\n[@rbuckton][] (Microsoft) presents syntax for [partial function application][]\n[at the same meeting and succeeds in advancing to Stage 1][PFA S1].\nHowever, parts of TC39 push back against its syntax.\n\n## 2017–2018\n[@littledan][] and collaborators [attempt to make a stopgap with `|> await`][I66]\nbut encounter several conceptual and syntactic problems,\nincluding a problem related to unexpected automatic semicolon insertion.\n[@littledan][] decides to try to defer handling `await` at all to a later proposal;\nhe also drops Elixir pipes in favor of F# pipes.\n\nOn [2017-11-29][S2 2017], [@littledan][] makes\n[another presentation for F# pipes and does not succeed in advancing to Stage 2][S2 2017].\nDuring the presentation, he proposes to TC39 that `|> await` be deferred,\nbut there is pushback from several other representatives, and presentation time overflows.\n\nAdvancement of F# pipes is therefore stymied.\n\n[@gilbert][] suggests resurrecting Hack pipes,\nwhich were [previously explored in 2015][I4],\nas a solution to TC39’s blocking concerns.\nHe also suggests two possible compromises that mix F# pipes and Hack pipes:\n[“split-mix pipes” and “smart-mix pipes”][I89].\n[@littledan][] (Igalia) agrees to investigate all three styles.\n[@mAAdhaTTah][] (pro-F#-pipes) and [@js-choi][] (slightly pro-Hack-pipes)\nvolunteer to collaborate on competing specs:\n[@mAAdhaTTah][] writes a [spec for F# pipes][F# spec]\nand [@js-choi][] writes a [spec for smart-mix pipes][smart-mix-pipes spec].\n\n## 2018–2020\nOn [2018-03-22][S2 2018], [@littledan][] presents F# pipes again—alongside\nsmart-mix pipes—in an\n[update presentation, trying to gain more consensus within TC39 for Stage 2][S2 2018].\nHowever, neither proposal is able to achieve much consensus among TC39 representatives\ndue to syntactic concerns.\nSome TC39 representatives state that no pipe operator\nmay be worth standardizing at all.\n\nAdvancement of F# pipes therefore continues to be stymied;\nadvancement of smart-mix pipes is also stymied.\n\n[@rbuckton][] (Microsoft) also presents [partial function application][]\nagain [on 2018-07, attempting to advance it to Stage 2][PFA 2018-07].\nHowever, several TC39 representatives continue to push back against its syntax.\n[@syg][] (Google V8) also expresses “strong reservations” about PFA syntax\nincreasing the “ease with which [developers] can allocate many many closures”,\nwith regards to memory use.\nPartial function application is also unable to advance to Stage 2,\nand its advancement is therefore also stymied.\n\n[@codehag][] (Mozilla SpiderMonkey) meanwhile leads a\n[Mozilla user study about pipes][Mozilla study].\nIts results suggest that developers like and prefer smart-mix pipes slightly more,\nbut they make slightly less errors with F# pipes.\nHer conclusions from the study were that no difference between smart-mix pipes or F# pipes\nwas significant enough to justify any decision one way or the other.\n(There is also another Mozilla user study about partial function application,\nand its results suggests that the JavaScript community\nis much more interested in partial function application than any pipe operator.)\nThe Mozilla SpiderMonkey team becomes weakly against any pipe operator.\n\nWork on F# pipes, smart-mix pipes, and PFA syntax stalls.\n\nFor the three years, GitHub debate online and debate offline\ncontinues back and forth in circles:\nabout the best way to increase the odds that smart-mix pipes vs. F# pipes\nwill reach consensus in TC39.\n\n## 2021-01\nThe State of JS 2020 is published,\nand it reports that one of the [language’s top requested features][SoJS 20]\nis some kind of pipe operator.\nThis galvanizes [@littledan][] (Igalia)’s further work on pipe,\nand he prepares a presentation for 2021-03’s TC39 meeting.\n\n## 2021-03\n[@littledan][] (Igalia) is managing other projects\nand is now unable to devote time to the pipe operator.\nHe presents about it again to TC39 and asks there for a new lead champion.\n[@tabatkins][] (Google), who also does much work in Web Platform standards\nsuch as HTML5 DOM and CSS,\nis personally enthusiastic about helping with any pipe operator\nand agrees to take on being co-champion.\n[@rbuckton][] (Microsoft) also agrees to co-champion the proposal.\n\n[@tabatkins][] (Google) publishes a [Gist comparing F#, Hack, and smart-mix pipes][Gist], concluding that they are all functionally the same,\nwith only small differences in actual usage,\nand that all three would benefit everyone.\nDiscussion is sparked in the Gist’s comments.\n\nGalvanized by the Gist,\n[@js-choi][] switches from writing the [smart-mix-pipes spec][]\nto writing a [Hack-pipes spec][].\n\n## 2021-07\n[@tabatkins][] (Google) schedules a\n[TC39 incubator meeting devoted to pipes][2021-07 incubator]\n(see [general information on incubator calls][]).\nAttendees of special note in this meeting are [@syg][] (Google V8),\n[@littledan][] (Igalia), [@rbuckton][] (Microsoft), and [@ljharb][]. [@codehag][] (Mozilla SpiderMonkey) is unable to attend.\n\n[@tabatkins][] (Google) presents three choices to the attendees again:\nF# pipes, Hack pipes, and Elixir pipes.\n\n[@rbuckton][] (Microsoft) is still in favor of F# pipes with his proposed syntax for\n[partial function application][] (see [§ 2016–2017](#20162017)).\n[@rbuckton][] (Microsoft) debates with [@tabatkins][] (Google)\nabout whether F# pipes or Hack pipes are more intuitive.\n(He also mentions that [@codehag][] (Mozilla SpiderMonkey)\nmight be interested in co-championing partial function application without pipes,\nbased on her user studies’ findings; see [§ 2018–2020](#20182020).)\n\n[@syg][] (Google V8) voices concerns again about engine performance\nof partial function application and F# pipes (see [§ 2018–2020](#20182020)).\n\n[@tabatkins][] (Google) and [@ljharb][] are supportive\nof either Hack pipes or F# pipes:\n“90%” F# pipes and “100%” Hack pipes.\nHowever, their 90% support of F# pipes would drop a lot if [@syg][]\n(Google V8)’s performance concerns about F# pipes are borne out.\n\nNobody in the meeting seems to think Elixir pipes are a good fit for JavaScript.\n\nMost everyone in the meeting seems to be in favor of picking some style for pipes\nafter three years of indecision.\n\n## 2021-08\n[@tabatkins][] (Google) plans to present *some* pipe-operator style for Stage 2.\nBased on the results of the the preceding meeting, they pick Hack pipes.\nThis has support from [@ljharb][] and some other TC39 representatives.\n[@js-choi][] (Indiana University) joins as co-champion.\n\nThrough this month, [@tabatkins][] (Google) continues to debate offline\nwith [@mAAdhaTTah][] regarding Hack pipes vs. F# pipes.\nAs a result, [@mAAdhaTTah][] changes his mind from being in favor of F# pipes\nto being in favor of Hack pipes,\ndeciding that [Hack pipes would be better for bridging functional programming][JDG essay]\nwith the rest of the JavaScript ecosystem.\n\n[@rbuckton][] (Microsoft) joins in debating with [@tabatkins][] (Google) in late August.\n[@rbuckton][] (Microsoft) notes the groundswell of support within TC39 about Hack pipes\ndue to “some of the limitations of F# pipes”.\nTherefore feeling that F# pipes would continue to be indefinitely stuck at an impasse,\n[@rbuckton][] (Microsoft) thus decides to give “tentative agreement” to Hack pipes.\n(See [@rbuckton’s narrative][].)\n\n***\n\nOn [2021-08-31][S2 2021], a formal Committee plenary occurs,\nand [@tabatkins][] (Google) therefore\n[presents Hack pipes as the tentative consensus among the champions,\nproposing that TC39 advance them to Stage 2][S2 2021].\nThere are several responses from other representatives:\n\n[@ljharb][] voices concern that advancing pipe\nwould kill any future bind operator (see [§ 2017-09](#2017-09)).\nOther representatives respond that Hack pipes are now orthogonal to any bind operator\nand would not kill it. [@ljharb][] decides not to block Stage 2.\n\n[@codehag][] (Mozilla SpiderMonkey) voices some concerns:\nthe Mozilla SpiderMonkey team is still somewhat against any pipe operator,\nwhatever the style.\nHowever, she decides that these concerns are not strong enough for her to block Stage 2.\n\n[@syg][] (Google V8), having previously expressed concerns about memory allocation\nencouraged by F# pipes and partial function application\n(see [§ 2021-07](#2021-07)), does not give any objection.\n\n[@rbuckton][] (Microsoft) continues to give tentative agreement to Hack pipes.\n\nNo other representatives give objections to Stage 2.\nHack pipes therefore succeed in advancing to Stage 2.\n[@tabatkins][] (Google) resolves to continue discussing concerns\nwith [@rbuckton][] (Microsoft), [@codehag][] (Mozilla SpiderMonkey), [@mAAdhaTTah][],\nand others offline.\nThey also discuss concerns with the community on GitHub,\nboth in the [2021-03 comparison Gist][Gist]’s comments (see [§ 2021-03](#2021-03))\nand in the [pipe proposal’s issues][issues].\n\n## 2021-09\nIn order to explain this proposal’s history and process to other community members,\n[@js-choi][] (Indiana University) creates this document.\n\nInspired by a [defense of unary functions][I233], [@js-choi][] (Indiana University)\nalso creates a new proposal, [proposal-function-helpers][], that would add several Function\nhelper methods. These include Function.pipe, pipeAsync, flow, and flowAsync.\n\n## 2021-10\nStarting on 2021-10-25, another formal Commitee plenary occurs.\nThe pipe operator is not presented at this meeting, although\nan [incubator meeting on 2021-11 is chartered][incubator charter 2021-11]\nfor bikeshedding the pipe operator’s topic token.\n\n[On 2021-10-25, PFA syntax is presented again to the Committee\nplenary][2021-10 PFA] by [@rbuckton][] (Microsoft) for Stage 2.\nThe Committee rejects this proposal; several representatives,\nincluding those from Mozilla SpiderMonkey and Google V8, state\nthat there were insufficiently specific and compelling use cases presented,\nwith high syntax cost and novelty in comparison to arrow functions.\n\n[On 2021-10-28, proposal-function-helpers is also presented to the\nCommittee plenary][2021-10 Function] for Stage 1 by [@js-choi][].\nThe Committee also rejects this proposal due to its being overly broad,\nand it requests that it be split up into multiple proposals.\nThese split proposals would include a proposal specifically\nabout [Function.pipe and flow][].\n\n## 2021-12: Holistic-dataflow articles\nSince December, TC39 has continued to discuss the pipe operator in the greater\ncontext of “dataflow”.\n\nThe “dataflow” proposals include the following:\n\n* The [pipe operator][Hack pipes] `… |> …` (aka “Hack pipes”)\n* [Function.pipe][] (a function version of the F# pipe operator)\n* The [bind-this][] operator `…::…` (and its variant [call-this][] `…@(…)`)\n* The [Extensions][] syntaxes `…::…`, `…::…:…`, and `const ::{ … } = …;`\n* [Partial function application][PFA syntax] `…~(…)` (aka “PFA syntax”)\n\nThese dataflow proposals overlap in various complicated ways. Multiple TC39\nrepresentatives expressed concerns about redundancies between these\nproposals—that the space as a whole needs to be holistically considered, that\ngoals need to be more specifically articulated, and that there is not enough\n“syntax budget” in the language to approve all of these proposals. This applies\nto the pipe operator, as well as all the others in that list.\n\n![][diagram]\n\n* In late December, [@js-choi][] wrote [an article detailing how these\n  proposals overlap][2022-12 jschoi dataflow article].\n* [@tabatkins then wrote a response article](https://www.xanthir.com/b5Gd0) on\n  their own blog.\n* Later, [@hax would also write another response\n  article](https://hackmd.io/yDDJCsS-Sv2AJwo8arAn3w?view). (@hax is a TC39\n  champion of the [Extensions][] syntaxes.)\n\n## 2022-01: Plenary meeting\nOn [January 26, 2022, a plenary meeting was held][2022-01 plenary] to discuss these overlapping proposals holistically. This discussion overflowed into an [ad-hoc meeting on the next day][2022-01 overflow].\n\nIn these two meetings, TC39 representatives debated over such topics as:\n* Creating a unified language versus accommodating multiple programming paradigms (e.g., object oriented versus functional).\n* [TMTOWTDI][] versus [TOOWTDI][].\n* Whether generalized  language features (like the Hack-style pipe operator) or specialized features (like Function.pipe, the F#-style pipe operator, and the bind-this operator) were more desirable.\n* Whether it is better for language features to be universal or prescriptive in their usage.\n* The merits of specific dataflow proposals, including the pipe operator.\n\nSupport among TC39 representatives for the pipe operator as it is now (with a Hack-style topic reference) appears to range from strongly in favor to weakly against. Several representatives reaffirmed that they are moderately or strongly against F#-style syntax. Support for Function.pipe appears to be tepid: neither strongly positive or negative. For more details, see the [conclusions of the ad-hoc overflow meeting][2022-01 overflow conclusions].\n\n## 2022-03 and 2022-04\nAt the [2022-03 plenary, several candidate tokens for the topic reference were presented][2022-03 plenary pipe]. The Committee mildly preferred `@` as the topic reference. (However, a [delegate subsequently raised serious concerns about `@`][2022-04 serious @ concerns], and thus `@` was excluded again as a topic reference.)\n\nAdditionally, an [update about call-this was also presented at the plenary][2022-03 plenary call-this]. The call-this proposal continues to polarize the Committee due to ecosystem-schism concerns.\n\n## 2022-07\n[In the plenary on July 21, proposal-function-pipe-flow was formally presented to the Committee, and it was rejected for Stage 1][2022-07 plenary]. The Committee generally found its use cases not compelling enough compared to the pipe operator. Its champion subsequently withdrew it from consideration. (Eventually, after the pipe operator gains users, pain points with the pipe operator may be enough motivation to revive proposal-function-pipe-flow, but that would not occur for a long time.)\n\nThere is another [incubator call chartered for more pipe-operator bikeshedding](https://github.com/tc39/incubator-agendas/issues/26), which might or might not occur before the [September plenary](https://github.com/tc39/agendas/blob/main/2022/09.md).\n\n[issues]: https://github.com/tc39/proposal-pipeline-operator/issues?q=is%3Aissue+\n[CONTRIBUTING.md]: https://github.com/tc39/proposal-pipeline-operator/blob/main/CONTRIBUTING.md\n[general information on incubator calls]: https://github.com/tc39/how-we-work/blob/master/incubator-calls.md\n\n[bind]: https://github.com/tc39/proposal-bind-operator\n[partial function application]: https://github.com/tc39/proposal-partial-application\n[proposal-function-helpers]: https://github.com/js-choi/proposal-function-helpers\n[Function.pipe and flow]: https://github.com/js-choi/proposal-function-pipe-flow\n\n[F# spec]: https://github.com/valtech-nyc/proposal-fsharp-pipelines/\n[smart-mix-pipes spec]: https://github.com/js-choi/proposal-smart-pipelines\n[Hack-pipes spec]: https://github.com/tc39/proposal-hack-pipes\n[Function.pipe]: https://github.com/js-choi/proposal-function-pipe-flow\n[bind-this]: https://github.com/tc39/proposal-bind-this\n[call-this]: https://github.com/tabatkins/proposal-call-this-operator\n[Extensions]: https://github.com/tc39/proposal-extensions\n[PFA syntax]: https://github.com/tc39/proposal-partial-application\n[diagram]: https://jschoi.org/21/es-dataflow/map/\n[Hack pipes]: https://github.com/tc39/proposal-pipeline-operator\n[TMTOWTDI]: https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it\n[TOOWTDI]: https://wiki.python.org/moin/TOOWTDI\n\n[first pipe preso]: https://docs.google.com/presentation/d/1qiWFzi5dkjuUVGcFXwypuQbEbZk-BV7unX0bYurcQsA/edit#slide=id.g1fa08b5c5c_0_93\n\n[I4]: https://github.com/tc39/proposal-pipeline-operator/issues/4\n[I75]: https://github.com/tc39/proposal-pipeline-operator/issues/75\n[I66]: https://github.com/tc39/proposal-pipeline-operator/pull/66\n[I89]: https://github.com/tc39/proposal-pipeline-operator/issues/89\n[I233]: https://github.com/tc39/proposal-pipeline-operator/issues/233\n\n[S1]: https://github.com/tc39/notes/blob/master/meetings/2017-09/sept-26.md#11iia-pipeline-operator\n[S2 2017]: https://github.com/tc39/notes/blob/master/meetings/2017-11/nov-29.md#9iii-pipeline-operator-for-stage-2\n[PFA S1]: https://github.com/tc39/notes/blob/master/meetings/2017-09/sept-28.md#13i-partial-application\n[S2 2018]: https://github.com/tc39/notes/blob/master/meetings/2018-03/mar-22.md#10ive-pipeline-operator\n[PFA 2018-07]: https://github.com/tc39/notes/blob/master/meetings/2018-07/july-25.md#partial-application\n[2021-07 incubator]: https://github.com/tc39/incubator-agendas/blob/master/notes/2021/06-17.md#pipeline\n[Mozilla study]: https://github.com/tc39/notes/blob/master/meetings/2019-06/june-6.md#javascript-and-syntax-research-methods\n[S2 2021]: https://github.com/tc39/notes/blob/master/meetings/2021-08/aug-31.md#pipeline-operator-for-stage-2\n[incubator charter 2021-11]: https://github.com/tc39/incubator-agendas/issues/21\n[2021-10 PFA]: https://github.com/tc39/notes/blob/master/meetings/2021-10/oct-25.md#partial-function-application-for-stage-2\n[2021-10 Function]: https://github.com/tc39/notes/blob/master/meetings/2021-10/oct-28.md#function-helpers\n[2022-01 plenary]: https://github.com/tc39/notes/blob/main/meetings/2022-01/jan-26.md#holistic-discussion-of-tc39-dataflow-proposals\n[2022-01 overflow]: https://github.com/tc39/incubator-agendas/blob/main/notes/2022/01-27.md\n[2022-01 overflow conclusions]: https://github.com/tc39/incubator-agendas/blob/main/notes/2022/01-27.md#conclusions\n[2022-12 jschoi dataflow article]: https://jschoi.org/21/es-dataflow/\n[2022-03 plenary pipe]: https://github.com/tc39/notes/blob/main/meetings/2022-03/mar-29.md#bikeshedding-the-pipe-operator-topic-token\n[2022-03 plenary call-this]: https://github.com/tc39/notes/blob/main/meetings/2022-03/mar-29.md#bikeshedding-call-this-syntax\n[2022-04 serious @ concerns]: https://github.com/tc39/proposal-pipeline-operator/issues/91#issuecomment-1084946624\n[2022-07 plenary]: https://github.com/tc39/notes/blob/main/meetings/2022-07/jul-21.md#functionpipe--flow-for-stage-1\n\n[TC39 process]: https://tc39.es/process-document/\n[Gist]: https://gist.github.com/tabatkins/1261b108b9e6cdab5ad5df4b8021bcb5\n[@rbuckton’s narrative]: https://github.com/tc39/proposal-pipeline-operator/issues/91#issuecomment-917645179\n[SoJS 20]: https://2020.stateofjs.com/en-US/opinions/?missing_from_js\n[JDG essay]: https://jamesdigioia.com/hack-pipe-for-functional-programmers-how-i-learned-to-stop-worrying-and-love-the-placeholder/\n\n[@littledan]: https://github.com/littledan/\n[@gilbert]: https://github.com/gilbert/\n[@tabatkins]: https://github.com/tabatkins/\n[@codehag]: https://github.com/codehag/\n[@mAAdhaTTah]: https://github.com/mAAdhaTTah/\n[@js-choi]: https://github.com/js-choi/\n[@syg]: https://github.com/syg/\n[@ljharb]: https://github.com/ljharb/\n[@rbuckton]: https://github.com/rbuckton/\n[@zenparsing]: https://github.com/zenparsing\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright 2021 J. S. Choi, James DiGioia, Ron Buckton, Tab Atkins-Bittner\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\n**This software is provided by the copyright holders and contributors “as is” and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright holder or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.**\n"
  },
  {
    "path": "README.md",
    "content": "# Pipe Operator (`|>`) for JavaScript\n\n* **Stage**: 2\n* **Champions**: J. S. Choi, James DiGioia, Ron Buckton, Tab Atkins-Bittner, \\[list incomplete] <!-- Alpha order by first name, plz -->\n* **Former champions**: Daniel Ehrenberg\n* **[Specification][]**\n* **[Contributing guidelines][]**\n* **[Proposal history][]**\n* **Babel plugin**: [Implemented in v7.15][Babel 7.15]. See [Babel documentation][].\n\n(This document uses `%`\nas the placeholder token for the topic reference.\nThis will ***almost certainly not be the final choice***;\nsee [the token bikeshedding discussion][token bikeshedding] for details.)\n\n[specification]: http://tc39.github.io/proposal-pipeline-operator/\n[Babel 7.15]: https://babeljs.io/blog/2021/07/26/7.15.0#hack-style-pipeline-operator-support-13191httpsgithubcombabelbabelpull13191-13416httpsgithubcombabelbabelpull13416\n[Babel documentation]: https://babeljs.io/docs/en/babel-plugin-proposal-pipeline-operator\n[token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91\n[contributing guidelines]: https://github.com/tc39/proposal-pipeline-operator/blob/main/CONTRIBUTING.md\n[proposal history]: https://github.com/tc39/proposal-pipeline-operator/blob/main/HISTORY.md\n\n## Why a pipe operator\nIn the State of JS 2020 survey, the **fourth top answer** to\n[“What do you feel is currently missing from\nJavaScript?”](https://2020.stateofjs.com/en-US/opinions/#missing_from_js)\nwas a **pipe operator**. Why?\n\nWhen we perform **consecutive operations** (e.g., function calls)\non a **value** in JavaScript,\nthere are currently two fundamental styles:\n* passing the value as an argument to the operation\n  (**nesting** the operations if there are multiple operations),\n* or calling the function as a method on the value\n  (**chaining** more method calls if there are multiple methods).\n\nThat is, `three(two(one(value)))` versus `value.one().two().three()`.\nHowever, these styles differ much in readability, fluency, and applicability.\n\n### Deep nesting is hard to read\nThe first style, **nesting**, is generally applicable –\nit works for any sequence of operations:\nfunction calls, arithmetic, array/object literals, `await` and `yield`, etc.\n\nHowever, nesting is **difficult to read** when it becomes deep:\nthe flow of execution moves **right to left**,\nrather than the left-to-right reading of normal code.\nIf there are **multiple arguments** at some levels,\nreading even bounces **back and forth**:\nour eyes must **jump left** to find a function name,\nand then they must **jump right** to find additional arguments.\nAdditionally, **editing** the code afterwards can be fraught:\nwe must find the correct **place to insert** new arguments\namong **many nested parentheses**.\n\n<details>\n<summary><strong>Real-world example</strong></summary>\n\nConsider this [real-world code from React](https://github.com/facebook/react/blob/17.0.2/scripts/jest/jest-cli.js#L295).\n\n```js\nconsole.log(\n  chalk.dim(\n    `$ ${Object.keys(envars)\n      .map(envar =>\n        `${envar}=${envars[envar]}`)\n      .join(' ')\n    }`,\n    'node',\n    args.join(' ')));\n```\n\nThis real-world code is made of **deeply nested expressions**.\nIn order to read its flow of data, a human’s eyes must first:\n\n1. Find the **initial data** (the innermost expression, `envars`).\n2. And then scan **back and forth** repeatedly from **inside out**\n   for each data transformation,\n   each one either an easily missed prefix operator on the left\n   or a suffix operators on the right:\n\n   1. `Object.keys()` (left side),\n   2. `.map()` (right side),\n   3. `.join()` (right side),\n   4. A template literal (both sides),\n   5. `chalk.dim()` (left side), then\n   6. `console.log()` (left side).\n\nAs a result of deeply nesting many expressions\n(some of which use **prefix** operators,\nsome of which use **postfix** operators,\nand some of which use **circumfix** operators),\nwe must check **both left and right sides**\nto find the **head** of **each expression**.\n\n</details>\n\n### Method chaining is limited\nThe second style, **method chaining**, is **only** usable\nif the value has the functions designated as **methods** for its class.\nThis **limits** its applicability.\nBut **when** it applies, thanks to its postfix structure,\nit is generally more usable and **easier** to read and write.\nCode execution flows **left to right**.\nDeeply nested expressions are **untangled**.\nAll arguments for a function call are **grouped** with the function’s name.\nAnd editing the code later to **insert or delete** more method calls is trivial,\nsince we would just have to put our cursor in one spot,\nthen start typing or deleting one **contiguous** run of characters.\n\nIndeed, the benefits of method chaining are **so attractive**\nthat some **popular libraries contort** their code structure\nspecifically to allow **more method chaining**.\nThe most prominent example is **[jQuery][]**, which\nstill remains the **most popular JS library** in the world.\njQuery’s core design is a single über-object with dozens of methods on it,\nall of which return the same object type so that we can **continue chaining**.\nThere is even a name for this style of programming:\n**[fluent interfaces][]**.\n\n[jQuery]: https://jquery.com/\n[fluent interfaces]: https://en.wikipedia.org/wiki/Fluent_interface\n\nUnfortunately, for all of its fluency,\n**method chaining** alone cannot accommodate JavaScript’s **other syntaxes**:\nfunction calls, arithmetic, array/object literals, `await` and `yield`, etc.\nIn this way, method chaining remains **limited** in its **applicability**.\n\n### Pipe operators combine both worlds\nThe pipe operator attempts to marry the **convenience** and ease of **method chaining**\nwith the wide **applicability** of **expression nesting**.\n\nThe general structure of all the pipe operators is\n`value |>` <var>e1</var> `|>` <var>e2</var> `|>` <var>e3</var>,\nwhere <var>e1</var>, <var>e2</var>, <var>e3</var>\nare all expressions that take consecutive values as their parameters.\nThe `|>` operator then does some degree of magic to “pipe” `value`\nfrom the lefthand side into the righthand side.\n\n<details>\n<summary><strong>Real-world example</strong>, continued</summary>\n\nContinuing this deeply nested [real-world code from React][react/scripts/jest/jest-cli.js]:\n\n```js\nconsole.log(\n  chalk.dim(\n    `$ ${Object.keys(envars)\n      .map(envar =>\n        `${envar}=${envars[envar]}`)\n      .join(' ')\n    }`,\n    'node',\n    args.join(' ')));\n```\n\n…we can **untangle** it as such using a pipe operator\nand a placeholder token (`%`) standing in for the previous operation’s value:\n\n```js\nObject.keys(envars)\n  .map(envar => `${envar}=${envars[envar]}`)\n  .join(' ')\n  |> `$ ${%}`\n  |> chalk.dim(%, 'node', args.join(' '))\n  |> console.log(%);\n```\n\nNow, the human reader can **rapidly find** the **initial data**\n(what had been the most innermost expression, `envars`),\nthen **linearly** read, from **left to right**,\neach transformation on the data.\n\n</details>\n\n### Temporary variables are often tedious\nOne could argue that using **temporary variables**\nshould be the only way to untangle deeply nested code.\nExplicitly naming every step’s variable\ncauses something similar to method chaining to happen,\nwith similar benefits to reading and writing code.\n\n<details>\n<summary><strong>Real-world example</strong>, continued</summary>\n\nFor example, using our previous modified\n[real-world example from React][react/scripts/jest/jest-cli.js]:\n\n```js\nObject.keys(envars)\n  .map(envar => `${envar}=${envars[envar]}`)\n  .join(' ')\n  |> `$ ${%}`\n  |> chalk.dim(%, 'node', args.join(' '))\n  |> console.log(%);\n```\n\n…a version using temporary variables would look like this:\n\n```js\nconst envarString = Object.keys(envars)\n  .map(envar => `${envar}=${envars[envar]}`)\n  .join(' ');\nconst consoleText = `$ ${envarString}`;\nconst coloredConsoleText = chalk.dim(consoleText, 'node', args.join(' '));\nconsole.log(coloredConsoleText);\n```\n\n</details>\n\nBut there are reasons why we encounter deeply nested expressions\nin each other’s code **all the time in the real world**,\n**rather than** lines of temporary variables.\nAnd there are reasons why the **method-chain-based [fluent interfaces][]**\nof jQuery, Mocha, and so on are still **popular**.\n\nIt is often simply too **tedious and wordy** to **write**\ncode with a long sequence of temporary, single-use variables.\nIt is arguably even tedious and visually noisy for a human to **read**, too.\n\nIf [**naming** is one of the **most difficult tasks** in programming][naming hard],\nthen programmers will **inevitably avoid naming** variables\nwhen they perceive their benefit to be relatively small.\n\n[naming hard]: https://martinfowler.com/bliki/TwoHardThings.html\n\n### Reusing temporary variables is prone to unexpected mutation\nOne could argue that using a single **mutable variable** with a short name\nwould reduce the wordiness of temporary variables, achieving\nsimilar results as with the pipe operator.\n\n<details>\n<summary><strong>Real-world example</strong>, continued</summary>\n\nFor example, our previous modified\n[real-world example from React][react/scripts/jest/jest-cli.js]\ncould be re-written like this:\n```js\nlet _;\n_ = Object.keys(envars)\n  .map(envar => `${envar}=${envars[envar]}`)\n  .join(' ');\n_ = `$ ${_}`;\n_ = chalk.dim(_, 'node', args.join(' '));\n_ = console.log(_);\n```\n\n</details>\n\nBut code like this is **not common** in real-world code.\nOne reason for this is that mutable variables can **change unexpectedly**,\ncausing silent bugs that are hard to find.\nFor example, the variable might be accidentally referenced in a closure.\nOr it might be mistakenly reassigned within an expression.\n\n<details>\n<summary>Example code</summary>\n\n```js\n// setup\nfunction one () { return 1; }\nfunction double (x) { return x * 2; }\n\nlet _;\n_ = one(); // _ is now 1.\n_ = double(_); // _ is now 2.\n_ = Promise.resolve().then(() =>\n  // This does *not* print 2!\n  // It prints 1, because `_` is reassigned downstream.\n  console.log(_));\n\n// _ becomes 1 before the promise callback.\n_ = one(_);\n```\n\nThis issue would not happen with the pipe operator.\nThe topic token cannot be reassigned, and\ncode outside of each step cannot change its binding.\n\n```js\nlet _;\n_ = one()\n  |> double(%)\n  |> Promise.resolve().then(() =>\n    // This prints 2, as intended.\n    console.log(%));\n\n_ = one();\n```\n\n</details>\n\nFor this reason, code with mutable variables is also harder to read.\nTo determine what the variable represents at any given point,\nyou must to **search the entire preceding scope** for places where it is **reassigned**.\n\nThe topic reference of a pipeline, on the other hand, has a limited lexical scope,\nand its binding is immutable within its scope.\nIt cannot be accidentally reassigned, and it can be safely used in closures.\n\nAlthough the topic value also changes with each pipeline step,\nwe only scan the previous step of the pipeline to make sense of it,\nleading to code that is easier to read.\n\n### Temporary variables must be declared in statements\nAnother benefit of the pipe operator over sequences of assignment statements\n(whether with mutable or with immutable temporary variables)\nis that they are **expressions**.\n\nPipe expressions are expressions that can be directly returned,\nassigned to a variable, or used in contexts such as JSX expressions.\n\nUsing temporary variables, on the other hand, requires sequences of statements.\n\n<details>\n<summary>Examples</summary>\n\n<table>\n<thead>\n<th>Pipelines</th>\n<th>Temporary Variables</th>\n</thead>\n\n<tbody>\n<tr>\n<td>\n\n```js\nconst envVarFormat = vars =>\n  Object.keys(vars)\n    .map(var => `${var}=${vars[var]}`)\n    .join(' ')\n    |> chalk.dim(%, 'node', args.join(' '));\n```\n\n</td>\n<td>\n\n```js\nconst envVarFormat = (vars) => {\n  let _ = Object.keys(vars);\n  _ = _.map(var => `${var}=${vars[var]}`);\n  _ = _.join(' ');\n  return chalk.dim(_, 'node', args.join(' '));\n}\n```\n\n</td>\n</tr>\n<tr>\n<td>\n\n```jsx\n// This example uses JSX.\nreturn (\n  <ul>\n    {\n      values\n        |> Object.keys(%)\n        |> [...Array.from(new Set(%))]\n        |> %.map(envar => (\n          <li onClick={\n            () => doStuff(values)\n          }>{envar}</li>\n        ))\n    }\n  </ul>\n);\n```\n\n</td>\n<td>\n\n```js\n// This example uses JSX.\nlet _ = values;\n_= Object.keys(_);\n_= [...Array.from(new Set(_))];\n_= _.map(envar => (\n  <li onClick={\n    () => doStuff(values)\n  }>{envar}</li>\n));\nreturn (\n  <ul>{_}</ul>\n);\n```\n\n</td>\n</tr>\n</tbody>\n</table>\n\n</details>\n\n## Why the Hack pipe operator\nThere were **two competing proposals** for the pipe operator: Hack pipes and F# pipes.\n(Before that, there **was** a [third proposal for a “smart mix” of the first two proposals][smart mix],\nbut it has been withdrawn,\nsince its syntax is strictly a superset of one of the proposals’.)\n\n[smart mix]: https://github.com/js-choi/proposal-smart-pipelines/\n\nThe two pipe proposals just differ **slightly** on what the “magic” is,\nwhen we spell our code when using `|>`.\n\n**Both** proposals **reuse** existing language concepts:\nHack pipes are based on the concept of the **expression**,\nwhile F# pipes are based on the concept of the **unary function**.\n\nPiping **expressions** and piping **unary functions**\ncorrespondingly have **small** and nearly **symmetrical trade-offs**.\n\n### This proposal: Hack pipes\nIn the **Hack language**’s pipe syntax,\nthe righthand side of the pipe is an **expression** containing a special **placeholder**,\nwhich is evaluated with the placeholder bound to the result of evaluating the lefthand side's expression.\nThat is, we write `value |> one(%) |> two(%) |> three(%)`\nto pipe `value` through the three functions.\n\n**Pro:** The righthand side can be **any expression**,\nand the placeholder can go anywhere any normal variable identifier could go,\nso we can pipe to any code we want **without any special rules**:\n\n* `value |> foo(%)` for unary function calls,\n* `value |> foo(1, %)` for n-ary function calls,\n* `value |> %.foo()` for method calls,\n* `value |> % + 1` for arithmetic,\n* `value |> [%, 0]` for array literals,\n* `value |> {foo: %}` for object literals,\n* `` value |> `${%}` `` for template literals,\n* `value |> new Foo(%)` for constructing objects,\n* `value |> await %` for awaiting promises,\n* `value |> (yield %)` for yielding generator values,\n* `value |> import(%)` for calling function-like keywords,\n* etc.\n\n**Con:** Piping through **unary functions**\nis **slightly more verbose** with Hack pipes than with F# pipes.\nThis includes unary functions\nthat were created by **[function-currying][] libraries** like [Ramda][],\nas well as [unary arrow functions\nthat perform **complex destructuring** on their arguments][destruct]:\nHack pipes would be slightly more verbose\nwith an **explicit** function call suffix `(%)`.\n\n(Complex destructuring of the topic value\nwill be easier when [do expressions][] progress,\nas you will then be able to do variable assignment/destructuring\ninside of a pipe body.)\n\n[function-currying]: https://en.wikipedia.org/wiki/Currying\n[Ramda]: https://ramdajs.com/\n[destruct]: https://github.com/js-choi/proposal-hack-pipes/issues/4#issuecomment-817208635\n\n### Alternative proposal: F# pipes\nIn the [**F# language**’s pipe syntax][F# pipes],\nthe righthand side of the pipe is an expression\nthat must **evaluate into a unary function**,\nwhich is then **tacitly called**\nwith the lefthand side’s value as its **sole argument**.\nThat is, we write `value |> one |> two |> three` to pipe `value`\nthrough the three functions.\n`left |> right` becomes `right(left)`.\nThis is called [tacit programming or point-free style][tacit].\n\n[F# pipes]: https://github.com/valtech-nyc/proposal-fsharp-pipelines\n[tacit]: https://en.wikipedia.org/wiki/Tacit_programming\n\n<details>\n<summary><strong>Real-world example</strong>, continued</summary>\n\nFor example, using our previous modified\n[real-world example from React][react/scripts/jest/jest-cli.js]:\n\n```js\nObject.keys(envars)\n  .map(envar => `${envar}=${envars[envar]}`)\n  .join(' ')\n  |> `$ ${%}`\n  |> chalk.dim(%, 'node', args.join(' '))\n  |> console.log(%);\n```\n\n…a version using F# pipes instead of Hack pipes would look like this:\n\n```js\nObject.keys(envars)\n  .map(envar => `${envar}=${envars[envar]}`)\n  .join(' ')\n  |> x=> `$ ${x}`\n  |> x=> chalk.dim(x, 'node', args.join(' '))\n  |> console.log;\n```\n\n</details>\n\n**Pro:** The restriction that the righthand side\n**must** resolve to a unary function\nlets us write very terse pipes\n**when** the operation we want to perform\nis a **unary function call**:\n\n* `value |> foo` for unary function calls.\n\nThis includes unary functions\nthat were created by **[function-currying][] libraries** like [Ramda][],\nas well as [unary arrow functions\nthat perform **complex destructuring** on their arguments][destruct]:\nF# pipes would be **slightly less verbose**\nwith an **implicit** function call (no `(%)`).\n\n**Con:** The restriction means that **any operations**\nthat are performed by **other syntax**\nmust be made **slightly more verbose** by **wrapping** the operation\nin a unary **arrow function**:\n\n* `value |> x=> x.foo()` for method calls,\n* `value |> x=> x + 1` for arithmetic,\n* `value |> x=> [x, 0]` for array literals,\n* `value |> x=> ({foo: x})` for object literals,\n* `` value |> x=> `${x}` `` for template literals,\n* `value |> x=> new Foo(x)` for constructing objects,\n* `value |> x=> import(x)` for calling function-like keywords,\n* etc.\n\nEven calling **named functions** requires **wrapping**\nwhen we need to pass **more than one argument**:\n\n* `value |> x=> foo(1, x)` for n-ary function calls.\n\n**Con:** The **`await` and `yield`** operations are **scoped**\nto their **containing function**,\nand thus **cannot be handled by unary functions** alone.\nIf we want to integrate them into a pipe expression,\n[`await` and `yield` must be handled as **special syntax cases**][enhanced F# pipes]:\n\n* `value |> await` for awaiting promises, and\n* `value |> yield` for yielding generator values.\n\n[enhanced F# pipes]: https://github.com/valtech-nyc/proposal-fsharp-pipelines/\n\n### Hack pipes favor more common expressions\n**Both** Hack pipes and F# pipes respectively impose\na small **syntax tax** on different expressions:\\\n**Hack pipes** slightly tax only **unary function calls**, and\\\n**F# pipes** slightly tax **all expressions except** unary function calls.\n\nIn **both** proposals, the syntax tax per taxed expression is **small**\n(**both** `(%)` and `x=>` are **only three characters**).\nHowever, the tax is **multiplied** by the **prevalence**\nof its respectively taxed expressions.\nIt therefore might make sense\nto impose a tax on whichever expressions are **less common**\nand to **optimize** in favor of whichever expressions are **more common**.\n\nUnary function calls are in general **less common**\nthan **all** expressions **except** unary functions.\nIn particular, **method** calling and **n-ary function** calling\nwill **always** be **popular**;\nin general frequency,\n**unary** function calling is equal to or exceeded by\nthose two cases **alone** –\nlet alone by other ubiquitous syntaxes\nsuch as **array literals**, **object literals**,\nand **arithmetic operations**.\nThis explainer contains several [real-world examples][]\nof this difference in prevalence.\n\n[real-world examples]: #real-world-examples\n\nFurthermore, several other proposed **new syntaxes**,\nsuch as **[extension calling][]**,\n**[do expressions][]**,\nand **[record/tuple literals][]**,\nwill also likely become **pervasive** in the **future**.\nLikewise, **arithmetic** operations would also become **even more common**\nif TC39 standardizes **[operator overloading][]**.\nUntangling these future syntaxes’ expressions would be more fluent\nwith Hack pipes compared to F# pipes.\n\n[extension calling]: https://github.com/tc39/proposal-extensions/\n[do expressions]: https://github.com/tc39/proposal-do-expressions/\n[record/tuple literals]: https://github.com/tc39/proposal-record-tuple/\n[operator overloading]: https://github.com/tc39/proposal-operator-overloading/\n\n### Hack pipes might be simpler to use\nThe syntax tax of Hack pipes on unary function calls\n(i.e., the `(%)` to invoke the righthand side’s unary function)\nis **not a special case**:\nit simply is **explicitly writing ordinary code**,\nin **the way we normally would** without a pipe.\n\nOn the other hand, **F# pipes require** us to **distinguish**\nbetween “code that resolves to an unary function”\nversus **“any other expression”** –\nand to remember to add the arrow-function wrapper around the latter case.\n\nFor example, with Hack pipes, `value |> someFunction + 1`\nis **invalid syntax** and will **fail early**.\nThere is no need to recognize that `someFunction + 1`\nwill not evaluate into a unary function.\nBut with F# pipes, `value |> someFunction + 1` is **still valid syntax** –\nit’ll just **fail late** at **runtime**,\nbecause `someFunction + 1` isn’t callable.\n\n### TC39 has rejected F# pipes multiple times\nThe pipe champion group has presented F# pipes for Stage 2 to TC39 **twice**.\nIt was **unsuccessful** in advancing to Stage 2 both times.\nBoth F# pipes (and [partial function application (PFA)][PFA syntax])\nhave run into strong pushback from multiple other TC39 representatives\ndue to various concerns. These have included:\n\n* Memory performance concerns (e.g., [especially from browser-engine implementors][V8 pushback]),\n* Syntax concerns about `await`.\n* Concerns about encouraging ecosystem bifurcation/forking, etc.\n\n[V8 pushback]: https://github.com/tc39/proposal-pipeline-operator/blob/main/HISTORY.md#2021-07\n\nThis pushback has occurred from **outside** the pipe champion group.\nSee [HISTORY.md][] for more information.\n\nIt is the pipe champion group’s belief that any pipe operator is better than none,\nin order to [easily linearize deeply nested expressions](#why-a-pipe-operator)\nwithout resorting to named variables.\nMany members of the champion group believe that Hack pipes are slightly better than F# pipes,\nand some members of the champion group believe that F# pipes are slightly better than Hack pipes.\nBut everyone in the champion group agrees that F# pipes have met with far too much resistance\nto be able to pass TC39 in the foreseeable future.\n\nTo emphasize, it is likely that an attempt to switch from Hack pipes back to F# pipes\nwill result in TC39 never agreeing to any pipes at all.\n[PFA syntax][] is similarly facing an uphill battle in TC39 (see [HISTORY.md][]).\nMany members of the pipe champion group think this is unfortunate,\nand they are willing to fight again **later** for an [F#-pipe split mix][split mix] and [PFA syntax][].\nBut there are quite a few representatives (including [browser-engine implementers][V8 pushback])\noutside of the Pipe Champion Group\nwho are generally against encouraging [tacit programming][] (and [PFA syntax][]),\nregardless of Hack pipes.\n\n[HISTORY.md]: https://github.com/tc39/proposal-pipeline-operator/blob/main/HISTORY.md\n[tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming\n[PFA syntax]: https://github.com/tc39/proposal-partial-application\n[split mix]: #tacit-unary-function-application-syntax\n\n## Description\n(A [formal draft specification][specification] is available.)\n\nThe **topic reference** `%` is a **nullary operator**.\nIt acts as a placeholder for a **topic value**,\nand it is **lexically scoped** and **immutable**.\n\n<details>\n<summary><code>%</code> is not a final choice</summary>\n\n(The precise [**token** for the topic reference is **not final**][token bikeshedding].\n`%` could instead be `^`, or many other tokens.\nWe plan to [**bikeshed** what actual token to use][token bikeshedding]\nbefore advancing to Stage 3.\nHowever, `%` seems to be the [least syntactically problematic][],\nand it also resembles the placeholders of **[printf format strings][]**\nand [**Clojure**’s `#(%)` **function literals**][Clojure function literals].)\n\n[least syntactically problematic]: https://github.com/js-choi/proposal-hack-pipes/issues/2\n[Clojure function literals]: https://clojure.org/reference/reader#_dispatch\n[printf format strings]: https://en.wikipedia.org/wiki/Printf_format_string\n\n</details>\n\nThe **pipe operator** `|>` is an **infix operator**\nthat forms a **pipe expression** (also called a **pipeline**).\nIt evaluates its lefthand side (the **pipe head** or **pipe input**),\nimmutably **binds** the resulting value (the **topic value**) to the **topic reference**,\nthen evaluates its righthand side (the **pipe body**) with that binding.\nThe resulting value of the righthand side\nbecomes the whole pipe expression’s final value (the **pipe output**).\n\nThe pipe operator’s precedence is the **same** as:\n* the function arrow `=>`;\n* the assignment operators `=`, `+=`, etc.;\n* the generator operators `yield` and `yield *`;\n\nIt is **tighter** than only the comma operator `,`.\\\nIt is **looser** than **all other** operators.\n\nFor example, `v => v |> % == null |> foo(%, 0)`\\\nwould group into `v => (v |> (% == null) |> foo(%, 0))`,\\\nwhich in turn is equivalent to `v => foo(v == null, 0)`.\n\nA pipe body **must** use its topic value **at least once**.\nFor example, `value |> foo + 1` is **invalid syntax**,\nbecause its body does not contain a topic reference.\nThis design is because **omission** of the topic reference\nfrom a pipe expression’s body\nis almost certainly an **accidental** programmer error.\n\nLikewise, a topic reference **must** be contained in a pipe body.\nUsing a topic reference outside of a pipe body\nis also **invalid syntax**.\n\nTo prevent confusing grouping,\nit is **invalid** syntax to use **other** operators that have **similar precedence**\n(i.e., the arrow `=>`, the ternary conditional operator `?` `:`,\nthe assignment operators, and the `yield` operator)\nas a **pipe head or body**.\nWhen using `|>` with these operators, we must use **parentheses**\nto explicitly indicate what grouping is correct.\nFor example, `a |> b ? % : c |> %.d` is invalid syntax;\nit should be corrected to either `a |> (b ? % : c) |> %.d`\nor `a |> (b ? % : c |> %.d)`.\n\nLastly, topic bindings **inside dynamically compiled** code\n(e.g., with `eval` or `new Function`)\n**cannot** be used **outside** of that code.\nFor example, `v |> eval('% + 1')` will throw a syntax error\nwhen the `eval` expression is evaluated at runtime.\n\nThere are **no other special rules**.\n\nA natural result of these rules is that,\nif we need to interpose a **side effect**\nin the middle of a chain of pipe expressions,\nwithout modifying the data being piped through,\nthen we could use a **comma expression**,\nsuch as with `value |> (sideEffect(), %)`.\nAs usual, the comma expression will evaluate to its righthand side `%`,\nessentially passing through the topic value without modifying it.\nThis is especially useful for quick debugging: `value |> (console.log(%), %)`.\n\n## Real-world examples\nThe only changes to the original examples were dedentation and removal of comments.\n\nFrom [jquery/build/tasks/sourceMap.js][]:\n```js\n// Status quo\nvar minLoc = Object.keys( grunt.config( \"uglify.all.files\" ) )[ 0 ];\n\n// With pipes\nvar minLoc = grunt.config('uglify.all.files') |> Object.keys(%)[0];\n```\n\nFrom [node/deps/npm/lib/unpublish.js][]:\n```js\n// Status quo\nconst json = await npmFetch.json(npa(pkgs[0]).escapedName, opts);\n\n// With pipes\nconst json = pkgs[0] |> npa(%).escapedName |> await npmFetch.json(%, opts);\n```\n\nFrom [underscore.js][]:\n```js\n// Status quo\nreturn filter(obj, negate(cb(predicate)), context);\n\n// With pipes\nreturn cb(predicate) |> _.negate(%) |> _.filter(obj, %, context);\n```\n\nFrom [ramda.js][].\n```js\n// Status quo\nreturn xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc));\n\n// With pipes\nreturn xf\n  |> bind(%['@@transducer/step'], %)\n  |> obj[methodName](%, acc)\n  |> xf['@@transducer/result'](%);\n```\n\nFrom [ramda.js][].\n```js\n// Status quo\ntry {\n  return tryer.apply(this, arguments);\n} catch (e) {\n  return catcher.apply(this, _concat([e], arguments));\n}\n\n// With pipes: Note the visual parallelism between the two clauses.\ntry {\n  return arguments\n    |> tryer.apply(this, %);\n} catch (e) {\n  return arguments\n    |> _concat([e], %)\n    |> catcher.apply(this, %);\n}\n```\n\nFrom [express/lib/response.js][].\n```js\n// Status quo\nreturn this.set('Link', link + Object.keys(links).map(function(rel){\n  return '<' + links[rel] + '>; rel=\"' + rel + '\"';\n}).join(', '));\n\n// With pipes\nreturn links\n  |> Object.keys(%).map(function (rel) {\n    return '<' + links[rel] + '>; rel=\"' + rel + '\"';\n  })\n  |> link + %.join(', ')\n  |> this.set('Link', %);\n```\n\nFrom [react/scripts/jest/jest-cli.js][].\n```js\n// Status quo\nconsole.log(\n  chalk.dim(\n    `$ ${Object.keys(envars)\n      .map(envar => `${envar}=${envars[envar]}`)\n      .join(' ')}`,\n    'node',\n    args.join(' ')\n  )\n);\n\n// With pipes\nObject.keys(envars)\n  .map(envar => `${envar}=${envars[envar]}`)\n  .join(' ')\n  |> `$ ${%}`\n  |> chalk.dim(%, 'node', args.join(' '))\n  |> console.log(%);\n```\n\nFrom [ramda.js][].\n```js\n// Status quo\nreturn _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list);\n\n// With pipes\nreturn fn\n  |> (typeof % === 'function' ? _xwrap(%) : %)\n  |> xf(%)\n  |> _reduce(%, acc, list);\n```\n\nFrom [jquery/src/core/init.js][].\n```js\n// Status quo\njQuery.merge( this, jQuery.parseHTML(\n  match[ 1 ],\n  context && context.nodeType ? context.ownerDocument || context : document,\n  true\n) );\n\n// With pipes\ncontext\n  |> (% && %.nodeType ? %.ownerDocument || % : document)\n  |> jQuery.parseHTML(match[1], %, true)\n  |> jQuery.merge(%);\n```\n\n[ramda.js]: https://github.com/ramda/ramda/blob/v0.27.1/dist/ramda.js\n[node/deps/npm/lib/unpublish.js]: https://github.com/nodejs/node/blob/v16.x/deps/npm/lib/unpublish.js\n[node/deps/v8/test/mjsunit/regress/regress-crbug-158185.js]: https://github.com/nodejs/node/blob/v16.x/deps/v8/test/mjsunit/regress/regress-crbug-158185.js\n[express/lib/response.js]: https://github.com/expressjs/express/blob/5.0/lib/response.js\n[react/scripts/jest/jest-cli.js]: https://github.com/facebook/react/blob/17.0.2/scripts/jest/jest-cli.js\n[jquery/build/tasks/sourceMap.js]: https://github.com/jquery/jquery/blob/2.2-stable/build/tasks/sourcemap.js\n[jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js\n[underscore.js]: https://underscorejs.org/docs/underscore-esm.html\n\n## Relationships with other proposals\n\n### `Function` helpers\nHack pipes can and would coexist with the [`Function` helpers proposal][helpers],\nincluding its `pipe` and `flow` functions.\nThese simple (and commonly downloaded) convenience functions\nmanipulate unary functions without extra syntax.\n\n[helpers]: https://github.com/js-choi/proposal-function-helpers\n\n[TC39 has rejected the F# pipe operator twice][rejected].\nGiven this reality, TC39 is considerably more likely to pass\n`pipe` and `flow` helper functions than a similar syntactic operator.\n\n[rejected]: #tc39-has-rejected-f-pipes-multiple-times\n\nStandardized `pipe` and `flow` convenience functions\nmay also obviate some of the need for a F#-pipe infix operator.\n(They would not preclude standardizing an equivalent operator later.\nFor example, TC39 standardized binary `**` even when `Math.pow` existed.)\n\n### Partial-function-application syntax\nHack pipes can coexist with a syntax for **partial function application** (PFA).\nThere are two approaches with which they may coexist.\n\nThe **first approach** is with an **eagerly** evaluated PFA syntax,\nwhich has [already been proposed in proposal-partial-application][PFA syntax].\nThis eager PFA syntax would add an `…~(…)` operator.\nThe operator’s right-hand side would be a list of arguments,\neach of which is an ordinary expression or a `?` placeholder.\nEach consecutive `?` placeholder would represent another parameter.\n\nOrdinary expressions would be evaluated **before** the function is created.\nFor example, `f~(g(), ?, h(), ?)` would evaluate `f`, then `g()`, then `h()`,\nand *then* it would create a partially applied version of `f` with two arguments.\n\nAn optional number after `?` placeholder\nwould override the parameter’s position.\nFor example, `f~(?1, ?0)` would have two parameters but would switch them when calling `f`.\n\nThe **second approach** is with a **lazily** evaluated syntax.\nThis could be handled with an **extension to Hack pipes**,\nwith a syntax further inspired by\n[Clojure’s `#(%1 %2)` function literals][Clojure function literals].\nIt would do so by **combining** the Hack pipe `|>`\nwith the **arrow function** `=>`\ninto a **pipe-function** operator `+>`,\nwhich would use the same general rules as `|>`.\n\n`+>` would be a **prefix operator** that **creates a new function**,\nwhich in turn **binds its argument(s)** to topic references.\n**Non-unary functions** would be created\nby including topic references with **numbers** (`%0`, `%1`, `%2`, etc.) or `...`.\n`%0` (equivalent to plain `%`) would be bound to the **zeroth argument**,\n`%1` would be bound to the next argument, and so on.\n`%...` would be bound to an array of **rest arguments**.\nAnd just as with `|>`, `+>` would require its body\nto contain at least one topic reference\nin order to be syntactically valid.\n\n| Eager PFA                  | Pipe functions             |\n| ---------------------------| -------------------------- |\n|`a.map(f~(?, 0))`           |`a.map(+> f(%, 0))`         |\n|`a.map(f~(?, ?, 0))`        |`a.map(+> f(%0, %1, 0))`    |\n|`a.map(x=> x + 1)`          |`a.map(+> % + 1)`           |\n|`a.map(x=> x + x)`          |`a.map(+> % + %)`           |\n|`a.map(x=> f(x, x))`        |`a.map(+> f(%, %))`         |\n\nIn contrast to the [eagerly evaluated PFA syntax][PFA syntax],\ntopic functions would **lazily** evaluate its arguments,\njust like how an arrow function would.\n\nFor example, `+> f(g(), %0, h(), %1)` would evaluate `f`,\nand then it would create an arrow function that closes over `g` and `h`.\nThe created function would **not** evaluate `g()` or `h()`\nuntil the every time the created function is called.\n\nNo matter the approach taken, Hack pipes could coexist with PFA.\n\n### Eventual sending / pipelining\nDespite sharing the word “pipe” in their name,\nthe pipe operator and the [eventual-send proposal][]’s remote-object pipelines\nare orthogonal and independent.\nThey can coexist and even work together.\n\n```js\nconst fileP = E(\n  E(target).openDirectory(dirName)\n).openFile(fileName);\n\nconst fileP = target\n|> E(%).openDirectory(dirName)\n|> E(%).openFile(fileName);\n```\n\n[eventual-send proposal]: https://github.com/tc39/proposal-eventual-send/\n\n## Possible future extensions\n\n### Hack-pipe syntax for `if`, `catch`, and `for`–`of`\nMany **`if`, `catch`, and `for` statements** could become pithier\nif they gained **“pipe syntax”** that bound the topic reference.\n\n`if () |>` would bind its condition value to `%`,\\\n`catch |>` would bind its caught error to `%`,\\\nand `for (of) |>` would consecutively bind each of its iterator’s values to `%`.\n\n| Status quo                  | Hack-pipe statement syntax |\n| --------------------------- | -------------------------- |\n|`const c = f(); if (c) g(c);`|`if (f()) \\|> g(%);`        |\n|`catch (e) f(e);`            |`catch \\|> f(%);`           |\n|`for (const v of f()) g(v);` |`for (f()) \\|> g(%);`       |\n\n### Optional Hack pipes\nA **short-circuiting** optional-pipe operator `|?>` could also be useful,\nmuch in the way `?.` is useful for optional method calls.\n\nFor example, `value |> (% == null ? % : await foo(%) |> (% == null ? % : % + 1))`\\\nwould be equivalent to `value |?> await foo(%) |?> % + 1`.\n\n### Tacit unary function application syntax\n**Syntax** for **tacit unary function application** – that is, the F# pipe operator –\nhas been [rejected twice by TC39][rejected].\nHowever, they could still eventually be added to the language in two ways.\n\nFirst, it can be added as a convenience function `Function.pipe`.\nThis is what the [function-helpers proposal][helpers] proposes.\n`Function.pipe` may obviate much of the need for an F#-pipe operator,\nwhile still not closing off the possibility of an F#-pipe operator.\n\nSecondly, it can be added as **another pipe operator** `|>>` –\nsimilarly to how [Clojure has multiple pipe macros][Clojure pipes]\n`->`, `->>`, and `as->`.\\\nFor example, `value |> % + 1 |>> f |> g(%, 0)`\\\nwould mean `value |> % + 1 |> f(%) |> g(%, 0)`.\n\n[Clojure pipes]: https://clojure.org/guides/threading_macros\n\nThere was an [informal proposal for such a **split mix** of two pipe operators][split mix],\nwhich was set aside in favor of single-operator proposals.\nThis split mix might return as a proposal after Hack pipes.\n\n[split mix]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-3-split-mix\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"proposal-pipeline-operator\",\n  \"version\": \"1.0.0\",\n  \"description\": \"ECMAScript pipe-operator proposal\",\n  \"repository\": \"tc39/proposal-pipeline-operator\",\n  \"author\": \"Ecma TC39\",\n  \"license\": \"BSD-3-Clause\",\n  \"homepage\": \"https://tc39.github.io/proposal-pipeline-operator/\",\n  \"dependencies\": {\n    \"ecmarkup\": \"^12.0.0\"\n  },\n  \"scripts\": {\n    \"prebuild\": \"mkdir -p dist\",\n    \"build\": \"ecmarkup --verbose spec.html dist/index.html\",\n    \"watch\": \"npm run build -- --watch\"\n  }\n}\n"
  },
  {
    "path": "spec.html",
    "content": "<pre class=metadata>\ntitle: ES pipe operator (2021)\nstatus: proposal\nstage: 2\nlocation: https://github.com/tc39/proposal-pipeline-operator\ncopyright: false\ncontributors: J. S. Choi, James DiGioia, Ron Buckton, Tab Atkins-Bittner\n</pre>\n<script src=ecmarkup.js defer></script>\n<link rel=stylesheet href=ecmarkup.css>\n\n<emu-intro id=introduction>\n  <h1>Introduction</h1>\n  <p>This is the formal specification for a proposed Hack-style pipe\n  operator `|&gt;` in JavaScript. It modifies the original <a\n  href=https://tc39.github.io/ecma262/>ECMAScript specification</a> with\n  several new or revised clauses. See <a\n  href=https://github.com/js-choi/proposal-hack-pipes/blob/main/README.md>the proposal's\n  explainer</a> for the proposal's background, motivation, and usage examples.</p>\n\n  <p>This document presumptively uses `%` as the token\n  for the topic reference. This choice of token is not a final decision;\n  `%` could instead be `^` or some other token.</p>\n</emu-intro>\n\n<emu-clause id=\"sec-syntax-directed-operations\">\n  <h1>Syntax-Directed Operations</h1>\n\n  <emu-clause id=\"sec-syntax-directed-operations-function-name-inference\">\n    <h1>Function Name Inference</h1>\n\n    <emu-clause id=\"sec-static-semantics-isfunctiondefinition\" type=\"sdo\"\n    aoid=\"IsFunctionDefinition\">\n      <h1>Static Semantics: IsFunctionDefinition</h1>\n\n      <emu-note type=editor>\n        <p>This section augments the <a\n        href=https://tc39.es/ecma262/#sec-static-semantics-isfunctiondefinition>original\n        IsFunctionDefinition clause</a>.</p>\n\n        <p>It presumptively uses `%` as the placeholder token for the\n        topic reference. This choice of token is not a final decision; `%`\n        could instead be `^` or some other token.</p>\n      </emu-note>\n\n      <emu-grammar>\n        PrimaryExpression :\n          `this`\n          <ins>`%`</ins>\n          IdentifierReference\n          Literal\n          ArrayLiteral\n          ObjectLiteral\n          RegularExpressionLiteral\n          TemplateLiteral\n\n        <ins>PipeExpression :\n          ShortCircuitExpression `|&gt;` PipeBody</ins>\n      </emu-grammar>\n      <emu-alg>\n        1. Return *false*.\n      </emu-alg>\n    </emu-clause>\n\n    <emu-clause id=\"sec-static-semantics-isidentifierref\" type=\"sdo\"\n    aoid=\"IsIdentifierRef\">\n      <h1>Static Semantics: IsIdentifierRef</h1>\n\n      <emu-note type=editor>\n        <p>This section augments the <a\n        href=https://tc39.es/ecma262/#sec-static-semantics-isidentifierref>original IsIdentifierRef\n        clause</a>.</p>\n\n        <p>It presumptively uses `%` as the placeholder token for the\n        topic reference. This choice of token is not a final decision; `%`\n        could instead be `^` or some other token.</p>\n      </emu-note>\n\n      <emu-grammar>PrimaryExpression : IdentifierReference</emu-grammar>\n      <emu-alg>\n        1. Return *true*.\n      </emu-alg>\n      <emu-grammar>\n        PrimaryExpression :\n          `this`\n          <ins>`%`</ins>\n          Literal\n          ArrayLiteral\n          ObjectLiteral\n          FunctionExpression\n          ClassExpression\n          GeneratorExpression\n          AsyncFunctionExpression\n          AsyncGeneratorExpression\n          RegularExpressionLiteral\n          TemplateLiteral\n          CoverParenthesizedExpressionAndArrowParameterList\n      </emu-grammar>\n      <emu-alg>\n        1. Return *false*.\n      </emu-alg>\n    </emu-clause>\n  </emu-clause>\n\n  <emu-clause id=\"sec-syntax-directed-operations-contains\">\n    <h1>Contains</h1>\n\n    <emu-clause id=\"sec-static-semantics-ContainsOuterTopic\" type=\"sdo\" aoid=\"ContainsOuterTopic\">\n      <h1>Static Semantics: ContainsOuterTopic</h1>\n      <emu-note type=editor>\n        <p>This section is a wholly new sub-clause of the <a\n        href=https://tc39.github.io/ecma262/#sec-syntax-directed-operations-contains\n        >original Contains clause</a>.</p>\n      </emu-note>\n\n      <emu-note>\n        <p>Several early error rules for |ScriptBody| and for\n        |ModuleItemList|, as well as a step in CreateDynamicFunction,\n        use the ContainsOuterTopic operation to check for any unbound topic reference `%`.\n        Any inner topic reference within a |PipeBody| is hidden from these rules,\n        preventing them from triggering the rules during program\n        compilation.</p>\n\n        <p>This guarantees that any topic reference in a program must be\n        present within a topic-binding environment\n        created by a |PipeBody| within that program.</p>\n      </emu-note>\n\n      <p>Every grammar production alternative in this specification which is not listed below implicitly has the following default definition of ContainsOuterTopic:</p>\n\n      <emu-alg>\n        1. For each child node _child_ of this Parse Node, do\n          1. If _child_ is an instance of `%`, return *true*.\n          1. If _child_ is an instance of a nonterminal, and if ContainsOuterTopic of _child_ is *true*, return *true*.\n        1. Return *false*.\n      </emu-alg>\n\n      <emu-grammar>MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression</emu-grammar>\n\n      <emu-alg>\n        1. If ContainsOuterTopic of |MultiplicativeExpression| is *true*, or if ContainsOuterTopic of |ExponentiationExpression| is *true*, return *true*.\n        1. Return *false*.\n      </emu-alg>\n\n      <emu-grammar>PipeBody : AssignmentExpression</emu-grammar>\n\n      <emu-alg>\n        1. Return *false*.\n      </emu-alg>\n    </emu-clause>\n  </emu-clause>\n\n  <emu-clause id=\"sec-syntax-directed-operations-miscellaneous\">\n    <h1>Miscellaneous</h1>\n\n    <emu-clause id=\"sec-static-semantics-assignmenttargettype\" type=\"sdo\"\n    aoid=\"AssignmentTargetType\">\n      <h1>Static Semantics: AssignmentTargetType</h1>\n\n      <emu-note type=editor>\n        <p>This section augments the <a\n        href=https://tc39.es/ecma262/#sec-static-semantics-assignmenttargettype>original\n        AssignmentTargetType clause</a>.</p>\n\n        <p>It presumptively uses `%` as the placeholder token for the\n        topic reference. This choice of token is not a final decision; `%`\n        could instead be `^` or some other token.</p>\n      </emu-note>\n\n      <emu-grammar>\n        PrimaryExpression :\n          `this`\n          <ins>`%`</ins>\n          Literal\n          ArrayLiteral\n          ObjectLiteral\n          FunctionExpression\n          ClassExpression\n          GeneratorExpression\n          AsyncFunctionExpression\n          AsyncGeneratorExpression\n          RegularExpressionLiteral\n          TemplateLiteral\n\n        <ins>PipeExpression :\n          ShortCircuitExpression `|&gt;` PipeBody</ins>\n      </emu-grammar>\n      <emu-alg>\n        1. Return ~invalid~.\n      </emu-alg>\n    </emu-clause>\n  </emu-clause>\n</emu-clause>\n\n<emu-clause id=executable-code-and-execution-contexts>\n  <h1>Executable Code and Execution Contexts</h1>\n\n  <emu-clause id=sec-environment-records>\n    <h1>Environment Records</h1>\n\n    <emu-clause id=sec-the-environment-record-type-hierarchy>\n      <h1>The Environment Record Type Hierarchy</h1>\n\n      <emu-note type=editor>\n        <p>This section augments the <a\n        href=https://tc39.es/ecma262/#sec-the-environment-record-type-hierarchy>original\n        Environment Records clause</a>.</p>\n      </emu-note>\n\n      <emu-table id=table-15 caption=\"Abstract Methods of Environment Records\">\n        <table>\n          <thead>\n            <tr>\n              <th>Method</th>\n              <th>Purpose</th>\n            </tr>\n          </thead>\n          <tbody>\n            <tr>\n              <td><ins><emu-xref\n                href=#sec-declarative-environment-records-hastopicbinding\n                >HasTopicBinding()</emu-xref></ins></td>\n              <td><ins>Determine whether an Environment Record is a\n                topic-binding environment. Return *true* if it establishes a\n                topic binding and *false* if it does not.</ins></td>\n            </tr>\n          </tbody>\n        </table>\n      </emu-table>\n\n      <emu-clause id=sec-declarative-environment-records>\n        <h1>Declarative Environment Records</h1>\n\n        <emu-note type=editor>\n          <p>This section augments the <a\n          href=https://tc39.github.io/ecma262/#sec-declarative-environment-records\n          >original Declarative Environment Records clause</a>.</p>\n\n          <p>It presumptively uses `%` as the placeholder token for the\n          topic reference. This choice of token is not a final decision; `%`\n          could instead be `^` or some other token.</p>\n        </emu-note>\n\n        <ins class=block>\n          <p>Declarative Environment Records have the additional state fields\n          listed in <emu-xref href=\"#table-61\"></emu-xref>.</p>\n\n          <emu-table id=table-61\n            caption=\"Additional Fields of Declarative Environment Records\"\n          >\n            <table>\n              <thead>\n                <tr>\n                  <th>Method</th>\n                  <th>Value</th>\n                  <th>Purpose</th>\n                </tr>\n              </thead>\n              <tbody>\n                <tr>\n                  <td>[[TopicValues]]</td>\n                  <td>List of any</td>\n                  <td>If the declarative Environment Record is a topic-binding\n                  environment, then [[TopicValues]] is a List containing the one element\n                  which is the environment's topic value (that is, the value of\n                  the topic reference within its program scope).\n                  Otherwise, the value of [[TopicValues]] is an empty List.</td>\n                </tr>\n              </tbody>\n            </table>\n          </emu-table>\n\n          <emu-note type=editor>\n            <p>[[TopicValues]] is a List in order to be forward compatible with\n            future extensions that would use more than one topic value, e.g., <a\n         href=https://github.com/js-choi/proposal-hack-pipes/blob/master/README.md#hack-pipe-functions\n            >\"pipe functions\".</a></p>\n          </emu-note>\n\n          <p>Declarative Environment Records support all of the abstract methods\n          of Environment Records listed in <emu-xref href=\"#table-15\"></emu-xref>.\n          In addition, declarative Environment Records support the methods listed\n          in <emu-xref href=\"#table-62\"></emu-xref>.</p>\n\n          <emu-table id=table-62 caption=\"Additional Methods of Declarative Environment Records\">\n            <table>\n              <thead>\n                <tr>\n                  <th>Method</th>\n                  <th>Purpose</th>\n                </tr>\n              </thead>\n              <tbody>\n                <tr>\n                  <td>BindTopicValues(V)</td>\n                  <td>Establish the immutable topic binding of this\n                  Environment Record and set the topic binding's value.\n                  _V_ is a List containing the one element which is the\n                  topic value and is a value of any ECMAScript language\n                  type. Afterward, the Environment Record is a\n                  topic-binding environment, and the value returned by the\n                  Environment Record's HasTopicBinding method is *true*.\n                  This method cannot be called more than once on any\n                  single Environment Record.</td>\n                </tr>\n              </tbody>\n            </table>\n          </emu-table>\n\n          <emu-note type=editor>\n          <p>BindTopicValues accepts a List argument rather than a single-value\n          argument in order to be forward compatible with future extensions that\n          would use more than one topic value, e.g., <a\n          href=https://github.com/js-choi/proposal-hack-pipes/blob/master/README.md#hack-pipe-functions\n          >\"pipe functions\"</a>.</p>\n          </emu-note>\n        </ins>\n\n        <p>The behaviour of the concrete <ins>and additional</ins> specification\n        methods for declarative Environment Records is defined by the following\n        algorithms.</p>\n\n        <emu-clause id=sec-declarative-environment-records-hastopicbinding>\n          <h1><ins>HasTopicBinding ( )</ins></h1>\n          <emu-note type=editor>\n          <p>This section is a wholly new sub-clause of the <a\n          href=https://tc39.github.io/ecma262/#sec-declarative-environment-records\n          >original Declarative Environment Records clause</a>.</p>\n          </emu-note>\n\n          <p>The concrete Environment Record method HasTopicBinding for\n          declarative Environment Records returns whether the Environment Record\n          is a topic-binding environment. The value is *true* only if its\n          BindTopicValues method has been called.</p>\n          <emu-alg>\n            1. Let _envRec_ be the declarative Environment Record for which the\n               method was invoked.\n            1. Assert: _envRec_.[[TopicValues]] is a List.\n            1. If _envRec_.[[TopicValues]] is an empty List, then return *false*.\n            1. Return *true*.\n          </emu-alg>\n        </emu-clause>\n\n        <emu-clause id=sec-declarative-environment-records-bindtopicvalues>\n          <h1><ins>BindTopicValues ( _V_ )</ins></h1>\n          <emu-note type=editor>\n            <p>This section is a wholly new sub-clause of the <a\n            href=https://tc39.github.io/ecma262/#sec-declarative-environment-records\n            >original Declarative Environment Records clause</a>.</p>\n          </emu-note>\n          <p>The method BindTopicValues for declarative Environment Records may\n          only be called on an Environment Record when it is not yet a\n          topic-binding environment, after which it does become a topic-binding\n          environment.</p>\n          <emu-alg>\n            1. Assert: _V_ is a List.\n            1. Let _envRec_ be the declarative Environment Record for which the\n               method was invoked.\n            1. Assert: _envRec_.HasTopicBinding() is *false*.\n            1. Set _envRec_.[[TopicValues]] to _V_.\n            1. Assert: _envRec_.HasTopicBinding() is *true*.\n            1. Return NormalCompletion(~empty~).\n          </emu-alg>\n        </emu-clause>\n      </emu-clause>\n\n      <emu-clause id=sec-object-environment-records>\n        <h1>Object Environment Records</h1>\n\n        <emu-clause id=sec-object-environment-records-hastopicbinding>\n          <h1><ins>HasTopicBinding ( )</ins></h1>\n\n          <emu-note type=editor>\n          <p>This section is a wholly new sub-clause of the <a\n          href=https://tc39.github.io/ecma262/#sec-object-environment-records>\n          original Object Environment Records clause</a>.</p>\n          </emu-note>\n\n          <p>An Object Environment Record may never have a topic binding.</p>\n          <emu-alg>\n            1. Return *false*.\n          </emu-alg>\n          </emu-clause>\n      </emu-clause>\n\n      <emu-clause id=sec-global-environment-records>\n          <h1>Global Environment Records</h1>\n\n          <emu-clause id=sec-global-environment-records-hastopicbinding>\n            <h1><ins>HasTopicBinding ( )</ins></h1>\n\n            <emu-note type=editor>\n              <p>This section is a wholly new sub-clause of the <a\n              href=https://tc39.github.io/ecma262/#sec-object-environment-records>\n              original Global Environment Records clause</a>.</p>\n            </emu-note>\n\n            <p>A Global Environment Record may never have a topic binding.</p>\n            <emu-alg>\n              1. Return *false*.\n            </emu-alg>\n          </emu-clause>\n        </emu-clause>\n    </emu-clause>\n\n    <emu-clause id=sec-topic-bindings>\n      <h1><ins>Topic Bindings</ins></h1>\n\n      <emu-note type=editor>\n        <p>This section is a wholly new sub-clause of the <a\n        href=https://tc39.github.io/ecma262/#sec-environment-records>original\n        Environment Records clause</a>.</p>\n\n        <p>It presumptively uses `%` as the placeholder token for the\n        topic reference. This choice of token is not a final decision; `%`\n        could instead be `^` or some other token.</p>\n      </emu-note>\n\n      <p>The <dfn>topic binding</dfn> of a declarative Environment Record\n      immutably binds the topic reference `%` to one value of any\n      ECMAScript language type (called the <dfn>topic value</dfn> or simply\n      the <dfn>topic</dfn>), within that declarative Environment Record, at\n      the time of the Environment Record's instantiation. The topic of a\n      declarative Environment Record conceptually serves as the value that its\n      lexical context is \"about\".</p>\n\n      <p>A <dfn>topic-binding environment</dfn> is a declarative Environment\n      Record that establishes a topic binding.\n      The <dfn>topic environment</dfn> of the running execution context is its\n      LexicalEnvironment's innermost Environment Record that is also a\n      topic-binding environment (or *null* if no such Environment Record\n      exists), as defined by the abstract operator GetTopicEnvironment.</p>\n\n      <emu-note>\n        <p>An Environment Record is a topic-binding environment\n        <strong>only</strong> when it is a declarative Environment Record that\n        was created by a |PipeBody|.</p>\n      </emu-note>\n    </emu-clause>\n  </emu-clause>\n\n  <emu-clause id=\"sec-execution-contexts\">\n    <h1>Execution Contexts</h1>\n\n    <emu-note type=editor>\n      <p>This section augments the <a\n      href=https://tc39.es/ecma262/#sec-execution-contexts>original\n      Execution Contexts clause</a>.</p>\n    </emu-note>\n\n    <emu-clause id=\"sec-evaluatewithtopics\" type=\"abstract operation\">\n      <h1>\n        EvaluateWithTopics (\n          _topicValues_: a List,\n          _expression_: a Parse Node,\n        )\n      </h1>\n      <dl class=\"header\"></dl>\n      <emu-alg>\n        1. Assert: _topicValues_ is a List.\n        1. Let _outerEnv_ be the running execution context's LexicalEnvironment.\n        1. Let _topicEnv_ be NewDeclarativeEnvironment(_outerEnv_).\n        1. Perform ! _topicEnv_.BindTopicValues(_topicValues_).\n        1. Set the running execution context's LexicalEnvironment to\n           _topicEnv_.\n        1. Let _result_ be the result of evaluating _expression_.\n        1. Set the running execution context's LexicalEnvironment to _outerEnv_.\n        1. Return _result_.\n      </emu-alg>\n      <emu-note>\n        <p>EvaluateWithTopics creates a new topic-binding environment and\n        evaluates the given _expression_ with that as its topic environment.\n        The previous Lexical Environment is restored afterward.</p>\n      </emu-note>\n    </emu-clause>\n\n    <emu-clause id=sec-gettopicenvironment type=\"abstract operation\">\n      <h1>GetTopicEnvironment ( )</h1>\n      <dl class=\"header\"></dl>\n      <emu-alg>\n      1. Let _envRec_ be the running execution context's LexicalEnvironment.\n      1. Repeat,\n        1. Let _status_ be _envRec_.HasTopicBinding().\n        1. If _status_ is *true*, return _envRec_.\n        1. If _envRec_ is a global Environment Record, return *null*.\n        1. Let _outer_ be the value of _envRec_.[[OuterEnv]].\n        1. Set _envRec_ to _outer_.\n      1. Return _envRec_.\n      </emu-alg>\n      <emu-note>\n        <p>GetTopicEnvironment returns the running execution context's topic environment\n        (i.e., its LexicalEnvironment's innermost topic-binding environment)\n        or *null* if the running execution context has no topic binding.</p>\n      </emu-note>\n    </emu-clause>\n\n    <emu-clause id=sec-getprimarytopicvalue type=\"abstract operation\">\n      <h1>GetPrimaryTopicValue ( )</h1>\n      <dl class=\"header\"></dl>\n      <emu-alg>\n      1. Let _topicEnv_ be GetTopicEnvironment().\n      1. Assert: _topicEnv_ is a declarative Environment Record.\n      1. Assert: _topicEnv_.HasTopicBinding() is *true*.\n      1. Let _topicValues_ be _envRec_.[[TopicValues]].\n      1. Assert: _topicValues_ has at least one element.\n      1. Return _topicValues_[0].\n      </emu-alg>\n      <emu-note>\n        <p>GetPrimaryTopicValue returns the topic value\n        of the running execution context's topic environment.\n        It may be called only when the running execution context's topic environment\n        is not *null*.</p>\n      </emu-note>\n    </emu-clause>\n  </emu-clause>\n</emu-clause>\n\n<emu-clause id=sec-ecmascript-language-lexical-grammar>\n  <h1>ECMAScript Language: Lexical Grammar</h1>\n\n  <emu-clause id=sec-punctuators>\n    <h1>Punctuators</h1>\n\n    <emu-note type=editor>\n      <p>This section augments the <a\n      href=https://tc39.github.io/ecma262/#sec-punctuators>original\n      Punctuators clause</a>.</p>\n\n      <p>It presumptively uses `%` as the placeholder token for the\n      topic reference. This choice of token is not a final decision; `%`\n      could instead be `^` or some other token.</p>\n    </emu-note>\n\n    <emu-grammar>\n      OtherPunctuator :: one of\n        `{` `(` `)` `[` `]`\n        `.` `...` `;` `,`\n        `&lt;` `&gt;` `&lt;=` `&gt;=`\n        `==` `!=` `===` `!==`\n        `+` `-` `*` `%` `**`\n        `++` `--`\n        `&lt;&lt;` `&gt;&gt;` `&gt;&gt;&gt;`\n        `&amp;` `|` `%`\n        `!` `~`\n        `&amp;&amp;` `||` `??`\n        `?` `:`\n        <ins>`|&gt;`</ins>\n        `=` `+=` `-=` `*=` <del>`%=`</del> `**=`\n        `&lt;&lt;=` `&gt;&gt;=` `&gt;&gt;&gt;=` `&amp;=` `|=` `^=`\n        `&amp;&amp;=` `||=` `??=`\n        `=&gt;`\n\n      DivPunctuator ::\n        `/`\n        `/=`\n        <ins>`%=`</ins>\n    </emu-grammar>\n  </emu-clause>\n</emu-clause>\n\n<emu-clause id=sec-ecmascript-language-expressions>\n  <h1>ECMAScript Language: Expressions</h1>\n\n  <emu-clause id=sec-primary-expression>\n    <h1>Primary Expression</h1>\n\n    <emu-note type=editor>\n      <p>This section augments the <a\n      href=https://tc39.github.io/ecma262/#sec-primary-expression>original\n      Primary Expression clause</a>.</p>\n\n      <p>It presumptively uses `%` as the placeholder token for the\n      topic reference. This choice of token is not a final decision; `%`\n      could instead be `^` or some other token.</p>\n    </emu-note>\n\n    <h2>Syntax</h2>\n    <emu-grammar type=\"definition\">\n      PrimaryExpression[Yield, Await] :\n        `this`\n        <ins>`%`</ins>\n        IdentifierReference[?Yield, ?Await]\n        Literal\n        ArrayLiteral[?Yield, ?Await]\n        ObjectLiteral[?Yield, ?Await]\n        FunctionExpression\n        ClassExpression[?Yield, ?Await]\n        GeneratorExpression\n        AsyncFunctionExpression\n        AsyncGeneratorExpression\n        RegularExpressionLiteral\n        TemplateLiteral[?Yield, ?Await, ~Tagged]\n        CoverParenthesizedExpressionAndArrowParameterList[?Yield, ?Await]\n    </emu-grammar>\n\n    <emu-clause id=sec-topic-references>\n      <h1><ins>Topic Reference</ins></h1>\n\n      <emu-note type=editor>\n        <p>This section is a wholly new sub-clause to be inserted between the <a\n        href=https://tc39.github.io/ecma262/#sec-this-keyword>original `this`\n        Keyword clause</a> and the <a\n        href=https://tc39.github.io/ecma262/#sec-identifier-reference>original\n        Identifier Reference clause</a>.</p>\n\n        <p>It presumptively uses `%` as the placeholder token for the\n        topic reference. This choice of token is not a final decision; `%`\n        could instead be `^` or some other token.</p>\n      </emu-note>\n\n      <emu-note>\n        <p>The <dfn>topic reference</dfn>, which is the token `%`, is a\n        nullary operator that evaluates to the current Environment Record's\n        topic value. The topic reference acts as if it were a special variable,\n        implicitly bound to the topic value, yet still lexically scoped. But\n        `%` is not actually an |IdentifierName| and the topic reference is\n        not a variable, and it cannot be bound by typical assignment.\n        Instead, the topic reference is immutably bound to a value\n        during the instantiation of any topic-binding environment by a |PipeBody|.</p>\n\n        <p>The concept of the topic binding is further discussed in <emu-xref\n        href=\"#sec-topic-bindings\">Topic Bindings</emu-xref> and in <emu-xref\n        href=\"#sec-declarative-environment-records\">Declarative Environment\n        Records</emu-xref>.</p>\n      </emu-note>\n\n      <emu-note>\n        <p>An <dfn>unbound topic reference</dfn> is a topic reference that\n        is not present within any topic-binding environment created by a |PipeBody|.\n        All unbound topic references are invalid syntax.\n        Several early error rules for |ScriptBody| and for\n        |ModuleItemList|, as well as a step in CreateDynamicFunction,\n        use ContainsOuterTopic to check for any unbound topic reference `%`.\n        Any inner topic reference within a |PipeBody| is hidden from these rules,\n        preventing them from triggering the rules during program\n        compilation.</p>\n\n        <p>This guarantees that every topic reference in a program must be\n        present within a topic-binding environment\n        created by a |PipeBody| within that program.</p>\n      </emu-note>\n\n      <emu-clause id=sec-topic-references-runtime-semantics-evaluation>\n        <h1>Runtime Semantics: Evaluation</h1>\n        <emu-note>\n          <p>A topic reference may be evaluated only when\n          the running execution context's topic environment is not *null*.\n          This is syntactically enforced by early error rules\n          for |ScriptBody| and for |ModuleItemList|,\n          as well as a step in CreateDynamicFunction.\n          These rules use ContainsOuterTopic to check for any unbound topic reference.</p>\n        </emu-note>\n\n        <emu-grammar>PrimaryExpression : `%`</emu-grammar>\n        <emu-alg>\n        1. Return GetPrimaryTopicValue().\n        </emu-alg>\n      </emu-clause>\n    </emu-clause>\n  </emu-clause>\n\n  <emu-clause id=sec-pipe-operator>\n    <h1><ins>Pipe Operator</ins></h1>\n\n    <emu-note type=editor>\n      <p>This section is a wholly new sub-clause to be inserted between the <a\n      href=https://tc39.github.io/ecma262/#sec-conditional-operator>original\n      Conditional Operator (`?` `:`) clause</a> and the <a\n      href=https://tc39.github.io/ecma262/#sec-assignment-operators>original\n      Assignment Operators clause</a>.</p>\n    </emu-note>\n\n    <h2>Syntax</h2>\n    <emu-grammar type=definition>\n      PipeExpression[In, Yield, Await] :\n        ShortCircuitExpression[?In, ?Yield, ?Await] `|&gt;` PipeBody[?In, ?Yield, ?Await]\n\n      PipeBody[In, Yield, Await] :\n        AssignmentExpression[?In, ?Yield, ?Await]\n    </emu-grammar>\n\n    <emu-clause id=sec-pipe-operator-static-semantics-early-errors>\n      <h1>Static Semantics: Early Errors</h1>\n      <emu-note type=editor>\n        <p>This section is a wholly new sub-clause.</p>\n\n        <p>It presumptively uses `%` as the placeholder token for the\n        topic reference. This choice of token is not a final decision; `%`\n        could instead be `^` or some other token.</p>\n      </emu-note>\n\n      <emu-grammar>PipeBody : AssignmentExpression</emu-grammar>\n      <emu-alg>\n        1. It is a Syntax Error if |PipeBody| ContainsOuterTopic is *false*.\n      </emu-alg>\n\n      <emu-note>\n        <p>A |PipeBody| must use its topic at least once.\n        `value |&gt; foo + 1` is an early error,\n        because ContainsOuterTopic of its |PipeBody| is *false*.\n        This design is such because omission of any topic reference from a |PipeBody|\n        is almost certainly an accidental programmer error.</p>\n      </emu-note>\n\n      <emu-grammar>PipeBody : AssignmentExpression</emu-grammar>\n      <emu-alg>\n        1. It is a Syntax Error if one of the following productions is covering |PipeBody|:\n            * |ShortCircuitExpression| ? |AssignmentExpression| : |AssignmentExpression|\n            * |YieldExpression|\n            * |ArrowFunction|\n            * |AsyncArrowFunction|\n            * |LeftHandSideExpression| `=` |AssignmentExpression|\n            * |LeftHandSideExpression| |AssignmentOperator| |AssignmentExpression|\n            * |LeftHandSideExpression| `&&=` |AssignmentExpression|\n            * |LeftHandSideExpression| `||=` |AssignmentExpression|\n            * |LeftHandSideExpression| `??=` |AssignmentExpression|\n      </emu-alg>\n\n      <emu-note>\n        <p>A |PipeBody| must not be an unparenthesized |AssignmentExpression|, such as |YieldExpression|, |ArrowFunction|, or |ConditionalExpression|—unless it is a |ShortCircuitExpression|.</p>\n        <p>This is to prevent confusing expressions from being valid, such as:</p>\n        <pre><code class=\"javascript\">\n          x |> yield % |> % + 1 // Syntax Error\n        </code></pre>\n        <p>This expression would otherwise be equivalent to:</p>\n        <pre><code class=\"javascript\">\n          x |> (yield % |> % + 1)\n        </code></pre>\n        <p>Likewise, this expression:</p>\n        <pre><code class=\"javascript\">\n          x |> y ? % : z |> % + 1 // Syntax Error\n        </code></pre>\n        <p>…would otherwise be equivalent to:</p>\n        <pre><code class=\"javascript\">\n          x |> (y ? % : z |> % + 1)\n        </code></pre>\n        <p>These expressions are visually unclear and are therefore made invalid. The developer may make them valid with explicit parentheses:</p>\n        <pre><code class=\"javascript\">\n          x |> (yield %) |> % + 1\n          x |> (yield % |> % + 1)\n          x |> (y ? % : z) |> % + 1\n          x |> (y ? % : z |> % + 1)\n        </code></pre>\n      </emu-note>\n    </emu-clause>\n\n    <emu-clause id=sec-pipe-operator-runtime-semantics-evaluation>\n    <h1>Runtime Semantics: Evaluation</h1>\n\n    <emu-grammar>PipeExpression : ConditionalExpression `|&gt;` PipeBody</emu-grammar>\n    <emu-alg>\n      1. Let _inputRef_ be the result of evaluating _ConditionalExpression_.\n      1. Let _inputValues_ be « ? GetValue(_inputRef_) ».\n      1. Let _outputValue_ be ? EvaluateWithTopics(_inputValues_, |PipeBody|).\n      1. Return _outputValue_.\n    </emu-alg>\n    </emu-clause>\n  </emu-clause>\n</emu-clause>\n\n<emu-clause id=\"sec-ecmascript-language-scripts-and-modules\">\n  <h1>ECMAScript Language: Scripts and Modules</h1>\n\n  <emu-clause id=\"sec-scripts\">\n    <h1>Scripts</h1>\n\n    <emu-note type=editor>\n      <p>This section augments the <a\n      href=https://tc39.github.io/ecma262/#sec-scripts>original\n      Scripts clause</a>.</p>\n\n      <p>It presumptively uses `%` as the placeholder token for the\n      topic reference. This choice of token is not a final decision; `%`\n      could instead be `^` or some other token.</p>\n    </emu-note>\n\n    <emu-clause id=\"sec-scripts-static-semantics-early-errors\">\n      <h1>Static Semantics: Early Errors</h1>\n\n      <emu-grammar>Script : ScriptBody</emu-grammar>\n      <ul>\n        <li>\n          <ins>It is a Syntax Error if ContainsOuterTopic of |ScriptBody| is *true*.</ins>\n        </li>\n      </ul>\n      <ins class=\"block\">\n      <emu-note>\n        <p>An early error rule uses ContainsOuterTopic\n        to check for any unbound topic reference.\n        Any inner topic reference within a |PipeBody| is hidden from this rule,\n        preventing them from triggering the rule during program\n        compilation.</p>\n\n        <p>This guarantees that every topic reference in a |Script| must be\n        present within a topic-binding environment created\n        by a |PipeBody| within that |Script|.</p>\n      </emu-note>\n      </ins>\n    </emu-clause>\n  </emu-clause>\n\n  <emu-clause id=\"sec-modules\">\n    <h1>Modules</h1>\n\n    <emu-clause id=\"sec-module-semantics\">\n      <h1>Module Semantics</h1>\n\n      <emu-note type=editor>\n        <p>This section augments the <a\n        href=https://tc39.github.io/ecma262/#sec-module-semantics>original\n        Module Semantics clause</a>.</p>\n\n        <p>It presumptively uses `%` as the placeholder token for the\n        topic reference. This choice of token is not a final decision; `%`\n        could instead be `^` or some other token.</p>\n      </emu-note>\n\n      <emu-clause id=\"sec-module-semantics-static-semantics-early-errors\">\n        <h1>Static Semantics: Early Errors</h1>\n        <emu-grammar>ModuleBody : ModuleItemList</emu-grammar>\n        <ul>\n          <li>\n            <ins>It is a Syntax Error if ContainsOuterTopic of |ModuleItemList|\n            is *true*.</ins>\n          </li>\n        </ul>\n\n        <ins class=\"block\">\n        <emu-note>\n          <p>An early error rule uses ContainsOuterTopic\n          to check for any unbound topic reference.\n          Any inner topic reference within a |PipeBody| is hidden from this rule,\n          preventing them from triggering the rule during program\n          compilation.</p>\n\n          <p>This guarantees that every topic reference in a |ModuleBody| must be\n          present within a topic-binding environment created\n          by a |PipeBody| within that |ModuleBody|.</p>\n        </emu-note>\n        </ins>\n      </emu-clause>\n    </emu-clause>\n  </emu-clause>\n</emu-clause>\n\n<emu-clause id=\"sec-fundamental-objects\">\n  <h1>Fundamental Objects</h1>\n\n  <emu-clause id=\"sec-function-objects\">\n    <h1>Function Objects</h1>\n\n    <emu-clause id=\"sec-function-constructor\">\n      <h1>The Function Constructor</h1>\n\n      <emu-clause id=\"sec-function-p1-p2-pn-body\">\n        <h1>Function ( _p1_, _p2_, &hellip; , _pn_, _body_ )</h1>\n\n        <emu-clause id=\"sec-createdynamicfunction\" aoid=\"CreateDynamicFunction\">\n          <h1>CreateDynamicFunction ( _constructor_, _newTarget_, _kind_, _args_ )</h1>\n          <emu-note type=editor>\n            <p>This section augments the <a\n            href=https://tc39.github.io/ecma262/#sec-createdynamicfunction>original\n            CreateDynamicFunction clause</a>.</p>\n\n            <p>It presumptively uses `%` as the placeholder token for the\n            topic reference. This choice of token is not a final decision; `%`\n            could instead be `^` or some other token.</p>\n          </emu-note>\n\n          <emu-alg>\n            1. Assert: The execution context stack has at least two elements.\n            1. Let _callerContext_ be the second to top element of the execution context stack.\n            1. Let _callerRealm_ be _callerContext_'s Realm.\n            1. Let _calleeRealm_ be the current Realm Record.\n            1. Perform ? HostEnsureCanCompileStrings(_callerRealm_, _calleeRealm_).\n            1. If _newTarget_ is *undefined*, set _newTarget_ to _constructor_.\n            1. If _kind_ is ~normal~, then\n              1. Let _exprSym_ be the grammar symbol |FunctionExpression|.\n              1. Let _bodySym_ be the grammar symbol |FunctionBody[~Yield, ~Await]|.\n              1. Let _parameterSym_ be the grammar symbol |FormalParameters[~Yield, ~Await]|.\n              1. Let _fallbackProto_ be *\"%Function.prototype%\"*.\n            1. Else if _kind_ is ~generator~, then\n              1. Let _exprSym_ be the grammar symbol |GeneratorExpression|.\n              1. Let _bodySym_ be the grammar symbol |GeneratorBody|.\n              1. Let _parameterSym_ be the grammar symbol |FormalParameters[+Yield, ~Await]|.\n              1. Let _fallbackProto_ be *\"%GeneratorFunction.prototype%\"*.\n            1. Else if _kind_ is ~async~, then\n              1. Let _exprSym_ be the grammar symbol |AsyncFunctionExpression|.\n              1. Let _bodySym_ be the grammar symbol |AsyncFunctionBody|.\n              1. Let _parameterSym_ be the grammar symbol |FormalParameters[~Yield, +Await]|.\n              1. Let _fallbackProto_ be *\"%AsyncFunction.prototype%\"*.\n            1. Else,\n              1. Assert: _kind_ is ~asyncGenerator~.\n              1. Let _exprSym_ be the grammar symbol |AsyncGeneratorExpression|.\n              1. Let _bodySym_ be the grammar symbol |AsyncGeneratorBody|.\n              1. Let _parameterSym_ be the grammar symbol |FormalParameters[+Yield, +Await]|.\n              1. Let _fallbackProto_ be *\"%AsyncGeneratorFunction.prototype%\"*.\n            1. Let _argCount_ be the number of elements in _args_.\n            1. Let _P_ be the empty String.\n            1. If _argCount_ = 0, let _bodyArg_ be the empty String.\n            1. Else if _argCount_ = 1, let _bodyArg_ be _args_[0].\n            1. Else,\n              1. Assert: _argCount_ &gt; 1.\n              1. Let _firstArg_ be _args_[0].\n              1. Set _P_ to ? ToString(_firstArg_).\n              1. Let _k_ be 1.\n              1. Repeat, while _k_ &lt; _argCount_ - 1,\n                1. Let _nextArg_ be _args_[_k_].\n                1. Let _nextArgString_ be ? ToString(_nextArg_).\n                1. Set _P_ to the string-concatenation of _P_, *\",\"* (a comma), and _nextArgString_.\n                1. Set _k_ to _k_ + 1.\n              1. Let _bodyArg_ be _args_[_k_].\n            1. Let _bodyString_ be the string-concatenation of 0x000A (LINE FEED), ? ToString(_bodyArg_), and 0x000A (LINE FEED).\n            1. Let _prefix_ be the prefix associated with _kind_ in <emu-xref href=\"#sec-createdynamicfunction\"></emu-xref>.\n            1. Let _sourceString_ be the string-concatenation of _prefix_, *\" anonymous(\"*, _P_, 0x000A (LINE FEED), *\") {\"*, _bodyString_, and *\"}\"*.\n            1. Let _sourceText_ be ! StringToCodePoints(_sourceString_).\n            1. Let _parameters_ be ParseText(! StringToCodePoints(_P_), _parameterSym_).\n            1. If _parameters_ is a List of errors, throw a *SyntaxError* exception.\n            1. Let _body_ be ParseText(! StringToCodePoints(_bodyString_), _bodySym_).\n            1. If _body_ is a List of errors, throw a *SyntaxError* exception.\n            1. NOTE: The parameters and body are parsed separately to ensure that each is valid alone. For example, `new Function(\"/*\", \"*/ ) {\")` is not legal.\n            1. NOTE: If this step is reached, _sourceText_ must match _exprSym_ (although the reverse implication does not hold). The purpose of the next two steps is to enforce any Early Error rules which apply to _exprSym_ directly.\n            1. Let _expr_ be ParseText(_sourceText_, _exprSym_).\n            1. If _expr_ is a List of errors, throw a *SyntaxError* exception.\n            1. <ins>NOTE: The dynamic function must not contain an unbound topic reference `%`.)</ins>\n            1. <ins>If ContainsOuterTopic of _expr_ is *true*, throw a *SyntaxError* exception.</ins>\n            1. Let _proto_ be ? GetPrototypeFromConstructor(_newTarget_, _fallbackProto_).\n            1. Let _realmF_ be the current Realm Record.\n            1. Let _scope_ be _realmF_.[[GlobalEnv]].\n            1. Let _privateScope_ be *null*.\n            1. Let _F_ be ! OrdinaryFunctionCreate(_proto_, _sourceText_, _parameters_, _body_, ~non-lexical-this~, _scope_, _privateScope_).\n            1. Perform SetFunctionName(_F_, *\"anonymous\"*).\n            1. If _kind_ is ~generator~, then\n              1. Let _prototype_ be ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).\n              1. Perform DefinePropertyOrThrow(_F_, *\"prototype\"*, PropertyDescriptor { [[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false* }).\n            1. Else if _kind_ is ~asyncGenerator~, then\n              1. Let _prototype_ be ! OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).\n              1. Perform DefinePropertyOrThrow(_F_, *\"prototype\"*, PropertyDescriptor { [[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false* }).\n            1. Else if _kind_ is ~normal~, perform MakeConstructor(_F_).\n            1. NOTE: Functions whose _kind_ is ~async~ are not constructible and do not have a [[Construct]] internal method or a *\"prototype\"* property.\n            1. Return _F_.\n          </emu-alg>\n        </emu-clause>\n      </emu-clause>\n    </emu-clause>\n  </emu-clause>\n</emu-clause>\n"
  }
]