Metadata-Version: 2.1
Name: wexample-filestate-flutter
Version: 6.6.6
Summary: Extends wexample-filestate with Flutter/Dart file targets and a Docker-backed dart fix + dart format content option.
Author-Email: weeger <contact@wexample.com>
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Requires-Dist: attrs>=23.1.0
Requires-Dist: cattrs>=23.1.0
Requires-Dist: wexample-filestate>=17.0.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Description-Content-Type: text/markdown

# filestate_flutter

Version: 6.6.6

`wexample-filestate-flutter` extends [wexample-filestate](https://pypi.org/project/wexample-filestate/) with Flutter and Dart support: it adds a `FlutterFile` target that enforces the `.dart` extension, and a `DartFormatOption` that runs `dart fix --apply && dart format` inside a dedicated Docker container built from src/wexample_filestate_flutter/resources/docker/Dockerfile.flutter-option, eliminating any dependency on a local Flutter or Dart SDK. It is intended for Python developers who use `wexample-filestate` to manage file state in Flutter or Dart projects.

## Table of Contents

- [Installation](#installation)
- [Quickstart](#quickstart)
- [Tests](#tests)
- [Architecture](#architecture)
- [Integration in the Suite](#integration-in-the-suite)
- [Dependencies](#dependencies)
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
- [License](#license)
- [About us](#about-us)
- [Known Limitations & Roadmap](#known-limitations--roadmap)
- [Status & Compatibility](#status--compatibility)
- [Useful Links](#useful-links)
- [Migration Notes](#migration-notes)

## Installation

```bash
pip install wexample-filestate-flutter
```

Requires Python >=3.10.

## Quickstart

Install the package:

```bash
pip install wexample-filestate-flutter
```

The example below declares that `main.dart` inside an existing Flutter project must be processed with `dart fix --apply && dart format`. `apply()` runs both commands inside a Docker container built from the bundled src/wexample_filestate_flutter/resources/docker/Dockerfile.flutter-option, then writes the result back to disk if the content changed:

```python
from wexample_filestate.options_provider.default_options_provider import DefaultOptionsProvider
from wexample_filestate.utils.file_state_manager import FileStateManager
from wexample_filestate_flutter.file.flutter_file import FlutterFile
from wexample_filestate_flutter.options_provider.flutter_options_provider import FlutterOptionsProvider
from wexample_prompt.common.io_manager import IoManager

manager = FileStateManager.create_from_path(
    path="/path/to/my_flutter_project",
    io=IoManager(),
    options_providers=[DefaultOptionsProvider, FlutterOptionsProvider],
)
manager.configure({
    "children": [
        {
            "class": FlutterFile,
            "name": "main.dart",
            "flutter": {
                "dart_format": True,
            },
        }
    ]
})
result = manager.apply()
```

`options_providers` must include both `DefaultOptionsProvider` (which supplies the standard file-state options) and `FlutterOptionsProvider` (which adds the `flutter` key). The `class: FlutterFile` entry tells the manager to instantiate a `FlutterFile` instead of a generic `ItemTargetFile`; `FlutterFile` enforces the `.dart` extension.

`apply()` returns a `FileStateResult`. Its `.operations` list contains one entry when the file was reformatted, and is empty when the file already matched the output of `dart format`:

```python
if result.operations:
    print(f"{len(result.operations)} file(s) updated")
else:
    print("nothing to do")
```

Docker must be running on the host. The container is built automatically on first use; subsequent calls reuse it. `flutter pub get` is re-run inside the container whenever a new project root is encountered in the same Python process.

## Tests

This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.

### Installation

First, install the required testing dependencies:
```bash
.venv/bin/python -m pip install pytest pytest-cov
```

### Basic Usage

Run all tests with coverage:
```bash
.venv/bin/python -m pytest --cov --cov-report=html
```

### Common Commands
```bash
# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
```

### Viewing HTML Reports

After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.

### Coverage Threshold

To enforce a minimum coverage percentage:
```bash
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
```

This will cause the test suite to fail if coverage drops below 80%.

## Architecture

`wexample-filestate-flutter` is a thin extension layer on top of `wexample-filestate`. It adds one file target type, one nested config option, one concrete content option, and the Docker image that makes that option work without a local Flutter SDK. The five source modules map cleanly onto those four concerns.

### File target

src/wexample_filestate_flutter/file/flutter_file.py defines `FlutterFile`, a subclass of `ItemTargetFile`. Its only addition is `EXTENSION_ENV = "dart"`, which the base class uses to enforce that the target file carries a `.dart` extension. Constants for that extension live separately in src/wexample_filestate_flutter/const/flutter_file.py.

### Option layer

### FlutterOption

src/wexample_filestate_flutter/option/flutter_option.py is the entry point from the config tree. It inherits `AbstractNestedConfigOption` and two mixins—`OptionMixin` and `WithBatchDockerOptionMixin`—and registers itself at `Scope.CONTENT`. Its `get_allowed_options` method returns the list of child options (currently only `DartFormatOption`). `set_value` normalises a list of option names to a `dict` before passing the value upstream, so both `[dart_format]` and `{dart_format: true}` are valid.

`create_required_operation` delegates entirely to `_create_child_required_operation`, which iterates the child options and lets each one produce its own operation.

### FlutterConfigValue

src/wexample_filestate_flutter/config_value/flutter_config_value.py is the typed dataclass for the `flutter` key. It exposes a single `dart_format: bool | None` field and serialises back to `{"dart_format": self.dart_format}` via `to_option_raw_value`. This is the structured alternative to passing a plain dict.

### DartFormatConfigOption

src/wexample_filestate_flutter/config_option/dart_format_config_option.py is a minimal `AbstractConfigOption` whose `get_name` returns `"dart_format"`. It exists so the config system can look up the option by name.

### Content options

### AbstractFlutterFileContentOption

src/wexample_filestate_flutter/option/flutter/abstract_flutter_file_content_option.py is the base for all Flutter content operations. It mixes in `WithBatchDockerOptionMixin` and `AbstractFileContentOption`. Key responsibilities:

- `DOCKER_IMAGE_NAME = "flutter-option"` — the name under which the Docker image is registered.
- `_DOCKERFILE_PATH` — resolved once at class-definition time to `resources/docker/Dockerfile.flutter-option`.
- `_cleanup_host_cache` — removes `.dart_tool/` and `.packages` from the project root before any container run, because those files contain host-absolute paths that break inside the container.
- `_prepare_container_environment` — called once per Python process per project root. It cleans the cache, ensures the container is running, and executes `flutter pub get` (falling back to `dart pub get`) inside the container so that `package_config.json` is generated with container-internal paths.
- `_run_from_container_root` — convenience wrapper that prepends `export PATH=…` and `cd /var/www/html` to any shell command before passing it to `_execute_in_docker`.

The class-level set `_prepared_roots` prevents `pub get` from running more than once per root across multiple files processed in the same Python process.

### DartFormatOption

src/wexample_filestate_flutter/option/flutter/dart_format_option.py is the only concrete content option currently shipped. `_apply_content_change` does three things in sequence:

1. Calls `_prepare_container_environment` to ensure the container is ready.
2. Runs `dart fix --apply <file> && dart format <file>` as a single `bash -lc` command through `_run_from_container_root`, which halves the number of `docker exec` round-trips.
3. Reads and returns the file content after it has been modified in place by the container process.

### Options provider

src/wexample_filestate_flutter/options_provider/flutter_options_provider.py implements `AbstractOptionsProvider`. `get_options` returns `[FlutterOption]`; `get_docker_image_name` forwards to `AbstractFlutterFileContentOption.DOCKER_IMAGE_NAME`. This is the registration point through which the parent `wexample-config` system discovers what this package contributes.

### Docker image

src/wexample_filestate_flutter/resources/docker/Dockerfile.flutter-option builds from `ghcr.io/cirruslabs/flutter:stable`, adjusts ownership of the Flutter SDK for UID 1000, copies src/wexample_filestate_flutter/resources/docker/analysis_options.yaml into the image, and keeps the container alive with `tail -f /dev/null`. The working directory is `/var/www/html`, which is what `_CONTAINER_ROOT` in the abstract base class points to.

### Call path through the layers

Given a `FlutterFile` configured with `flutter: [dart_format]`:

1. `FlutterOption.set_value` converts the list to `{"dart_format": True}`.
2. `FlutterOption.create_required_operation` calls `_create_child_required_operation`, which resolves `DartFormatOption` from `get_allowed_options`.
3. `DartFormatOption._apply_content_change` calls `_prepare_container_environment`: the host cache is wiped, the Docker container is started from `Dockerfile.flutter-option`, and `pub get` runs inside it (skipped on subsequent files from the same root).
4. A single `docker exec bash -lc "dart fix --apply <file> && dart format <file>"` runs.
5. The modified file is read back from disk and returned as the new content.

## Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

### Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.

## Dependencies

- attrs: >=23.1.0
- cattrs: >=23.1.0
- wexample-filestate: >=17.0.0

## Versioning & Compatibility Policy

Wexample packages follow **Semantic Versioning** (SemVer):

- **MAJOR**: Breaking changes
- **MINOR**: New features, backward compatible
- **PATCH**: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

Free to use in both personal and commercial projects.

## About us

[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

## Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the [project roadmap](https://github.com/wexample/python-filestate_flutter/issues) for upcoming features and improvements.

## Status & Compatibility

**Maturity**: Production-ready

**Python Support**: >=3.10

**OS Support**: Linux, macOS, Windows

**Status**: Actively maintained

## Useful Links

- **Homepage**: https://github.com/wexample/python-filestate-flutter
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
- **Issue Tracker**: https://github.com/wexample/python-filestate-flutter/issues
- **Discussions**: https://github.com/wexample/python-filestate-flutter/discussions
- **PyPI**: [pypi.org/project/wexample-filestate-flutter](https://pypi.org/project/wexample-filestate-flutter/)

## Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.
