An open API service indexing awesome lists of open source software.

https://github.com/gosuperscript/axiom


https://github.com/gosuperscript/axiom

Last synced: 5 months ago
JSON representation

Awesome Lists containing this project

README

          

# Axiom Library

A powerful PHP library for data transformation, type validation, and expression evaluation. This library provides a flexible framework for defining data schemas, transforming values, and evaluating complex expressions with type safety.

## Features

- **Type System**: Robust type validation and transformation for numbers, strings, booleans, lists, and dictionaries
- **Expression Evaluation**: Support for infix expressions with custom operators
- **Resolver Pattern**: Pluggable resolver system for different data sources
- **Symbol Registry**: Named value resolution and reuse
- **Operator Overloading**: Extensible operator system for custom evaluation logic
- **Monadic Error Handling**: Built on functional programming principles using Result and Option types

## Requirements

- PHP 8.4 or higher
- ext-intl extension

## Installation

```bash
composer require gosuperscript/axiom
```

## Quick Start

### Basic Type Transformation

```php
resolve($source);
$value = $result->unwrap()->unwrap(); // 42 (as integer)
```

### Expression Evaluation

```php
instance(SymbolRegistry::class, new SymbolRegistry([
'PI' => new StaticSource(3.14159),
'radius' => new StaticSource(5),
]));

// Calculate: PI * radius * radius (area of circle)
$expression = new InfixExpression(
left: new SymbolSource('PI'),
operator: '*',
right: new InfixExpression(
left: new SymbolSource('radius'),
operator: '*',
right: new SymbolSource('radius')
)
);

$result = $resolver->resolve($expression);
$area = $result->unwrap()->unwrap(); // ~78.54
```

### Using Namespaced Symbols

The `SymbolRegistry` supports namespaces to organize related symbols:

```php
new StaticSource('1.0.0'),
'debug' => new StaticSource(true),

// Math namespace
'math' => [
'pi' => new StaticSource(3.14159),
'e' => new StaticSource(2.71828),
'phi' => new StaticSource(1.61803),
],

// Constants namespace
'physics' => [
'c' => new StaticSource(299792458), // Speed of light
'g' => new StaticSource(9.80665), // Gravitational acceleration
],
]);

// Access global symbols
$version = $registry->get('version'); // Some('1.0.0')

// Access namespaced symbols
$pi = $registry->get('pi', 'math'); // Some(3.14159)
$c = $registry->get('c', 'physics'); // Some(299792458)

// Using with SymbolSource
$symbolSource = new SymbolSource('pi', 'math');
$result = $resolver->resolve($symbolSource); // ~3.14159

// Namespaces provide isolation
$registry->get('pi'); // None (no global 'pi')
$registry->get('c', 'math'); // None (no 'c' in math namespace)
```

## Core Concepts

### Types

The library provides several built-in types for data validation and coercion:

#### NumberType
Validates and coerces values to numeric types (int/float):
- Numeric strings: `"42"` → `42`
- Percentage strings: `"50%"` → `0.5`
- Numbers: `42.5` → `42.5`

#### StringType
Validates and coerces values to strings:
- Numbers: `42` → `"42"`
- Stringable objects: converted to string representation
- Special handling for null and empty values

#### BooleanType
Validates and coerces values to boolean:
- Truthy/falsy evaluation
- String representations: `"true"`, `"false"`

#### ListType and DictType
For collections and associative arrays with nested type validation.

### Type API: Assert vs Coerce

The `Type` interface provides two methods for value processing, following the [@azjezz/psl](https://github.com/azjezz/psl) pattern:

- **`assert(T $value): Result>`** - Validates that a value is already of the correct type
- **`coerce(mixed $value): Result>`** - Attempts to convert a value from any type to the target type

**When to use:**
- Use `assert()` when you expect a value to already be the correct type and want strict validation
- Use `coerce()` when you want to transform values from various input types (permissive conversion)

**Example:**
```php
$numberType = new NumberType();

// Assert - only accepts int/float
$result = $numberType->assert(42); // Ok(Some(42))
$result = $numberType->assert('42'); // Err(TransformValueException)

// Coerce - converts compatible types
$result = $numberType->coerce(42); // Ok(Some(42))
$result = $numberType->coerce('42'); // Ok(Some(42))
$result = $numberType->coerce('45%'); // Ok(Some(0.45))
```

Both methods return `Result, Throwable>` where:
- `Ok(Some(value))` - successful validation/coercion with a value
- `Ok(None())` - successful but no value (e.g., empty strings)
- `Err(exception)` - failed validation/coercion

**Note:** The `coerce()` method provides the same functionality as the previous `transform()` method.

### Sources

Sources represent different ways to provide data:

- **StaticSource**: Direct values
- **SymbolSource**: Named references to other sources (with optional namespace support)
- **TypeDefinition**: Combines a type with a source for validation and coercion
- **InfixExpression**: Mathematical/logical expressions
- **UnaryExpression**: Single-operand expressions

### Symbol Registry

The `SymbolRegistry` provides a centralized way to manage named values and organize them using namespaces:

**Key Features:**
- **Global Symbols**: Direct symbol registration without namespace isolation
- **Namespaced Symbols**: Group related symbols under namespaces for better organization
- **Isolation**: Symbols in different namespaces are isolated from each other
- **Type Safety**: Only `Source` instances can be registered

**Registration Format:**
```php
new SymbolRegistry([
'globalSymbol' => new StaticSource(value), // Global scope
'namespace' => [ // Namespaced scope
'symbol1' => new StaticSource(value1),
'symbol2' => new StaticSource(value2),
],
])
```

**Use Cases:**
- Organize constants by category (math, physics, config)
- Prevent naming conflicts between different domains
- Create clear separation between different symbol contexts
- Improve code maintainability with logical grouping

### Resolvers

Resolvers handle the evaluation of sources:

- **StaticResolver**: Resolves static values
- **ValueResolver**: Applies type coercion using the `coerce()` method
- **InfixResolver**: Evaluates binary expressions
- **SymbolResolver**: Looks up named symbols
- **DelegatingResolver**: Chains multiple resolvers together

### Operators

The library supports various operators through the overloader system:

- **Binary**: `+`, `-`, `*`, `/`, `%`, `**`
- **Comparison**: `==`, `!=`, `<`, `<=`, `>`, `>=`
- **Logical**: `&&`, `||`
- **Special**: `has`, `in`, `intersects`

## Advanced Usage

### Custom Types

Implement the `Type` interface to create custom data validations and coercions:

```php
, Throwable>` types:

- `Result::Ok(Some(value))`: Successful validation/coercion with value
- `Result::Ok(None())`: Successful validation/coercion with no value (null/empty)
- `Result::Err(exception)`: Validation/coercion failed with error

This approach ensures:
- No exceptions for normal control flow
- Explicit handling of success/failure cases
- Type-safe null handling

## License

This library is open-sourced software licensed under the [MIT license](LICENSE).

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.

## Security

If you discover any security-related issues, please review our [Security Policy](SECURITY.md) for information on how to responsibly report vulnerabilities.