Skip to content

Harineko0/more_visibility

Repository files navigation

more_visibility

Fine-grained visibility control for Dart & Flutter projects

Pub Version CI Dart SDK License: MIT


Why more_visibility?

Dart's built-in visibility is limited to library-private (_identifier) and public (everything else). This works for small projects, but as codebases grow, you often need finer control:

  • 🚫 Prevent accidental imports of internal utilities from parent directories
  • πŸ”’ Keep implementation details scoped to feature modules
  • πŸ“ Enforce architectural boundaries within your codebase

more_visibility brings Java-style visibility modifiers and automatic directory-private enforcement to Dart, making your codebase more maintainable and preventing architectural drift.


✨ Features

  • 🎯 Directory-private enforcement β€” Underscore-prefixed directories (_components, _hooks) are automatically restricted to same-level imports. Zero configuration.
  • πŸ›‘οΈ Java-style annotations β€” @mprotected and @mdefault for fine-grained control over symbol visibility
  • ⚑ Real-time feedback β€” Analysis server plugin catches violations in your IDE as you type
  • πŸ”§ Works with code generation β€” Auto-annotates generated files from Freezed, Riverpod, JsonSerializable, etc.
  • 🎨 Configurable severity β€” Set rules as errors, warnings, or info based on your needs

πŸš€ Quick Start

1. Install

Add to your pubspec.yaml:

dependencies:
  more_visibility_annotation: ^0.1.0

dev_dependencies:
  more_visibility: ^0.1.10

2. Enable the plugin

In your analysis_options.yaml:

include: package:more_visibility/more_visibility.yaml

That's it! The plugin is now active and will enforce visibility rules.


πŸ“– Usage

Directory-private (Automatic)

Simply prefix directories with _ to make them private to their parent directory:

lib/
β”œβ”€β”€ pages/
β”‚   β”œβ”€β”€ page.dart              βœ… Can import _components/
β”‚   β”œβ”€β”€ _components/
β”‚   β”‚   └── button.dart        πŸ”’ Private to lib/pages/
β”‚   └── profile/
β”‚       └── profile_page.dart  ❌ Cannot import _components/

Example:

// βœ… lib/pages/page.dart
import '_components/button.dart'; // Same depth - OK

// ❌ lib/pages/profile/profile_page.dart
import '../_components/button.dart'; // Different depth - ERROR

Note: Only applies to your application code. Dependencies are excluded to avoid false positives.


Annotation-based visibility

Control individual declarations with annotations:

import 'package:more_visibility_annotation/more_visibility_annotation.dart';

// πŸ›‘οΈ Protected: accessible from this directory and subdirectories
@mprotected
final sharedConfig = Config();

// πŸ”’ Module-default: accessible only within this directory
@mdefault
final localHelper = Helper();

File-level annotations:

@mprotected
library feature_auth;

// All declarations inherit @mprotected
class AuthService { }
final authToken = '';

🎨 Visual Examples

Before more_visibility

// lib/utils/internal_helper.dart
String formatSecret(String secret) => '***$secret***';

// lib/features/auth/login.dart
import '../../utils/internal_helper.dart'; // ⚠️ Unintended coupling

// lib/main.dart
import 'utils/internal_helper.dart'; // ⚠️ Internal API exposed

Problems:

  • No enforcement of architectural boundaries
  • Internal utilities leak across module boundaries
  • Difficult to refactor without breaking unknown dependents

After more_visibility

// lib/utils/_internal/helper.dart (in private directory)
String formatSecret(String secret) => '***$secret***';

// lib/features/auth/login.dart
import '../../utils/_internal/helper.dart'; // ❌ Compile-time error!
// Error: `formatSecret` is in a private directory `/lib/utils/_internal`

// lib/utils/public_api.dart
import '_internal/helper.dart'; // βœ… Same depth - OK
export '_internal/helper.dart' show allowedFunction;

Benefits:

  • βœ… Architectural boundaries enforced at compile-time
  • βœ… Clear separation between public API and internal implementation
  • βœ… Refactoring is safer with explicit visibility scopes

πŸ“š Documentation

Topic Description
Visibility Rules Detailed explanation of all visibility rules
Usage Guide Step-by-step usage instructions and patterns
Auto-annotation Configuring builders for generated code

βš™οΈ Configuration

Adjusting severity

analyzer:
  errors:
    directory_private: warning                  # Default: error
    more_visibility_protected: info             # Default: error
    more_visibility_module_default: ignore      # Disable completely

Disabling rules

plugins:
  more_visibility:
    diagnostics:
      directory_private: false              # Disable directory-private rule
      more_visibility_protected: false      # Disable @mprotected checks

Ignoring specific violations

// ignore_for_file: directory_private

// ignore: more_visibility_protected
import '../protected_api.dart';

πŸ”§ Auto-annotation for Generated Code

Works seamlessly with Freezed, Riverpod, JsonSerializable, and other code generators.

build.yaml:

post_process_builders:
  more_visibility:auto_annotate:
    options:
      visibility: mprotected  # Default annotation for generated files

Generated files automatically inherit visibility from their source files:

// user.dart
@mprotected
@freezed
class User with _$User {
  // ...
}

// user.freezed.dart (generated)
@mprotected  // ← Automatically added
part of 'user.dart';
// ...

πŸ“¦ Requirements

  • Dart SDK: 3.10.0 or later
  • Flutter SDK: 3.38.0 or later (if using Flutter)

🀝 Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


🌟 Star History

If you find this package useful, please consider giving it a star on GitHub!


Made with ❀️ for the Dart & Flutter community

Documentation β€’ Issues β€’ Pub.dev

About

A tiny static analyzer that adds Java-style visibility boundaries to Dart code using annotations

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages