Skip to content

Commit

Permalink
Merge branch 'releases/june' into feat/ability-to-pass-global-title-v…
Browse files Browse the repository at this point in the history
…alues
  • Loading branch information
aliemir authored May 29, 2024
2 parents d2517ec + a2e53d2 commit ac70f17
Show file tree
Hide file tree
Showing 2,461 changed files with 4,489 additions and 3,848 deletions.
7 changes: 7 additions & 0 deletions .changeset/tall-doors-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@refinedev/devtools-internal": patch
---

fix(devtools-internal): broken env conditional in useQuerySubscription hook

When using Refine with React Native, `process.env.NODE_ENV !== "development" ? () => ({}) : () => {...}` conditional in `useQuerySubscription` hook was causing a syntax error. This PR fixes the issue by explicitly returning an empty object on non-development environments.
7 changes: 7 additions & 0 deletions .changeset/thick-doors-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@refinedev/nestjs-query": minor
---

feat(nestjs-query): implemented getApiUrl

resolves #5606
42 changes: 42 additions & 0 deletions .changeset/weak-trees-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
"@refinedev/ably": patch
"@refinedev/airtable": patch
"@refinedev/antd": patch
"@refinedev/appwrite": patch
"@refinedev/chakra-ui": patch
"@refinedev/cli": patch
"@refinedev/codemod": patch
"@refinedev/core": patch
"@refinedev/devtools": patch
"@refinedev/devtools-internal": patch
"@refinedev/devtools-server": patch
"@refinedev/devtools-shared": patch
"@refinedev/devtools-ui": patch
"@refinedev/graphql": patch
"@refinedev/hasura": patch
"@refinedev/inferencer": patch
"@refinedev/kbar": patch
"@refinedev/mantine": patch
"@refinedev/medusa": patch
"@refinedev/mui": patch
"@refinedev/nestjs-query": patch
"@refinedev/nestjsx-crud": patch
"@refinedev/nextjs-router": patch
"@refinedev/react-hook-form": patch
"@refinedev/react-router-v6": patch
"@refinedev/react-table": patch
"@refinedev/remix-router": patch
"@refinedev/simple-rest": patch
"@refinedev/strapi": patch
"@refinedev/strapi-v4": patch
"@refinedev/supabase": patch
"@refinedev/ui-tests": patch
"@refinedev/ui-types": patch
---

chore: added `type` qualifier to imports used as type only.

```diff
- import { A } from "./example.ts";
+ import type { A } from "./example.ts";
```
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"lineWidth": 80
},
"javascript": {
"jsxRuntime": "reactClassic",
"formatter": {
"arrowParentheses": "always",
"quoteStyle": "double",
Expand Down Expand Up @@ -93,7 +94,7 @@
"useSelfClosingElements": "error",
"useSingleVarDeclarator": "error",
"useTemplate": "error",
"useImportType": "off",
"useImportType": "error",
"useNodejsImportProtocol": "off"
},
"suspicious": {
Expand Down
2 changes: 1 addition & 1 deletion cypress/support/commands/intercepts/hasura.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CyHttpMessages } from "cypress/types/net-stubbing";
import type { CyHttpMessages } from "cypress/types/net-stubbing";
import hasuraBlogPosts from "../../../fixtures/hasura-blog-posts.json";
import hasuraCategories from "../../../fixtures/hasura-categories.json";

Expand Down
2 changes: 1 addition & 1 deletion cypress/support/commands/intercepts/supabase.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference types="cypress" />
/// <reference types="../../index.d.ts" />

import { ICategory, IPost } from "../../types";
import type { ICategory, IPost } from "../../types";

const HOSTNAME = "iwdfzvfqbtokqetmbmbp.supabase.co";
const BASE_PATH = "/rest/v1";
Expand Down
4 changes: 2 additions & 2 deletions cypress/support/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import posts from "../../fixtures/posts.json";
import categories from "../../fixtures/categories.json";
import type posts from "../../fixtures/posts.json";
import type categories from "../../fixtures/categories.json";

export type IPost = (typeof posts)[number];
export type ICategory = (typeof categories)[number];
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ description: Deep dive into variadic currying in JavaScript with examples
slug: javascript-variadic-currying
authors: abdullah_numan
tags: [javascript]
image: https://refine.ams3.cdn.digitaloceanspaces.com/blog/2022-08-28-js-currying-functions/social.png
featured_image: https://refine.ams3.cdn.digitaloceanspaces.com/blog/2022-08-28-js-currying-functions/featured.png
image: https://refine.ams3.cdn.digitaloceanspaces.com/blog/2022-08-28-js-currying-functions/social-2.png
hide_table_of_contents: false
---

**_This article was last updated on May 27, 2024 to add new sections on advanced usage, explanations and performance consideration on JavaScript Currying_**

## Introduction

In this post, we first look at the confusion around currying in JavaScript, especially with respect to polyadic partial application. We find out that we're not really doing currying in the real sense that it is implemented in Haskell, rather in a much limited capacity.
Expand All @@ -17,13 +18,78 @@ In the later part, we delve into variadic currying in a stricter sense with an e

Steps we'll cover:

- [What is JavaScript Currying?](#what-is-javascript-currying)
- [What is Variadic Currying?](#what-is-variadic-currying)
- [Benefits of Variadic Currying](#benefits-of-variadic-currying)
- [Variadic Partial Application](#variadic-partial-application)
- [Using `Function.prototype` Methods](#using-functionprototype-methods)
- [Variadic Currying with Termination](#variadic-currying-with-termination)
- [Performance Consideration when Using Javascript Currying](#performance-consideration-when-using-javascript-currying)
- [Bonus: Advanced JavaScript Currying Techniques](#bonus-advanced-javascript-currying-techniques)

This post is about variadic currying in JavaScript. It is the fifth part of the series titled [Curry Functions in JavaScript](https://dev.to/anewman15/curry-functions-in-javascript-4jpa).

### Variadic Partial Application
## What is JavaScript Currying?

Currying is a way of transforming a multi-argument function into a sequence of functions with a single argument. In other words, if a function will generally receive multiple arguments, it can be represented as a series of functions in which the first one receives one argument and then returns another function to which the next argument is passed as an argument, and so on. This way, we build more modular functions, hence reusable.

As an instance here is a function that adds two numbers :

```javascript
function add(a, b) {
return a + b;
}
```

Using currying, we can transform this into:

```javascript
function add(a) {
return function (b) {
return a + b;
};
}
```

Now `add(2)(3)` would produce `5`. That is pretty useful when we want to build partially applied functions for a better readability/maintainability of the code.

This property of currying also supports the development of higher-order functions and hence can be used to make function compositions easier in a way that makes the code more graceful and functional.

Currying is very powerful stuff in terms of writing reusable code and empowering our functions with a lot of flexibility. It may take a bit of time to get used to, but when one sees the patterns, it is soon recognized as a very useful tool in our JavaScript toolkit.

## What is Variadic Currying?

Variadic currying is an advanced concept in functional programming. It is an extension of the idea of currying for functions that are supposed to handle variable arguments. In the case of currying with n arguments, the function gets converted into a succession of n functions where each function takes a single argument. Variadic currying extends that concept to handle functions when the number of function arguments is not fixed.

In the case of variadic currying, the function receives plural arguments in the first call and in all subsequent calls, but a requirement of each partial application is to still be able to receive a plural number of preferences. This allows the function to be called with plural arguments and made flexible to be useful and reusable with a dynamic number of parameters.

```javascript
function concatenate(...strings) {
return strings.join(" ");
}

function curry(f) {
return function curried(...args) {
if (args.length >= f.length) return f(...args);
return function (...nextArgs) {
return curried(...args, ...nextArgs);
};
};
}

const curriedConcatenate = curry(concatenate);
console.log(curriedConcatenate("Hello")("world!")("How", "are", "you?")()); // Outputs: "Hello world! How are you?"
```

### Benefits of Variadic Currying

**Flexibility**: Being able to partially apply functions regardless of the number of arguments, they lean more toward flexibility, molding them in various use cases.

**Reusability**: Functions can be modularized and then reused with different sets of arguments without developing the core logic again and again.

**Modularity**: It allows functions to be used in more modular ways, making the code modular

## Variadic Partial Application

In the previous article titled [Auto-currying in JavaScript](https://dev.to/anewman15/auto-currying-in-javascript-17il), we focused on the **unarity** of curried functions, because that's what a curried function ought to be.

Expand Down Expand Up @@ -132,7 +198,7 @@ So basically, what we've done is allow the accumulator to take multiple argument

But now our `curry()` function is much more powerful. We can pass any number of arguments to an accumulator, as long as that is returned. And it is common to implement this with native JavaScript `Function.prototype` methods.

### Using `Function.prototype` Methods
## Using `Function.prototype` Methods

We can re-write the `curry()` function with `Function.prototype.apply`, and with `Function.prototype.bind`:

Expand Down Expand Up @@ -292,36 +358,74 @@ Notice also that since we focused on unary implementation of variadic currying,

Currying a variadic function is quite different from currying functions with fixed arity in terms of the logic, especially with respect to how termination is achieved by passing an empty argument. Without termination, it can take infinite number of arguments. In the next article, we'll see an example of infinitely curried function that does not require termination at all.

## Conclusion
## Performance Consideration when Using Javascript Currying

In this post, we found out that deviating from unary currying in leads to variadic partial application in JavaScript, which turns out to be more powerful. We also saw how currying an existing variadic function follows a different logic than those with fixed arity with a unary implementation.
It, however, does have a bright side; the curried code could be much more readable and modular. On the flip side, however, there are issues related to performance. When a curried function is created, at least two functions are abstracted at that point in time to wrap around each other. This reinstates extra overhead, especially if the function is called from inside a performance-critical section or very frequently. Each level of currying adds a new level of function calling to the stack so, when the program is executed, unless that is well controlled, it's slower.

<br/>
<div>
<a href="https://discord.gg/refine">
<img src="https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/discord-banner.png" alt="discord banner" />
</a>
</div>
For instance, a simple curried addition function:

---
```javascript
function add(a) {
return function (b) {
return a + b;
};
}
```

That may look clean enough, but heavy use in a loop or in a performance-heavy application introduces a very noticeable latency compared to what a simple addition function would do.

Be cautious when using currying so that poor performance is avoided, especially in performance-critical paths. Prefer a direct usage style when currying in such paths. Besides, modern JavaScript engines try to optimize a lot around function calls. Knowledge about the trade-offs in the different ways those optimizations can be turned on or off will help you be sure to make a better decision when and where to apply currying.

While currying really helps to make the code readable and flexible, during such process we must not suffer much from performance at critical sections of our application. Striking the right balance between clean code and efficient execution is important.

## Build your React-based CRUD applications without constraints
## Bonus: Advanced JavaScript Currying Techniques

Building CRUD applications involves many repetitive task consuming your precious development time. If you are starting from scratch, you also have to implement custom solutions for critical parts of your application like authentication, authorization, state management and networking.
Beyond the most basic kind of currying that we've already seen, there's a host of more sophisticated tricks to be played. One of them is **partial application**, in which we pre-fill some of the function's arguments, so as to create a more specialised version of the function, but without actually running it. That can be used, in particular, to 'configure' functions with common settings.

Check out [Refine](https://github.com/refinedev/refine), if you are interested in a headless framework with robust architecture and full of industry best practices for your next CRUD project.
For example:

<div>
<a href="https://github.com/refinedev/refine">
<img src="https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/refine_blog_logo_1.png" alt="refine blog logo" />
</a>
</div>
```javascript
function multiply(a, b) {
return a * b;
}
const double = multiply.bind(null, 2);
console.log(double(5)); // Outputs 10
```

Another operation is **function composition** which allows to combine several functions into a new one. Function composition is a way to make it easier to tap into the power of currying when transforming and passing data through a pipeline of functions. One can do that with a little help of utility functions from libraries like lodash and Ramda.

<br/>
For instance:

**Refine** is an open-source React-based framework for building CRUD applications **without constraints.**
It can speed up your development time up to **3X** without compromising freedom on **styling**, **customization** and **project workflow.**
```javascript
const compose =
(...fns) =>
(x) =>
fns.reduceRight((y, f) => f(y), x);
const add = (a) => (b) => a + b;
const square = (x) => x * x;

const addAndSquare = compose(square, add(2));
console.log(addAndSquare(3)); // Outputs 25
```

**Refine** is headless by design and it connects **30+** backend services out-of-the-box including custom REST and GraphQL API’s.
We can also consider **infinite currying**; a function can continue to curry forever, holding its arguments, until enough arguments have been received, at which point it would carry out its computation. This is an attractive feature for function definition, but it needs to be used with care.

Visit [Refine GitHub repository](https://github.com/refinedev/refine) for more information, demos, tutorials, and example projects.
```javascript
function infiniteCurry(fn, seed) {
const reduceValue = (args, arg) => fn.apply(null, args.concat(arg));
const next =
(...args) =>
(arg) =>
arg ? next(...args, arg) : args.reduce(reduceValue, seed);
return next();
}

const sum = infiniteCurry((a, b) => a + b, 0);
console.log(sum(1)(2)(3)()); // Outputs 6
```

These advanced feature additions can significantly enhance our functional programming capabilities within JavaScript. It is a great way to write cleaner, more modular, and reusable code in dealing with big codebases.

## Conclusion

In this post, we found out that deviating from unary currying in leads to variadic partial application in JavaScript, which turns out to be more powerful. We also saw how currying an existing variadic function follows a different logic than those with fixed arity with a unary implementation.
2 changes: 1 addition & 1 deletion documentation/src/assets/examples.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PageIcon } from "@site/src/refine-theme/icons/page";
import { ShareIcon } from "@site/src/refine-theme/icons/share";
import React from "react";
import { Examples } from "../types/examples";
import type { Examples } from "../types/examples";

export const SHOW_CASES: Examples = [
{
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/ably.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAbly = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/airtable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAirtable = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/antd.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAntd = ({
withBrandColor = true,
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/appwrite.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAppwrite = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/atlassian.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAtlassian = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/auth-js.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAuthJs = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/auth0.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAuth0 = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/aws-cognito.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAwsCognito = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgAzureActiveDirectory = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/chakra.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgChakra = ({
withBrandColor = true,
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/clerk.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgClerk = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/custom-auth.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { SVGProps } from "react";
import React, { type SVGProps } from "react";

const CustomAuthIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/assets/integration-icons/directus.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { SVGProps } from "react";
import type { SVGProps } from "react";

const SvgDirectus = (props: SVGProps<SVGSVGElement>) => (
<svg
Expand Down
Loading

0 comments on commit ac70f17

Please sign in to comment.