Skip to content

Commit

Permalink
chore: sjel
Browse files Browse the repository at this point in the history
chore: sjel

chore: benchmarks
  • Loading branch information
Handfish committed Jan 14, 2024
1 parent 5fbff0f commit 2c26915
Show file tree
Hide file tree
Showing 41 changed files with 825 additions and 95 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<p align="center"><a href="https://github.com/Handfish/ajel" target="_blank"><img src="https://raw.githubusercontent.com/Handfish/ajel/main/apps/docs/public/ajel2.svg" width="100" alt="Laravel Logo"></a></p>

<p align="center">Ajel is a <b>133 byte</b> function that allows you to handle errors in a way that is similar to Golang.</p>
<p align="center">Ajel is a <b>312 byte</b> set of functions that encourage you to handle errors in a way that is similar to Golang.</p>

<p align="center">
<a href="https://www.npmjs.com/ajel" target="_blank"><img src="https://img.shields.io/npm/v/ajel.svg" alt="NPM Version" /></a>
Expand All @@ -12,7 +12,7 @@



# [ajel (Asynchronous Javascript Error Library)](https://handfish.github.io/ajel)
# [ajel](https://handfish.github.io/ajel)

### Installation

Expand Down
23 changes: 23 additions & 0 deletions apps/docs/src/pages/benchmarks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ Allocate 500kb Files 2 times
│ 1 │ 'ajel' │ '2,297' │ 435230.6347826253 │ '±8.77%' │ 230 │
│ 2 │ 'neverthrow' │ '2,417' │ 413718.4740590656 │ '±9.86%' │ 242 │
└─────────┴──────────────┴─────────┴───────────────────┴──────────┴─────────┘
------
sjel
Allocate 500kb Files 2 times
┌─────────┬─────────────┬─────────┬────────────────────┬──────────┬─────────┐
│ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
├─────────┼─────────────┼─────────┼────────────────────┼──────────┼─────────┤
│ 0 │ 'try_catch' │ '533' │ 1873371.6187653719 │ '±6.23%' │ 54 │
│ 1 │ 'sjel' │ '528' │ 1890484.647930793 │ '±8.25%' │ 53 │
└─────────┴─────────────┴─────────┴────────────────────┴──────────┴─────────┘
```


Expand Down Expand Up @@ -73,3 +84,15 @@ Allocate 500kb Files 2 times
│ 1 │ 'ajel' │ '2,408' │ 415190.9061981929 │ '±6.26%' │ 241 │
│ 2 │ 'neverthrow' │ '2,367' │ 422311.19659882557 │ '±8.50%' │ 237 │
└─────────┴──────────────┴─────────┴────────────────────┴──────────┴─────────┘
------
sjel
Allocate 500kb Files 2 times
┌─────────┬─────────────┬─────────┬───────────────────┬──────────┬─────────┐
│ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
├─────────┼─────────────┼─────────┼───────────────────┼──────────┼─────────┤
│ 0 │ 'try_catch' │ '594' │ 1682249.085108439 │ '±5.05%' │ 60 │
│ 1 │ 'sjel' │ '595' │ 1679521.369934082 │ '±3.10%' │ 60 │
└─────────┴─────────────┴─────────┴───────────────────┴──────────┴─────────┘
```
24 changes: 20 additions & 4 deletions apps/docs/src/pages/index.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# ajel (Asynchronous JavaScript Error Library)
# ajel

## What is ajel?

Ajel is a **133 byte** library that allows you to handle errors in a way that is similar to Golang.
Ajel is a **312 byte** set of functions that encourage you to handle errors in a way that is similar to Golang.

### Installation

Expand All @@ -14,6 +14,7 @@ Ajel is a **133 byte** library that allows you to handle errors in a way that is
### Usage

```typescript
// Handling async functions that throw
import { ajel } from 'ajel';

async function main() {
Expand All @@ -27,10 +28,25 @@ async function main() {
}
```

`ajel` is a function that consumes a promise and returns a tuple representing the result and the error.
```typescript
// Handling synchronous functions that throw
import { sjel } from 'ajel';

function main() {
const [result, err] = sjel(JSON.parse)("{}");

if (err) {
return err;
}

return result;
}
```

`ajel` and `sjel` are a set of functions that consume a promise and returns a tuple representing the result and the error.
On success, the result item has value. On error, the error item has value. It's that simple.

More interestingly, it comes with a series of linting tools to help enforce the paradigm available in the package `eslint-plugin-ajel`
More interestingly, they come with a series of linting tools to help enforce the paradigm available in the package `eslint-plugin-ajel`

## Why I ported Golang's most hated feature to JavaScript

Expand Down
11 changes: 11 additions & 0 deletions apps/docs/src/pages/rules/ajel-const-tuples.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This rule checks for Variable Declarations that include a call to the ajel metho
## Options

- `ajelAlias` (default: 'ajel'): Specify the alias for the ajel method. This allows you to customize the method name if it differs from the default 'ajel'.
- `sjelAlias` (default: 'sjel'): Specify the alias for the sjel method. This allows you to customize the method name if it differs from the default 'sjel'.

## Implementation

Expand All @@ -24,9 +25,19 @@ This rule checks for Variable Declarations that include a call to the ajel metho
## Examples

```javascript
// ajel
// Bad: Variable declaration without 'const' for ajel method
let [res, err] = await ajel(Promise.resolve(1));

// Good: Variable declaration with 'const' for ajel method
const [res, err] = await ajel(Promise.resolve(1));

// -----

// sjel
// Bad: Variable declaration without 'const' for sjel method
let [res, err] = sjel(() => 1)();

// Good: Variable declaration with 'const' for sjel method
const [res, err] = sjel(() => 1)();
```
16 changes: 15 additions & 1 deletion apps/docs/src/pages/rules/ajel-disable-try-catch.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The use of try-catch blocks does not align with preferred error-handling strateg
## Options

- `ajelAlias` (default: 'ajel'): Specify the alias for the ajel method. This allows you to customize the method name if it differs from the default 'ajel'.
- `sjelAlias` (default: 'sjel'): Specify the alias for the sjel method. This allows you to customize the method name if it differs from the default 'sjel'.

## Implementation

Expand All @@ -28,6 +29,7 @@ The use of try-catch blocks does not align with preferred error-handling strateg
## Examples

```javascript
// ajel
// Bad: Using TryStatement for error handling
let res;

Expand All @@ -41,5 +43,17 @@ try {
// Better: Utilizing ajel method for error handling
const [res, err] = await ajel(dangerousOperation());

if (err) return err;
// -----

// sjel
// Bad: Using TryStatement for error handling
try {
res = foo;
JSON.parse("{'badjson`: 'asd'}");
} catch (error) {
return error;
}

// Better: Utilizing sjel method for error handling
const [res, err] = sjel(JSON.parse)("{'badjson`: 'asd'}");
```
17 changes: 16 additions & 1 deletion apps/docs/src/pages/rules/ajel-require-error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

The `ajel-require-error-handling` rule ensures that when calling `ajel`, the error variable (typically named `err`) is properly handled. This helps prevent potential bugs and ensures that developers explicitly address errors returned from `ajel` calls.


## Rule Details

This rule checks for the usage of the error variable (`err`) in the context of a `VariableDeclaration` associated with an `ajel` call. If the error variable is declared but not used, a violation is reported.
Expand All @@ -24,6 +23,7 @@ This rule is not entirely redundant to `noUnusedLocals` - it is made in mind to
## Options

- `ajelAlias` (default: 'ajel'): Specify the alias for the ajel method. This allows you to customize the method name if it differs from the default 'ajel'.
- `sjelAlias` (default: 'sjel'): Specify the alias for the sjel method. This allows you to customize the method name if it differs from the default 'sjel'.

## Implementation

Expand All @@ -33,13 +33,28 @@ This rule is not entirely redundant to `noUnusedLocals` - it is made in mind to
## Examples

```javascript
// ajel
// Bad: Declaring error variable but not using it
const [data, err] = await ajel(Promise.resolve(1));
// 'err' should be handled, e.g., by logging or other usage

// Good: Properly handling the error variable
const [data, err] = await ajel(Promise.resolve(1));

if (err) {
console.error(err);
}

// -----

// sjel
// Bad: Declaring error variable but not using it
const [data, err] = sjel(fs.readFileSync)(path, { encoding: 'utf8' });
// 'err' should be handled, e.g., by logging or other usage

// Good: Properly handling the error variable
const [data, err] = sjel(fs.readFileSync)(path, { encoding: 'utf8' });

if (err) {
console.error(err);
}
Expand Down
14 changes: 14 additions & 0 deletions apps/docs/src/pages/rules/ajel-require-tuple-declaration.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This rule assists developers towards the proper usage of ajel.
## Options

- `ajelAlias` (default: 'ajel'): Specify the alias for the ajel method. This allows you to customize the method name if it differs from the default 'ajel'.
- `sjelAlias` (default: 'sjel'): Specify the alias for the sjel method. This allows you to customize the method name if it differs from the default 'sjel'.

## Implementation

Expand All @@ -28,6 +29,7 @@ This rule assists developers towards the proper usage of ajel.
## Examples

```javascript
// ajel
// Bad: Incorrect structure
const [value] = await ajel(Promise.resolve(1)); // Violation: Tuple must have exactly 2 elements

Expand All @@ -36,4 +38,16 @@ const err = await ajel(Promise.resolve(1)); // Violation: Limit declarations to

// Good: Correct tuple declaration
const [data, err] = await ajel(Promise.resolve(1));

// -----

// sjel
// Bad: Incorrect structure
const [value] = sjel(() => 1)(); // Violation: Tuple must have exactly 2 elements

// Bad: Incorrect structure
const err = sjel(() => 1)(); // Violation: Limit declarations to a tuple

// Good: Correct tuple declaration
const [data, err] = sjel(() => 1)();
```
19 changes: 19 additions & 0 deletions apps/docs/src/pages/rules/ajel-strict-error-instanceof.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Properly narrowing the error type with `instanceof` promotes more precise error
## Options

- `ajelAlias` (default: 'ajel'): Specify the alias for the ajel method. This allows you to customize the method name if it differs from the default 'ajel'.
- `sjelAlias` (default: 'sjel'): Specify the alias for the sjel method. This allows you to customize the method name if it differs from the default 'sjel'.

## Implementation

Expand All @@ -26,6 +27,7 @@ Properly narrowing the error type with `instanceof` promotes more precise error
## Examples

```javascript
// ajel
// Bad: Error variable not narrowed with instanceof
const [data, err] = await ajel(Promise.resolve(1));
// Missing instanceof check for specific error type
Expand All @@ -39,4 +41,21 @@ const [data, err] = await ajel(Promise.resolve(1));
if (err instanceof SpecificError) {
console.error(err.message);
}

// -----

// sjel
// Bad: Error variable not narrowed with instanceof
const [data, err] = sjel(() => 1)();
// Missing instanceof check for specific error type
if (err) {
console.error(err);
}

// Good: Error variable narrowed with instanceof
const [data, err] = sjel(() => 1)();
// Handle specific error type
if (err instanceof SpecificError) {
console.error(err.message);
}
```
32 changes: 32 additions & 0 deletions apps/docs/src/pages/rules/sjel-require-currying.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ajel/sjel-require-currying

> This rule provides clearer errors when trying to use sjel without currying. This should help more junior eyes.
- ⭐️ This rule is included in `plugin:ajel/recommended` preset.

## Summary

The `sjel-require-currying` rule provides a clear error that when calling sjel, you should be currying.

## Rule Details

- This rule checks for Variable Declarations that include a call to the sjel method. If a variable declaration does not find a AST nodes that denote currying, an error is reported.

## Options

- `sjelAlias` (default: 'sjel'): Specify the alias for the sjel method. This allows you to customize the method name if it differs from the default 'sjel'.

## Implementation

- [Rule source](https://github.com/Handfish/ajel/blob/main/packages/eslint-plugin-ajel/src/rules/sjel-require-currying.ts)
- [Test source](https://github.com/Handfish/ajel/blob/main/packages/eslint-plugin-ajel/tests/rules/sjel-require-currying.ts)

## Examples

```javascript
// Bad: calling sjel without currying (will provide 2 errors - a type error and our custom error)
let [res, err] = sjel(() => null);

// Good: calling sjel and currying
const [res, err] = sjel(() => null)();
```
4 changes: 2 additions & 2 deletions packages/ajel-core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ajel",
"description": "Ajel allows you to handle errors similarly to Golang.",
"version": "0.0.7",
"description": "ajel encourages to handle errors similarly to Golang",
"version": "0.0.8",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
Expand Down
20 changes: 18 additions & 2 deletions packages/ajel-core/readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<p align="center"><a href="https://github.com/Handfish/ajel" target="_blank"><img src="https://raw.githubusercontent.com/Handfish/ajel/main/apps/docs/public/ajel2.svg" width="100" alt="Laravel Logo"></a></p>

<p align="center">Ajel is a <b>133 byte</b> function that allows you to handle errors in a way that is similar to Golang.</p>
<p align="center">Ajel is a <b>312 byte</b> set of functions that encourage you to handle errors in a way that is similar to Golang.</p>

<p align="center">
<a href="https://www.npmjs.com/ajel" target="_blank"><img src="https://img.shields.io/npm/v/ajel.svg" alt="NPM Version" /></a>
Expand All @@ -12,7 +12,7 @@



# [ajel (Asynchronous Javascript Error Library)](https://handfish.github.io/ajel)
# [ajel](https://handfish.github.io/ajel)

### Installation

Expand All @@ -23,6 +23,7 @@

### Example usage
```typescript
// Handling async functions that throw
import { ajel } from 'ajel';

async function main() {
Expand All @@ -36,6 +37,21 @@ async function main() {
}
```

```typescript
// Handling async functions that throw
import { sjel } from 'ajel';

async function main() {
const [res, err] = sjel(fs.readFileSync)(path, { encoding: 'utf8' });

if (err) {
return err;
}

return result;
}
```

`ajel` is a function that consumes a promise and returns a tuple representing the result and the error.
On success, the result item has value. On error, the error item has value. It's that simple.

Expand Down
1 change: 1 addition & 0 deletions packages/ajel-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { ajel } from "./ajel";
export { sjel } from "./sjel";
10 changes: 10 additions & 0 deletions packages/ajel-core/src/sjel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type AnyFunction = (...args: any[]) => any;

export const sjel = <Result>(fn: AnyFunction) => (...args: any[]) => {
try {
const result = fn(...args);
return [result, undefined] as [result: Result, error?: undefined];
} catch (error) {
return [undefined, error] as [result: undefined, error: unknown];
}
};
11 changes: 11 additions & 0 deletions packages/benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,15 @@ Allocate 500kb Files 2 times
│ 1 │ 'ajel' │ '2,297' │ 435230.6347826253 │ '±8.77%' │ 230 │
│ 2 │ 'neverthrow' │ '2,417' │ 413718.4740590656 │ '±9.86%' │ 242 │
└─────────┴──────────────┴─────────┴───────────────────┴──────────┴─────────┘
------
sjel
Allocate 500kb Files 2 times
┌─────────┬─────────────┬─────────┬────────────────────┬──────────┬─────────┐
│ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
├─────────┼─────────────┼─────────┼────────────────────┼──────────┼─────────┤
│ 0 │ 'try_catch' │ '533' │ 1873371.6187653719 │ '±6.23%' │ 54 │
│ 1 │ 'sjel' │ '528' │ 1890484.647930793 │ '±8.25%' │ 53 │
└─────────┴─────────────┴─────────┴────────────────────┴──────────┴─────────┘
```
Loading

0 comments on commit 2c26915

Please sign in to comment.