profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/Volune/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.
Jeremy Judeaux Volune Education First / EdTech China, Shanghai

Volune/cancellable-chain-of-promises 1

A library to write Cancellable Chain of Promises, that is a sequence of asynchronous operations that you can cancel at any point.

Volune/dokku-arangodb-plugin 1

ArangoDB plugin for Dokku

Volune/aem-sass-compiler 0

Enable Sass support for AEM

Volune/AgriCraft 0

The source code for the Minecraft mod: AgriCraft

Volune/appium-desktop 0

Appium Server and Inspector in Desktop GUIs for Mac, Windows, and Linux

Volune/appium-xcuitest-driver 0

Appium iOS driver, backed by Apple XCUITest

Volune/avd-compose 0

Define and run android virtual devices

Volune/babel 0

:tropical_fish: Babel is a compiler for writing next generation JavaScript.

created repositorysroccaserra/hello-dependency-injection-kata

created time in 10 hours

issue commenttc39/proposal-pipeline-operator

Pipeline operator -> syntax sugar for Promise.then?

There is also this proposal which adds syntax sugar for .then in member expressions: https://github.com/tc39/proposal-wavy-dot

simov

comment created time in a day

issue commenttc39/proposal-pipeline-operator

Pipeline operator -> syntax sugar for Promise.then?

I don't think the proposal was stucked because of async issue.

simov

comment created time in a day

created repositorysroccaserra/learning-rabbitmq

created time in 3 days

PR opened Volune/use-event-callback

Bump glob-parent from 5.1.0 to 5.1.2

Bumps glob-parent from 5.1.0 to 5.1.2. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/gulpjs/glob-parent/releases">glob-parent's releases</a>.</em></p> <blockquote> <h2>v5.1.2</h2> <h3>Bug Fixes</h3> <ul> <li>eliminate ReDoS (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/36">#36</a>) (<a href="https://github.com/gulpjs/glob-parent/commit/f9231168b0041fea3f8f954b3cceb56269fc6366">f923116</a>)</li> </ul> <h2>v5.1.1</h2> <h3>Bug Fixes</h3> <ul> <li>unescape exclamation mark (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/26">#26</a>) (<a href="https://github.com/gulpjs/glob-parent/commit/a98874f1a59e407f4fb1beb0db4efa8392da60bb">a98874f</a>)</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md">glob-parent's changelog</a>.</em></p> <blockquote> <h3><a href="https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2">5.1.2</a> (2021-03-06)</h3> <h3>Bug Fixes</h3> <ul> <li>eliminate ReDoS (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/36">#36</a>) (<a href="https://github.com/gulpjs/glob-parent/commit/f9231168b0041fea3f8f954b3cceb56269fc6366">f923116</a>)</li> </ul> <h2><a href="https://www.github.com/gulpjs/glob-parent/compare/v5.1.2...v6.0.0">6.0.0</a> (2021-05-03)</h2> <h3>⚠ BREAKING CHANGES</h3> <ul> <li>Correct mishandled escaped path separators (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/34">#34</a>)</li> <li>upgrade scaffold, dropping node <10 support</li> </ul> <h3>Bug Fixes</h3> <ul> <li>Correct mishandled escaped path separators (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/34">#34</a>) (<a href="https://www.github.com/gulpjs/glob-parent/commit/32f6d52663b7addac38d0dff570d8127edf03f47">32f6d52</a>), closes <a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/32">#32</a></li> </ul> <h3>Miscellaneous Chores</h3> <ul> <li>upgrade scaffold, dropping node <10 support (<a href="https://www.github.com/gulpjs/glob-parent/commit/e83d0c5a411947cf69eb58f36349db80439c606f">e83d0c5</a>)</li> </ul> <h3><a href="https://github.com/gulpjs/glob-parent/compare/v5.1.0...v5.1.1">5.1.1</a> (2021-01-27)</h3> <h3>Bug Fixes</h3> <ul> <li>unescape exclamation mark (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/26">#26</a>) (<a href="https://github.com/gulpjs/glob-parent/commit/a98874f1a59e407f4fb1beb0db4efa8392da60bb">a98874f</a>)</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/gulpjs/glob-parent/commit/eb2c439de448c779b450472e591a2bc9e37e9668"><code>eb2c439</code></a> chore: update changelog</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/12bcb6c45c942e2d05fc1e6ff5402e72555b54b6"><code>12bcb6c</code></a> chore: release 5.1.2</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/f9231168b0041fea3f8f954b3cceb56269fc6366"><code>f923116</code></a> fix: eliminate ReDoS (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/36">#36</a>)</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/0b014a7962789b2d8f2cf0b6311f40667aecd62c"><code>0b014a7</code></a> chore: add JSDoc returns information (<a href="https://github-redirect.dependabot.com/gulpjs/glob-parent/issues/33">#33</a>)</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/2b24ebd64b2a045aa167c825376335555da139fd"><code>2b24ebd</code></a> chore: generate initial changelog</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/9b6e8747ddf664c9b1a36fbd2a23e43a35b8a52f"><code>9b6e874</code></a> chore: release 5.1.1</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/749c35ee084498ebb1ce8cc9cf655f6aa4d623c5"><code>749c35e</code></a> ci: try wrapping the JOB_ID in a string</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/5d39def48c9e9eaee0ca36dafdf7b6cdcd875b85"><code>5d39def</code></a> ci: attempt to switch to published coveralls</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/0b5b37f674a7e207457c99cb2f123299e5ab31c9"><code>0b5b37f</code></a> ci: put the npm step back in for only Windows</li> <li><a href="https://github.com/gulpjs/glob-parent/commit/473f5d87644bf19f32c53de21d2420f03aa02e5a"><code>473f5d8</code></a> ci: update azure build images</li> <li>Additional commits viewable in <a href="https://github.com/gulpjs/glob-parent/compare/v5.1.0...v5.1.2">compare view</a></li> </ul> </details> <br />

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


<details> <summary>Dependabot commands and options</summary> <br />

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
  • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
  • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
  • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the Security Alerts page.

</details>

+14 -310

0 comment

1 changed file

pr created time in 8 days

created repositorysroccaserra/house-that-jack-built-kata

created time in 11 days

issue commenttc39/proposal-pipeline-operator

Consider Elixir-style pipeline as one of the blessed alternatives

For completeness sake, this is what minimal pipelines + partial application proposal + some helpers would look like:

input |> func
input |> func(?, 2)
input |> func(1, ?)

That was part of the initial rationale for partial application, to allow both leading-arg (lodash style) and trailing-arg (Ramda style) usages (along with its other capabilities).

For me, both F#-style (w/partial application) and Hack-style feel like JavaScript, with semantics that fit with the language. Elixir-style doesn't quite fit with JavaScript semantics, and I'm concerned it would introduce a footgun that is the polar opposite of the confusion around this (wher instead of a hidden parameter, we now have a hidden argument).

littledan

comment created time in 20 days

issue commenttc39/proposal-pipeline-operator

Consider Elixir-style pipeline as one of the blessed alternatives

For completeness sake, this is what minimal pipelines + partial application proposal + some helpers would look like:

input |> func
input |> func(?, 2)
input |> func(1, ?)

const Promise = pipeable(globalThis.Promise) // https://gist.github.com/ducaale/93bd6d49314ef1383f50be95edca9d6e
await (input |> asyfunc |> Promise.then(regfunc) |> Promise.then(regfunc2))
littledan

comment created time in 20 days

issue commenttc39/proposal-pipeline-operator

Consider Elixir-style pipeline as one of the blessed alternatives

* Your code doesn't read like it was defined - all the arguments in a pipeline call are in the wrong position relative to calling the function literally.

I'm going to agree with @highmountaintea that this doesn't tend to be an issue when the syntax is clear and unambiguous. This function—argument order inversion can even be seen in non-pipe contexts, for example method calls in Python:

class K:
  # definition order is: funcName, subject(self), *args(x, y)
  def funcName(self, x, y): pass

obj = K()
# call order is: subject, funcName, *args
obj.funcName(x, y)

And it doesn't appear to cause trouble once you get used to it.

* It's an entirely novel calling syntax for JS.

For the language, yes, but there is precedent in libraries. For example Lodash:

// the basic form of lodash functions operate on the first argument:
_.mapValues( _.groupBy(bills, 'type'), g => _.sumBy(g, 'amount') )

// but you can also wrap your input in a proxy and pipe it like this (and since we're talking
// about syntax, let's ignore the semantic difference that this evaluates lazily; what's notable
// is that these methods are not documented individually, they simply defer to the documentation
// for the functions operating on their first argument):
_(bills)
.groupBy('type')
.mapValues(g => _(g).sumBy('amount'))
.value()

// which is very similar to how you would use the regular no-proxy functions with Elixir-style pipeline:
bills
|> _.groupBy('type')
|> _.mapValues(g => g |> _.sumBy('amount'))

First-argument injection is, I feel, the least good of all the options presented so far.

To me it feels like the most balanced of all the alternatives presented.

  • I like the minimal F# proposal for its simplicity and conciseness. It is perfect for piping through unary functions. To pass more than just the single argument you need to wrap the call in an arrow function. A bit clumsy, but still fine. However, it gets messy with await/yield. Even the impressively well thought out proposal for await/yield in F#-style makes it obvious that with this requirement, it's no longer just another operator you plug into the grammar; you need to bend the rules around it.

  • I like the Hack-style proposal for its consistency and flexibility. It doesn't need any special parsing rules, and it always looks the same, whether you're passing 1 or many arguments. However it does look awkward with unary functions. And I absolutely hate the idea of denoting the topic variable with punctuation, as if JS wasn't already littered with it.

Now why do I think the Elixir-style strikes a good balance between the two? Because F#-style is only really good with unary functions. Elixir-style is good whenever you want to pipe the first argument, i.e. unary functions and then some, and the price you pay over F# for that wider range of easily usable functions is mere ().

Elixir-style balance

With unary functions - F# wins:

input |> func // F#
input |> func() // Elixir
input |> func(#) // Hack
func(input) // desugar

Binary with topic first - Elixir wins:

input |> (x => func(x, 2)) // F#
input |> func(2) // Elixir
input |> func(#, 2) // Hack
func(input, 2) // desugar

Binary with topic second - Hack wins:

input |> (x => func(1, x)) // F#
input |> (x => func(1, x)) // Elixir **1 (implicit arrow-function call)
input |> (x => func(1, x))() // Elixir (explicit call)
input |> func(1, #) // Hack
func(1, input) // desugar

**1 this is the extension proposed earlier. Elixir-style requires a call-expression on the right-hand-side. If there's an arrow-function-expression instead, it's safe to assume you want it called. Of course you can add explicit (), but they're redundant, the function will be called either way. As for removing the parentheses surrounding the arrow function, that's a can of worms affecting any style that allows it, so no point lifting the lid here.

Mid-pipeline await:

input |> asyfunc |> await |> regfunc // F#
input |> await asyfunc() |> regfunc() // Elixir **2
input |> await asyfunc(#) |> regfunc(#) // Hack
regfunc(await asyfunc(input)) // desugar

**2 this is another extension. Again, Elixir-style requires a call-expression on the right-hand-side. If there's an await-prefixed call instead, you want to await the result (similarly with yield).

Note that unlike special parsing rules needed for await in F#-style, in Hack-style |> is a regular binary operator, and in Elixir-style it's almost like a regular binary operator, only with right-hand-side restricted to certain expression types (call or arrow, optionally prefixed with await or yield; i.e. existing productions, no new restrictions on specific token sequences).

littledan

comment created time in 20 days

issue commenttc39/proposal-pipeline-operator

How about overloading `|` instead?

Thanks for the input. I forgot to update the typeof test in the description, but in the overload-simulating code I did take the .valueOf first, so that particular example would still resolve as bitwise or.

lightmare

comment created time in 21 days

issue commenttc39/proposal-pipeline-operator

How about overloading `|` instead?

It's not always NaN, for example:

const Nums = Object.fromEntries(
  ["zero", "one", "two", "three", "four", "five"].map((name, val) =>
    [
      name,
      Object.assign(x => x * val, { valueOf: () => val })
    ]
  )
);

console.log(typeof Nums.two); // "function"

console.log(Nums.one + Nums.two); // 3
console.log(Nums.two(Nums.three)); // "take two times three", 6
console.log(Nums.five - Nums.three); // 2
console.log(Nums.five / 10); // 0.5
console.log(4 + Nums.three); // 7

// And this:
console.log(4 | Nums.two); // 6
lightmare

comment created time in 21 days

issue openedtc39/proposal-pipeline-operator

How about overloading `|` instead?

Have you considered overloading an existing operator instead of introducing a new one? I looked around, and only found some mentions of possible future user-defined operator overloading, like C++ or Python have. That's not quite what I mean. I was thinking about overloading just | for functions, similar to how + is overloaded for strings.

Currently if typeof Foo === 'function' then (x | Foo) === (x | NaN) === (x | 0). Even though this operation is well-defined, I couldn't come up with a sensible use case where you'd have a calculation relying on the coercion function ~> NaN on the right-hand-side of |.

Pipe operator overload

I experimented a bit with AST explorer, rewriting a | b into:

    lhs = a,
    rhs = b.valueOf(),
    typeof rhs === 'function'
        ? rhs(lhs)
        : lhs | rhs

An upside of overloading an existing operator is that there'd be no changes to grammar. Everything would parse exactly as it parses now. Which could also be seen as a downside, in that it's essentially stripped-down minimal F# semantics without special rules for await/yield.

Another downside is not-immediately-obvious interaction with arrow function expressions:

    res = input
        | x => foo(x, 1)
        | y => bar(2, y)   // still inside x =>
        ;

    // gets parsed as
    res = input | (x => foo(x, 1) | y => bar(2, y));

    // resulting in:
    t1 = input, res = (t2 = foo(t1, 1), bar(2, t2));

It may be surprising to some, that the second arrow function is inside the first, meaning it has access to x. Others might consider that useful, I'm not sure. If such nesting is undesired, it can be prevented by parenthesizing each arrow function:

    res = input
        | (x => foo(x, 1))
        | (y => bar(2, y))
        ;

    // gets parsed as:
    res = input | (x => foo(x, 1)) | (y => bar(2, y));

    // resulting in:
    t1 = input, t2 = foo(t1, 1), res = bar(2, t2);

This might not even be a big issue, because regardless of whether the functions are nested (as in the first example where the line breaks are deceptive), or individually parenthesized (as in the second example), the order of operations and the result will be the same (as long as the inner function doesn't reach for x, of course). Since the pipe operator is left-associative, arrow function gobbling up subsequent | terms doesn't alter the sequence of calls:

    (a | x => (f(x) | g))  ==  (x => (f(x) | g))(a)  ==  (f(a) | g)  ==  g(f(a))
    (a | (x => f(x)) | g)  ==  ((x => f(x))(a) | g)  ==  (f(a) | g)  ==  g(f(a))

AST explorer snippet

Here's the experimental transform adding compile-time and run-time | overloads in AST explorer:

https://astexplorer.net/#/gist/1d15ff515bc1dfab22e64820ea6b4a18/latest

It also overloads shift-right operators, which I'm not really suggesting. I was just trying different stuff, figured one could use a secondary operator to resolve promises before calling the right-hand-side, and | doesn't have a same-precedence "twin" for this purpose.

created time in 21 days

GollumEvent

issue commenttc39/proposal-partial-application

Can '?' be used to declare function currying?

Ah, got it. I can see the value in that.

mwc

comment created time in 24 days

issue commenttc39/proposal-partial-application

Can '?' be used to declare function currying?

Is this curried shorthand being suggested because people don't like the arrow function shorthand, or because people have needed to declare curried functions that didn't bind "this"?

@theScottyJam The main limitation that I see with the higher-order arrow function style of currying is this: You need to decide to use it up-front. You may not think you need it when you write the function, and so don't bother with the extra effort of both writing it and using it that way. Or you may think that it's enough to separate the arguments into two groups. If later you decide you do want to use currying (or more currying) with that function, you will need to refactor in all the places that use it (going from add(1, 2, 3) to add(1)(2)(3)). Compare this to the ideas explored above, where we can add curried or @curried to the function declaration, keeping backward compatibility (e.g. we can still do add(1, 2, 3)) while allowing the use of currying in a more flexible way than we ever could with just higher-order arrow functions (e.g. we can do add(1)(2)(3) and add(1, 2)(3))

mwc

comment created time in 24 days

issue commenttc39/proposal-partial-application

Make notation more explicit and understandable

Huh - didn't actually know that x => { ... } || 2 was a syntax error. That's actually kind of nice, precisely because it forces parentheses around the function whenever you're doing something extra with it.

Nixinova

comment created time in 24 days

issue commenttc39/proposal-partial-application

Make notation more explicit and understandable

For the pipeline operator example, I would expect it to be a syntax error similarly to how x => {} || 2 is a syntax error. You would have to wrap the arrow function in parens, so it's clear that "something is going on" (maybe I would expect it to be an iife, but I would at least check the end).

Nixinova

comment created time in 24 days

issue commenttc39/proposal-partial-application

Make notation more explicit and understandable

The issue is that, at this point you might as well just use a normal arrow function.

const n = =>getId(2, %) |> addOne |> =>power(%, 3);
// vs
const n = _ => getId(2, _) |> addOne |> _ =>power(_, 3);

I agree that I don't like the surprise aspect of having to read part-way into the expression to realize we're not actually calling the function. Especially if we're dealing with large function calls.

const myFn = memoizeResults(x => {
  // ...
  // ...
}, ?)

But, maybe I'm just paranoid about a non-real issue. I guess a similar surprise-at-the-end can happen with the pipeline operator, and this feels fine to me (syntax-wise - I wouldn't actually code like this):

const myFn = x => {
  // ...
  // ...
} |> fn => opts => memoizeResults(fn, opts)

Looking at the top, one might think myFn is getting defined by the giant arrow function. It's not until you reach the bottom that you realize that myFn will be a factory function that takes some memoization options, then returns the giant arrow function with memoization applied to it.

Nixinova

comment created time in 24 days

issue commenttc39/proposal-partial-application

Can '?' be used to declare function currying?

I've always liked the arrow function syntax we already have to make curried functions:

const addThreeNumbs = a => b => c => a + b + c

It's true this only supports arrow functions, but usually, when following the functional paradigm in a strict way, you're not creating classes, and so don't have to worry as much about this-bindings.

Is this curried shorthand being suggested because people don't like the arrow function shorthand, or because people have needed to declare curried functions that didn't bind "this"?


Also, @munizart is probably right, I don't really see a strong connection between currying and this proposal. it would probably need to be a separate proposal.

mwc

comment created time in 24 days

PR opened Volune/callback-to-promise-operator

Bump browserslist from 4.9.1 to 4.16.6

Bumps browserslist from 4.9.1 to 4.16.6. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md">browserslist's changelog</a>.</em></p> <blockquote> <h2>4.16.6</h2> <ul> <li>Fixed <code>npm-shrinkwrap.json</code> support in <code>--update-db</code> (by Geoff Newman).</li> </ul> <h2>4.16.5</h2> <ul> <li>Fixed unsafe RegExp (by Yeting Li).</li> </ul> <h2>4.16.4</h2> <ul> <li>Fixed unsafe RegExp.</li> <li>Added artifactory support to <code>--update-db</code> (by Ittai Baratz).</li> </ul> <h2>4.16.3</h2> <ul> <li>Fixed <code>--update-db</code>.</li> </ul> <h2>4.16.2</h2> <ul> <li>Fixed <code>--update-db</code> (by <a href="https://github.com/ialarmedalien"><code>@​ialarmedalien</code></a>).</li> </ul> <h2>4.16.1</h2> <ul> <li>Fixed Chrome 4 with <code>mobileToDesktop</code> (by Aron Woost).</li> </ul> <h2>4.16</h2> <ul> <li>Add <code>browserslist config</code> query.</li> </ul> <h2>4.15</h2> <ul> <li>Add TypeScript types (by Dmitry Semigradsky).</li> </ul> <h2>4.14.7</h2> <ul> <li>Fixed Yarn Workspaces support to <code>--update-db</code> (by Fausto Núñez Alberro).</li> <li>Added browser changes to <code>--update-db</code> (by <a href="https://github.com/AleksandrSl"><code>@​AleksandrSl</code></a>).</li> <li>Added color output to <code>--update-db</code>.</li> <li>Updated <code>package.funding</code> to have link to our Open Collective.</li> </ul> <h2>4.14.6</h2> <ul> <li>Fixed Yarn support in <code>--update-db</code> (by Ivan Storck).</li> <li>Fixed npm 7 support in <code>--update-db</code>.</li> </ul> <h2>4.14.5</h2> <ul> <li>Fixed <code>last 2 electron versions</code> query (by Sergey Melyukov).</li> </ul> <h2>4.14.4</h2> <ul> <li>Fixed <code>Unknown version 59 of op_mob</code> error.</li> </ul> <h2>4.14.3</h2> <ul> <li>Update Firefox ESR.</li> </ul> <h2>4.14.2</h2> <ul> <li>Fixed <code>--update-db</code> on Windows (by James Ross).</li> <li>Improved <code>--update-db</code> output.</li> </ul> <h2>4.14.1</h2> <ul> <li>Added <code>--update-db</code> explanation (by Justin Zelinsky).</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/browserslist/browserslist/commit/6fe3614db05b40f9dc1c63588a83d2ada05bae75"><code>6fe3614</code></a> Release 4.16.6 version</li> <li><a href="https://github.com/browserslist/browserslist/commit/33ebac933839847a62ede680273449f6cdca1e18"><code>33ebac9</code></a> Update dependencies</li> <li><a href="https://github.com/browserslist/browserslist/commit/2128170f231a6c9f462276006e09f302d811df31"><code>2128170</code></a> Add support for npm-shrinkwrap files alongside package-lock (<a href="https://github-redirect.dependabot.com/browserslist/browserslist/issues/595">#595</a>)</li> <li><a href="https://github.com/browserslist/browserslist/commit/7cc2aedd0047d800d44aa0259c02b6db1414105c"><code>7cc2aed</code></a> Release 4.16.5 version</li> <li><a href="https://github.com/browserslist/browserslist/commit/27e4afdc68798ca93f8c01c5ea6208b4b361a704"><code>27e4afd</code></a> Update dependencies</li> <li><a href="https://github.com/browserslist/browserslist/commit/1013a1847931a209c34a704aebc85a8c091286e7"><code>1013a18</code></a> Fix version RegExp</li> <li><a href="https://github.com/browserslist/browserslist/commit/b879a1a304def2563f42cc3d3f5711e760662be3"><code>b879a1a</code></a> Use Node.js 16 on CI</li> <li><a href="https://github.com/browserslist/browserslist/commit/bd1e9e01c95cad24be706fb11be7d151cd99ed0a"><code>bd1e9e0</code></a> Fix ReDoS (<a href="https://github-redirect.dependabot.com/browserslist/browserslist/issues/593">#593</a>)</li> <li><a href="https://github.com/browserslist/browserslist/commit/209adf9e0051fa39a2b25354cffd493300f34b02"><code>209adf9</code></a> Release 4.16.4 version</li> <li><a href="https://github.com/browserslist/browserslist/commit/3e2ae3b52daf7f5203247fd4f583b3bda66ea57d"><code>3e2ae3b</code></a> Fix types</li> <li>Additional commits viewable in <a href="https://github.com/browserslist/browserslist/compare/4.9.1...4.16.6">compare view</a></li> </ul> </details> <br />

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


<details> <summary>Dependabot commands and options</summary> <br />

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
  • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
  • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
  • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the Security Alerts page.

</details>

+41 -292

0 comment

1 changed file

pr created time in 24 days

issue commenttc39/proposal-pipeline-operator

argue this proposal's design-pattern is less readable than using a temp-variable

Another option would be the following, if the bind proposal goes through.

const { filter, map, join } = Array.prototype

const maleNameList = users
  |> ?::filter(user => user.gender === 'male')
  |> ?::map(user => user.givenName)
  |> ?::join('\n')

I'm not necessarily saying it can't be done, I'm just hesitant about actually doing it in production code - just using the array methods as a fluent API will make my code much easier to understand by more people, without sacrificing too much (in most cases). Maybe in personal projects, I would be more inclined to pick these functions off of the prototype.

kaizhu256

comment created time in a month

issue commenttc39/proposal-pipeline-operator

argue this proposal's design-pattern is less readable than using a temp-variable

With a little bit of magic, it is possible to come up with a nice API for using pipelines with native prototype functions

const pipeable = (class_) => new Proxy({}, {
  get: (target, prop) => (
    (prop in class_.prototype)
      ? (...args) => (receiver) => class_.prototype[prop].call(receiver, ...args)
      : class_[prop].bind(class_) // https://stackoverflow.com/a/30819436/5915221
  )
});

const x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
  |> Array.map(n => n * 2)
  |> Array.filter(n => n > 10)

See https://gist.github.com/ducaale/93bd6d49314ef1383f50be95edca9d6e

kaizhu256

comment created time in a month

issue commenttc39/proposal-pipeline-operator

argue this proposal's design-pattern is less readable than using a temp-variable

@theScottyJam You should be able to chain fluent interfaces and pipeline operators together as long as they return the same data type. (example using F# syntax + partial application).

 const maleNameList = users.filter(user => user.gender === 'male')
                           |> Array.prototype.map.call(?, user => user.givenName)
                           |> filterOutNullishFromArray
                           .join('\n')
kaizhu256

comment created time in a month

issue commenttc39/proposal-pipeline-operator

Pipeline operator -> syntax sugar for Promise.then?

I can't say I disagree, but at the same time this is a 'reasonable' way to unstuck this proposal, with its own downsides. Because all else failed for the past 3 years, correct me if I'm wrong.

And again, just to clarify - using Promise.then because it's there instead of pipe operator is not a solution for me, using |> await .. seems equally as bad, contrary to the idea of composing functions.

Probably if you put await in front of the pipeline it can be treated as Promise.then and otherwise as synchronous code? The pipelines that I'm talking about are much higher level then simply transforming a string for example.

simov

comment created time in a month

issue commenttc39/proposal-pipeline-operator

Pipeline operator -> syntax sugar for Promise.then?

Almost all of the JavaScript code on the server or serverless if you will, have to deal with asynchronous operations.

Yes, a lot of Javascript runs in async environments, but most written code is still doing synchronous tasks. Have you ever made a helper function to parse data from a string? To reshape data that some server provided to you? These would all be synchronous helper functions (even if they're being used on a server) that would benefit from a pipeline operator. Have you ever used a library such as underscore? Wouldn't you find it fishy if you had to "await" each time you called one of their functions - and it turns out the only reason the await was needed, was because lodash wanted to use the pipeline operator?

The truth is a lot of today's JavaScript developers know almost nothing about the language.

That's fine, and it's important to keep that in mind. But ... these people are also learning. Instead of trying to hide important parts of the language from them, it would be better to teach these parts to them, when the time is right. Promises are a very important part of the language - async/await allows people to hide a lot of the details of promises away in many scenarios, but it can never fully hide them, and sooner or later these newer programmers need to understand them to be effective at asynchronous programming.

And literally no one is using Promise.then

Maybe that's what you've seen in your experience, I've certainly seen many people who still like to use Promise.then - there are times where it makes for cleaner code than await does. This is one of those scenarios. If some asynchronous task reads better when written as a pipeline, why not just use .then() - it's what it's for. The introduction of async/await was never meant to cause the community to shun .then() and .catch(), and if you choose to embrace promises instead of shunning them, then you can immediately start reaping the benefits of asynchronous pipelining too, among other things.

The whole point you seem to be making is that "promises are confusing, especially to newcomers - better to just make all functions async and provide language constructs to help people pretend they're not a thing". This is not really a reasonable request - we can't just have people making all of their functions async, plus, this flies against a lot of the ideology behind promises and async/await. It would be better to view promises as a useful tool that newcomers can learn and utilize one day, when they're ready. Many language features fall into this category - just because it might not be newcommer friendly does not mean it's bad or useless - maybe it shouldn't be used in a project where you expect a lot of newcommers to contribute to it (maybe that's the type of project you're often working on), but not all projects are like that, and sometimes these more advance language features are the only things that can keep the code clean, fast, and organized.

simov

comment created time in a month

issue commenttc39/proposal-pipeline-operator

Pipeline operator -> syntax sugar for Promise.then?

The pipeline operator provides the most value to sync code (or mostly sync code, with the occasional await in the middle).

I disagree with that. Almost all of the JavaScript code on the server or serverless if you will, have to deal with asynchronous operations. And literally no one is using Promise.then, see my first comment about that. Having pipes can help pushing that pattern into the mainstream. The truth is a lot of today's JavaScript developers know almost nothing about the language.

simov

comment created time in a month

issue commenttc39/proposal-pipeline-operator

Pipeline operator -> syntax sugar for Promise.then?

The "await" thing is certainly an issue - but I was under the impression that the current holdup was simply some TC39 members being unsure if the new syntax is actually useful enough to warrant adding it to the language (though someone can correct me if I'm wrong here). There's generally a lot of hesitance when it comes to adding syntax to the language, which is a good thing, adding syntax left and right will create an over-bloated and difficult to learn language.

Also, promises already have a way of doing pipelining - it's just slightly more verbose.

Compare this:

const result = await doAsyncTask()
  .then(x => anotherAsyncTask(x))
  .then(x => andYetAnotherTask(x))

with this:

const result = await doAsyncTask()
  |> await anotherAsyncTask(?)
  |> await andYetAnotherTask(?)

pipelines certainly help make to make async code a little nicer, but not enough to warrant its own syntax. The pipeline operator provides the most value to sync code (or mostly sync code, with the occasional await in the middle).

simov

comment created time in a month

issue commenttc39/proposal-pipeline-operator

argue this proposal's design-pattern is less readable than using a temp-variable

You can think of the pipeline operator simply as a more functional alternative to fluent APIs.

If Javascript had the pipeline operator from the beginning, then our array-manipulation functions might have been designed as static methods instead of instance methods, so that they would fit well into a pipeline. Many other languages that have a pipeline operator design their array functions this way.

 const maleNameList = users
  |> Array.filter(?, user => user.gender === 'male')
  |> Array.map(?, user => user.givenName)
  |> Array.join(?, '\n')

This makes it very easy to add your own, home-baked array helper functions into the pipeline (something that can't be done with a fluent API)

 const maleNameList = users
  |> Array.filter(?, user => user.gender === 'male')
  |> Array.map(?, user => user.givenName)
  |> filterOutNullish(?)
  |> Array.join(?, '\n')

While it's too late to design our array methods this way (a shame), future APIs can still benefit from this pipeline syntax.

And, who knows, maybe some proposal down the pipeline would make it very easy to use instance methods in a pipeline. They are, after all, available as static methods on the prototype - we would just need a shorthand to do Array.prototype.someFunction.call(yourArray, ...), and then any fluent-API could be used in a pipeline instead, and reap the same benefits. But - I doubt that would ever happen.

As an aside, No one's rooting for this pipeline operator because it adds extra power to the language, in fact, it's quite the opposite. People love the pipeline operator precisely because it's constraining. At a glance, it's very easy to know what a pipeline is doing - it's taking the previous value, injecting it into the next line, and so forth. That's all it can do, and all it'll ever do. People are so against the "temp variable" idea because it's way too flexible. You have to look at every line to understand that you're just feeding the temp variable through as if it were a pipeline, and you have to look at the rest of the function definition to make sure you're not using the final temp variable anywhere else because that's very possible. You also have to make sure that no extra variables are being created in the middle of that "temp variable pipeline" that might get used elsewhere. It takes a lot more work to read code using a temporary variable - especially when it's in the middle of a longer, cluttered function.

This is a similar reason why "goto" has been abandoned in most languages - it's way too powerful and makes code harder to reason about. It's why constructs such as const has been added to Javascript - it doesn't add any power to the language, rather, it enforces certain restrictions that help make the code easier to read.

kaizhu256

comment created time in a month