# S2DM Tools

This directory contains various tools for working with S2DM schemas and generated artifacts.

## Available Tools

### Unified S2DM Logger

The S2DM Logger (`../logger.py`) provides a unified logging system that combines Python's standard logging with CLI-specific formatting methods. This single logger handles both internal logging (with levels, file output) and user-facing CLI output.

#### Features

- **Standard logging** - DEBUG, INFO, WARNING, ERROR, CRITICAL levels with file output support
- **User-facing messages** - success(), user_error(), user_warning(), user_info() with icons
- **Structured output** - Key-value pairs, highlighted text, list items
- **Rich formatting** - Colors, styles, rules/separators via RichHandler
- **Single source of truth** - One logger for all output needs

#### API Reference

**Standard Logging Methods**:

| Method | Description | Example |
|--------|-------------|---------|
| `debug(message)` | Debug-level logging | `log.debug("Loading config")` |
| `info(message)` | Info-level logging | `log.info("Processing files")` |
| `warning(message)` | Warning-level logging | `log.warning("Update available")` |
| `error(message)` | Error-level logging | `log.error("Failed to load file")` |
| `critical(message)` | Critical-level logging | `log.critical("System failure")` |

**Special Display Methods**:

| Method | Description | Example |
|--------|-------------|---------|
| `success(message)` | Green message with ✓ icon | `log.success("Operation completed")` |
| `hint(message)` | Dimmed secondary message | `log.hint("Use --help for options")` |

**Formatting Helpers**:

| Method | Description | Example |
|--------|-------------|---------|
| `print(message)` | Plain Rich-formatted message | `log.print("Plain text")` |
| `print_json(data)` | JSON with syntax highlighting | `log.print_json(json_string)` |
| `colored(message, style)` | Custom styled message | `log.colored("Custom", "cyan")` |
| `rule(title, style)` | Horizontal separator with title | `log.rule("Results")` |
| `key_value(key, value, key_style)` | Formatted key-value pair | `log.key_value("Type", "Vehicle")` |
| `list_item(text, prefix, style)` | Formatted list item | `log.list_item("Field", "  •")` |

#### Usage Examples

**Standard Logging (use for everything):**
```python
from s2dm import log

# Standard Python logging - works for both internal and user-facing
log.debug("Schema validation starting")
log.info("Processing 10 files")
log.warning("Update available")
log.error("Failed to load file")

# Special display method (only one!)
log.success("Units are up to date")

# Formatting helpers
log.hint("Use --help for more options")
log.rule("Search Results")
log.colored("Vehicle", "green")
log.key_value("Type", "Vehicle")
log.list_item("id: String", prefix="  •")
```

#### Design Notes

- **Simple & Pythonic**: Use standard logging methods (`info`, `warning`, `error`) for everything
- **Only one special method**: `success()` is the only custom display method (logging doesn't have this)
- **RichHandler does the magic**: Automatic colors, nice formatting via RichHandler
- **Log levels**: Support DEBUG, INFO, WARNING, ERROR, CRITICAL with file output
- **No confusion**: Just use Python's standard logging - it's already great!
- **DRY principles**: Formatting helpers (`colored`, `hint`, `rule`, `key_value`) reuse base methods

### SKOS Search Service

The SKOS Search Service provides efficient SPARQL-based search functionality for SKOS RDF data generated by S2DM. Features include:

- **Configurable result limits** - Default 10 results, customizable via `--limit` option
- **Unlimited search** - Use special keywords (`inf`, `no`, `unlimited`, etc.) for no limit
- **Case-sensitive/insensitive matching** - Flexible search options
- **SPARQL-based queries** - Efficient and scalable for large RDF datasets

For detailed usage examples and documentation, see [examples/graphql-to-skos/README.md](../../examples/graphql-to-skos/README.md#searching-skos-concepts).

### GraphQL Inspector

The GraphQL Inspector wrapper (`graphql_inspector.py`) provides a Python interface to the `@graphql-inspector/cli` Node.js tool for GraphQL schema analysis.

#### Architecture

**Decorator Pattern:**
- `@requires_graphql_inspector` - Automatically locates and injects the `node_modules` path to CLI commands
- Applied to CLI commands that need GraphQL Inspector functionality
- The decorator calls `locate_graphql_inspector()` to find the installation

**Location Resolution:**
- `locate_graphql_inspector()` - Searches upward from current directory for `node_modules`
- Handles both local project installations and global installations
- Resolves the CLI path once during `GraphQLInspector.__init__()` for performance

**Dependency Checking:**
- `_check_node_dependencies()` - Verifies npm packages can be loaded by Node.js
- More reliable than file existence checks (catches broken installations)
- Used by `diff_structured()` which directly requires npm packages

#### Key Features

- **CLI Operations**: `diff()`, `validate()`, `introspect()`, `similar()` - Use the graphql-inspector CLI binary
- **Structured Diff**: `diff_structured()` - Uses custom Node.js script for JSON output (requires npm packages)
- **Automatic Fallback**: Tries local installation first, falls back to global installation
- **Clear Error Messages**: Guides users to install missing dependencies

#### Usage in CLI Commands

CLI commands decorated with `@requires_graphql_inspector` automatically receive an `inspector_path` parameter:

```python
@requires_graphql_inspector
def diff_graphql(..., inspector_path: Path | None = None) -> None:
    inspector = GraphQLInspector(schema_path, node_modules_path=inspector_path)
    result = inspector.diff_structured(other_schema)
```

See `graphql_inspector.py` for detailed implementation.

### Constraint Checker

Tool for validating constraints in GraphQL schemas. See `constraint_checker.py` for implementation details.

## Development

When adding new tools to this directory:

1. Follow the existing code structure with proper typing annotations
2. Add comprehensive docstrings using PEP 257 convention
3. Include error handling and logging
4. Create corresponding test files in the `tests/` directory
5. Update this README with documentation for the new tool

## Testing

Run tests for the tools using pytest:

```bash
# Run all tool tests
pytest tests/test_*_tools.py

# Run specific SKOS search tests
pytest tests/test_skos_search.py

# Run with coverage
pytest --cov=s2dm.tools tests/
```
