Skip to content

Commit

Permalink
feat: base implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Wroud committed Nov 20, 2024
1 parent 9504af1 commit 2efb8ba
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 0 deletions.
113 changes: 113 additions & 0 deletions packages/@wroud/preconditions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# @wroud/preconditions

[![ESM-only package][package]][esm-info-url]
[![NPM version][npm]][npm-url]

<!-- [![Install size][size]][size-url] -->

[package]: https://img.shields.io/badge/package-ESM--only-ffe536.svg
[esm-info-url]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[npm]: https://img.shields.io/npm/v/@wroud/preconditions.svg
[npm-url]: https://npmjs.com/package/@wroud/preconditions
[size]: https://packagephobia.com/badge?p=@wroud/preconditions
[size-url]: https://packagephobia.com/result?p=@wroud/preconditions

@wroud/preconditions is a flexible and extensible library for managing preconditions in JavaScript and TypeScript applications. It simplifies the process of validating and preparing entities (e.g., nodes, connections, features) by providing a robust framework for defining and applying preconditions.

## Features

- **Entity-Specific Managers**: Manage preconditions independently for different types of entities.
- **Dynamic Applicability**: Apply preconditions selectively to specific instances based on their data.
- **Extensibility**: Add new preconditions dynamically in a plugin-style manner.
- **Check-Only and Fulfill Modes**: Support both validating preconditions and attempting to fulfill them.
- **TypeScript Support**: Provides strong typing for enhanced developer experience.
- [Pure ESM package][esm-info-url]

## Installation

Install via npm:

```sh
npm install @wroud/preconditions
```

Install via yarn:

```sh
yarn add @wroud/preconditions
```

## Documentation

For detailed usage and API reference, visit the [documentation site](https://wroud.dev).

## Example

### Define Your Entities

```ts
export interface Node {
id: string;
data: {
requiresDatabaseConnection?: boolean;
};
}
```

### Define Preconditions

```ts
import type { IPrecondition } from "@wroud/preconditions";

export class DatabaseConnectionPrecondition implements IPrecondition<Node> {
isApplicable(node: Node): boolean {
return node.data.requiresDatabaseConnection === true;
}

async check(node: Node): Promise<boolean> {
return databaseConnection.isEstablished();
}

async fulfill(node: Node): Promise<void> {
await databaseConnection.connect();
}
}
```

### Set Up a Precondition Manager

```ts
import { PreconditionManager } from "@wroud/preconditions";
import { Node } from "./Node";
import { DatabaseConnectionPrecondition } from "./NodePreconditions";

const nodePreconditionManager = new PreconditionManager<Node>();
nodePreconditionManager.register(new DatabaseConnectionPrecondition());
```

### Check and Fulfill Preconditions

```ts
const node: Node = { id: "node1", data: { requiresDatabaseConnection: true } };

const canLoad = await nodePreconditionManager.checkPreconditions(node);

if (canLoad) {
console.log("Node can be loaded.");
} else {
try {
await nodePreconditionManager.fulfillPreconditions(node);
console.log("Preconditions fulfilled. Node is ready to load.");
} catch (error) {
console.error("Failed to fulfill preconditions:", error);
}
}
```

## Changelog

All notable changes to this project will be documented in the [CHANGELOG](./CHANGELOG.md) file.

## License

This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.
38 changes: 38 additions & 0 deletions packages/@wroud/preconditions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@wroud/preconditions",
"type": "module",
"sideEffects": [],
"exports": {
".": "./lib/index.js",
"./*": "./lib/*.js"
},
"scripts": {
"ci:release": "yarn ci release --prefix preconditions-v",
"ci:git-tag": "yarn ci git-tag --prefix preconditions-v",
"ci:release-github": "yarn ci release-github --prefix preconditions-v",
"clear": "rimraf lib",
"build": "tsc -b",
"watch": "tsc -b -w"
},
"files": [
"package.json",
"LICENSE",
"README.md",
"CHANGELOG.md",
"lib",
"!lib/**/*.d.ts.map",
"!lib/**/*.test.js",
"!lib/**/*.test.d.ts",
"!lib/**/*.test.d.ts.map",
"!lib/**/*.test.js.map",
"!lib/tests",
"!.tsbuildinfo"
],
"packageManager": "[email protected]",
"devDependencies": {
"@wroud/ci": "workspace:^",
"@wroud/tsconfig": "workspace:^",
"rimraf": "^6",
"typescript": "^5"
}
}
22 changes: 22 additions & 0 deletions packages/@wroud/preconditions/src/IPrecondition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface IPrecondition<T> {
/**
* Determines if this precondition applies to the given data.
* @param data - The data to check applicability for.
* @return {boolean} - True if applicable, false otherwise.
*/
isApplicable(data: T): boolean;

/**
* Checks if the precondition is already fulfilled.
* @param data - The data context.
* @return {Promise<boolean>} - Resolves to true if fulfilled, false otherwise.
*/
check(data: T): Promise<boolean>;

/**
* Attempts to fulfill the precondition.
* @param data - The data context.
* @return {Promise<void>}
*/
fulfill(data: T): Promise<void>;
}
50 changes: 50 additions & 0 deletions packages/@wroud/preconditions/src/PreconditionManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { IPrecondition } from "./IPrecondition.js";

export class PreconditionManager<T> {
private preconditions: IPrecondition<T>[] = [];

/**
* Registers a new precondition for this entity type.
* @param precondition - The precondition to register.
*/
public register(precondition: IPrecondition<T>): void {
this.preconditions.push(precondition);
}

/**
* Checks if all applicable preconditions are fulfilled for the given entity instance.
* @param entity - The entity instance.
* @return {Promise<boolean>} - Resolves to true if all applicable preconditions are fulfilled.
*/
public async checkPreconditions(entity: T): Promise<boolean> {
for (const precondition of this.getApplicablePreconditions(entity)) {
const isFulfilled = await precondition.check(entity);
if (!isFulfilled) {
return false;
}
}
return true;
}

/**
* Attempts to fulfill all applicable preconditions for the given entity instance.
* @param entity - The entity instance.
* @return {Promise<void>}
*/
public async fulfillPreconditions(entity: T): Promise<void> {
for (const precondition of this.getApplicablePreconditions(entity)) {
const isFulfilled = await precondition.check(entity);
if (!isFulfilled) {
await precondition.fulfill(entity);
}
}
}

public *getApplicablePreconditions(entity: T): Iterable<IPrecondition<T>> {
for (const precondition of this.preconditions) {
if (precondition.isApplicable(entity)) {
yield precondition;
}
}
}
}
2 changes: 2 additions & 0 deletions packages/@wroud/preconditions/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./IPrecondition.js";
export * from "./PreconditionManager.js";
16 changes: 16 additions & 0 deletions packages/@wroud/preconditions/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "@wroud/tsconfig/tsconfig.json",
"compilerOptions": {
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"rootDirs": [
"src"
],
"outDir": "lib",
"incremental": true,
"composite": true
},
"include": [
"src"
]
}
1 change: 1 addition & 0 deletions packages/_aggregate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@wroud/docs": "workspace:*",
"@wroud/git": "workspace:*",
"@wroud/github": "workspace:*",
"@wroud/preconditions": "workspace:^",
"@wroud/ts-project-linker": "workspace:*",
"@wroud/ts-template": "workspace:^",
"@wroud/tsconfig": "workspace:*",
Expand Down
3 changes: 3 additions & 0 deletions packages/_aggregate/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
{
"path": "../@wroud/github"
},
{
"path": "../@wroud/preconditions"
},
{
"path": "../@wroud/ts-project-linker"
},
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3954,6 +3954,7 @@ __metadata:
"@wroud/docs": "workspace:*"
"@wroud/git": "workspace:*"
"@wroud/github": "workspace:*"
"@wroud/preconditions": "workspace:^"
"@wroud/ts-project-linker": "workspace:*"
"@wroud/ts-template": "workspace:^"
"@wroud/tsconfig": "workspace:*"
Expand Down Expand Up @@ -4205,6 +4206,17 @@ __metadata:
languageName: unknown
linkType: soft

"@wroud/preconditions@workspace:^, @wroud/preconditions@workspace:packages/@wroud/preconditions":
version: 0.0.0-use.local
resolution: "@wroud/preconditions@workspace:packages/@wroud/preconditions"
dependencies:
"@wroud/ci": "workspace:^"
"@wroud/tsconfig": "workspace:^"
rimraf: "npm:^6"
typescript: "npm:^5"
languageName: unknown
linkType: soft

"@wroud/tests-runner@workspace:*, @wroud/tests-runner@workspace:^, @wroud/tests-runner@workspace:packages/@wroud/tests-runner":
version: 0.0.0-use.local
resolution: "@wroud/tests-runner@workspace:packages/@wroud/tests-runner"
Expand Down

0 comments on commit 2efb8ba

Please sign in to comment.