-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* wip * Update labs.ts * Revert "Update labs.ts" This reverts commit 244ba7d. * Update labs.ts * Update labs.ts * Update labs.ts * Update labs.ts * wip * Update labs.ts * wip * remove unused function overloads * wip * consolidate procedurelab into lab * generalize link procedure to link n linkables * rename import to extend * wip * satisfies: type check spec compliancy * update docs, add check workflow * update does * add use cases section to readme
- Loading branch information
1 parent
4a0bb25
commit a97aca0
Showing
9 changed files
with
692 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
name: Check | ||
"on": | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
branches: | ||
- main | ||
jobs: | ||
check: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: denoland/setup-deno@v1 | ||
- name: Lint | ||
run: deno lint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"deno.enable": true, | ||
"deno.unstable": true, | ||
"editor.formatOnSave": true, | ||
"editor.defaultFormatter": "esbenp.prettier-vscode", | ||
"[markdown]": { | ||
"editor.defaultFormatter": "denoland.vscode-deno" | ||
}, | ||
"[jsonc]": { | ||
"editor.defaultFormatter": "denoland.vscode-deno" | ||
}, | ||
"[typescript]": { | ||
"editor.defaultFormatter": "denoland.vscode-deno" | ||
}, | ||
"[typescriptreact]": { | ||
"editor.defaultFormatter": "denoland.vscode-deno" | ||
}, | ||
"files.eol": "\n" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# Getting Started | ||
|
||
## Your first lab | ||
|
||
The Notes Lab is a simple example that demonstrates the basic concepts of Labs. | ||
Follow the steps below to create a new Lab that manages notes. | ||
|
||
1\. Import the `Lab` class in a new TypeScript file, `main.ts`. | ||
|
||
```ts | ||
import { Lab } from "./labs.ts"; | ||
``` | ||
|
||
2\. Define the `Note` interface. | ||
|
||
```ts | ||
export interface Note { | ||
title?: string; | ||
content: string; | ||
} | ||
``` | ||
|
||
3\. Create a new Lab instance. | ||
|
||
```ts | ||
export const notesLab = new Lab(); | ||
``` | ||
|
||
4\. Define the `notes` variable in the Lab. | ||
|
||
```ts | ||
export const notesLab = new Lab() | ||
.variable("notes", new Map<string, Note>()); | ||
``` | ||
|
||
5\. Define the `notes.add` procedure in the Lab. | ||
|
||
```ts | ||
export const notesLab = new Lab() | ||
// ... | ||
.procedure( | ||
"notes.add", | ||
(note: Note, { notes }) => { | ||
const id = crypto.randomUUID(); | ||
notes.set(id, note); | ||
return { id }; | ||
}, | ||
["notes"], | ||
); | ||
``` | ||
|
||
6\. Define the `notes.get` procedure in the Lab. | ||
|
||
```ts | ||
export const notesLab = new Lab() | ||
// ... | ||
.procedure( | ||
"notes.get", | ||
({ id }: { id: string }, { notes }) => { | ||
return notes.get(id); | ||
}, | ||
["notes"], | ||
); | ||
``` | ||
|
||
7\. Define the `notes.list` procedure in the Lab. | ||
|
||
```ts | ||
export const notesLab = new Lab() | ||
// ... | ||
.procedure( | ||
"notes.list", | ||
(_, { notes }) => { | ||
return Array.from(notes.values()); | ||
}, | ||
["notes"], | ||
); | ||
``` | ||
|
||
At this point, the `notesLab` Lab is ready to be used. | ||
|
||
8\. Execute the `notes.add` procedure. | ||
|
||
```ts | ||
notesLab.execute("notes.add", { title: "Hello", content: "World" }); | ||
``` | ||
|
||
9\. Execute the `notes.list` procedure. | ||
|
||
```ts | ||
const notes = notesLab.execute("notes.list", {}); | ||
console.log(notes); | ||
``` | ||
|
||
10\. Test it out! | ||
|
||
```ts | ||
import { Lab } from "./labs.ts"; | ||
|
||
export interface Note { | ||
title?: string; | ||
content: string; | ||
} | ||
|
||
export const notesLab = new Lab() | ||
.variable("notes", new Map<string, Note>()) | ||
.procedure( | ||
"notes.add", | ||
(note: Note, { notes }) => { | ||
const id = crypto.randomUUID(); | ||
notes.set(id, note); | ||
return { id }; | ||
}, | ||
["notes"], | ||
) | ||
.procedure( | ||
"notes.get", | ||
({ id }: { id: string }, { notes }) => { | ||
return notes.get(id); | ||
}, | ||
["notes"], | ||
) | ||
.procedure( | ||
"notes.list", | ||
(_, { notes }) => { | ||
return Array.from(notes.values()); | ||
}, | ||
["notes"], | ||
); | ||
|
||
notesLab.execute("notes.add", { title: "Hello", content: "World" }); | ||
|
||
const notes = notesLab.execute("notes.list", {}); | ||
console.log(notes); | ||
``` | ||
|
||
Run the program and observe the output. | ||
|
||
```sh | ||
deno run main.ts | ||
``` | ||
|
||
--- | ||
|
||
Developed with ❤️ [**@FartLabs**](https://github.com/FartLabs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,86 @@ | ||
# labs | ||
🧪 Labs by FartLabs. | ||
# Labs | ||
|
||
[![GitHub Actions](https://github.com/FartLabs/labs/actions/workflows/check.yaml/badge.svg)](https://github.com/FartLabs/labs/actions/workflows/check.yaml) | ||
|
||
🧪 Labs by [**@FartLabs**](https://github.com/FartLabs) | ||
|
||
## Overview | ||
|
||
A Lab is a data structure designed for composable and type-safe management of | ||
variables and procedures. | ||
|
||
Labs excel in promoting modularity and reusability. Small, well-defined Labs can | ||
be composed to create complex data structures. This approach simplifies code | ||
composition and improves code quality by reducing _redundancy_ and enhancing | ||
_readability_. Additionally, this approach avoids the need for intricate | ||
inheritance hierarchies with keywords like `super`, `this`, and `extends`. | ||
|
||
### Concepts | ||
|
||
- **Lab**: A container that holds a collection of named variables and functions | ||
(procedures). | ||
- **Variable**: A named storage location within a Lab that holds a value. | ||
- **Procedure**: A function defined within a Lab that performs a specific task | ||
and has type-safe access to variables and procedures within the same Lab. | ||
|
||
### Benefits | ||
|
||
By adopting Labs, developers can build applications with cleaner, more | ||
maintainable, and reusable code. | ||
|
||
- **Simplified composition**: Labs are easier to compose and work with compared | ||
to native classes. Accessing variables and procedures within a composed Lab is | ||
straightforward. | ||
- **Improved code quality**: By encouraging the breakdown of complex data | ||
structures into smaller, modular Labs, code becomes: | ||
- **Maintainable**: Changes to a Lab's structure are localized and isolated, | ||
reducing the risk of unintended side effects. | ||
- **Less duplicated**: Shared functionalities can be encapsulated in reusable | ||
Labs, minimizing redundancy. | ||
- **More readable**: Clear separation of concerns improves code comprehension. | ||
- **Easier to reason about**: Smaller, well-defined Labs simplify code | ||
analysis and reasoning. | ||
|
||
### Use cases | ||
|
||
> [!NOTE] | ||
> | ||
> Example Labs demonstrating the following use cases will be added in the | ||
> future. | ||
- **State management**: Labs can be used to manage application state by | ||
encapsulating state variables and state-changing procedures within a Lab. | ||
- **Data processing**: Labs can be used to encapsulate data processing logic, | ||
making it easier to manage and reuse. | ||
- **API clients**: Labs can be used to encapsulate API clients, making it easier | ||
to manage API calls and responses. | ||
- **Configuration management**: Labs can be used to manage application | ||
configuration by encapsulating configuration variables and procedures within a | ||
Lab. | ||
- **Second brain**: Labs can be used to encapsulate knowledge and procedures | ||
that are useful for a specific domain or task. | ||
- **Testing**: Labs can be used to encapsulate test data and test procedures, | ||
making it easier to manage and reuse test cases. | ||
- **Miscellaneous**: Labs can be used for any task that requires encapsulation, | ||
modularity, and reusability. | ||
|
||
## Usage | ||
|
||
- The [GETTING_STARTED.md](./GETTING_STARTED.md) guide is a Notes Lab example | ||
that demonstrates the basic concepts of Labs. | ||
- The [example.ts](./example.ts) file contains a more advanced example that | ||
showcases the composability of Labs. | ||
|
||
## Contribute | ||
|
||
We appreciate your help! | ||
|
||
### Style | ||
|
||
Run `deno fmt` to format the code. | ||
|
||
Run `deno lint` to lint the code. | ||
|
||
--- | ||
|
||
Developed with ❤️ [**@FartLabs**](https://github.com/FartLabs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { Lab } from "./labs.ts"; | ||
import { notesLab } from "./notes.ts"; | ||
import { linksLab } from "./links.ts"; | ||
|
||
const myLab = new Lab() | ||
.extend(notesLab) | ||
.extend(linksLab); | ||
|
||
// deno run -A example.ts | ||
// | ||
// Proof-of-concept Lab. | ||
// | ||
if (import.meta.main) { | ||
const note1 = myLab.execute( | ||
"notes.add", | ||
{ content: "Hello, world!" }, | ||
); | ||
const note2 = myLab.execute( | ||
"notes.add", | ||
{ content: "Goodbye, world!" }, | ||
); | ||
myLab.execute("links.link", { ids: [note1.id, note2.id] }); | ||
|
||
printLinkedNotes(note1.id); | ||
printLinkedNotes(note2.id); | ||
} | ||
|
||
function printLinkedNotes(id: string) { | ||
const noteA = myLab.execute("notes.get", { id }); | ||
console.log(`Note "${noteA?.content ?? "No content."}" is linked with:`); | ||
|
||
const linkedNotes = myLab.execute("links.get", { id }); | ||
if (linkedNotes === undefined || linkedNotes.links.length === 0) { | ||
console.log("- No linked notes."); | ||
return; | ||
} | ||
|
||
for (const link of linkedNotes.links) { | ||
const noteB = notesLab.execute("notes.get", { id: link.id }); | ||
console.log(`- Note "${noteB?.content ?? "No content."}"`); | ||
} | ||
} |
Oops, something went wrong.