Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
13 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,26 @@
- [@synstack/xml](./packages/xml/README.md) - Lax, non spec-compliant XML utils tailored for LLMs
- [@synstack/yaml](./packages/yaml/README.md) - Safe and opiniated YAML serialization and deserialization

#### Functional programming
#### System Utilities

- [@synstack/enhance](./packages/enhance/README.md) - Utility functions for enhancing objects and functions with additional capabilities
- [@synstack/fs-cache](./packages/fs-cache/README.md) - File system caching with deep equality checks and automatic invalidation
- [@synstack/git](./packages/git/README.md) - Git operations with type-safe command building and execution
- [@synstack/glob](./packages/glob/README.md) - Type-safe glob pattern matching and file filtering utilities

#### Functional Programming

- [@synstack/pipe](./packages/pipe/README.md) - Simple typesafe pipe utility for Functional Programming
- [@synstack/resolved](./packages/resolved/README.md) - A piping utility which preserves the sync/async state of the value

#### Text manipulation
#### Text and Document Processing

- [@synstack/llm](./packages/llm/README.md) - Type-safe LLM message handling with support for text, images, and tool calls
- [@synstack/markdown](./packages/markdown/README.md) - Type-safe markdown processing with YAML frontmatter support
- [@synstack/str](./packages/str/README.md) - Advanced chainable string manipulation
- [@synstack/text](./packages/text/README.md) - String templating as it was meant to be

#### Web scraping
#### Web Scraping

- [@synstack/web](./packages/web/README.md) - Web scraping utilities

Expand Down
154 changes: 153 additions & 1 deletion packages/enhance/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,153 @@
# @synstack/enhance
# @synstack/enhance

> Type-safe object enhancement with proxy-based method extension

This package provides a type-safe way to extend JavaScript objects with additional methods while maintaining access to the original object through proxies.

> [!WARNING]
> This package is included in the [@synstack/synscript](https://github.com/pAIrprogio/synscript) package. It is not recommended to install both packages at the same time.

## What is it for?

Sometimes you need to add functionality to existing objects without modifying their prototype or risking property collisions. This package provides a safe way to enhance objects with new methods while maintaining type safety:

```typescript
import { enhance } from "@synstack/enhance";

// Create an extension with new methods
const objExtensions = {
stringify: function() { return JSON.stringify(this) },
clone: function() { return { ...this } }
};

// Enhance an object with new methods
const obj = { name: "example", value: 42 };
const enhanced = enhance("object", obj, objExtensions);

// Use the enhanced object
console.log(enhanced.stringify()); // '{"name":"example","value":42}'
console.log(enhanced.clone()); // { name: "example", value: 42 }

// Access the original object
console.log(enhanced.$()); // { name: "example", value: 42 }
```

## Installation

```bash
# Using npm
npm install @synstack/enhance

# Using yarn
yarn add @synstack/enhance

# Using pnpm
pnpm add @synstack/enhance
```

## Features

### Object Enhancement

The package provides two main functions for enhancing objects:

#### enhance()

The `enhance()` function combines an object with extension methods:

```typescript
import { enhance } from "@synstack/enhance";

// Define extension methods
const loggerExtensions = {
log: function() { console.log(JSON.stringify(this)) },
getTimestamp: function() { return { ...this, timestamp: Date.now() } }
};

// Enhance an object
const data = { id: 1, message: "Hello" };
const enhanced = enhance("logger", data, loggerExtensions);

// Use enhanced methods
enhanced.log(); // Logs: {"id":1,"message":"Hello"}
const timestamped = enhanced.getTimestamp(); // { id: 1, message: "Hello", timestamp: 1234567890 }
```

#### enhanceFactory()

Create reusable enhancers with `enhanceFactory()`:

```typescript
import { enhanceFactory } from "@synstack/enhance";

// Create a reusable enhancer
const withLogging = enhanceFactory("logger", {
log: function() { console.log(JSON.stringify(this)) },
getTimestamp: function() { return { ...this, timestamp: Date.now() } }
});

// Enhance multiple objects
const obj1 = withLogging({ id: 1, name: "First" });
const obj2 = withLogging({ id: 2, name: "Second" });

obj1.log(); // Logs: {"id":1,"name":"First"}
obj2.log(); // Logs: {"id":2,"name":"Second"}
```

## API Reference

### enhance()

```typescript
function enhance<TName, TBaseObject, TExtension>(
name: TName,
obj: TBaseObject,
extendObj: TExtension
): Enhanced<TName, TBaseObject, TExtension>
```

- `name`: Unique identifier for this enhancement
- `obj`: The base object to enhance
- `extendObj`: Object containing extension methods
- Returns: A proxy that combines the base object with extension methods

### enhanceFactory()

```typescript
function enhanceFactory<TName, TExtension>(
name: TName,
extendObj: TExtension
): <TBaseObject>(obj: TBaseObject) => Enhanced<TName, TBaseObject, TExtension>
```

- `name`: Unique identifier for this enhancement factory
- `extendObj`: Object containing extension methods
- Returns: A function that enhances objects with the provided extensions

### Enhanced Type

```typescript
type Enhanced<TName, TBaseObject, TExtension> = {
$: TBaseObject;
[ENHANCER_NAME]: TName;
} & TExtension & TBaseObject
```

A type representing an enhanced object that combines:
- Original object properties (`TBaseObject`)
- Extension methods (`TExtension`)
- Special `$` property to access the original object
- Symbol property to identify the enhancer

## TypeScript Support

This package is written in TypeScript and provides full type definitions:

- Generic type parameters for base objects and extensions
- Type-safe access to both original and enhanced methods
- Proper typing for extension method context (`this`)
- IntelliSense support for all enhanced properties

## License

Apache-2.0 - see LICENSE file for details.
10 changes: 7 additions & 3 deletions packages/enhance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
"access": "public"
},
"version": "1.1.2",
"description": "Safely enhance a JS object with additional properties",
"description": "Type-safe object enhancement with proxy-based method extension - for objects only, not primitives",
"keywords": [
"proxy",
"object",
"enhance"
"object-enhancement",
"type-safe",
"method-extension",
"object-only",
"typescript",
"javascript-proxy"
],
"author": {
"name": "pAIrprog",
Expand Down
27 changes: 27 additions & 0 deletions packages/enhance/src/enhance.lib.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
/**
* Symbol used to identify enhanced objects and their original enhancer name
*/
export const ENHANCER_NAME = Symbol("EnhancerName");

// The order of the types is important as it affects overriding
/**
* Type representing an enhanced object that combines base object properties with extensions
* @template TName - The name identifier for the enhancer
* @template TBaseObject - The type of the original object being enhanced
* @template TExtension - The type of the extension object adding new functionality
*/
export type Enhanced<
TName extends string,
TBaseObject extends object,
TExtension extends object,
> = { $: TBaseObject; [ENHANCER_NAME]: TName } & TExtension & TBaseObject;

/**
* Enhances an object by combining it with extension methods while maintaining access to the original object
* @template TName - The name identifier for the enhancer
* @template TBaseObject - The type of the object to enhance
* @template TExtension - The type of the extension object containing new methods
* @param name - Unique name for this enhancement
* @param obj - The base object to enhance
* @param extendObj - Object containing extension methods
* @returns A proxy that combines the base object with extension methods
*/
export const enhance = <
TName extends string,
TBaseObject extends object | (object & { [ENHANCER_NAME]: TName; $: object }),
Expand Down Expand Up @@ -36,6 +55,14 @@ export const enhance = <
}) as unknown as Enhanced<TName, TBaseObject, TExtension>;
};

/**
* Creates a reusable enhancer function that applies the same extensions to multiple objects
* @template TName - The name identifier for the enhancer
* @template TExtension - The type of the extension object containing new methods
* @param name - Unique name for this enhancement factory
* @param extendObj - Object containing extension methods
* @returns A function that can enhance objects with the provided extensions
*/
export const enhanceFactory =
<TName extends string, TExtension extends object>(
name: TName,
Expand Down
144 changes: 143 additions & 1 deletion packages/fs-cache/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,143 @@
# @synstack/fs-cache
# @synstack/fs-cache

> File system-based caching with type-safe function memoization

This package provides a strongly-typed caching system that stores function results in the file system, with support for custom cache keys and value locking.

> [!WARNING]
> This package is included in the [@synstack/synscript](https://github.com/pAIrprogio/synscript) package. It is not recommended to install both packages at the same time.

## What is it for?

Sometimes you need to cache expensive function results between program runs. This package makes it easy to cache function outputs to disk with type safety:

```typescript
import { fsCache } from "@synstack/fs-cache";

// Create a cache in the .cache directory
const cache = fsCache(".cache")
.key(["expensive", "function"])
.pretty(true);

// Cache an expensive function
const expensiveFunction = cache.fn(async (input: string) => {
// Simulate expensive operation
await new Promise(resolve => setTimeout(resolve, 1000));
return `Processed: ${input}`;
});

// First call: takes 1 second
await expensiveFunction("test"); // "Processed: test"

// Second call: instant (reads from cache)
await expensiveFunction("test"); // "Processed: test"
```

## Installation

```bash
# Using npm
npm install @synstack/fs-cache

# Using yarn
yarn add @synstack/fs-cache

# Using pnpm
pnpm add @synstack/fs-cache
```

## Features

### Function Caching

Cache expensive function results with type safety:

```typescript
import { fsCache } from "@synstack/fs-cache";

const cache = fsCache(".cache");

// Cache with static key
const cachedFn = cache
.key("myFunction")
.fn((x: number) => x * x);

// Cache with dynamic key based on arguments
const cachedFn2 = cache
.key([
"myFunction",
(arg: string) => arg.length.toString()
])
.fn((arg: string) => arg.toUpperCase());
```

### Cache Control

Fine-grained control over cache behavior:

```typescript
// Pretty-print cached JSON
const cache = fsCache(".cache").pretty(true);

// Custom cache key generation
const cache2 = fsCache(".cache")
.signatureFn((arg: string) => arg.toLowerCase())
.key("normalized");

// Lock cached values
await cache.lock(true, ["key"]); // Prevent updates
await cache.lock(false, ["key"]); // Allow updates

// Manual cache operations
const [status, value] = await cache.get(["key"]);
await cache.set(["key"], "value");
await cache.setDefault(["key"], "default");
```

## API Reference

### FsCache

The main class for file system caching:

#### Creation
- `fsCache(cwd)` - Create cache in working directory
- `key(keys)` - Set cache key or key generators
- `signatureFn(fn)` - Set input signature function
- `pretty(enabled)` - Enable/disable pretty JSON

#### Cache Operations
- `get(args)` - Get cached value
- `set(args, value)` - Set cache value
- `setDefault(args, value)` - Set default value
- `lock(isLocked, args)` - Lock/unlock cached value
- `fn(function)` - Create cached function wrapper

### Types

#### KeyFn
```typescript
type KeyFn<TFnArgs extends any[]> =
| string
| ((...args: TFnArgs) => string);
```

#### SignatureFn
```typescript
type SignatureFn<TFnArgs extends any[]> = (
...args: TFnArgs
) => any;
```

## TypeScript Support

This package is written in TypeScript and provides full type definitions:

- Generic type parameters for function arguments
- Type-safe function wrapping
- Strongly typed cache operations
- IntelliSense support for all methods

## License

Apache-2.0 - see LICENSE file for details.
Loading
Loading